本文用到的反匯編工具是objconv,使用方法可以看我另一篇文章https://blog.csdn.net/weixin_45001971/article/details/128660642。
成都創(chuàng)新互聯(lián)公司自2013年創(chuàng)立以來,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項目成都網(wǎng)站設(shè)計、成都做網(wǎng)站、外貿(mào)網(wǎng)站建設(shè)網(wǎng)站策劃,項目實(shí)施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元府谷做網(wǎng)站,已為上家服務(wù),為府谷各地企業(yè)和個人服務(wù),聯(lián)系電話:18980820575其它文章:
從匯編的角度了解C++原理——類的儲存結(jié)構(gòu)和函數(shù)調(diào)用
從匯編的角度了解C++原理——new和malloc的區(qū)別
從匯編的角度了解C++原理——虛函數(shù)
反匯編。
main:
sub rsp, 56
lea rcx, [rsp+20H]
call ??0A@@QEAA@XZ //調(diào)用構(gòu)造函數(shù)
mov eax, 4294967295
add rsp, 56
ret
??0A@@QEAA@XZ: //調(diào)用A類的構(gòu)造函數(shù)
mov qword [rsp+8H], rcx
mov rax, qword [rsp+8H]
lea rcx, [rel ??_7A@@6B@] //獲取虛表??_7A@@6B@的地址
mov qword [rax], rcx //把虛表地址放在對象的頭部
mov rax, qword [rsp+8H]
mov dword [rax+8H], 10 //在對象首地址偏移8個字節(jié)的位置定義d1變量
mov rax, qword [rsp+8H]
ret
??_7A@@6B@: //A類虛表
dq ?func2@A@@UEAAXXZ //虛函數(shù)func2
以上例的匯編代碼可以得出帶虛函數(shù)的類的儲存結(jié)構(gòu)如下圖所示。
帶有虛函數(shù)的對象的頭部會放置8個字節(jié)大小的虛表地址,有了虛表之后的對象會以8個字節(jié)為單位去對齊,如上例中的A類,如果沒有虛函數(shù),它的大小為4個字節(jié),而加了虛函數(shù)之后,大小變?yōu)榱?6個字節(jié)。
在代碼中添加A的子類B,重寫func2方法。
反匯編
main:
sub rsp, 56
lea rcx, [rsp+20H]
call ??0B@@QEAA@XZ //調(diào)用B類構(gòu)造
mov eax, 4294967295
add rsp, 56
ret
??0A@@QEAA@XZ: //A類構(gòu)造函數(shù)
mov qword [rsp+8H], rcx
mov rax, qword [rsp+8H]
lea rcx, [rel ??_7A@@6B@] //把A類虛表的地址放在頭部
mov qword [rax], rcx
mov rax, qword [rsp+8H]
mov dword [rax+8H], 10
mov rax, qword [rsp+8H]
ret
??0B@@QEAA@XZ: //B類構(gòu)造函數(shù)
mov qword [rsp+8H], rcx
sub rsp, 40
mov rcx, qword [rsp+30H]
call ??0A@@QEAA@XZ //調(diào)用A類構(gòu)造
mov rax, qword [rsp+30H]
lea rcx, [rel ??_7B@@6B@] //把B類虛表的地址放在頭部
mov qword [rax], rcx
mov rax, qword [rsp+30H]
add rsp, 40
ret
??_7A@@6B@: //A類虛表
dq ?func2@A@@UEAAXXZ //A::func2
dq ?func3@A@@UEAAXXZ //A::func3
??_7B@@6B@: //B類虛表
dq ?func2@B@@UEAAXXZ //B::func2,被替換為了B實(shí)現(xiàn)的func2
dq ?func3@A@@UEAAXXZ //A::func3
從該例中我們可以看到,父類有虛函數(shù)時,不光它自己有一張?zhí)摫?,它的子子孫孫都會各帶有一個自己的虛表,子類重寫虛函數(shù)時,會把子類實(shí)現(xiàn)的函數(shù)指針替換上虛表,把原先父類的函數(shù)指針覆蓋掉。
1.3、在棧上調(diào)用虛函數(shù)在main里添加方法的調(diào)用。
反匯編。
main:
sub rsp, 56
lea rcx, [rsp+20H]
call ??0B@@QEAA@XZ
lea rcx, [rsp+20H]
call ?func1@A@@QEAAXXZ //調(diào)用A::func1
lea rcx, [rsp+20H]
call ?func2@B@@UEAAXXZ //調(diào)用B::func2
lea rcx, [rsp+20H]
call ?func3@A@@UEAAXXZ //調(diào)用A::func3
mov eax, 4294967295
add rsp, 56
ret
在棧上調(diào)用方法時,因?yàn)轭愋褪谴_定的,所以編譯器在編譯階段就會找到對應(yīng)的函數(shù)去調(diào)用,調(diào)用過程與普通方法一樣。
1.4、在堆上調(diào)用虛函數(shù)(通過指針調(diào)用,多態(tài))修改例程如下。
反匯編
main:
sub rsp, 72
mov ecx, 16
call ??2@YAPEAX_K@Z
mov qword [rsp+28H], rax
cmp qword [rsp+28H], 0
jz ?_001
mov rcx, qword [rsp+28H] //定義指針b
call ??0B@@QEAA@XZ
mov qword [rsp+30H], rax //rsp+30H指向?qū)ο?
jmp ?_002 //跳到?_002
?_001: mov qword [rsp+30H], 0
?_002: mov rax, qword [rsp+30H]
mov qword [rsp+38H], rax //rsp+38H指向?qū)ο?
mov rax, qword [rsp+38H] //rax指向?qū)ο?
mov qword [rsp+20H], rax //rsp+20H指向?qū)ο?
mov rcx, qword [rsp+20H] //rcx指向?qū)ο?
call ?func1@A@@QEAAXXZ //調(diào)用A::func1
mov rax, qword [rsp+20H]
mov rax, qword [rax] //取虛表
mov rcx, qword [rsp+20H]
call near [rax] //執(zhí)行虛表第一個函數(shù),即B::func2
mov rax, qword [rsp+20H]
mov rax, qword [rax]
mov rcx, qword [rsp+20H]
call near [rax+8H] //執(zhí)行虛表第二個函數(shù),即A::func3
mov eax, 4294967295
add rsp, 72
ret
??_7B@@6B@:
dq ?func2@B@@UEAAXXZ
dq ?func3@A@@UEAAXXZ
從該例可以看到,通過指針來調(diào)用函數(shù)時。
如果是普通函數(shù),編譯器會直接根據(jù)指針類型,找到對應(yīng)的的方法,而不是根據(jù)對象本身的類型,如本例中B類也實(shí)現(xiàn)了func1方法,但通過A類指針調(diào)用時,寫到匯編里的時A::func1。
如果是虛函數(shù),編譯器不會根據(jù)名字來查找函數(shù),而是讓匯編代碼通過虛表中的偏移量來調(diào)用,如本例中,b指針執(zhí)行了func2和func3,這兩個函數(shù)都沒有被直接調(diào)用,而是以“call near [rax + 偏移量]”的形式調(diào)用了,這也是C++中父類指針指向子類對象的多態(tài)的實(shí)現(xiàn)原理。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
分享文章:從匯編的角度了解C++原理——虛函數(shù)-創(chuàng)新互聯(lián)
分享路徑:http://muchs.cn/article42/cdcoec.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、營銷型網(wǎng)站建設(shè)、App開發(fā)、服務(wù)器托管、用戶體驗(yàn)、品牌網(wǎng)站設(shè)計
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容