如何理解栈的地址是由高端地址向低端增长?

PE文件被Load到内存之后,代码区基址一般为0x00400000以上的区域,栈基址小于代码区加载的基址,如0x00130000。ebp是栈基址,esp是栈顶指针。 0x00400000大小为4MB,从0x00000000-0x00400000这个4MB大小的区域容纳了常量,全局变量,静态变量,栈。因此栈的空间不会太大,应该避免使用大的局部数组和多层次的递归,否则很容易溢出。而堆则在代码区之后,比如0x10000000到0x80000000-1,也就是接近2GB。当然代码区基址不是必须规定为0x00400000,这是由编译器决定的,编译器里可以指定栈大小,VC编译器默认是1MB,如果你指定为6MB,代码区基址必然会增加,如0x00800000。
向低地址扩展是指分配内存时是通过esp-分配的大小,假如ebp为0x00120004,esp开始和ebp是相同的,也为0x00120004,这时栈里是没有数据的,你定义了一个int i;那么编译器会esp-4,变为0x00120000,0x00120000 - 0x00120004存放4字节的i。如果再分配的话esp还会减少,即栈顶向低地址移动。显而易见,如果你要分配的内存太大,比如int data[100000000],那么esp-4*100000000会变为负值,就造成溢出了。当函数结束的时候,会收回局部变量的栈空间,如esp+4,使栈顶变回0x00120004。虽然0x00120000-0x00120004的内存区域里的数据仍然等于i,但这段内存已经不被esp保护,随时可以被覆盖了。
其实就跟库房摞箱子是一样的。来了一批箱子,就往上摞,相当于分配内存。出货的时候,当然也是从上面开始拿,不会从最底下抽,就是销毁内存。箱子摞得超过房顶就是栈溢出。至于栈向高地址生长而不是向高地址生长则是人为规定的,规则制定者认为向低地址生长有好处。就像仓库里放箱子,第一个可以挂房顶,第二个挂第一个下面,一直挂到地面上。这就相当于向高地址生长,至于是从地面往上摞方便还是从房顶往下挂方便则是人制定的。

BY jackson35296

你可能感兴趣的:(C++编程)