浅谈栈帧(一)

来源:互联网 发布:win7网络连接受限 编辑:程序博客网 时间:2024/05/17 04:50

    好久没有更新了,最近打算把近期所学的内容更新一下

    今天说一说内存栈帧方面的吧=。=

 关于栈帧:首先我们呢来了解一下它的基本概念。

 1.堆栈:对于堆栈,其实就是我们程序进行执行,那么我们必须给它一块地盘,有了地基,才能够建筑出我们所需要的东西。没有地我们是无法去干任何事情的。

     在计算机中,这个地盘其实就对于我们的内存空间。我们的程序其实就相当于施工队伍。我们所给出命令。然后对其进行指挥,完成我们布置的任务。

    (1)堆栈中有什么呢?

      1.函数调用框架。

      2.传递参数。

      3.保存返回地址。

      4.提供局部变量空间。

      等等。

    堆栈空间对应的是一段虚拟地址,这是关于计算机的寻址机制。

    (2)那么堆栈是地盘,它的机构设计是怎么样的呢?

图片源于深入理解计算机系统:

    wKiom1b9Gw6jthaUAAGuoQ6KXI4496.jpg

    其中需要进行了解的有:

堆栈相关的寄存器:

     esp,堆栈指针(stack pointer),相当于栈帧中的栈顶。

    ebp,基址指针(base pointer),相当于栈帧中的栈低。

     对于这2个寄存器指针我们怎么理解呢?

    其实我们可以认为这个就相当于我们盖楼楼层的地面与屋顶,当然。这个屋顶是根据需要可以动态变大的。我们利用两个之间的指向空间来进行我们当前物品(临时变量和函数变量)进行保存管理。

    在ebp当前存储的是被保存的esp,因为在我们函数调用的过程中,其实就相当于我们盖楼的过程(在堆栈中,栈的空间是高地址到低地址的向下增长。)

    ebp-4中保存的是我们的返回地址,当我们调用的函数执行完毕时候,我们通过利用这个赋值,来对ebp找到上一楼层的地面(上一调用函数的ebp所在地址。)


我们通过一段代码来进行解析一下:

    

#include <stdio.h>void 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来看一下他的汇编代码。

wKiom1b9HxeS2oPqAAWkmdUeFYM491.jpg   

 下面是swap函数的:

wKioL1b9H_-Q3OCCAA3ezoUInEM443.jpg

    其中esp,ebp就相当于我们的通知跳转值,毕竟楼再高也必须有个限度好么,要不,你是要上天?

    堆栈操作:

    上文中的push,栈顶地址减少4个字节。

        pop,栈顶地址增加4个字节。

    不难理解,其实就相当于我们楼层的电梯呗,不过你下去了,楼层就销毁了(针对于操作ebp,esp而言奥。)

    栈帧其实就是这样,然后我们来看两段程序分析一下为什么会出现这样的结果:

    Linux平台下:

#include<stdio.h>#include<stdlib.h>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;}

其实对应的图就是:

    wKiom1b9O5rCdSo8AAAzLLPjpCs821.png

然后我们看代码:

        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函数中的重启命令。



浅谈栈帧(二)

本文出自 “剩蛋君” 博客,请务必保留此出处http://memory73.blog.51cto.com/10530560/1759029

0 0
原创粉丝点击