对于理解这一点的人来说,这是一个很快的问题。但我的问题是我有一个任务,使用各种方法的选择排序,我正在尝试理清如何使用堆栈来保存返回地址。我的问题是我可以让它一直到最后一个加载返回地址代码块,但后来我在数据/堆栈读取中得到一个错误的地址,有人可以指出我可能在保存到的地方搞砸了堆栈?非常感谢你!
main:
sub $sp, $sp, 4
sw $ra, ($sp)
jal sort
j exit
swap:
sub $sp, $sp, 8
sw $fp, 4($sp)
add $fp, $sp, 4
sw $ra, ($fp)
lw $ra, ($fp)
jr $ra
min:
sub $sp, $sp, 8
sw $fp, 4($sp)
add $fp, $sp, 4
sw $ra, ($fp)
lw $ra, ($fp)
jr $ra
sort:
sub $sp, $sp, 8
sw $fp, 4($sp)
add $fp, $sp, 4
sw $ra, ($fp)
jal min
jal swap
lw $ra, ($fp) <---- Bad address in data/stack read Exception
lw $fp, 4($fp)
jr $ra
exit:
li $v0, 10 #exit
syscall
答案 0 :(得分:0)
是否有理由使用帧指针? 您正在以非常复杂的方式使用堆栈。
swap:
sub $sp, $sp, 8 ; room for 2 words
sw $fp, 4($sp) ; store sp in the first
add $fp, $sp, 4 ; fp = sp + 4 ? Why?
sw $ra, ($fp) ; store return address
lw $ra, ($fp) ; get return address - leave the fp and sp alone
jr $ra ; return, and leave the sp and fp unbalanced
现在,您应该在调用者或被调用者中处理堆栈帧以保持清晰。 两者都制作一个新的框架,并在完成子程序时将其删除。
在排序中你同时调用min和swap,然后两者都改变sp和fp而不恢复它们。
This可能会有所启发......
[编辑]
如果你坚持使用框架:
push ra
push fp
fp = sp
{ push local variables }
do the deed
sp = fp
pop fp
pop ra
ret
这样你就拥有了fp-chain,如果你的堆栈被破坏了,你仍然可以返回 精细。你不需要推sp,因为sp存储在fp。
中答案 1 :(得分:0)
一般约定是在堆栈上存储任何可以覆盖的寄存器。因此,如果在排序过程中要保存$ra
,则需要在堆栈上保留1个单词。在从程序返回之前执行所有计算之后,您需要使用restora $ra
和堆栈指针:
sort:
addi $sp, $sp, -4
sw $ra, 0($sp) # saves $ra on stack
# do calculations
sort_end:
lw $ra, 0($sp)
addi $sp, $sp, 4
jr $ra