2013-02-22 51 views
17

没错,我确信这已经隐含地回答了很多次,但我似乎无法完全理解它。ESP和EBP之间是什么?

如果您有一个(x86)堆栈跟踪(比如说,在WinDbg中查看它),并且您查看寄存器,那么EBP和ESP值相距x字节意味着什么?

链接:

举一个最近的堆栈跟踪我有一个例子:

0:016> k 
ChildEBP RetAddr 
1ac5ee8c 76b831bb ntdll!NtDelayExecution+0x15 
1ac5eef4 76b83a8b KERNELBASE!SleepEx+0x65 
1ac5ef04 0060e848 KERNELBASE!Sleep+0xf 
1ac5ef10 76859d77 MyApp!application_crash::CommonUnhandledExceptionFilter+0x48 [...\applicationcrash.inc.cpp @ 47] 
1ac5ef98 775a0df7 kernel32!UnhandledExceptionFilter+0x127 
1ac5efa0 775a0cd4 ntdll!__RtlUserThreadStart+0x62 
1ac5efb4 775a0b71 ntdll!_EH4_CallFilterFunc+0x12 
1ac5efdc 77576ac9 ntdll!_except_handler4+0x8e 
1ac5f000 77576a9b ntdll!ExecuteHandler2+0x26 
1ac5f0b0 7754010f ntdll!ExecuteHandler+0x24 
1ac5f0b0 6e8858bb ntdll!KiUserExceptionDispatcher+0xf 
1ac5f400 74e68ed7 mfc80u!ATL::CSimpleStringT<wchar_t,1>::GetString [f:\dd\vctools\vc7libs\ship\atlmfc\include\atlsimpstr.h @ 548] 
1ac5fec0 6e8c818e msvcr80!_NLG_Return [F:\dd\vctools\crt_bld\SELF_X86\crt\prebuild\eh\i386\lowhelpr.asm @ 73] 
1ac5ff48 74e429bb mfc80u!_AfxThreadEntry+0xf2 [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\thrdcore.cpp @ 109] 
1ac5ff80 74e42a47 msvcr80!_callthreadstartex+0x1b [f:\dd\vctools\crt_bld\self_x86\crt\src\threadex.c @ 348] 
1ac5ff88 76833677 msvcr80!_threadstartex+0x66 [f:\dd\vctools\crt_bld\self_x86\crt\src\threadex.c @ 326] 
1ac5ff94 77569f02 kernel32!BaseThreadInitThunk+0xe 
1ac5ffd4 77569ed5 ntdll!__RtlUserThreadStart+0x70 
1ac5ffec 00000000 ntdll!_RtlUserThreadStart+0x1b 

0:016> r 
eax=00000000 ebx=1ac5efc8 ecx=19850614 edx=00000000 esi=1ac5eed0 edi=00000000 
eip=7754fd21 esp=1ac5ee8c ebp=1ac5eef4 iopl=0   nv up ei pl nz na pe nc 
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b    efl=00010206 

ESP 1ac5ee8c的值 - EBP 1ac5eef4 = 104字节的差异。那里有什么?

回答

55

ESP是当前堆栈指针。 EBP是当前堆栈帧的基址指针。

当您调用一个函数时,通常会在堆栈中为局部变量保留空间。这个空间通常通过EBP来引用(所有局部变量和函数参数都是函数调用期间该寄存器的已知常量偏移量)。另一方面,在函数调用期间ESP会随着其他函数的调用而改变,或者将临时堆栈空间用于部分操作结果。

请注意,现在大多数编译器都可以通过ESP引用所有局部变量。这释放了EBP用作通用寄存器。

一般来说,当你在看反汇编代码在函数的顶部,你会看到这样的内容:

push EBP 
mov EBP, ESP 
sub ESP, <some_number> 

所以EBP将指向堆栈的顶部为这个框架,并ESP将指向堆栈中的下一个可用字节。 (堆栈通常是 - 但不必 - 向下生长在内存中)

为NtDelayExecution
+0

Wrt。我的例子中,我在调试器中检查了Sleep的调用:'SleepEx'和'NtDelayExecution'都没有'push EBP',特别是'SleepEx'似乎不平凡。因此,在我的例子中,EBP仍然指向'Sleep'堆栈位置,所有来自两个被调用函数的东西也在堆栈中。 – 2013-02-22 09:53:39

+0

是的,大多数WinAPI函数都可以使用编译器选项构建,这样可以释放EBP以供一般用途使用。也就是说,编译器会跟踪它在整个函数中修改ESP的程度,并根据需要使用不同的偏移量引用相对于ESP的局部变量。在这种情况下,无法知道EBP-ESP是否准确反映当前堆栈帧的大小。很可能它没有。 – 2013-02-22 12:31:56

+0

什么是'some_number'?不总是0? – zoujyjs 2017-08-29 10:58:30

1

通常,这个空间是为保存在堆栈上的局部变量保留的。在函数开始时,ESP将递减适当的值。

在你的情况下,在这个函数中有104个字节的当地人。

+0

104字节似乎惊人......但话又说回来,也许所示坏调用堆栈... – 2013-02-22 09:45:06

+0

好,104个字节是不是这很多,特别是如果NtDelayExecution()由于某种原因在栈上分配字符串缓冲区时。 – 2013-02-22 09:47:27

+1

我经过检查。 *'SleepEx'和NtDelayExecution都不会'推EBP',特别是'SleepEx'似乎不平凡。所以在我的例子中,EBP仍然指向“睡眠”堆栈位置。 – 2013-02-22 09:52:30

相关问题