為什麼我不能在調試/反彙編期間進入呼叫指令?
反彙編看起來像:
methShort( ref x, ref y ); 000007FF00163F67 lea r8,[rsp+34h] 000007FF00163F6C lea rdx,[rsp+30h] 000007FF00163F71 mov rcx,qword ptr [rsp+20h] 000007FF00163F76 mov rcx,qword ptr [rcx+8] 000007FF00163F7A mov rax,qword ptr [rsp+20h] 000007FF00163F7F call qword ptr [rax+18h]方法“methShort”是在 .NET 中使用 Reflection.Emit 動態創建的。它採用兩個 Int32 參數作為“byRef”值。這被調試為“發布模式”建構。
我可以逐步完成程序集,直到“呼叫”指令。R8 和 RDX(參數)指向的記憶體內容看起來不錯。我不知道什麼樣的魔法允許 JIT 使用寄存器而不是堆棧進行呼叫,但這不是重點。
當我嘗試“步入”呼叫指令時,調試器會“跳過”它。該常式確實被呼叫了——該方法正確地執行了它的功能。但我似乎無法拆卸也無法進入該方法。
在呼叫之前的點,RAX 包含值 00000000025C67A8h。加上 18h 後,間接地址變為 00000000025C67C0h。這個地址的 QWORD 是 000000001b64dc48h。
如果我嘗試反彙編這個地址(000000001b64dc48h),調試器會返回“無法顯示指定的地址。提供的位置沒有程式碼”。
作為 Hail Mary 的嘗試,我嘗試在沒有間接的情況下在 RAX 上反彙編程式碼,但正如我預期的那樣,這也失敗了。
誰能告訴我如何獲取地址中的任何程式碼,或者是否需要在地址 (RAX+18h) 上執行類似於 LEA 的操作,然後再分解那裡的程式碼?
您需要記住,調試器正試圖讓您免於浪費幾個小時的生命。 是委託呼叫,在該呼叫完成之前
methShort()仍需要完成*大量工作。*您不會喜歡單步執行將動態方法編譯為機器程式碼、CAS 檢查連結需求、CLR 創建委託存根並將其綁定到呼叫站點的單步調試。我將回答發布的問題,調試器不會向您顯示呼叫目標程式碼,因為它是非託管程式碼。您可以從地址中看出,遠離您的 jit 程式碼的位置。說服它你想看到它需要幾個技巧:
- 項目+屬性,調試選項卡,勾選“啟用本機程式碼調試”選項
- 您必須將調試器從託管模式切換到非託管模式。沒有明確的命令,我知道如何做到這一點的最簡單方法是使用呼叫堆棧視窗。點兩下底部框架 (__RtlUserThreadStart@8)。
- 點擊“源不可用”彈出視窗中的“查看反彙編”連結,以便您返回“反彙編”視窗。調試器現在處於非託管模式。請注意,您無法再使用新的調試引擎輕鬆分辨,因為它現在顯示正確的程式碼地址。
- 現在您可以在地址框中輸入您發現的地址。一定要在它前面加上“0x”。
否則對調試動態方法不太可能有用,儘管我在嘗試時很快就放棄了。通過兩次呼叫該方法,您可能領先,因此您可以繞過第二次呼叫的所有成本。
一種完全不同的方法是暫時向方法發出對 Debugger.Break() 的呼叫,現在它更容易了。