2013-02-22 49 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

相關問題