欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解如何實(shí)現(xiàn)C++虛函數(shù)調(diào)用匯編代碼

 更新時(shí)間:2021年11月15日 11:19:50   作者:link-初揚(yáng)  
多態(tài)是C++中最重要的特性之一,對(duì)虛函數(shù)的調(diào)用在C++代碼中是隨處可見(jiàn)的,本篇文章我們?cè)敿?xì)探討一下,感興趣的朋友快來(lái)看看吧

虛函數(shù)(代碼段地址)被存放在虛函數(shù)表中,調(diào)用虛函數(shù)的流程是這樣子的:先獲取虛函數(shù)表的首地址,然后根據(jù)目標(biāo)虛函數(shù)在虛函數(shù)表的位置(offset偏移)取出虛函數(shù)表中的虛函數(shù)地址,最后去call這個(gè)虛函數(shù)(地址),就完成虛函數(shù)的調(diào)用。這個(gè)虛函數(shù)調(diào)用的流程在匯編代碼中可以最直觀的反映出來(lái)。

在排查軟件異?;虮罎r(shí),我們時(shí)常要借助匯編代碼的上下文去輔助分析問(wèn)題。讀懂C++虛函數(shù)調(diào)用的匯編代碼實(shí)現(xiàn),對(duì)于搞懂匯編代碼的上下文時(shí)很有好處的。今天我們就來(lái)看看虛函數(shù)調(diào)用的匯編代碼實(shí)現(xiàn)。

比如如下的C++代碼:

// 1、虛接口類中定義了純虛接口
class IContactInterface
{
    //...
 
    virtual BOOL IsLoadFinish() == 0;  // 虛接口
 
    //...
}
 
 
// 2、子類中實(shí)現(xiàn)虛接口
class Contact : public IContactInterface
{
    //...
 
    BOOL IsLoadFinish(); 
 
    //...
}
 
 
// 3、new出子類的對(duì)象,存放到父類的指針變量中
IContactInterface* g_pContactPtr = new Contact;
 
 
// 4、獲取子類對(duì)象的接口實(shí)現(xiàn)
IContactInterface* GetContactPtr()
{
    return g_pContactPtr;
} 
 
 
// 5、調(diào)用GetContactPtr獲取子類的對(duì)象去調(diào)用虛函數(shù)IsLoadFinish
GetContactPtr()->IsLoadFinish();

上述C++代碼片中,主要包含了以下幾點(diǎn):

1)定義了虛接口類IContactInterface,在類中有個(gè)IsLoadFinish虛函數(shù);

2)定義了一個(gè)子類Contact,繼承于IContactInterface接口類,并實(shí)現(xiàn)了虛函數(shù)IsLoadFinish;

3)new出一個(gè)Contact類的對(duì)象,賦值給父類IContactInterface的指針變量;

4)調(diào)用GetContactPtr接口獲取IContactInterface指針變量,調(diào)用虛函數(shù)IsLoadFinish。

其中,GetContactPtr()->IsLoadFinish()這句虛函數(shù)調(diào)用的匯編代碼如下所示:

.text:005103EB call ds:__imp__GetContactPtr
.text:005103F1 mov [ebp+var_2AF4], eax
.text:005103F7 mov ecx, [ebp+var_2AF4]
.text:005103FD mov edx, [ecx]
.text:005103FF mov ecx, [ebp+var_2AF4]
.text:00510405 mov eax, [edx+78h]
.text:00510408 call eax

現(xiàn)在我們就來(lái)詳細(xì)解讀一下這段實(shí)現(xiàn)虛函數(shù)調(diào)用的匯編代碼。

1、匯編代碼段1:

.text:005103EB call ds:__imp__GetContactPtr
.text:005103F1 mov [ebp+var_2AF4], eax
.text:005103F7 mov ecx, [ebp+var_2AF4]

