最近我反彙編了一個DLL(用c/C++編寫),並注意到代碼段中有很多「跳轉存根」。這些存根(stub)什麼都不做,只是跳轉到DLL中的一個函數。PE文件中的跳轉存根
如:
jmp foo()
jmp foo2()
...
爲什麼編譯器(的Visual Studio 2012),包括二進制文件內這些功能存根?
謝謝!
最近我反彙編了一個DLL(用c/C++編寫),並注意到代碼段中有很多「跳轉存根」。這些存根(stub)什麼都不做,只是跳轉到DLL中的一個函數。PE文件中的跳轉存根
如:
jmp foo()
jmp foo2()
...
爲什麼編譯器(的Visual Studio 2012),包括二進制文件內這些功能存根?
謝謝!
在所有存根之後是否有一大堆0xCC字節?如果是這樣,您正在查看已啓用增量鏈接編譯的代碼(默認爲調試版本)。
編譯增量鏈接時,編譯器會爲每個函數創建一個存根,並確保所有調用都通過存根。如果需要用更新後的代碼替換某個功能,新代碼可以添加到最後,並且只需要修補跳轉thunk - 所有現有的調用都將被重定向到新代碼。在添加新功能的情況下,額外的CC被預留給更多的存根。
欲瞭解更多背景信息,see MSDN。
這就是鏈接器和DLL的符號如何「混合在一起」。它保證在符號表中使用正確的偏移量,可以通過加載DLL的加載程序來解析(從而更新DLL中函數的地址),並且編譯後的代碼仍然可以處理函數指針:
void (*fptr)() = foo;
如果foo
僅僅是一個地方一個參考的DLL,這個地址是如何解決將取決於裝載機。解決這個問題要複雜得多,而不是解決「這是一個foo()入口點,讓你到真正的foo」的問題。
DLL =共享庫。是的,我們討論的是'foo'是'mydll.dll'的一部分,而不是'myprog.exe'。 –
DLL的可重定位,這意味着它們可能會在內存中的任何地方結束。這意味着所有對它們的呼叫都必須重寫。通過以小跳躍方式將所有這些呼叫保持在一起,在重定位的情況下只需要重寫一個頁面。這很重要,因爲可以跨進程共享未改變的代碼頁面,但每個進程都有自己的修改頁面副本。
yes在這些thunk之後有一個0xcc字節的buch。而這些thunk只出現在發佈版本中。 – user2458855