我一直髮現這是Visual Studio中非常有用的功能。對於那些不知道它的人來說,它允許您在調試正在運行的進程時編輯代碼,在二進制文件仍在運行時重新編譯代碼並繼續無縫地使用該應用程序與新代碼,而無需需要重新啓動它。「編輯並繼續」在Visual Studio中如何工作?
該功能是如何實現的?如果我正在修改的代碼位於由應用程序加載的DLL中,應用程序是否簡單地卸載DLL並重新加載它?這在我看來似乎很容易出現不穩定問題,所以我認爲它會比這更聰明。有任何想法嗎?
我一直髮現這是Visual Studio中非常有用的功能。對於那些不知道它的人來說,它允許您在調試正在運行的進程時編輯代碼,在二進制文件仍在運行時重新編譯代碼並繼續無縫地使用該應用程序與新代碼,而無需需要重新啓動它。「編輯並繼續」在Visual Studio中如何工作?
該功能是如何實現的?如果我正在修改的代碼位於由應用程序加載的DLL中,應用程序是否簡單地卸載DLL並重新加載它?這在我看來似乎很容易出現不穩定問題,所以我認爲它會比這更聰明。有任何想法嗎?
我的理解是,當應用程序編譯時支持編輯並繼續啓用,編譯器會在二進制映像中爲函數留出額外空間以允許添加其他代碼。然後調試器可以編譯新版本的函數,替換現有版本(根據需要使用填充空間),修改堆棧,設置指令指針並繼續。這樣你就不必修正任何跳轉指針,只要你有足夠的填充。
請注意,編輯並繼續通常不會在libs/dll中的代碼上工作,只能使用主要的可執行代碼。
我的猜測是它重新編譯應用程序(對於小的更改,這並不意味着非常需要重新編譯)。然後,由於微軟同時提供了編譯器和調試器,所以他們可以確保如何佈置內存等。因此,只要變化足夠小,他們就可以使用調試API重新編寫新代碼段。
如果更改重定向到全新的代碼,這顯然可以以與DLL相似的樣式加載到內存中。
微軟還有一個「熱補丁」機制。在任何真正的代碼之前,函數都有一個2字節的非操作指令,通常類似「mov edx,edx」。這使他們能夠乾淨地重定向函數的執行。這也是一種選擇。
要記住的關鍵是應用程序不是「正在運行」,它的所有線程都處於停止狀態。所以就流程而言,調試器所做的任何修改都是完全原子化的。
當然,這都是猜測;)
我的猜測是所有的對象都對齊到4096字節存儲器邊界。所以如果你對一些代碼做了小的修改,那麼這些對象仍然在這些邊界之內,因此就像以前一樣運行。
我已經有了更改幾行代碼會導致完全重新編譯和鏈接的情況,以及其他對函數進行相當大的重構將會很好的重構。
我喜歡將函數重新路由到外部的想法。當我使用「/ ZI」構建exe文件時,我在可執行文件中看到一個新的「.textbss」部分,可能它用於存儲編輯後的代碼。 – stgatilov 2016-11-10 17:31:10
根據dumpbin,「.textbss」部分被標記爲未初始化,並且具有讀取+寫入+執行權限,這使得它非常適合存儲和執行動態生成的代碼=) – stgatilov 2016-11-10 17:37:39