GDB调试汇编堆栈过程分析

GDB调试汇编堆栈过程分析

分析过程

  • 这是我的C源文件:click here

  • 使用gcc - g example.c -o example -m32指令在64位的机器上产生32位汇编,然后使用gdb example指令进入gdb调试器:

    GDB调试汇编堆栈过程分析

  • 进入之后先在main函数处设置一个断点,再run一下,使用disassemble指令获取汇编代码,用i(info) r(registers)指令查看各寄存器的值:

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

  • 可见此时主函数的栈基址为0xffffd068,用x(examine)指令查看内存地址中的值,但目前%esp所指堆栈内容为0,%ebp所指内容也为0

    GDB调试汇编堆栈过程分析

  • 首先,结合display命令和寄存器或pc内部变量,做如下设置:display /i $pc,这样在每次执行下一条汇编语句时,都会显示出当前执行的语句。下面展示每一步时%esp、%ebp和堆栈内容的变化:

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

  • call指令将下一条指令的地址入栈,此时%esp,%ebp和堆栈的值为:

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

  • 将上一个函数的基址入栈,从当前%esp开始作为新基址:

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

  • 先为传参做准备:

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

  • 实参的计算在%eax中进行:

    GDB调试汇编堆栈过程分析

  • f函数的汇编代码:

    GDB调试汇编堆栈过程分析

  • 实参入栈:

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

  • call指令将下一条指令的地址入栈:

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

  • 计算short+int:

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

  • pop %ebp指令将栈顶弹到%ebp中,同时%esp增加4字节:

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

  • ret指令将栈顶弹给%eip:

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

  • 因为函数f修改了%esp,所以用leave指令恢复。leave指令先将%esp对其到%ebp,然后把栈顶弹给%ebp:

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

  • 主函数汇编代码:

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

指令 %esp %ebp 堆栈
push $0x8 0xffffd068 0xffffd068 0x0
call 0x80483ef 0xffffd064 0xffffd068 0x8 0x0
push %ebp 0xffffd060 0xffffd068 0x8048412 0x8 0x0
mov %esp,%ebp 0xffffd05c 0xffffd068 0xffffd068 0x8048412 0x8 0x0
mov 0x804a01c,%edx 0xffffd05c 0xffffd05c 0xffffd068 0x8048412 0x8 0x0
call 0x80483db 0xffffd058 0xffffd05c 0xa 0xffffd068 0x8048412 0x8 0x0
push %ebp 0xffffd054 0xffffd05c 0x8048403 0xa 0xffffd068 0x8048412 0x8 0x0
mov %esp,%ebp 0xffffd050 0xffffd05c 0xffffd05c 0x8048403 0xa 0xffffd068 0x8048412 0x8 0x0
movzwl 0x804a018,%eax 0xffffd050 0xffffd050 0xffffd05c 0x8048403 0xa 0xffffd068 0x8048412 0x8 0x0
ret 0xffffd054 0xffffd05c 0x8048403 0xa 0xffffd068 0x8048412 0x8 0x0
leave 0xffffd05c 0xffffd05c 0xffffd068 0x8048412 0x8 0x0
ret 0xffffd060 0xffffd068 0x8048412 0x8 0x0
add $0x4,%esp 0xffffd064 0xffffd068 0x8 0x0
mov $0x3,%edx 0xffffd068 0xffffd068 0x0
ret 0xffffd06c 0x0

遇见的问题

  • 使用-m32指令报错:

    GDB调试汇编堆栈过程分析

  • 这是因为编译64位Linux版本32位的二进制文件,需要安装一个库,使用指令sudo apt-get install libc6-dev-i386即可

上一篇:TF版本的Word2Vec和余弦相似度的计算


下一篇:为什么operator>>(istream&, string&)能够安全地读入长度未知的字符串?