汇编与栈帧学习(一)

最近学习《深入理解计算机系统》,书中全是汇编,正好借着GDB来研究一下汇编语言和函数调用时栈帧的变化。于是写下这个开篇的博客,我先以一个简单的程序进行研究:

如上图这个程序(func.c)含有两个函数。main和add,功能很简单就是求两个两个数的和然后输出。

用命令:gcc func.c -o func.o 编译成目标文件func.o。用GDB加载:

首先在main和add两处设置了断点。为了便于观察程序运行时栈帧的变化。之后运行程序,对main进行反汇编看一下main的汇编程序。

如上所示,断点在地址0x08048436停住了(这行没有执行),可以看出加载进来运行后已经执行了两条指令。即将ebp压栈,令ebp 和 esp指向同一个内存。

这时可以看一下在ebp中的值是0xbffff0e8,和栈帧的一些信息。

输入了3次ni命令(ni命令是每次执行一个语句),所以这时程序执行到了0x08048444停住了。因为需要存储一些参数,所以程序分配了32字节来分配空间,然后将在main函数里的两个值传入到分配好的空间中。即将10 和 8 分别存入0x4(esp),即这个参数10存储在内存地址为0xbffff0c4里和0x8(esp)处(8存在内存地址为0xbffff0c8里)

同理。一次执行一条指令。执行了两次进入了add函数的栈帧。以此同时在这个栈帧里已经把空间分配好了。在0x08048423处指令表示分配16个字节这个函数使用。

上图是两次ebp和esp的变化。上边是main栈帧下面是add栈帧。之后继续逐条运行程序产生下面的结果:

通过读这个汇编程序。第四条看出将0xc(%ebp)里的值存入寄存器%eax中。通过计算可以知道0xc(%ebp)的地址就是0xbffff0c4。 即我们在main栈帧中存放参数10的地址,也就是将10存入eax寄存器中。同理将8存放到edx寄存器中。对两个寄存器相加存入eax,同时将结果存入0xbffff0b4中。返回。

 

如上图。返回后,在main栈帧中继续执行。来到了0x08048450处,这时ebp和esp值有恢复成了main栈帧中的值。继续执行程序。执行完后会有如下结果:

上边的程序看到将结果存入到0x1c(%esp)处的内存处,然后调用printf的库函数,进行输出结果。结束。

 

posted @ 2015-12-19 19:42  Dormant  阅读(1591)  评论(0编辑  收藏  举报