2013-02-22 48 views
17

Phải, tôi chắc chắn điều này được trả lời ngầm rất nhiều lần, nhưng dường như tôi không thể thực hiện được.Giữa ESP và EBP là gì?

Nếu bạn có dấu vết ngăn xếp (x86) (và nhìn vào nó trong WinDbg), và bạn nhìn vào thanh ghi, các giá trị EBP và ESP có nghĩa là gì x byte ngoài?

Links:

Để đưa ra một ví dụ về một dấu vết ngăn xếp gần đây tôi đã:

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 

Giá trị của ESP 1ac5ee8c - EBP 1ac5eef4 = 104 byte khác biệt. Vậy có gì trong đó?

Trả lời

55

ESP là con trỏ ngăn xếp hiện tại. EBP là con trỏ cơ sở cho khung ngăn xếp hiện tại.

Khi bạn gọi một hàm, thường không gian được đặt trước trên ngăn xếp cho các biến cục bộ. Không gian này thường được tham chiếu qua EBP (tất cả các biến cục bộ và tham số chức năng là một hằng số không đổi được biết đến từ thanh ghi này trong suốt thời gian của cuộc gọi hàm.) Mặt khác, ESP sẽ thay đổi trong khi gọi hàm. hoặc là không gian ngăn tạm thời được sử dụng cho các kết quả hoạt động một phần.

Lưu ý rằng hầu hết các trình biên dịch trong những ngày này đều có tùy chọn để tham khảo tất cả các biến cục bộ thông qua ESP. Điều này giải phóng EBP để sử dụng như một mục đích chung đăng ký.

Nói chung, khi bạn nhìn vào mã tháo dỡ ở phía trên cùng của một hàm bạn sẽ thấy một cái gì đó như thế này:

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

Vì vậy, EBP sẽ trỏ đến phía trên cùng của ngăn xếp của bạn cho khung này, và ESP sẽ trỏ đến byte sẵn có tiếp theo trên ngăn xếp. (Stacks thường - nhưng không phải - phát triển trong bộ nhớ.)

+0

Wrt. ví dụ của tôi, tôi đã kiểm tra trong trình gỡ lỗi cho một cuộc gọi đến Sleep: Không phải 'SleepEx' cũng không' NtDelayExecution' thực hiện một 'push EBP' và đặc biệt là' SleepEx' dường như là không cần thiết. Vì vậy, trong ví dụ của tôi, EBP vẫn trỏ đến vị trí ngăn xếp 'Sleep', với tất cả các công cụ từ hai hàm được gọi cũng trên stack. –

+0

Có, có thể hầu hết các chức năng của WinAPI được xây dựng với tùy chọn trình biên dịch giải phóng EBP cho mục đích sử dụng chung. Tức là trình biên dịch theo dõi bao nhiêu nó sửa đổi ESP trong suốt chức năng và tham khảo các biến địa phương liên quan đến ESP với các offset khác nhau khi cần thiết.Trong trường hợp này, không có cách nào để biết EBP-ESP có phản ánh chính xác kích thước của khung stack hiện tại hay không. Hầu hết có lẽ nó không. –

+0

'some_number' là gì? Không phải lúc nào cũng là 0? – zoujyjs

1

Thông thường, không gian này được dành riêng cho các biến cục bộ được lưu trữ trên ngăn xếp. Khi bắt đầu chức năng, ESP được giảm theo giá trị thích hợp.

Trong trường hợp của bạn, có 104 byte giá trị của người dân địa phương trong hàm.

+0

104 byte cho NtDelayExecution có vẻ tuyệt vời ... nhưng sau đó một lần nữa, có thể callstack hiển thị bị hỏng ... –

+0

Vâng, 104 byte không phải là nhiều, đặc biệt nếu 'NtDelayExecution()' cấp phát một bộ đệm chuỗi trên ngăn xếp vì một lý do nào đó. –

+1

Tôi đã kiểm tra chéo. * Không có 'SleepEx' hay NtDelayExecution nào thực hiện một' push EBP' và đặc biệt là 'SleepEx' dường như không phát triển. Vì vậy, trong ví dụ của tôi, EBP vẫn trỏ đến vị trí ngăn xếp 'Sleep'. –

Các vấn đề liên quan