百科问答小站 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




  

相关话题

  怎样评价《数码宝贝》第一部中的泉光子郎的编程水平? 
  关于后端程序员写前端用什么框架更好? 
  for 循环的 "for" 是什么意思?为什么用这个词? 
  vscode是用什么语言写出来的?为什么华为能做出鸿蒙系统,却开发不出类似vscode的开发工具? 
  如何反驳「程序员离开电脑就是废物」这个观点? 
  如何入门 Python 爬虫? 
  能用电脑模拟计划生育后人口的变化吗? 
  国外的程序员是如何保养「革命的本钱」? 
  作为非计算机专业的学生,觉得 C 语言远比其他语言易于上手,正常吗? 
  重载 Throwable.fillInStackTrace() 方法以提高Java性能这样的做法对吗? 

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





© 2024-09-19 - tinynew.org. All Rights Reserved.
© 2024-09-19 - tinynew.org. 保留所有权利