没有合适的资源?快使用搜索试试~ 我知道了~
本节通过代码实例分析函数调用过程中栈帧的布局、形成和消亡。示例代码如下:该程序每个函数都嵌入汇编代码,以获取各函数运行时刻EBP和ESP寄存器的值。每个函数都打印出EBP寄存器所指向内存地址处的值,以及位于其后的函数返回地址。图7给出程序的编译和运行结果。图7StackReg运行结果为便于理解输出结果中数据间的关系,将其转化为图8所示。图左还示出栈的增长方向和栈的内存地址。黑色箭头和寄存器名表示当前栈帧,否则用灰色表示。图中表示tail函数内所看到的栈布局,其中完整示出tail和middle函数的栈帧结构,以及main函数的部分。注意,形参1、2、3(常量)不在栈内。图8StackReg栈帧布
资源推荐
资源详情
资源评论
C语言函数调用栈语言函数调用栈(三三)
6 调用栈实例分析
本节通过代码实例分析函数调用过程中栈帧的布局、形成和消亡。
6.1 栈帧的布局
示例代码如下:
//StackReg.c
#include
//获取函数运行时寄存器%ebp和%esp的值
#define FETCH_SREG(_ebp, _esp) do{\
asm volatile( \
"movl %%ebp, %0 " \
"movl %%esp, %1 " \
: "=r" (_ebp), "=r" (_esp) \
); \
}while(0)
//也可使用gcc扩展register void *pvEbp __asm__ ("%ebp"); register void *pvEsp __asm__ ("%esp");获取,
// pvEbp和pvEsp指针变量的值就是FETCH_SREG(_ebp, _esp)中_ebp和_esp的值
#define PRINT_ADDR(x) printf("[%s]: &"#x" = %p", __FUNCTION__, &x)
#define PRINT_SREG(_ebp, _esp) do{\
printf("[%s]: EBP = 0x%08x", __FUNCTION__, _ebp); \
printf("[%s]: ESP = 0x%08x", __FUNCTION__, _esp); \
printf("[%s]: (EBP) = 0x%08x", __FUNCTION__, *(int *)_ebp); \
printf("[%s]: (EIP) = 0x%08x", __FUNCTION__, *((int *)_ebp + 1)); \
printf("[%s]: &"#_esp" = %p", __FUNCTION__, &_esp); \
printf("[%s]: &"#_ebp" = %p", __FUNCTION__, &_ebp); \
}while(0)
void tail(int paraTail){
int locTail = 0;
int ebpReg, espReg;
FETCH_SREG(ebpReg, espReg);
PRINT_SREG(ebpReg, espReg);
PRINT_ADDR(paraTail);
PRINT_ADDR(locTail);
}
int middle(int paraMid1, int paraMid2, int paraMid3){
int ebpReg, espReg;
tail(paraMid1);
FETCH_SREG(ebpReg, espReg);
PRINT_SREG(ebpReg, espReg);
PRINT_ADDR(paraMid1);
PRINT_ADDR(paraMid2);
PRINT_ADDR(paraMid3);
return 1;
}
int main(void){
int ebpReg, espReg;
int locMain = middle(1, 2, 3);
FETCH_SREG(ebpReg, espReg);
PRINT_SREG(ebpReg, espReg);
PRINT_ADDR(locMain);
return 0;
}
StackReg
该程序每个函数都嵌入汇编代码,以获取各函数运行时刻EBP和ESP寄存器的值。每个函数都打印出EBP寄存器所指
向内存地址处的值,以及位于其后的函数返回地址。图7给出程序的编译和运行结果。
图7 StackReg运行结果
为便于理解输出结果中数据间的关系,将其转化为图8所示。图左还示出栈的增长方向和栈的内存地址。黑色箭头和寄
存器名表示当前栈帧,否则用灰色表示。图中表示tail函数内所看到的栈布局,其中完整示出tail和middle函数的栈帧结
构,以及main函数的部分。注意,形参1、2、3(常量)不在栈内。
图8 StackReg栈帧布局
通常每个函数都有自己的栈帧。各栈帧中存放前一个调用函数的栈帧基址,通过该地址域将所有主调函数与被调函数
的栈帧以链表形式连在一起。函数调用级数越多,占用的栈空间也越大,因此应小心使用递归函数。
6.2 栈帧的形成
为方便讲解,获取StackReg示例程序所对应的汇编代码片段,如图9所示。在汇编代码中,最左列为指令在内存中的
地址,栈帧中的返回地址(return address)即指此类地址。最右列为待执行的汇编指令语句,中间列为该指令在代码段
中的16进制表示,可见push %ebp指令仅占一个字节(0x55)。每次CPU执行都要先读取%eip寄存器值,然后定位
到%eip指向的汇编指令内存地址,读取该指令并执行。读取指令会使%eip寄存器值增加相应指令的长度(字节数),执
剩余8页未读,继续阅读
资源评论
weixin_38621870
- 粉丝: 7
- 资源: 936
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 使用C++实现的常见算法
- travel-web-springboot【程序员VIP专用】.zip
- 基于Matlab, ConvergeCase中部分2D结果文件输出至EXCEL中 能力有限,代码和功能极其简陋.zip
- java桌面小程序,主要为游戏.zip学习资源
- Java桌面-坦克大战小游戏.zip程序资源
- java语言做的魔板小游戏.zip
- 初学JAVA制作的坦克大战小游戏,使用JAVA 的GUI模拟2,5D界面.zip
- 公开整理-2024年832个国家级贫困县摘帽情况分省分年统计.xlsx
- 纯js+Jquery实现2048游戏
- 叠罗汉游戏,安卓java实现,自定义Framlayout,属性动画.zip
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功