浅谈栈帧(一)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈栈帧(一)相关的知识,希望对你有一定的参考价值。

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

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

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

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

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

    (1)堆栈中有什么呢?

      1.函数调用框架。

      2.传递参数。

      3.保存返回地址。

      4.提供局部变量空间。

      等等。

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

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

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

    技术分享

    其中需要进行了解的有:

堆栈相关的寄存器:

     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来看一下他的汇编代码。

技术分享   

 下面是swap函数的:

技术分享

    其中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;
}

其实对应的图就是:

    技术分享

然后我们看代码:

        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

以上是关于浅谈栈帧(一)的主要内容,如果未能解决你的问题,请参考以下文章

浅谈栈

浅谈栈与队列(C语言)

浅谈栈与队列(C语言)

浅谈栈与队列(C语言)

浅谈栈与队列(C语言)

浅谈函数栈帧