.data
.text
main:
# 5 parameters
li $s0, 2
li $s1, 3
li $s2, 5
li $s3, 10
li $s4, 20
addi $sp, $sp, -20 # 5 Words are 5 * 4 bytes
sw $s0, 0($sp)
sw $s1, 4($sp)
sw $s2, 8($sp)
sw $s3, 16($sp)
sw $s4, 20($sp)
jal addFiveNumbers
# free stack
addi $sp, $sp, 20
# print the result in $v0
move $a0, $v0
li $v0, 1
syscall
# terminate program
li $v0, 10
syscall
addFiveNumbers:
lw $t0, 0($sp)
lw $t1, 4($sp)
lw $t2, 8($sp)
lw $t3, 16($sp)
lw $t4, 20($sp)
add $v0, $t0, $t1
add $v0, $v0, $t2
add $v0, $v0, $t3
add $v0, $v0, $t4
jr $ra
我接受了这个程序from here。
假设,我想添加10个值。
由于只有8个$ s寄存器,如何传递10个参数?
首先,你问题中的代码是在堆栈上传递args,而不是遵循通常的C调用约定,并且没有触及任何$s
寄存器,所以我不明白为什么你认为这是相关的。你如何使用被调用者中的args显然受到机器中可用寄存器数量的限制,但这与你传递它们的方式是分开的。
正常的MIPS调用约定在$a0..$a3
中传递args。 a
代表争论。 $s
寄存器是调用保留的,通常不用于arg传递。
与所有正常的ISA一样,MIPS上的标准C调用约定会在堆栈中传递args,这些args不适合寄存器。 (或者因为它是一个值大的结构,或者因为已经存在4个寄存器args。)
查看https://godbolt.org/上用于MIPS GCC的C编译器输出,以获取传递或接收10个参数的函数,以查看它在哪里查找它们。 (也许将每个arg存储到volatile int sink
,因此您可以通过优化进行编译,但仍然可以看到它做了些什么。)
如果您在asm中写信给调用者和被调用者,您显然可以编写您想要的任何自定义调用约定。如果我想传递超过4个寄存器args,我认为自然的选择可能是在填充$t0..$t9
后使用$v0..$v1
和/或$a0..$a3
。
但是可以肯定的是,如果我想传递调用者不会破坏的一些只读参数,那么$s
寄存器将适用于那些。我不知道任何具有任何调用保留的arg传递寄存器的ISA的C调用约定,但它在asm中非常有意义。
此时,您只使用一个调用者,但可能来自同一函数中的多个调用点,并且可能根据调用者的方便选择寄存器。所以它几乎不是一个独立的功能。但那没关系。