WEB开发网
开发学院软件开发VC ATL布幔之下的秘密(4) 阅读

ATL布幔之下的秘密(4)

 2006-07-22 22:54:54 来源:WEB开发网   
核心提示: 现在来探究一下编译器为我们产生的代码,编译器插入这个代码来创建堆栈帧,ATL布幔之下的秘密(4)(4),这样它就可以通过标准方式来存取参数和局部变量了,堆栈帧是一个为函数保留的区域,也就是定义在函数定义上方的这些东西: _a$ = 8_b$ = 12_x$ = -4_y$ = -8_z$

现在来探究一下编译器为我们产生的代码。编译器插入这个代码来创建堆栈帧,这样它就可以通过标准方式来存取参数和局部变量了。堆栈帧是一个为函数保留的区域,用来存储关于参数、局部变量和返回地址的信息。堆栈帧通常是在新的函数调用的时候创建,并在函数返回的时候销毁。在8086体系中,EBP寄存器就被用于存储堆栈帧的地址,有时叫做栈指针。(译注:ESP和EBP在本文中都被作者笼统地称为“Stack Pointer”,事实上ESP应称作“堆栈指针[Stack Pointer]寄存器”,它指示堆栈的栈顶便宜地址;EBP应称作“基址指针[Base Pointer]寄存器”,它用来作为基地址并和偏移量组合使用来访问堆栈中的信息。)

这样,编译器首先保存前一个堆栈帧的地址,然后使用ESP的值创建新的堆栈帧。函数返回之前,先前的堆栈帧就恢复了。

现在来看看堆栈帧中都有什么。在EBP的高地址一边存放所有参数,EBP的低地址一边则存放所有的局部变量。

函数的返回地址保存在EBP中,前一个堆栈帧的地址保存在EBP + 4。现在看看下面的例子,它拥有两个参数和三个局部变量。

程序61. extern "C" void fun(int a, int b) {
 int x = a;
 int y = b;
 int z = x + y;
 return;
}
int main() {
 fun(5, 10);
 return 0;
}
现在来看看编译器产生的函数代码。push ebp
mov  ebp, esp
sub  esp, 12         ; 0000000cH
; int x = a;
mov  eax, DWORD PTR _a$[ebp]
mov  DWORD PTR _x$[ebp], eax
; int y = b;
mov  ecx, DWORD PTR _b$[ebp]
mov  DWORD PTR _y$[ebp], ecx
; int z = x + y;
mov  edx, DWORD PTR _x$[ebp]
add  edx, DWORD PTR _y$[ebp]
mov  DWORD PTR _z$[ebp], edx
mov  esp, ebp
pop  ebp
ret  0
现在来看看_x、_y这些东西都是什么。也就是定义在函数定义上方的这些东西: _a$ = 8
_b$ = 12
_x$ = -4
_y$ = -8
_z$ = -12
这就意味着你可以像这样阅读代码: ; int x = a;
mov eax, DWORD PTR [ebp + 8]
mov DWORD PTR [ebp - 4], eax
; int y = b;
mov ecx, DWORD PTR [ebp + 12]
mov DWORD PTR [ebp - 8], ecx
; int z = x + y;
mov edx, DWORD PTR [ebp - 4]
add edx, DWORD PTR [ebp - 8]
mov DWORD PTR [ebp - 12], edx
这也就意味着参数a和b的地址分别为EBP + 8和EBP + 12。并且,x、y和z的值分别存储在内存中EBP - 4、EBP - 8、EBP - 12的位置上。

上一页  1 2 3 4 5 6  下一页

Tags:ATL 之下 秘密

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接