如何在 MIPS 中传递 10 个参数?
how can I pass 10 arguments in MIPS?
.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个参数?
首先,你问题中的代码是在堆栈上传递参数,没有遵循通常的 C 调用约定,也没有触及任何 $s
寄存器,所以我不明白为什么你认为这是相关的。你如何在被调用者内部使用参数显然受机器中可用寄存器数量的限制,但这与你如何传递它们是分开的。
正常的 MIPS 调用约定在 $a0..$a3
中传递参数。 a
代表参数。 $s
寄存器是调用保留的,通常不用于 arg 传递。
MIPS 上的标准 C 调用约定,就像在所有普通 ISA 上一样,为不适合寄存器的参数在堆栈上传递参数。(要么是因为它是一个大按值构造,或者因为已经有 4 个寄存器参数。)
查看 MIPS GCC https://godbolt.org/ 上的 C 编译器输出,了解传递或接收 10 个参数的函数,看看它在哪里寻找它们。 (也许将每个 arg 存储到一个 volatile int sink
,这样你就可以进行优化编译,并且仍然可以看到它做了一些事情。)
如果您在 asm 中写信给调用者和被调用者,显然 可以 编写您想要的任何自定义调用约定。如果我想传递超过 4 个寄存器参数,我认为自然的选择可能是在填充 $a0..$a3
.
之后使用 $t0..$t9
and/or $v0..$v1
但是可以肯定的是,如果我想传递一些调用者不会破坏的只读参数,$s
寄存器将适合这些参数。我不知道任何具有任何调用保留 arg 传递寄存器的 ISA 的 C 调用约定,但它在 asm 中非常有意义。
那时您只将它与一个调用者一起使用,但可能来自同一函数中的多个调用站点,并且可能会根据该调用者的方便选择寄存器。所以它几乎不是一个独立的功能。不过没关系。
.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个参数?
首先,你问题中的代码是在堆栈上传递参数,没有遵循通常的 C 调用约定,也没有触及任何 $s
寄存器,所以我不明白为什么你认为这是相关的。你如何在被调用者内部使用参数显然受机器中可用寄存器数量的限制,但这与你如何传递它们是分开的。
正常的 MIPS 调用约定在 $a0..$a3
中传递参数。 a
代表参数。 $s
寄存器是调用保留的,通常不用于 arg 传递。
MIPS 上的标准 C 调用约定,就像在所有普通 ISA 上一样,为不适合寄存器的参数在堆栈上传递参数。(要么是因为它是一个大按值构造,或者因为已经有 4 个寄存器参数。)
查看 MIPS GCC https://godbolt.org/ 上的 C 编译器输出,了解传递或接收 10 个参数的函数,看看它在哪里寻找它们。 (也许将每个 arg 存储到一个 volatile int sink
,这样你就可以进行优化编译,并且仍然可以看到它做了一些事情。)
如果您在 asm 中写信给调用者和被调用者,显然 可以 编写您想要的任何自定义调用约定。如果我想传递超过 4 个寄存器参数,我认为自然的选择可能是在填充 $a0..$a3
.
$t0..$t9
and/or $v0..$v1
但是可以肯定的是,如果我想传递一些调用者不会破坏的只读参数,$s
寄存器将适合这些参数。我不知道任何具有任何调用保留 arg 传递寄存器的 ISA 的 C 调用约定,但它在 asm 中非常有意义。
那时您只将它与一个调用者一起使用,但可能来自同一函数中的多个调用站点,并且可能会根据该调用者的方便选择寄存器。所以它几乎不是一个独立的功能。不过没关系。