2

I loaded a shared library (I don't know the source of that) and made a header for that with IDA.

Is this

class Tester {
    public:
    virtual void test();
    virtual void replay();
};

different from this?

class Tester {
    public:
    virtual void replay();
    virtual void test();
};
  • I guess it depends on the compiler? – rec Mar 22 '16 at 19:49
  • I think also that it should depend on the compiler. – Ta Thanh Dinh Mar 22 '16 at 20:45
2

The order of virtual functions is significant; altering the order in the source code will alter the order in the generated machine code. In your example, the two source samples will generate different machine code.

Edit: using the sample code provided by @tathanhdinh below, MSVC generates the two vtables as follows:

;   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

Note that the order of the member function pointers in the two vtables differs. As I mentioned, the order in which virtual functions matters in at least one compiler.

| improve this answer | |
  • How about normal functions? – user160368 Mar 22 '16 at 10:29
  • Non-virtual member functions won't affect the layout of your class or its vtable in memory. It's the linker that will decide what offset the function bodies will be located in. – John Källén Mar 22 '16 at 10:30
  • + Can I omit one or more virtual function declarations? – user160368 Mar 22 '16 at 10:35
  • You need to make sure that you don't misalign the vtable. You may omit any virtual function declarations that appear after the function(s) you wish to have disassembled. – John Källén Mar 22 '16 at 10:36
  • @JohnKällén Thanks for you answer, but it seems to me unintuitive the idea that the order virtual function in source affects the order in machine code. It is hard to me to believe that somewhere in C++ standard (or even in C++ ABI) says that, I think that it should be compiler dependent. – Ta Thanh Dinh Mar 22 '16 at 13:40
0

i dont think you mean using the same class name if so it may generate redefinition error if not the order should be considered

#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;
}

compiled & linked with

cl /nologo /Zi /EHsc /O1 /analyze /W4 *.cpp /link /release

executed will result in

classmagic.exe
class A bust virtual function
class B bust virtual function
| improve this answer | |
0

Since I do not think the order of virtual functions in source could affect their order in machine code, I try to give a counter example. The main idea is first to give a layout for the vtable of a base class

struct A
{
  void virtual test() {};
  void virtual replay() {};
}

then using two classes which inherit A, but with different order of virtual functions:

struct B : public A
{
  void virtual test() {};
  void virtual replay() {};
}

struct C : public A
{
  void virtual replay() {};
  void virtual test() {};
}

If the order of virtual functions in B and C affects their machine code order, then their pointers in corresponding vtables should be different. But the following generated machine code (I have used clang as the compiler) shows that they are not:

.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)

The order of virtual functions in B and C are indeed the same (and respects one in A).

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.