系列文章目录
前言
最近正在学习栈帧方面的知识,由于本人对汇编不太熟悉,对其中频繁出现的ESP寄存器和EBP寄存器一直没搞清楚,在查找资料后,在此进行整理,方便以后温故知新。
一、预备知识
要清楚理解栈帧的概念,首先我们要明白内存分区和栈的概念。
1.内存分区
按照内存地址从高(0xffffffff)到低(0x00000000)的顺序排列,可分为5大分区:栈区 -> 堆区 -> 全局静态区 -> 常量区 -> 代码区。大致分布如下图所示,
栈:函数在调用过程中,会在内存中开辟一块名为栈帧的空间,用于存放局部变量等数据。
2.什么是栈?
栈是一种数据结构,有两个特点:1.只能从一端插入或删除数据。2.先进后出。
二、栈帧是什么?
C语言中,每个栈帧对应着一个未运行完的函数。栈帧中保存了该函数的返回地址和局部变量。(来自百度百科)。
1.ESP寄存器是什么?
ESP即Extended stack pointer的缩写,直译过来就是扩展的栈指针寄存器。之前学的计算机组成原理中提到的堆栈寻址就是使用SP寄存器存放操作数的地址。那么,ESP和SP有什么区别呢?显而易见,ESP是32位的,SP是16位的,存放的都是栈顶地址(或指针)。总之,该指针总指向栈的顶部(低地址)。
2.EBP寄存器是什么?
EBP即Extended base pointer的缩写,直译过来就是扩展的基址指针寄存器。该指针总是指向当前栈帧的底部(高地址)。
三、详解栈帧创建与销毁全过程
1.测试程序
我这里使用了compile explorer x86-64 gcc 11.2,这里的rsp和rbp可以分别看作是64位的esp和ebp。
代码如下:
int add(int a,int b)
{
int c = 0;
c = a + b;
return c;
}
int main()
{
int a=0;
int b=1;
int sum=0;
sum=add(a,b);
return 0;
}
生成的汇编代码如下:
add(int, int):
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-20], edi
mov DWORD PTR [rbp-24], esi
mov DWORD PTR [rbp-4], 0
mov edx, DWORD PTR [rbp-20]
mov eax, DWORD PTR [rbp-24]
add eax, edx
mov DWORD PTR [rbp-4], eax
mov eax, DWORD PTR [rbp-4]
pop rbp
ret
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 0
mov DWORD PTR [rbp-8], 1
mov DWORD PTR [rbp-12], 0
mov edx, DWORD PTR [rbp-8]
mov eax, DWORD PTR [rbp-4]
mov esi, edx
mov edi, eax
call add(int, int)
mov DWORD PTR [rbp-12], eax
mov eax, 0
leave
ret
2.分析汇编代码
假设执行main函数前,栈空间如图所示:
下面逐一执行指令:
push rbp
#将rbp寄存器中的地址压入栈中。
mov rbp, rsp
#将rsp的值赋值给rbp
sub rsp, 16
#rsp的地址减16
mov DWORD PTR [rbp-4], 0
mov DWORD PTR [rbp-8], 1
mov DWORD PTR [rbp-12], 0
#rbp-4指向的内存单元存放0
#rbp-8指向的内存单元存放1
#rbp-12指向的内存单元存放0
mov edx, DWORD PTR [rbp-8]
mov eax, DWORD PTR [rbp-4]
mov esi, edx
mov edi, eax
#1存放到edx和esi,0存放到eax和edi
call add(int, int)
调用add函数
push rbp
mov rbp, rsp
将此时rbp的值压入栈中,rsp的值赋给rbp
mov DWORD PTR [rbp-20], edi
mov DWORD PTR [rbp-24], esi
mov DWORD PTR [rbp-4], 0
mov edx, DWORD PTR [rbp-20]
mov eax, DWORD PTR [rbp-24]
add eax, edx
#将0和1送入累加寄存器进行加法运算,结果写回eax
mov DWORD PTR [rbp-4], eax
mov eax, DWORD PTR [rbp-4]
pop rbp
#rbp出栈
ret
#返回,此时add函数栈帧销毁
总结
以上是对栈帧的总结。