assembly MIPS -调用子程序时为什么要恢复堆栈

gc0ot86w  于 2023-01-21  发布在  其他
关注(0)|答案(2)|浏览(129)

假设我们使用堆栈帧向子例程传递参数,如下所示:

addi $sp, $sp, -8
sw $s0, 0($sp)
jal sub
lw $s1, 4($sp)
addi $sp, $sp, 8

sub: lw $t0, 0($sp)
... do stuff ...
sw $t1, 4($sp)
jr $ra

我理解通过堆栈传递参数并使用$ra寄存器返回给调用者的概念。
我不太清楚的是:

addi $sp, $sp, 8

这将恢复堆栈帧中的空间。有人能帮我理解一下吗:
1.如果我不这么做会怎么样?
1.如果我不恢复空间,汇编程序会“关心”吗?
1.这是否与c++中的内存管理类似?(即:删除指针、析构函数等)

ffdz8vbo

ffdz8vbo1#

堆栈指针是一个调用保留寄存器,就像$s0 .. $s7-调用者希望它的值在jal之后保持不变,这样它就可以找到 * 自己的 * 堆栈内容(比如它自己保存的返回地址)。
另请参阅我在谷歌上找到的MIPS通话惯例摘要:https://courses.cs.washington.edu/courses/cse410/09sp/examples/MIPSCallingConventionsSummary.pdf
想象一下,如果你想调用一个函数,但是这个函数会让$sp指向更远的未知距离,你将如何恢复呢?这将是一个很大的痛苦,所以我们需要函数来恢复$sp(或者一开始就不要碰它)。
在C语言中,这是一种在退出函数时释放自动存储空间(如int i;这样的局部变量)的机制(即使您通过longjmp返回多个父函数级别,而不是一次返回一个级别,这种机制仍然有效)。
这并不像对每个变量分别运行析构函数,这就是为什么你可以用一个大的addiu $sp, $sp, 16一次释放四个单词的空间。
如果我不恢复空间,汇编程序会"关心"吗?
不,汇编程序本身只是将源代码行翻译成输出文件(或当前部分)中的字节,一次一行。引用其他行的只有符号和宏。它根本不做任何事情来强制结构化编程。

r1wp621o

r1wp621o2#

每次我们想要保存任何寄存器的值,在覆盖之前,我们将其保存在堆栈中。
例如,如果我们重写返回地址寄存器$RA,则程序将崩溃或以无限循环结束。
为了避免重写每个函数的返回地址,我们将其存储在堆栈中。
回答你们的问题
1-你最好清理你使用过的内存(置零)。
2-汇编程序并不关心
3-不,它不像c++。在c中,使用malloc或constructors分配空间的指针占用堆中的空间,而不是堆栈中的空间。堆有一个由块和头组成的有组织的结构。每个头保存关于块的信息,例如块大小-下一个空闲块-这个块是空闲/保留的。
当我们在C/C
中释放这样的块时,我们基本上将头部重置为自由状态。
顺便说一句,您提供的代码应该更像:

addi $sp, $sp, -8
sw $s0, 4($sp)
sw $ra, 0($sp)
jal sub
lw $ra, 0($sp)
lw $s0, 4($sp)
addi $sp, $sp, 8
jr $ra

sub: lw $t0, 0($sp)
... do stuff ...
sw $t1, 4($sp)
jr $ra

相关问题