【发布时间】:2021-07-26 07:24:11
【问题描述】:
我试图通过函数调用了解更多关于堆栈指针的行为,但我不确定我是否理解当我们调用函数并从函数返回时会发生什么。 假设我有这个主程序:
int main()
{
demo();
return 0;
}
而demo是这样定义的:
void demo()
{
}
我使用的是 VS2019,当我调试时,我会通过时间检查以下 SP 值与汇编代码相关的内容(调试会话的值示例):
- 在输入
demo之前-
EAX = 00DDD006 EBX = 00608000 ECX = 00DDD006 EDX = 00000001 ESI = 00DD1023 EDI = 008FFBA8 EIP = 00DD1D4F ESP = 008FFAB8 EBP = 008FFBA8 EFL = 00000246
demo();
00DD1D4F call _bar (0DD1410h)
- 进入
call-EAX = 00DDD006 EBX = 00608000 ECX = 00DDD006 EDX = 00000001 ESI = 00DD1023 EDI = 008FFBA8 EIP = 00DD1410 ESP = 008FFAB4 EBP = 008FFBA8 EFL = 00000246
在装配中的位置是:
00DD1410 jmp demo (0DD1A30h)
- 一步入
jmp函数-EAX = 00DDD006 EBX = 00608000 ECX = 00DDD006 EDX = 00000001 ESI = 00DD1023 EDI = 008FFBA8 EIP = 00DD1A30 ESP = 008FFAB4 EBP = 008FFBA8 EFL = 00000246
汇编中的函数流程:
void demo()
{
(1) 00DD1A30 push ebp
(2) 00DD1A31 mov ebp,esp
(3) 00DD1A33 sub esp,0C0h
(4) 00DD1A39 push ebx
(5) 00DD1A3A push esi
(6) 00DD1A3B push edi
(7) 00DD1A3C lea edi,[ebp-0C0h]
(8) 00DD1A42 mov ecx,30h
(9) 00DD1A47 mov eax,0CCCCCCCCh
(10)00DD1A4C rep stos dword ptr es:[edi]
(11)00DD1A4E mov ecx,offset _2D317A6C_scratch_pad@c (0DDD00Ch)
(12)00DD1A53 call @__CheckForDebuggerJustMyCode@4 (0DD134Dh)
}
- 进入 (1),更改 -
EAX = 00DDD006 EBX = 00608000 ECX = 00DDD006 EDX = 00000001 ESI = 00DD1023 EDI = 008FFBA8 EIP = 00DD1A31 ESP = 008FFAB0 EBP = 008FFBA8 EFL = 00000246 - 进入 (2),更改 -
AX = 00DDD006 EBX = 00608000 ECX = 00DDD006 EDX = 00000001 ESI = 00DD1023 EDI = 008FFBA8 EIP = 00DD1A33 ESP = 008FFAB0 EBP = 008FFAB0 EFL = 00000246 - 进入 (3),更改 -
EAX = 00DDD006 EBX = 00608000 ECX = 00DDD006 EDX = 00000001 ESI = 00DD1023 EDI = 008FFBA8 EIP = 00DD1A39 ESP = 008FF9F0 EBP = 008FFAB0 EFL = 00000206 - 进入 (4),更改 -
EAX = 00DDD006 EBX = 00608000 ECX = 00DDD006 EDX = 00000001 ESI = 00DD1023 EDI = 008FFBA8 EIP = 00DD1A3A ESP = 008FF9EC EBP = 008FFAB0 EFL = 00000206 - 进入 (5),更改 -
EAX = 00DDD006 EBX = 00608000 ECX = 00DDD006 EDX = 00000001 ESI = 00DD1023 EDI = 008FFBA8 EIP = 00DD1A3B ESP = 008FF9E8 EBP = 008FFAB0 EFL = 00000206 - 进入 (6),更改 -
EAX = 00DDD006 EBX = 00608000 ECX = 00DDD006 EDX = 00000001 ESI = 00DD1023 EDI = 008FFBA8 EIP = 00DD1A3C ESP = 008FF9E4 EBP = 008FFAB0 EFL = 00000206 - 进入 (7),更改 -
EAX = 00DDD006 EBX = 00608000 ECX = 00DDD006 EDX = 00000001 ESI = 00DD1023 EDI = 008FF9F0 EIP = 00DD1A42 ESP = 008FF9E4 EBP = 008FFAB0 EFL = 00000206 - 进入 (8),更改 -
EAX = 00DDD006 EBX = 00608000 ECX = 00000030 EDX = 00000001 ESI = 00DD1023 EDI = 008FF9F0 EIP = 00DD1A47 ESP = 008FF9E4 EBP = 008FFAB0 EFL = 00000206 - 进入 (9),更改 -
EAX = CCCCCCCC EBX = 00608000 ECX = 00000030 EDX = 00000001 ESI = 00DD1023 EDI = 008FF9F0 EIP = 00DD1A4C ESP = 008FF9E4 EBP = 008FFAB0 EFL = 00000206 - 跨步进入 (10),更改-
EAX = CCCCCCCC EBX = 00608000 ECX = 00000000 EDX = 00000001 ESI = 00DD1023 EDI = 008FFAB0 EIP = 00DD1A4E ESP = 008FF9E4 EBP = 008FFAB0 EFL = 00000206 - 跨过 (11),改变——
EAX = CCCCCCCC EBX = 00608000 ECX = 00DDD00C EDX = 00000001 ESI = 00DD1023 EDI = 008FFAB0 EIP = 00DD1A53 ESP = 008FF9E4 EBP = 008FFAB0 EFL = 00000206 - 进入(12),改变——
EAX = CCCCCCCC EBX = 00608000 ECX = 00DDD00C EDX = 00000001 ESI = 00DD1023 EDI = 008FFAB0 EIP = 00DD134D ESP = 008FF9E0 EBP = 008FFAB0 EFL = 00000206
我的问题是:
- 在进入演示之前,
ESP = 008FFAB8,然后将ESP更改为ESP = 008FFAB4。在这 4 个字节中插入了什么导致堆栈指针增加(向下)? - EBP 本质上是“帧指针”吗?在它下面的 4 个字节中,我们可以假设返回地址驻留?然后是函数的参数?
- 差异
EBP - ESP是否导致为函数的本地分配的内存? - 是否每次我们在
demo范围内推送某些内容(如 (1) 中所做的那样),堆栈指针会增加吗? - 希望能解释一下步骤 (1)-(9) 中堆栈中究竟发生了什么。
【问题讨论】:
-
您也可以使用 VS2019 单步执行汇编代码。使用 Debug>Windows>Disassembly 命令。
-
我怀疑这个问题的上下文是this previous question。
-
在“2. 进入
demo,就在开头”和“3. 进入demo函数”之后,不清楚您在代码中的哪个位置。以及究竟是什么意思“4.从demo返回到main”。第 4 步实际上可能是为局部变量释放内存并返回调用函数的两个步骤。 (函数调用的实现很大程度上取决于处理器架构。) -
我已经详细说明了我的问题,可以重新打开吗?
标签: c stack-frame stack-pointer