調(diào)用GetContactPtr接口,返回IContactInterface*指針,其中存放的是子類Contact對(duì)象。GetContactPtr接口返回的IContactInterface*指針中的值,放到eax寄存器中。

在C++的匯編代碼中,調(diào)用函數(shù)的返回值是放到eax寄存器中的。

所以eax中存放的是子類Contact對(duì)象的地址。然后將eax中存放的子類Contact對(duì)象的地址,放到函數(shù)棧內(nèi)存[ebp+var_2AF4]中。然后又將子類Contact對(duì)象的地址放到ecx寄存器中。

2、匯編代碼段2:

.text:005103FD mov edx, [ecx]

代碼運(yùn)行至此,此時(shí)ecx中存放的就是子類Contact對(duì)象的地址。該句匯編代碼是以ecx中的值作為內(nèi)存地址,取出該地址中的值放到edx寄存器中。

在C++中,C++類中如果有虛函數(shù),則類中會(huì)掩藏一個(gè)虛函數(shù)指針成員變量,是排放在C++類所有數(shù)據(jù)成員的首位,所以C++對(duì)象的地址,就是虛函數(shù)表指針變量的內(nèi)存首地址(是指針變量的地址,不是指針變量中的值),所以此處的[ecx]操作,是取出虛函數(shù)表指針變量中存放的內(nèi)容,即虛函數(shù)表的首地址。所以edx寄存器中存放的是Contact對(duì)象中的虛函數(shù)表的首地址。

C++類中如果有虛函數(shù),則該類中會(huì)掩藏一個(gè)用來(lái)存放虛函數(shù)表地址的虛函數(shù)表指針變量,該虛函數(shù)表指針變量放置在該C++對(duì)象所有數(shù)據(jù)成員的首位,所以C++對(duì)象的地址就是其虛函數(shù)指針變量的內(nèi)存首地址。

3、匯編代碼段3:

.text:005103FF mov ecx, [ebp+var_2AF4]

回到整段匯編代碼最開(kāi)始的地方,[ebp+var_2AF4]中存放的是子類Contact對(duì)象的地址。因?yàn)橄旅嬉{(diào)用Contact類對(duì)象的虛函數(shù),調(diào)用時(shí)要將Contact類對(duì)象的地址傳給被調(diào)用的函數(shù),即this指針。C++匯編代碼中,是通過(guò)ecx寄存器將類對(duì)象的地址傳給被調(diào)用函數(shù),所以此句代碼是為下面調(diào)用類Contact的虛函數(shù)IsLoadFinish做準(zhǔn)備的。

在調(diào)用C++類的函數(shù)時(shí),是通過(guò)ecx寄存器傳遞C++類對(duì)象的地址的,即this指針的存放的C++對(duì)象的地址。

4、匯編代碼段4:

.text:00510405 mov eax, [edx+78h]
.text:00510408 call eax

接著上面,當(dāng)前edx寄存器中存放的值是虛函數(shù)表的首地址(虛函數(shù)表指針中存放的值),78h是目標(biāo)虛函數(shù)IsLoadFinish在虛函數(shù)中的偏移,所以對(duì)edx+78h地址取址,是讀出虛函數(shù)表該位置存放的就是目標(biāo)虛函數(shù)IsLoadFinish的地址(代碼段地址),所以執(zhí)行這行代碼后,eax寄存器中存放的就是目標(biāo)虛函數(shù)IsLoadFinish的地址,然后call eax就是調(diào)用虛函數(shù)IsLoadFinish了。

在C++中,函數(shù)名稱其實(shí)就是該函數(shù)在代碼段的首地址,去call這個(gè)首地址,就是去調(diào)用這個(gè)虛函數(shù)了。要注意區(qū)分?jǐn)?shù)據(jù)段地址和代碼段的地址。

