您的位置:首页 > 其它

栈帧 --- 程序运行中数据的更改问题

2016-04-01 21:19 176 查看
一、
栈作为一种特殊的数据结构而存在(“后入先出”存储),是一种只能在一端进行插入和删除操作的特殊线性表。
大多数CPU上的程序实现使用栈来支持函数调用操作。栈用来传递函数参数、存储返回信息、临时保存寄存器原有值以用于回复以及存储局部数据。
栈有很多自己的特性,它具有记忆功能,对栈的插入与删除操作中,不需要改变栈底指针;而且栈是从高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息。因此栈作用就是用来保持栈帧的活动记录(即函数调用)。
栈相对整个系统而言,调用栈相对某个进程而言,栈帧则是相对某个函数而言,调用栈就是正在使用的栈空间,由多个嵌套调用函数所使用的栈帧组成。
如果C语言的地址符'&'被应用到一个局部变量时,栈则需要为该变量生成一个地址值即变量的地址值分配一个空间。



二、栈帧
栈帧表示程序的函数调用记录,而栈帧又是记录在栈上面,很明显栈上保持了N个栈帧的实体,那就可以说栈帧将栈分割成了N个记录块,但是这些记录块大小不是固定的,因为栈帧不仅保存诸如:函数入参、出参、返回地址和上一个栈帧的栈底指针等信息,还保存了函数内部的自动变量(甚至可以是动态分配内存,alloca函数就可以实现,但在某些系统中不行),因此,不是所有的栈帧的大小都相同。
单个函数调用操作所使用的栈部分称为栈帧结果。栈帧结构的两端由两个指针来指定。寄存器ebp通常用作栈帧的指针、esp用作栈的指针。esp随着数据的入栈和出栈。因此对于函数中大部分数据的访问都是通过基于帧帧指针ebp来实现。


ebp指向当前位于系统栈最上边一个栈帧的底部,而不是系统栈的底部; esp所指的栈帧顶部和系统栈的顶部是同一个位置。



例:
程序代码:
#include<stdio.h>
#include<stdlib.h>
int stack_test(int a,int b)
{
printf("before write: 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;
}
运行结果:





结果分析:
程序运行中数据的改变:




程序运行前,&b=0xbbbb;
当程序运行后,系统重新分配一个临时空间。*p=&a,即此时临时拷贝a至新的内存空间;p++,*p向上移动一位,而此时*p的地址被赋予0xdddd.
而栈以“后入先出”存储,即此时*p是该新栈帧的底部,先一步出去,因而&b=*p=0xdddd.
例:
程序如下;
#include<stdio.h>
#include<stdlib.h>
int bug()
{
system("reboot");
exit(0);
}
int stack_test(int a,int b)
{
int *p=&a;
p--;
*p=bug();

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;
}
运行结果:
系统重启
结果分析:
情况和上例类似,当程序运行到bug()时,程序内部函数system("reboot")会命令系统重启,而随后exit(0)以正常情况结束程序。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  栈帧