我對Visual C++ 2015(x86)的彙編輸出感到困惑。Visual C++ 2015中虛擬表的彙編輸出的混淆
我想知道VC中的虛擬表格佈局,所以我用虛擬函數編寫下面的簡單類。
#include <stdio.h>
struct Foo
{
virtual int GetValue()
{
uintptr_t vtbl = *(uintptr_t *)this;
uintptr_t slot0 = ((uintptr_t *)vtbl)[0];
uintptr_t slot1 = ((uintptr_t *)vtbl)[1];
printf("vtbl = 0x%08X\n", vtbl);
printf(" [0] = 0x%08X\n", slot0);
printf(" [1] = 0x%08X\n", slot1);
return 0xA11BABA;
}
};
extern "C" void Check();
int main()
{
Foo *pFoo = new Foo;
int x = pFoo->GetValue();
printf("x = 0x%08X\n", x);
printf("\n");
Check();
}
,並檢查佈局,我實現了一個彙編函數(神奇的名字來自於彙編輸出vtab.asm
的vtab.cpp
,並且是Foo::GetValue
錯位的版本)。
.model flat
extern _printf : proc
extern [email protected]@@UAEHXZ : proc
.const
FUNC_ADDR db "Address of Foo::GetValue = 0x%08X", 10, 0
.code
_Check proc
push ebp
mov esp, ebp
push offset [email protected]@@UAEHXZ
push offset FUNC_ADDR
call _printf
add esp, 8
pop ebp
ret
_Check endp
end
然後,我編譯並運行。
ml /c check.asm
cl /Fa vtab.cpp check.obj
vtab
並在我的電腦上得到以下輸出。
vtbl = 0x00FF2174
[0] = 0x00FE1300
[1] = 0x6C627476
x = 0x0A11BABA
Address of Foo::GetValue = 0x00FE1300
它清楚地示出了虛擬函數GetValue
是在偏移的虛擬表的0。但vtab.cpp
的彙編輸出似乎暗示GetValue
位於偏移4處(請參閱以下注釋,以三個分號開頭)。
; COMDAT [email protected]@[email protected]
CONST SEGMENT
[email protected]@[email protected] DD FLAT:[email protected]@[email protected] ; Foo::`vftable'
DD FLAT:[email protected]@@UAEHXZ ;;; GetValue at offset 4
CONST ENDS
; Function compile flags: /Odtp
; COMDAT [email protected]@[email protected]
_TEXT SEGMENT
_this$ = -4 ; size = 4
[email protected]@[email protected] PROC ; Foo::Foo, COMDAT
; _this$ = ecx
push ebp
mov ebp, esp
push ecx
mov DWORD PTR _this$[ebp], ecx
mov eax, DWORD PTR _this$[ebp]
mov DWORD PTR [eax], OFFSET [email protected]@[email protected] ;;; Init ptr to virtual table
mov eax, DWORD PTR _this$[ebp]
mov esp, ebp
pop ebp
ret 0
[email protected]@[email protected] ENDP ; Foo::Foo
感謝您的回答!
更新
@Hans帕桑特這似乎是一個錯誤。 I ml /c
程序集輸出vtab.asm
(帶有幾個符號刪除)並將其與check.obj
鏈接以獲得exe vtab2.exe
。但vtab2.exe
將無法正常運行。然後我修改下面的代碼
; COMDAT [email protected]@[email protected]
CONST SEGMENT
[email protected]@[email protected] DD FLAT:[email protected]@[email protected] ; Foo::`vftable'
DD FLAT:[email protected]@@UAEHXZ
CONST ENDS
到
; COMDAT [email protected]@[email protected]
CONST SEGMENT
__NOT_USED_ DD FLAT:[email protected]@[email protected] ; Foo::`vftable'
[email protected]@[email protected] DD FLAT:[email protected]@@UAEHXZ
CONST ENDS
和ml
和link
再次得到vtab3.exe
。現在vtab3.exe
正確運行併產生類似於vtab.exe
的輸出。
不,v表只有一個條目。 Just Foo :: GetValue()。 ?_ R4Foo @@ 6B @的條目不屬於v表,它是RTTI對象定位器。用/ GR-編譯,使其更加明顯。和/ d1reportAllClassLayout讓編譯器給你更多關於佈局的信息。 –
我明白只有Foo :: GetValue()在v表中。我的困惑是爲什麼'mov DWORD PTR [eax],OFFSET ?? _7Foo @@ 6B @'不是'mov DWORD PTR [eax],OFFSET ?? _7Foo @@ 6B @ + 4'。無論如何,RTTI對象從標籤'?? _Fu @@ 6B @'開始,然後是Foo :: GetValue()。 –
「GetValue」的彙編代碼是什麼? – Jester