MIPS:将 `$ra` 保存到堆栈以用于嵌套函数
MIPS: saving `$ra` to stack for nested functions
我是 MIPS 的新手,正在尝试找出 return 嵌套函数中的值。我试图弄清楚为什么在函数 test
中,当我从堆栈加载 $ra
时,它会在我调用 main
中的 calcs
函数之后将我带到指令而不是calcs
函数中 jal test
之后的指令?是否为每个函数都创建了一个新堆栈?
当我在 test
函数中时,堆栈中应该有 2 个 $ra
值,当我加载 $ra
中的最后一个值时,它应该是 return 我在 calcs
函数中 jal test
之后的指令,但那没有发生,我不明白为什么。
.data
newline: .asciiz " XXXX "
.text
main:
addi $s0, [=10=], 39 # val 1
addi $s1, [=10=], 2 # val 2
addi $s2, [=10=], 14 # val 3
addi $s3, [=10=], 11 # val 4
add $a0, [=10=], $s0 # copy val 1 to $a0
add $a1, [=10=], $s1 # copy val 2 to $a1
jal calcs
add $s4, [=10=], $v0 # move returned value to $s4
# Exit program
li $v0, 10 # system call to exit program
syscall
calcs:
addi $sp, $sp, -4 # make space in stack
sw $ra, 0($sp) # add $ra value to stack
add $t8, $s0, $a0 # save arg $a0 to $t8
add $t9, $s0, $a1 # save arg $a1 to $t9
jal test
add $t0, [=10=], $v0 # move returned value to $t0
add $a0, [=10=], $v0 # move returned value to $a0
# print
li $v0, 1
syscall
li $v0, 4
la $a0, newline
syscall
# get value from stack
addi $sp, $sp, 4
lw $ra, 0($sp)
add $v0, [=10=], $t0
jr $ra
test:
addi $sp, $sp, -4 # make space in stack
sw $ra, 0($sp) # push $ra value to stack
add $t0, [=10=], -989898989
add $v0, [=10=], $t0
#### If I keep the two lines below then the $ra value jumps to be right after I call the calcs function in main. But if I remove it then it goes to the value right after I call the test function in calcs
lw $ra, 0($sp) # load $ra value from stack
addi $sp, $sp, 4 # pop value off stack
# printing
add $a0, [=10=], $t0
li $v0, 1
syscall
li $v0, 4
la $a0, newline
syscall
add $v0, [=10=], $t0 # copy $t0 value to $v0 again
jr $ra
在 calcs
你有:
addi $sp, $sp, 4
lw $ra, 0($sp)
此(不正确的)代码序列将弹出堆栈,然后尝试从空堆栈中获取 $ra 值。当我 运行 这个时,由于空堆栈被零填充,因此序列将 0
加载到 $ra
中,这导致程序在执行 jr $ra
之后很快崩溃$ra
.
中为零
弹出的正确代码顺序是先获取,然后释放堆栈 space。
lw $ra, 0($sp)
addiu $sp, $sp, 4
I am trying to figure out why in the function test when I load $ra
from the stack it takes me to the instruction after I call calcs
function in main
instead of to the instruction after jal test
in calcs
function?
我们在发布的代码中没有看到这种行为,所以它一定发生在您正在试验的其他版本中。
例如,如果您在 test
中也有相同的双指令弹出序列。 代码将 return 直接从 test
到 main
(而不是从 test
正确地 return 到 calcs
,然后才通过尝试 return 到崩溃与张贴的一样的空地址)。
Is a new stack created for every function?
不,进程线程中的所有函数通过彼此共享堆栈指针共享同一个堆栈。 $sp
堆栈指针在调用时与函数隐式共享(即作为参数)。
When I am in the test function I should have 2 $ra values in the stack and when I load the last in $ra value it should be the one to return me to the instruction after jal test in calcs function, but that isn't happening and I can't figure out why.
我不确定你说的 last 是什么意思,但是一旦你在所有地方都使用了正确的弹出序列,堆栈上就会有两个 return 地址,一个较旧的 return 来自calcs
到 main
,较新的 return 从 test
到 calcs
。由于(调用)堆栈的性质,首先使用较新的,然后再使用较旧的。
由于指针是无符号的,因此在操作它们时使用 addiu,例如调整 $sp.
时
我是 MIPS 的新手,正在尝试找出 return 嵌套函数中的值。我试图弄清楚为什么在函数 test
中,当我从堆栈加载 $ra
时,它会在我调用 main
中的 calcs
函数之后将我带到指令而不是calcs
函数中 jal test
之后的指令?是否为每个函数都创建了一个新堆栈?
当我在 test
函数中时,堆栈中应该有 2 个 $ra
值,当我加载 $ra
中的最后一个值时,它应该是 return 我在 calcs
函数中 jal test
之后的指令,但那没有发生,我不明白为什么。
.data
newline: .asciiz " XXXX "
.text
main:
addi $s0, [=10=], 39 # val 1
addi $s1, [=10=], 2 # val 2
addi $s2, [=10=], 14 # val 3
addi $s3, [=10=], 11 # val 4
add $a0, [=10=], $s0 # copy val 1 to $a0
add $a1, [=10=], $s1 # copy val 2 to $a1
jal calcs
add $s4, [=10=], $v0 # move returned value to $s4
# Exit program
li $v0, 10 # system call to exit program
syscall
calcs:
addi $sp, $sp, -4 # make space in stack
sw $ra, 0($sp) # add $ra value to stack
add $t8, $s0, $a0 # save arg $a0 to $t8
add $t9, $s0, $a1 # save arg $a1 to $t9
jal test
add $t0, [=10=], $v0 # move returned value to $t0
add $a0, [=10=], $v0 # move returned value to $a0
# print
li $v0, 1
syscall
li $v0, 4
la $a0, newline
syscall
# get value from stack
addi $sp, $sp, 4
lw $ra, 0($sp)
add $v0, [=10=], $t0
jr $ra
test:
addi $sp, $sp, -4 # make space in stack
sw $ra, 0($sp) # push $ra value to stack
add $t0, [=10=], -989898989
add $v0, [=10=], $t0
#### If I keep the two lines below then the $ra value jumps to be right after I call the calcs function in main. But if I remove it then it goes to the value right after I call the test function in calcs
lw $ra, 0($sp) # load $ra value from stack
addi $sp, $sp, 4 # pop value off stack
# printing
add $a0, [=10=], $t0
li $v0, 1
syscall
li $v0, 4
la $a0, newline
syscall
add $v0, [=10=], $t0 # copy $t0 value to $v0 again
jr $ra
在 calcs
你有:
addi $sp, $sp, 4
lw $ra, 0($sp)
此(不正确的)代码序列将弹出堆栈,然后尝试从空堆栈中获取 $ra 值。当我 运行 这个时,由于空堆栈被零填充,因此序列将 0
加载到 $ra
中,这导致程序在执行 jr $ra
之后很快崩溃$ra
.
弹出的正确代码顺序是先获取,然后释放堆栈 space。
lw $ra, 0($sp)
addiu $sp, $sp, 4
I am trying to figure out why in the function test when I load
$ra
from the stack it takes me to the instruction after I callcalcs
function inmain
instead of to the instruction afterjal test
incalcs
function?
我们在发布的代码中没有看到这种行为,所以它一定发生在您正在试验的其他版本中。
例如,如果您在 test
中也有相同的双指令弹出序列。 代码将 return 直接从 test
到 main
(而不是从 test
正确地 return 到 calcs
,然后才通过尝试 return 到崩溃与张贴的一样的空地址)。
Is a new stack created for every function?
不,进程线程中的所有函数通过彼此共享堆栈指针共享同一个堆栈。 $sp
堆栈指针在调用时与函数隐式共享(即作为参数)。
When I am in the test function I should have 2 $ra values in the stack and when I load the last in $ra value it should be the one to return me to the instruction after jal test in calcs function, but that isn't happening and I can't figure out why.
我不确定你说的 last 是什么意思,但是一旦你在所有地方都使用了正确的弹出序列,堆栈上就会有两个 return 地址,一个较旧的 return 来自calcs
到 main
,较新的 return 从 test
到 calcs
。由于(调用)堆栈的性质,首先使用较新的,然后再使用较旧的。
由于指针是无符号的,因此在操作它们时使用 addiu,例如调整 $sp.
时