1.通过输入gcc -S -o main.s main.c 将下面c程序”week0303学号.c“编译成汇编代码
2.使用gdb跟踪汇编代码,在纸上画出f中每一条语句引起的eip(rip),ebp(rbp),esp(rsb),eax(rax)的值和栈的变化情况。提交照片,要有学号信息。
相关知识:
esp:寄存器存放当前线程的栈顶指针
ebp:寄存器存放当前线程的栈底指针
eip:寄存器存放下一个CPU指令存放的内存地址,当CPU执行完当前的指令后,从EIP寄存器中读取下一条指令的内存地址,然后继续执行。
eax:是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器。
一个标准的函数起始代码:
push ebp ;保存当前ebp
mov ebp,esp ;EBP设为当前堆栈指针
sub esp, xxx ;预留xxx字节给函数临时变量.
使用gcc - g example.c -o example -m32指令在64位的机器上产生32位汇编,然后使用gdb example指令进入gdb调试器
这里我遇到了一个问题,有下图的报错
后来上网查了资料,解决办法是输入命令sudo apt-get install gcc-multilib
进入之后先在main函数处设置一个断点,再run一下.
使用disassemble指令获取汇编代码,用i(info) r(registers)指令查看各寄存器的值
这里我发现了一条陌生的指令,<__x86.get_pc_thunk.ax>,其他的指令都差不多可以理解。
后来上网查了资料,get_pc_thunk.xx是一个子程序,是被调用的,程序调用时,会把调用者的下一条指令的地址压栈保存(用于返回),所以进入get_pc_thunk.xx时,栈顶esp就是调用者的下一条指令地址。
<__x86.get_pc_thunk.ax>这样的一条指令,就类似下面的操作:
__get_pc_thunk.ax:
movel (%esp),%eax
return
就是把esp的内容赋值给eax。
call 0x56556213 <__x86.get_pc_thunk.ax>执行时,会把该指令的下一条指令的地址压栈保存。也就是把指令add 0x2ddd,%eax的地址0x565561ff压入栈中
所以当进入子程序0x56556213<__x86.get_pc_thunk.ax>时,主要是执行:
movel (%esp),%eax
我的单步运行也证明了这一点:
当调用者call 0x56556213<__x86.get_pc_thunk.ax>执行完毕返回时,将要执行的是:
add 0x2ddd,%eax
这里eax原始值就是该条指令本身的地址(在<__x86.get_pc_thunk.ax>中给eax赋值的)!然后加上0x2ddd,就是在本条指令偏移0x2ddd地址。
所以call 0x56556213<__x86.get_pc_thunk.ax>的意义就是为了获取下一条指令的地址。
利用了调用子程序会将下一条指令地址压栈的特性,提前获取下一条指令的地址。
接着来分析
由图可知,esp所在的地址为0xffffd0dc,所以此时主函数的栈基址为0xffffd0dc,用x(examine)指令查看内存地址中的值
结合display命令和寄存器或pc内部变量,做如下设置:display /i $pc,这样在每次执行下一条汇编语句时,都会显示出当前执行的语句。下面展示每一步时%esp、%ebp和堆栈内容的变化:
执行到call函数时,esp和ebp的地址发生了变化,变为了0xffffd0d8
运行到即将调用f函数时,call指令将下一条指令的地址入栈,此时%esp,%ebp的值分别为0xffffd0d4和0xffffd0d8:
这样就真正进入了f函数,下面是f函数的汇编代码
将上一个函数的基址入栈,从当前%esp开始作为新基址
实参的计算在%eax中进行
通过一步一步调试,我记录了每一步运行时esp、ebp、eip、eax的变化
指令 | esp | ebp | eip | eax | 堆栈 |
---|---|---|---|---|---|
push %ebp | 0xffffd0d0 | 0xffffd0d8 | 0x565561ca | 0x56558fdc | 0x5655620b |
mov %esp,%ebp | 0xffffd0cc | 0xffffd0d8 | 0x565561cb | 0x56558fdc | 0xffffd0d8,0x5655620b |
sub $0x10,%esp | 0xffffd0cc | 0xffffd0cc | 0x565561cd | 0x56558fdc | 0xffffd0d8,0x5655620b |
call 0x56556213 | 0xffffd0bc | 0xffffd0cc | 0x565561d0 | 0x56558fdc | 0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b |
add $0x2e07,%eax | 0xffffd0bc | 0xffffd0cc | 0x565561d5 | 0x565561d5 | 0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b |
movl $0x10,-0x4(%epb) | 0xffffd0bc | 0xffffd0cc | 0x565561da | 0x56558fdc | 0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b |
pushl 0x8(%ebp) | 0xffffd0bc | 0xffffd0cc | 0x565561e1 | 0x56558fdc | 0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b |
call 0x565561ad | 0xffffd0b8 | 0xffffd0cc | 0x565561e4 | 0x56558fdc | 0x8,0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b |
add $0x4,%esp | 0xffffd0b8 | 0xffffd0cc | 0x565561e9 | 0xb | 0x8,0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b |
mov -0x4(%ebp),%edx | 0xffffd0bc | 0xffffd0cc | 0x565561ec | 0xb | 0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b |
add %edx,%eax | 0xffffd0bc | 0xffffd0cc | 0x565561ef | 0xb | 0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b |
leave | 0xffffd0bc | 0xffffd0cc | 0x565561f1 | 0xb | 0x56556241,0xf7fe22d0,0x0,0x0,0xffffd0d8,0x5655620b |
ret | 0xffffd0d0 | 0xffffd0d8 | 0x565561f2 | 0xb | 0x5655620b |
参考:
https://www.k2zone.cn/?p=1911
https://blog.csdn.net/u012060033/article/details/79218909此时