3

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();
};
2
  • I guess it depends on the compiler?
    – rec
    Mar 22, 2016 at 19:49
  • I think also that it should depend on the compiler. Mar 22, 2016 at 20:45

3 Answers 3

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.

7
  • How about normal functions?
    – user160368
    Mar 22, 2016 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. Mar 22, 2016 at 10:30
  • + Can I omit one or more virtual function declarations?
    – user160368
    Mar 22, 2016 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. Mar 22, 2016 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. Mar 22, 2016 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
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).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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