我加载了一个共享库(我不知道它的来源)并使用 IDA 为它制作了一个头文件。
这是
class Tester {
public:
virtual void test();
virtual void replay();
};
与此不同?
class Tester {
public:
virtual void replay();
virtual void test();
};
我加载了一个共享库(我不知道它的来源)并使用 IDA 为它制作了一个头文件。
这是
class Tester {
public:
virtual void test();
virtual void replay();
};
与此不同?
class Tester {
public:
virtual void replay();
virtual void test();
};
虚函数的顺序很重要;更改源代码中的顺序将更改生成的机器代码中的顺序。在您的示例中,两个源示例将生成不同的机器代码。
编辑:使用下面@tathanhdinh 提供的示例代码,MSVC 生成两个 vtables 如下:
; COMDAT ??_7B@@6B@
CONST SEGMENT
??_7B@@6B@ DD FLAT:??_R4B@@6B@ ; B::`vftable'
DD FLAT:?bust@B@@UAEXXZ
DD FLAT:?test@B@@UAEXXZ
CONST ENDS
; COMDAT ??_7A@@6B@
CONST SEGMENT
??_7A@@6B@ DD FLAT:??_R4A@@6B@ ; A::`vftable'
DD FLAT:?test@A@@UAEXXZ
DD FLAT:?bust@A@@UAEXXZ
CONST ENDS
注意两个vtable中成员函数指针的顺序是不同的。正如我所提到的,虚函数的顺序在至少一个编译器中很重要。
我不认为你的意思是使用相同的类名,如果是这样,它可能会产生重新定义错误,如果不应该考虑顺序
#include <iostream>
using namespace std;
class A {
public:
virtual void test() { cout<<"class A test virtual function \n"; }
virtual void bust() { cout<<"class A bust virtual function \n"; }
};
class B {
public:
virtual void bust() { cout<<"class B bust virtual function \n"; }
virtual void test() { cout<<"class B test virtual function \n"; }
};
int main(void) {
A *foo = nullptr;
B *bla = nullptr;
try{
foo = new(A);
bla = new(B);
foo->bust();
bla->bust();
delete foo;
delete bla;
} catch(...){
delete foo;
delete bla;
}
return 0;
}
编译和链接
cl /nologo /Zi /EHsc /O1 /analyze /W4 *.cpp /link /release
执行将导致
classmagic.exe
class A bust virtual function
class B bust virtual function
由于我认为源中虚函数的顺序不会影响它们在机器码中的顺序,我试着举一个反例。其主要思想是先给出一个布局为vtable一个基类的
struct A
{
void virtual test() {};
void virtual replay() {};
}
然后使用两个继承的类A,但具有不同顺序的虚函数:
struct B : public A
{
void virtual test() {};
void virtual replay() {};
}
struct C : public A
{
void virtual replay() {};
void virtual test() {};
}
如果虚函数 inB和的顺序C影响它们的机器码顺序,那么它们对应的指针vtables应该是不同的。但是以下生成的机器代码(我用作clang编译器)表明它们不是:
.rodata:0804888C ; vtable for B
.rodata:0804888C _ZTV1B db 0 ; DATA XREF: B::B(void)+1Co
...
.rodata:08048894 dd offset _ZN1B4testEv ; B::test(void)
.rodata:08048898 dd offset _ZN1B6replayEv ; B::replay(void)
...
...
.rodata:08048904 ; vtable for C
.rodata:08048904 _ZTV1C db 0 ; DATA XREF: C::C(void)+1Co
...
.rodata:0804890C dd offset _ZN1C4testEv ; C::test(void)
.rodata:08048910 dd offset _ZN1C6replayEv ; C::replay(void)
B和C中虚函数的顺序确实相同(并且尊重 中的一个A)。