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