好久没有更新了,最近打算把近期所学的内容更新一下
今天说一说内存栈帧方面的吧=。=
关于栈帧:首先我们呢来了解一下它的基本概念。
1.堆栈:对于堆栈,其实就是我们程序进行执行,那么我们必须给它一块地盘,有了地基,才能够建筑出我们所需要的东西。没有地我们是无法去干任何事情的。
在计算机中,这个地盘其实就对于我们的内存空间。我们的程序其实就相当于施工队伍。我们所给出命令。然后对其进行指挥,完成我们布置的任务。
(1)堆栈中有什么呢?
1.函数调用框架。
2.传递参数。
3.保存返回地址。
4.提供局部变量空间。
等等。
堆栈空间对应的是一段虚拟地址,这是关于计算机的寻址机制。
(2)那么堆栈是地盘,它的机构设计是怎么样的呢?
图片源于深入理解计算机系统:
其中需要进行了解的有:
堆栈相关的寄存器:
esp,堆栈指针(stack pointer),相当于栈帧中的栈顶。
ebp,基址指针(base pointer),相当于栈帧中的栈低。
对于这2个寄存器指针我们怎么理解呢?
其实我们可以认为这个就相当于我们盖楼楼层的地面与屋顶,当然。这个屋顶是根据需要可以动态变大的。我们利用两个之间的指向空间来进行我们当前物品(临时变量和函数变量)进行保存管理。
在ebp当前存储的是被保存的esp,因为在我们函数调用的过程中,其实就相当于我们盖楼的过程(在堆栈中,栈的空间是高地址到低地址的向下增长。)
ebp-4中保存的是我们的返回地址,当我们调用的函数执行完毕时候,我们通过利用这个赋值,来对ebp找到上一楼层的地面(上一调用函数的ebp所在地址。)
我们通过一段代码来进行解析一下:
#includevoid swap(int *a, int * b){ int c; c = * a; * a = *b ; * b = c;}int main(void ){ int a; int b; int ret; a = 16; b = 64; ret = 0; ret=swap(&a, &b); return ret;}
上面这段代码就是简单的一个函数调用,我们通过Linux来看一下他的汇编代码。
下面是swap函数的:
其中esp,ebp就相当于我们的通知跳转值,毕竟楼再高也必须有个限度好么,要不,你是要上天?
堆栈操作:
上文中的push,栈顶地址减少4个字节。
pop,栈顶地址增加4个字节。
不难理解,其实就相当于我们楼层的电梯呗,不过你下去了,楼层就销毁了(针对于操作ebp,esp而言奥。)
栈帧其实就是这样,然后我们来看两段程序分析一下为什么会出现这样的结果:
Linux平台下:
#include#include void bug(){ system("reboot"); exit(0);}int stack_test(int a,int b){ //int* p = &a; //p--; //*p = bug; printf("before writer : 0x%x\n",b); int *p = &a; p++; *p = 0xdddd; printf("after write : 0x%x\n",b); int c = 0xcccc; return c;}int main(){ int a = 0xaaaa; int b = 0xbbbb; int ret = stack_test(a,b); printf("you should run here\n"); return 0;}
其实对应的图就是:
然后我们看代码:
printf("before writer : 0x%x\n",b); int *p = &a; p++; *p = 0xdddd; printf("after write : 0x%x\n",b); int c = 0xcccc; return c;
让p指针指向了&a,在临时变量中,然后p++就跳转到了&b上,然后我们修改*p,导致b的值变为了
0xdddd;
接下来:
int* p = &a; p--; *p = bug;
这个一样的,p指针只上了传递的临时变量&a,然后p--就跳转到了返回地址,然而我们将返回地址赋值到了bug函数上,那么就出现我们不是跳转到main函数中,而是执行了bug函数中的重启命令。