自己在VS2008的环境下,对程序1进行了反汇编,并随着单步调试的进行察看了内存的变化,发现书上给出的图和描述存在一些小错误。在此将实际的过程记录下来。
//程序1
#include <iostream>
using namespacestd;
int foo(inti){
int a= 1, b= 2;
b = a;
return i;
}
int main(){
int a =foo(0xABCDEF);
return 0;
}
首先要说明的是,程序运行时的实现是根据编译器的不同而不同的,因此需要强调,本文中讨论的所有过程都是在VS2008的编译环境下进行的,且考察的是debug版本的反汇编。
图1 运行时的栈结构
图1 是函数调用时栈的结构,下面来具体说一说汇编指令每一步都做了什么。
要事先说明的是EBP指针和ESP指针,前者在一个函数的运行过程中(没有调用其他函数时)是一个固定值,它指向的位置如图1所示;后者是栈顶指针。
序
操作方
对应汇编
内存操作
1
main
函数
push 0ABCDEFh
函数参数压栈
ESP指向位置1
2
main
函数
call foo (11C1028h)
在调用的时候,会自动将调用函数之后下一条要执行的指令地址(也就是所谓的返回地址)压栈
ESP指向位置2
3
foo
函数
push ebp
mov ebp,esp
将旧的EBP值压栈;
ESP指向位置3
将当前ESP值赋给EBP,所以EBP也指向位置3
4
foo
函数
sub esp,0D8h
在栈上给局部变量预留空间
ESP指向位置4
5
foo
函数
push ebx
push esi
push edi
寄存器压栈保存
ESP指向位置5
6
foo
函数
lea edi,[ebp-0D8h]
mov ecx,36h
mov eax,0CCCCCCCCh
rep stos dword ptr es:[edi]