我对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