Почему подпрограммы MIPS возвращаются с помощью jr
, а x86 возвращаются с использованием ret
?
Почему в MIPS нет инструкции ret
?
В качестве альтернативы, почему x86 не использует jr
?
В x86 инструкция call помещает адрес возврата в память стека. В MIPS инструкция вызова (jal
) помещает обратный адрес в регистр.
В x86 инструкция ret удаляет адрес возврата из стека и переходит к нему. Философия MIPS не объединяет отдельные шаги в одну инструкцию. Это значительно упрощает набор инструкций. Удаление значения из стека и выполнение перехода — это отдельные операции, требующие отдельных инструкций. В частном случае вызова/возврата это также имеет то преимущество, что в листовой функции вообще нет необходимости записывать адрес возврата в память.
В X86 есть эквивалент инструкции jr, jmp r/m32
, с назначением, указанным в виде регистра. Эта инструкция обычно не используется для возврата из функции, потому что тогда потребуется отдельная инструкция для извлечения адреса возврата из стека в регистр (но я написал код, который делает именно это в особых случаях).
Особыми обстоятельствами была ситуация, когда я реализовывал функцию varargs, а-ля printf, но хотел очистить вызываемый объект. (Обычно очистка вызываемого объекта не используется с функциями с переменным числом аргументов, но это то, что я хотел, поэтому я так и сделал.) (en.wikipedia.org/wiki/X86_calling_conventions#Callee_clean-up)
По сути, это вопрос: «Почему в английском прилагательные ставятся перед существительным, а во французском — после?» Это разные процессоры, разработанные разными людьми, что привело к разным вариантам дизайна. (У MIPS нет архитектурного стека, так откуда
ret
взять обратный адрес?)