承接上篇,本文探討當對象向上轉型為接口類型時,CLR 如何實現多態調用。通過 Windbg 跟蹤發現,實際機制與教科書描述的「接口偏移表」不同,而是通過 ResolveWorkerAsmStub 動態解析。
《Essential .NET》描述:全局接口映射表 → 類型的 Interface Offset Table → 方法偏移 → 調用。匯編邏輯:
mov ecx, esi ; 對象引用
mov eax, [ecx] ; MethodTable
mov eax, [eax+0Ch] ; InterfaceOffsetTable
mov eax, [eax + ifaceOffset] ; 接口方法表入口
call [eax + methodOffset] ; 調用
實際調用指令:
mov ecx, esi
call dword ptr ds:[980010h] ; 數據段存根指針
; 跳轉到 mscorwks!ResolveWorkerAsmStub
__declspec(naked) void ResolveWorkerAsmStub()
{
// 保存寄存器
call VirtualCallStubManager::ResolveWorkerStatic
// 還原寄存器
jmp eax ; eax 保存實際目標方法地址
}
核心邏輯在 VirtualCallStubManager::ResolveWorkerStatic 中:首次調用時解析接口方法槽,緩存結果,後續直接跳轉。
ResolveWorkerStatic 具體如何從 MethodTable 定位接口方法槽?需進一步源碼分析(virtualcallstubcpu.hpp)。歡迎了解內部的同學補充。