[转载]CLR怎样实现虚方法的多态调用(2)
在上一篇文章CLR怎樣實現虛方法的多態調用(1)中主要介紹了CLR怎樣多態調用虛方法以及各種類型的方法在Method Table中的排布,但是沒有介紹怎樣調用接口方法,當某個對象向上轉型為接口時進行多態調用時,CLR是怎樣實現的呢?以下面這段代碼為例來說明:
namespace Demo { public interface IFoo { void Foo(); } public class Base : IFoo { public void Foo() { Console.WriteLine("In base's Foo function"); } } class Program { static void Main(string[] args) { IFoo i = new Base(); i.Foo(); } } }? 在Essential .NET中,Don Box向讀者簡單描述了基于接口的多態調用,在堆中有一個全局接口映射表,當某個類實現了一個接口,就會在這個接口表中增加項,而增加的這些項又指向這個具體類的Method Table中的Method,可能說的不是太清楚,就用個圖來表示:
?當進行方法調用的時候,首先通過對象找到該類型的Method Table,根據偏移量找到指向Interface Offset Table的指針來定位這個Interface Offset Table,然后CLR查找調用方法在這個Offset Table的偏移量,最后調用該方法。調用的匯編代碼如下:
?mov ecx, esi? -- 保存對象地址到ecx中
?mov eax, dword ptr [ecx] --?把類型的Method Table的地址保存在eax中
?mov eax, dword ptr [eax+0ch] -- 把Interface Offset Table的地址保存在eax中
?mov eax, dword ptr [eax + interface offset] -- 根據Interface在Table中的偏移量,找到其地址并保存到eax中
?call dword ptr [eax +? method offset] -- 根據該方法的偏移量定位改方法進行調用
可以說這樣的調用邏輯是很清楚容易讓人理解的。
?
但是當我用windbg進行跟蹤的時候卻發現接口方法調用機制和上面所說的不同,并沒有一個查找Interface Offset Table的過程,在Main函數里是這樣的調用:
?mov ecx, esi --? 保存對象地址到ecx中
?call dword ptr ds:[980010h]? 在數據段980010h上保存的是一個指針,實際上調用的是:
?jmp?mscorwks!ResolveWorkerAsmStub
?可以看到跳轉到ResolveWorkerAsmStub函數里去了。而這個函數是做什么的呢,下面的代碼是從SSCLI里面找到的(有興趣的可以看看virtualcallstubcpu.hpp):
__declspec (naked) void ResolveWorkerAsmStub(){
// 首先保存寄存器狀態
call VirtualCallStubManager::ResolveWorkerStatic //調用ResolveWorkerStatic方法 //還原寄存器狀態 jmp eax //eax保存著實際上要調用的方法的地址,所以這里就開始了方法調用}
所以猜想到在VirtualCallStubManager::ResolveWorkerStatic函數里面正確找到了方法的地址,保存在eax里。
看來到底是怎樣取到該方法地址這個問題只能等下次有時間再用windbg跟蹤。如果有人了解,也希望能解釋一下來幫助我解答疑惑。
轉載于:https://www.cnblogs.com/bariver/archive/2009/09/16/1567489.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的[转载]CLR怎样实现虚方法的多态调用(2)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 调试JavaScript/VB Scri
- 下一篇: P/Invoke调用SipEnumIM枚