汇编中main函数开头的栈内存操作
Stack memory operations at the beginning of main function in assembly
我把一个很简单的C程序转成了汇编文件(这里是RISC-V ISA),其中有一些栈指针操作我没看懂。
C 程序:
int main()
{
int a = 10;
return 0;
}
相关汇编代码:
.file "alternating_branches_2.c"
.option nopic
.text
.align 1
.globl main
.type main, @function
main:
addi sp,sp,-32
sd s0,24(sp)
addi s0,sp,32
li a5,10
sw a5,-20(s0)
li a5,0
mv a0,a5
ld s0,24(sp)
addi sp,sp,32
jr ra
.size main, .-main
.ident "GCC: (GNU) 8.3.0"
这是我的理解。
sp 包含堆栈内存的最后地址。因此,压栈会降低 sp 的值。
s0是帧指针,指向sp的前一个值。
在第一行中,从堆栈指针开始减少偏移量32。这是为了创建堆栈框架吗?通常,在堆栈中,压入操作会减少堆栈指针。但是,由于栈帧已经创建,sp现在指向栈的低位内存,push会增加sp的值吗?
-------------| <--sp
-------------|
-------------|
-------------|
-------------|
-------------|
-------------|
栈帧创建后:
-------------| <--s0
-------------|
-------------|
-------------|
-------------|
-------------|
-------------| <--sp
现在,压入堆栈必然导致 sp 增加,对吗?或者也可以使用帧指针 s0 来完成推送吗?如果这是一个非常基本的问题,我深表歉意。谢谢。
与 x86 ISA 不同——它有专门的入栈和出栈指令,RISC-V ISA 只能通过 load 和 访问内存存储 指令。它没有访问堆栈(即内存)和修改堆栈指针的压入和弹出指令。
由于堆栈向下增长,减少堆栈指针 sp
会在堆栈上分配 space,而增加它会释放 space。也就是说,addi sp,sp,-32
在堆栈上分配了 32 个字节,而 addi sp,sp,32
从堆栈中释放了 32 个字节。前者创建新的栈帧,后者销毁它。
s0
寄存器——与fp
相同——是帧指针并指向堆栈帧的开头。它的当前值保存在新创建的堆栈帧的最开头 (sd s0,24(sp)
)。然后,它被设置为指向堆栈帧开头的地址 (addi s0,sp,32
)。最后,帧指针在离开函数之前恢复为它的先前值 (ld s0,24(sp)
)。
堆栈帧创建和帧指针设置后的堆栈表示为:
| ... |
|-------------|<- s0 | beginning of stack frame
| previous s0 |
|-------------|<- sp-24
|-------------|
|-------------|
|-------------|
|-------------|
|-------------|
|-------------|
|-------------|<- sp | end of stack frame
我把一个很简单的C程序转成了汇编文件(这里是RISC-V ISA),其中有一些栈指针操作我没看懂。
C 程序:
int main()
{
int a = 10;
return 0;
}
相关汇编代码:
.file "alternating_branches_2.c"
.option nopic
.text
.align 1
.globl main
.type main, @function
main:
addi sp,sp,-32
sd s0,24(sp)
addi s0,sp,32
li a5,10
sw a5,-20(s0)
li a5,0
mv a0,a5
ld s0,24(sp)
addi sp,sp,32
jr ra
.size main, .-main
.ident "GCC: (GNU) 8.3.0"
这是我的理解。
sp 包含堆栈内存的最后地址。因此,压栈会降低 sp 的值。 s0是帧指针,指向sp的前一个值。
在第一行中,从堆栈指针开始减少偏移量32。这是为了创建堆栈框架吗?通常,在堆栈中,压入操作会减少堆栈指针。但是,由于栈帧已经创建,sp现在指向栈的低位内存,push会增加sp的值吗?
-------------| <--sp
-------------|
-------------|
-------------|
-------------|
-------------|
-------------|
栈帧创建后:
-------------| <--s0
-------------|
-------------|
-------------|
-------------|
-------------|
-------------| <--sp
现在,压入堆栈必然导致 sp 增加,对吗?或者也可以使用帧指针 s0 来完成推送吗?如果这是一个非常基本的问题,我深表歉意。谢谢。
与 x86 ISA 不同——它有专门的入栈和出栈指令,RISC-V ISA 只能通过 load 和 访问内存存储 指令。它没有访问堆栈(即内存)和修改堆栈指针的压入和弹出指令。
由于堆栈向下增长,减少堆栈指针 sp
会在堆栈上分配 space,而增加它会释放 space。也就是说,addi sp,sp,-32
在堆栈上分配了 32 个字节,而 addi sp,sp,32
从堆栈中释放了 32 个字节。前者创建新的栈帧,后者销毁它。
s0
寄存器——与fp
相同——是帧指针并指向堆栈帧的开头。它的当前值保存在新创建的堆栈帧的最开头 (sd s0,24(sp)
)。然后,它被设置为指向堆栈帧开头的地址 (addi s0,sp,32
)。最后,帧指针在离开函数之前恢复为它的先前值 (ld s0,24(sp)
)。
堆栈帧创建和帧指针设置后的堆栈表示为:
| ... |
|-------------|<- s0 | beginning of stack frame
| previous s0 |
|-------------|<- sp-24
|-------------|
|-------------|
|-------------|
|-------------|
|-------------|
|-------------|
|-------------|<- sp | end of stack frame