Используя несколько аргументов mips>4

Я пытаюсь запрограммировать функцию на использование дополнительных аргументов помимо 4 (поскольку моя версия mips поддерживает только $a0-$a3), помещая их в стек, но мой код неверен. Вот мой код в основном (фрагмент):

li $t0,40 #temp value for our 5th arg.

addi $sp, $sp, -4 #decrement stack pointer by 4
sw $t0, 0($sp) #save the value of $t0 on the stack.

jal printf

который устанавливает временное значение 40, освобождает место в стеке и сохраняет его. Моя функция тогда вызывается. Чтобы проверить, сработало ли это, внутри функции, когда я перемещаю эти временные аргументы $ a0- $ a3 в их сохраненные аналоги-регистры, у меня есть этот код:

lw $t0, 0($sp) 
addi $sp, $sp, 4
move $a0,$t0

li $v0, 1
syscall

... но он выводит только 0, а не 40, так что я делаю что-то неправильно. Любая помощь будет принята с благодарностью (и одобрение)

3 ответа

Решение

В наиболее распространенном 32-битном соглашении о вызовах MIPS пространство в стеке зарезервировано для $a0,$a1,$a2 а также $a3поэтому вызываемая функция должна ожидать найти 5-й аргумент в 16($sp),

Самый простой способ выяснить это - написать пустую версию вашей функции на C и разобрать .o файл, чтобы выяснить, как аргументы передаются компилятором.

Есть две проблемы, с которыми вы сталкиваетесь, глядя на полный код, который вы указали выше.

1) Ваш стек неправильно настроен для использования аргументов (особенно более четырех) для стандартных соглашений о вызовах MIPS o32. Другие ответы хорошо помогают вам в этом.

2) Используемый вами printf не использует стандартное соглашение о вызовах. Если вы видите комментарии:

## printf--
## A simple printf-like function. Understands just the basic forms
## of the %s, %d, %c, and %% formats, and can only have 3 embedded
## formats (so that all of the parameters are passed in registers).
## If there are more than 3 embedded formats, all but the first 3 are
## completely ignored (not even printed).
## Register Usage:
## $a0,$s0 - pointer to format string
## $a1,$s1 - format argument 1 (optional)
## $a2,$s2 - format argument 2 (optional)
## $a3,$s3 - format argument 3 (optional)
## $s4 - count of formats processed.
## $s5 - char at $s4.
## $s6 - pointer to printf buffer

Ожидается, что ничего не будет передано в стек. (Помните, что $s0-6 не связаны со стеком). Вы можете предоставить этой функции строку формата $a0-> и 3 аргумента (в $a1, $a2 и $a3). Обратите внимание, что в этих комментариях говорится, что он уничтожает $s0-$s6, хотя из неполного кода я могу сказать, сколько восстанавливается, не отслеживая его. Короче говоря, этот printf, который вы нашли, может быть удобен, но он не использует соглашения о стеке, которые вы должны изучать, и он довольно ограничен. Предполагая, что у вас есть разрешение на его использование, посмотрите, как получить разрешение на изменение и просто перепишите интерфейс на что-то вменяемое. Имейте в виду, что необходимость вызывать функцию несколько раз, если вам нужно вывести более 3 переменных одновременно, не имеет большого значения (если это так, просто напишите обертку).

Этот код абсолютно правильный, поэтому проблема кроется в другом. Мое лучшее предположение состоит в том, что указатель стека не был правильно обработан до этого момента в вашем коде или в printf у вас есть ошибка, прежде чем выскочить из стека. Почему бы не использовать отладчик, чтобы увидеть, что происходит? Если вы можете, опубликуйте работающую программу с удалением всего ненужного кода, который демонстрирует проблему. Вот рабочая программа MIPS, которая делает то, что вы пытаетесь сделать, и использует те же инструкции.

Другие вопросы по тегам