汇编中的堆栈关系

开始学习汇编,虽然以前上学时学过,但很多年不用,早就忘了。

主要分两种汇编,Intel格式的和AT&T格式的。前者windows上用,后者在Unix/LInux上用。 不过还是有工具可以转换的。

网上介绍AT&T的很多,与Intel格式的区别主要就是指令加长度表示,操作数顺序相反,[]变(),寄存器加%,立即数加$,寻址偏移格式等。

看汇编,以下是x86,intel格式,vc,release

int func(int x,int y){return x+y;}
00401000  mov eax,[esp+08] ;我在想为什么不用pop,后来理解原来esp处是上级函数的返回地址(因call调用),所以只能用内存寻址
00401004  mov ecx,[esp+04] ;一样
00401008  add eax,ecx  ;x+y,结果在eax中
0040100A  ret
0040100B  nop
void main(){
 printf("%d/n",func(1,2));
 ...
00401010  push 02 ;压参,从右边到左
00401012  push 01 ;
00401014  call 00401000 ;调用func,结果在eax中
00401019  add esp,08    ;恢复sp位置,因为func是c-call不会恢复main的参数堆栈位置。根据我的实验stdcall是不需要这句的,因为stdcall由被调用参数恢复压栈位置的。但c-call和stdcall参数入栈顺序都是从右向左。
0040101C  push eax ;printf的参数

当debug版和在linux上,函数内一般会先建栈框架,就是将当前esp赋给ebp做为当前函数的栈基地址,这样能够在退出函数时恢复栈地址。

push ebp ;开头:将上级函数的栈基地址保存
mov ebp,esp ;将当前栈位置做为当前函数的栈基地址
。。。。。
。。。。。 ;其它处理,如定义临时变量需要栈,调用其它函数时要压参数栈
。。。。。
mov esp,ebp ;结尾:恢复到开头的栈地址(保证了中间过程栈移动不匹配)
pop ebp  ;取出保存的上级函数的栈基

 

你可能感兴趣的:(汇编中的堆栈关系)