zoukankan      html  css  js  c++  java
  • GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析

    分析过程

    • .c代码文件

        #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指令在64位的机器上产生32位汇编,然后使用gdb example指令进入gdb调试器

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



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

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


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


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


    • 先为传参做准备:


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


    • 实参入栈06


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





    • 计算short+int





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


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


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





    • 主函数汇编代码,并结束栈帧的调用。

    • 综上可列表分析根据汇编代码得到栈帧的调用

    指令 %eip %ebp %esp %eax 堆栈数据
    push $0x8 0x804840b 0xffffd018 0xffffd018 0xf7fbadbc 0x0
    call 0x80483ef 0x804840d 0xffffd018 0xffffd014 0xf7fbadbc 0x8 0x0
    push %ebp 0x80483ef 0xfffffd018 0xffffd010 0xf7fbadbc 0xffffd018 0x8048412 0x8 0x0
    mov 0x804a01c,%edx 0x80483f2 0xffffd00c 0xffffd00c 0xf7fbadbc 0xffffd018 0x8048412 0x8 0x0
    mov 0x8(%ebp),%eax 0x80483f8 0xffffd00c 0xffffd00c 0xf7fbadbc 0xffffd018 0x8048412 0x8 0x0
    add %edx,%eax 0x80483fb 0xffffd00c 0xffffd00c 0x8 0xffffd018 0x8048412 0x8 0x0
    push %eax 0x80483fd 0xffffd00c 0xffffd00c 0xa 0xffffd018 0x8048412 0x8 0x0
    call 0x80483db 0x80483fe 0xffffd00c 0xffffd008 0xa 0xa 0xffffd018 0x8048412 0x8 0x0
    push %ebp 0x80483db 0xffffd00c 0xffffd004 0xa 0x8048403 0xa 0xffffd018 0x8048412 0x8 0x0
    mov %esp,%ebp 0x80483dc 0xffffd00c 0xffffd000 0xa 0xffffd00c 0x8048403 0xa 0xffffd018 0x8048412 0x8 0x0
    movzwl 0x804a018,%eax 0x80483de 0xffffd000 0xffffd000 0xa 0xffffd00c 0x8048403 0xa 0xffffd018 0x8048412 0x8 0x0
    movswl %ax,%edx 0x80483e5 0xffffd000 0xffffd000 0x1 0xffffd00c 0x8048403 0xa 0xffffd018 0x8048412 0x8 0x0
    mov 0x8(%ebp),%eax 0x80483e8 0xffffd000 0xffffd000 0x1 0xffffd00c 0x8048403 0xa 0xffffd018 0x8048412 0x8 0x0
    add %edx,%eax 0x80483eb 0xffffd000 0xffffd000 0xa 0xffffd00c 0x8048403 0xa 0xffffd018 0x8048412 0x8 0x0
    pop %ebp 0xffffcf80 0x80483ed 0xffffd000 0xffffd000 0xb 0xffffd00c 0x8048403 0xa 0xffffd018 0x8048412 0x8 0x0
    ret 0x80483ee 0xffffd00c 0xffffd004 0xb 0x8048403 0xa 0xffffd018 0x8048412 0x8 0x0
    add $0x4,%esp 0x8048403 0xffffd00c 0xffffd008 0xb 0xa 0xffffd018 0x8048412 0x8 0x0
    leave 0x8048406 0xffffd00c 0xffffd00c 0xb 0xffffd018 0x8048412 0x8 0x0
    ret 0x8048407 0xffffd018 0xffffd010 0xb 0x8048412 0x8 0x0
    add $0x4,%esp 0x8048412 0xffffd018 0xffffd014 0xb 0x8 0x0
    mov $0x3,%edx 0x8048415 0xffffd018 0xffffd018 0xb 0x0
    add %edx,%eax 0x804841a 0xfffd018 0xffffd018 0xb 0x0
    leave 0x804841c 0xffffd018 0xffffd018 0xe 0x0
    ret 0x804841d 0x0 0xffffd01c 0xe

    遇到的问题及解决过程

    • 使用-m32指令报错:

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

  • 相关阅读:
    BZOJ 1101 莫比乌斯函数+分块
    BZOJ 2045 容斥原理
    BZOJ 4636 (动态开节点)线段树
    BZOJ 2005 容斥原理
    BZOJ 2190 欧拉函数
    BZOJ 2818 欧拉函数
    BZOJ 3123 主席树 启发式合并
    812. Largest Triangle Area
    805. Split Array With Same Average
    794. Valid Tic-Tac-Toe State
  • 原文地址:https://www.cnblogs.com/20145335hh/p/6131873.html
Copyright © 2011-2022 走看看