Вы правы, заметив, что первый факториал хранится над указателем стека, стековым хранилищем, которое он не выделил и должен был быть выделен вызывающей стороной.
Это несколько нестандартное использование,но технически законно, так как соглашение о вызовах MIPS требует предоставления вызываемой верхних 4 местоположений стека любого фрейма стека. Функция выделяет только фрейм из 2 слов, и в соответствии с соглашением о вызовах (которое позволяет вызываемому абоненту использовать верхние 4 слова фрейма) она должна выделять как минимум фрейм из 4 слов.
Тем не менееПоскольку факториальная функция не вызывает ничего другого, кроме себя, это является законным и соответствует соглашению о вызовах - в том смысле, что ее задача заключается в обеспечении того, чтобы одна функция могла вызывать другую.
(Обратите внимание, что вRISC V (продолжение MIPS с открытым исходным кодом) этого требования в отношении стека из 4 слов для вызываемого абонента не существует, поэтому подобное не будет работать там.)
Второй пример более традиционный,тем не менее, он также не выделяет рамку стандартного размера - ту, которая дает 4 лучших слова для вызываемой стороны. Тем не менее, это также не является технически необходимым и менее зависимым от исходного вызывающего абонента (например, main
), обеспечивающего правильный кадр стека (один с 4 словами, передаваемыми вызываемому абоненту).
Давайте еще заметим, чтопервый пример кода хранит $ra
и $a0
в стеке, которые являются регистрами, которые мы ожидаем сохранить, тогда как во втором примере хранится $s0
(который мы ожидаем сохранить, поскольку они выделены как энергонезависимые), но также $t0
и $t1
, которые кажутся нестандартными, поскольку они являются выделенными временными.