Reverse Engineering Asked by 18446744073709551615 on March 3, 2021
In real code I have encountered some “non-virtual thunk” functions:
; `non-virtual thunk to'QTextCodecPlugin::create(QString const&)
EXPORT _ZThn8_N16QTextCodecPlugin6createERK7QString
_ZThn8_N16QTextCodecPlugin6createERK7QString
SUB.W R0, R0, #8
B.W _ZN16QTextCodecPlugin6createERK7QString; QTextCodecPlugin::create(QString const&)
; End of function `non-virtual thunk to'QTextCodecPlugin::create(QString const&)
; `non-virtual thunk to'QTextCodecPlugin::~QTextCodecPlugin()
EXPORT _ZThn8_N16QTextCodecPluginD1Ev
_ZThn8_N16QTextCodecPluginD1Ev
SUB.W R0, R0, #8
B.W _ZN16QTextCodecPluginD2Ev; QTextCodecPlugin::~QTextCodecPlugin()
; End of function `non-virtual thunk to'QTextCodecPlugin::~QTextCodecPlugin()
(GCC, C++, Android NDK, Qt, Necessitas, ARM)
c++filt
says:
$ c++filt _ZThn8_N16QTextCodecPlugin6createERK7QString
non-virtual thunk to QTextCodecPlugin::create(QString const&)
$ c++filt _ZThn8_N16QTextCodecPluginD1Ev
non-virtual thunk to QTextCodecPlugin::~QTextCodecPlugin()
What and why do these “non-virtual thunks” do?
These are object virtual table entries used to implement multiple inheritance.
The short story is, the sub
instruction is to do with offsetting the correct derived class object size to the virtual table; but the following (long) article does a much better job of explaining than I could fit here : http://thomas-sanchez.net/computer-sciences/2011/08/15/what-every-c-programmer-should-know-the-hard-part/
UPDATE: the link above does not work anymore, but there's a copy of this page at webarchive.org: http://web.archive.org/web/20131210001207/http://thomas-sanchez.net/computer-sciences/2011/08/15/what-every-c-programmer-should-know-the-hard-part/
Answered by 6EQUJ5 on March 3, 2021
The answer should really state what the difference is between a virtual thunk and a non virtual thunk. They are identical in operation but just have a different name. The thunk for a virtually inherited base class is called a virtual thunk and the base object will be at the end of the object, whereas a thunk for a regularly inherited class whose object is not at the start of the object is called a non virtual thunk.
If you have C inherits from A and B, then A's virtual pointer will be at the start of the object (with C's vtable pointer for A pasted over it) and therefore doesn't require a pointer offset to the start when calling methods of type C* with an A*, and subobject B (with C's vtable pointer for B pasted over it) will be at an offset in the object. The virtual table for B will have to contain a non-virtual thunk that will offset to the pointer to the start of the object because the method that's being called virtually is one of C that accepts a pointer to a C object and if this virtual table is used then it will be receiving a polymorphically cast pointer to B, hence the need for the call in the table to be a thunk.
If you have D inherits from B and C, and B and C inherit virtually from A, then this means that B's virtual table pointer will be at the start of the object (with D's vtable for B pasted over it) and C's vtable pointer (with D's vtable pointer for C pasted over it) will be at an offset and requires a non virtual thunk when it is called which will be when the object pointer it is called on is cast to a C* type. A and its vtable pointer (with D's vtable for A pasted over it) will be at the end of the object and will instead require a virtual thunk in the vtable instead of the actual virtual method, and the virtual thunk calls the actual virtual method, and this gets called when the method is called on an object pointer cast to A*.
The virtual thunk offsets the object address by e.g. - 32 (wherever the virtual base object is) and the non virtual thunk offsets the object address by e.g. - 16 (wherever the 2nd subobject is). Basically, a virtual thunk offsets an object of type of a virtually inherited class to the start of the object when calling a method that is defined in the most derived class. The virtual thunk is for virtually inherited classes, which only have 1 special object within the object rather than multiple. If you didn't virtually inherit, there would be multiple of those objects within the object, and youd use a non virtual thunk to offset them when calling a method in the most derived class
Answered by Lewis Kelsey on March 3, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP