GDB调试汇编堆栈
GDB调试汇编堆栈
第五周分析
-
stack.c反汇编成stack.s的代码
- 先从main程序开始执行,调用y前,先将返回地址入栈,再将%ebp入栈,将%ebp放在现在的栈顶位置,栈顶指针减4分配空间,再将参数8入栈,调用y
- y调用z前,再进行一次将返回地址和%ebp入栈,改变%ebp位置的操作,将栈顶指针减4分配空间,将8存贮在%eax寄存器中,再将现在%eax中的值入栈保存,调用z
- 再进行一次将返回地址和%ebp入栈,改变%ebp位置的操作,将8存入%eax便于操作,对8进行加3的操作,弹出到%ebp,返回main
- 返回main,将%eax中的参数加1,结束程序
GDB调试例子的汇编堆栈
- 根据卢肖明同学博客内容进行调试
#include<stdio.h>
short addend1 = 1;
static int addend2 = 2;
const static long addend3 = 3;
static int g(int x)
{
return x + addend1;
}
static const int f(int x)
{
return g(x + addend2);
}
int main(void)
{
return f(8) + addend3;
}
- 例子的源文件使用
gcc - g example.c -o example -m32
指令将C源文件在64位机器上编译成32位汇编代码 - 进入GDB调试器
- 在main处设置断点、运行并获取汇编代码查看各寄存器状态
- 主函数栈基址为0xffffcf74,值为0
- 单步执行并显示%esp和%ebp的值
- call指令将下一条指令地址入栈,%esp、%ebp值发生变化
- 上一个函数的基址入栈,从当前%esp开始作为新基址,原地址压栈保存
- 为传参做准备
- 实参计算在%eax中进行
- f函数汇编代码
- 实参入栈
- call指令将下一条指令的地址入栈
- 计算short+int
- pop %ebp指令将栈顶弹到%ebp中,同时%esp增加4字节
- ret指令将栈顶弹给%eip
堆栈情况
指令 | %esp | %ebp | 堆栈 |
---|---|---|---|
movl$0x8,(%esp) | 0ffffcf74 | 0ffffcf74 | 0x0 |
call 0x80483ef | 0ffffcf74 | 0ffffcf74 | 0x8 0x0 |
push %ebp | 0ffffcf70 | 0ffffcf78 | 0x804842e 0x8 0x0 |
mov %esp,%ebp | 0ffffcf6c | 0ffffcf78 | 0xffffcf78 0x804842e 0x8 0x0 |
mov 0x804a01c,%edx | 0ffffcf6c | 0ffffcf6c | 0xffffcf78 0x804842e 0x8 0x0 |
call 0x80483db | 0ffffcf68 | 0ffffcf6c | 0xa 0xffffcf78 0x804842e 0x8 0x0 |
push %ebp | 0ffffcf64 | 0ffffcf6c | 0x804841a 0xa 0xffffcf78 0x804842e 0x8 0x0 |
mov %esp,%ebp | 0ffffcf60 | 0ffffcf6c | 0xffffcf6c 0x804841a 0xa 0xffffcf78 0x804842e 0x8 0x0 |
movzwl 0x804a018,%eax | 0ffffcf60 | 0ffffcf60 | 0xffffcf6c 0x804841a 0xa 0xffffcf78 0x804842e 0x8 0x0 |
ret | 0ffffcf64 | 0xffffcf6c | 0x804841a 0xa 0xffffcf78 0x804842e 0x8 0x0 |
leave | 0ffffcf68 | 0ffffcf6c | 0xa 0xffffcf78 0x804842e 0x8 0x0 |
ret | 0ffffcf70 | 0ffffcf78 | 0x804842e 0x8 0x0 |