百科问答小站 logo
百科问答小站 font logo



汇编过程调用是怎样操作栈的? 第1页

  

user avatar   bei-ji-85 网友的相关建议: 
      

书里应该要表达的是stack frame的意思吧?

x86/x64里面,stack frame就是根据当前的ebp能反推出整个调用栈。

ebp esp eip的几个特性:

1. 主流编译器在函数调用的caller里,执行call指令会让eip入栈;

2. 被调函数(callee)里头两句一定是

push ebp

mov ebp, esp

最后一句一定是

mov esp, ebp

pop ebp

3. ebp在函数内部是不会改变的,入栈出栈动作只改变esp,于是通过ebp就能反推出整个调用栈了。

反推栈帧的方法

当前的ebp就是当前函数入口时的esp;

入口时的[esp-4]就是前一个函数的ebp;

入口时的[esp-8]就是前一个函数的eip值;

拿到前一个函数的ebp值继续反推就能获得整个调用栈的ebp esp eip,这就是stack frame。

如果是64位:

寄存器换成rip rbp rsp,栈指针一次减8;

其它方面:

1. 基本没有far call(系统调用、中断除外),所以,栈上一般只有IP,没有CS;

2. 32位多数情况下参数用栈传输,64位下是用寄存器的更多,具体要看编译器;

3. enter和leave指令等效于push ebp; mov ebp, esp和mov esp, ebp; pop ebp;

---------------------------------

实例:

函数调用up_align_to -> align_to,汇编为VS2008

       size_t up_align_to(size_t val, size_t align)     { 011914B0 55               push        ebp   011914B1 8B EC            mov         ebp,esp  011914B3 81 EC C0 00 00 00 sub         esp,0C0h  011914B9 53               push        ebx   011914BA 56               push        esi   011914BB 57               push        edi   011914BC 8D BD 40 FF FF FF lea         edi,[ebp-0C0h]  011914C2 B9 30 00 00 00   mov         ecx,30h  011914C7 B8 CC CC CC CC   mov         eax,0CCCCCCCCh  011914CC F3 AB            rep stos    dword ptr es:[edi]      return align_to(val, align, 1); 011914CE 6A 01            push        1                   //参数3 011914D0 8B 45 0C         mov         eax,dword ptr [align]  011914D3 50               push        eax                 //参数2 011914D4 8B 4D 08         mov         ecx,dword ptr [val]  011914D7 51               push        ecx                 //参数1 011914D8 E8 08 FD FF FF   call        align_to (11911E5h) //函数调用 011914DD 83 C4 0C         add         esp,0Ch      } 011914E0 5F               pop         edi   011914E1 5E               pop         esi   011914E2 5B               pop         ebx   011914E3 81 C4 C0 00 00 00 add         esp,0C0h  011914E9 3B EC            cmp         ebp,esp  011914EB E8 73 FC FF FF   call        @ILT+350(__RTC_CheckEsp) (1191163h)  011914F0 8B E5            mov         esp,ebp  011914F2 5D               pop         ebp   011914F3 C3               ret        size_t align_to(size_t val, size_t align, int is_up)     { 01191420 55               push        ebp                //保存ebp 01191421 8B EC            mov         ebp,esp            //保存esp 01191423 81 EC C0 00 00 00 sub         esp,0C0h  01191429 53               push        ebx   0119142A 56               push        esi   0119142B 57               push        edi   0119142C 8D BD 40 FF FF FF lea         edi,[ebp-0C0h]  01191432 B9 30 00 00 00   mov         ecx,30h  01191437 B8 CC CC CC CC   mov         eax,0CCCCCCCCh  0119143C F3 AB            rep stos    dword ptr es:[edi]      if (val % align == 0)     

执行到参数3以后

       [栈上其它数据] [参数3] []  <-esp,ebp为up_align_to入口时的esp值     

执行到参数2以后

       [栈上其它数据] [参数3] [参数2] []  <-esp,ebp为up_align_to入口时的esp值     

执行到参数1以后

       [栈上其它数据] [参数3] [参数2] [参数1] []  <-esp,ebp为up_align_to入口时的esp值     

执行CALL以后

       [栈上其它数据] [参数3] [参数2] [参数1] [eip] []  <-esp,ebp为up_align_to入口时的esp值     

执行到保存ebp以后

       [栈上其它数据] [参数3] [参数2] [参数1] [eip] [ebp] []  <-esp,ebp为up_align_to入口时的esp值     

执行到保存esp以后

       [栈上其它数据] [参数3] [参数2] [参数1] [eip] [ebp] []  <-esp,ebp为align_to入口时的esp值     

[ebp-4]就是up_align_to入口时的esp值

[ebp-8]就是call指令后面的地址(011914DD)

[[ebp-4]-4]是上上个调用函数入口时的esp值

[[ebp-4]-8]是上上个调用函数call后边的地址

所以,求stack frame只要递归求[ebp-4]就行了,每个ebp-4挨着的就是eip




  

相关话题

  为什么国外一些常见问答网站的地址栏中常常就给出了问题题目,相对于像国内一样使用ID来标记而言好在哪里? 
  高考录到北邮计算机,四年怎么做才能年薪百万? 
  C#的Lambda表达式捕获变量疑问? 
  Diffie-Hellman密码交换是如何运作的? 
  微软的编程处于什么样的水平? 
  数学/算法:正方形内有5个点,为什么最近点对的距离小于边长? 
  全世界有上千种编程语言,为什么程序员都只学习那几个主流语言? 
  天天写业务代码的程序员,怎么成为技术大牛,开始写技术代码? 
  感觉算法在程序员中快被吹上天了,如果只是搞编程的话,是不是没必要死磕算法? 
  c语言程序经过编译后,每条指令都有一个内存地址,那两个程序如果有相同内存地址的指令怎么办? 

前一个讨论
自己开发的Windows7 64位驱动程序需要签名,怎么解决?
下一个讨论
为什么广州和福州之间没有任何直达火车?





© 2024-12-22 - tinynew.org. All Rights Reserved.
© 2024-12-22 - tinynew.org. 保留所有权利