书里应该要表达的是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