到此這篇關(guān)于詳解如何實(shí)現(xiàn)C++虛函數(shù)調(diào)用匯編代碼的文章就介紹到這了,更多相關(guān)C++ 虛函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于C/C++ 常見(jiàn)誤區(qū)詳解

    基于C/C++ 常見(jiàn)誤區(qū)詳解

    本篇文章介紹了在c和c++中一些常見(jiàn)誤區(qū)的詳細(xì)概述。需要的朋友參考下
    2013-05-05
  • 關(guān)于C語(yǔ)言 const 和 define 區(qū)別

    關(guān)于C語(yǔ)言 const 和 define 區(qū)別

    這篇文章主要介紹了關(guān)于C語(yǔ)言 const 和 define 區(qū)別 的相關(guān)資料,需要的朋友可以參考下面文章內(nèi)容
    2021-09-09
  • C++踩坑實(shí)戰(zhàn)之構(gòu)造和析構(gòu)函數(shù)

    C++踩坑實(shí)戰(zhàn)之構(gòu)造和析構(gòu)函數(shù)

    不論是構(gòu)造函數(shù),還是析構(gòu)函數(shù),都是C++、C#語(yǔ)言相對(duì)于其他語(yǔ)言而言特殊的地方,它是為了方便類中對(duì)象的初始化,這篇文章主要給大家介紹了關(guān)于C++踩坑實(shí)戰(zhàn)之構(gòu)造和析構(gòu)函數(shù)的相關(guān)資料,需要的朋友可以參考下
    2021-07-07
  • C語(yǔ)言實(shí)現(xiàn)單詞小助手改進(jìn)版

    C語(yǔ)言實(shí)現(xiàn)單詞小助手改進(jìn)版

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)單詞小助手的改進(jìn)版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • C語(yǔ)言詳解實(shí)現(xiàn)鏈?zhǔn)蕉鏄?shù)的遍歷與相關(guān)接口

    C語(yǔ)言詳解實(shí)現(xiàn)鏈?zhǔn)蕉鏄?shù)的遍歷與相關(guān)接口

    二叉樹(shù)的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)是指,用鏈表來(lái)表示一棵二叉樹(shù),即用鏈來(lái)指示元素的邏輯關(guān)系。通常的方法是鏈表中每個(gè)結(jié)點(diǎn)由三個(gè)域組成,數(shù)據(jù)域和左右指針域,左右指針?lè)謩e用來(lái)給出該結(jié)點(diǎn)左孩子和右孩子所在的鏈結(jié)點(diǎn)的存儲(chǔ)地址
    2022-04-04
  • linux c多線程編程實(shí)例代碼

    linux c多線程編程實(shí)例代碼

    這篇文章主要介紹了linux系統(tǒng)中的c多線程編程實(shí)例,大家可以參考使用以下代碼
    2013-11-11
  • C語(yǔ)言實(shí)現(xiàn)萬(wàn)年歷小功能

    C語(yǔ)言實(shí)現(xiàn)萬(wàn)年歷小功能

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)萬(wàn)年歷小功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • C++17之std::visit的具體使用

    C++17之std::visit的具體使用

    本文主要介紹了C++17之std::visit的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • C/C++實(shí)現(xiàn)快速排序算法的兩種方式實(shí)例

    C/C++實(shí)現(xiàn)快速排序算法的兩種方式實(shí)例

    快速排序是一種采用分治思想,在實(shí)踐中通常運(yùn)行較快一種排序算法,這篇文章主要給大家介紹了關(guān)于C/C++實(shí)現(xiàn)快速排序的兩種方式的相關(guān)資料,文中給出了詳細(xì)的示例代碼,需要的朋友可以參考下
    2021-08-08
  • C語(yǔ)言指針入門的簡(jiǎn)單實(shí)例教程

    C語(yǔ)言指針入門的簡(jiǎn)單實(shí)例教程

    這篇文章主要給大家介紹了關(guān)于C語(yǔ)言指針入門的簡(jiǎn)單實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01

最新評(píng)論