Symbian
Symbian OS Library

FAQ-1284 What is the "EABI Thunk Offset Problem"?

[Index][spacer] [Previous] [Next]



 

Classification: C++ Category: Development
Created: 05/12/2005 Modified: 05/20/2005
Number: FAQ-1284
Platform: Symbian OS v8.1b, Symbian OS v9

Question:
When I recompile my DLL, I see MAKEDEF errors and warnings which mention symbols that begin with _ZTh - what causes this, and how can I deal with it?

Answer:
The "EABI Thunk Offset Problem" is the name that Symbian uses to describe a particular kind of build error which arises when multiple inheritance is used, and the size of a base class is changed. Here is an example of a typical symptom:

    MAKEDEF ERROR: 1 Frozen Export(s) missing from object files:
    \src\example\MyDLLU.DEF(3) : _ZThn8_N7Derived3fooEv @2
    MAKEDEF WARNING: 1 export(s) not yet Frozen in \src\example\MyDLLU.DEF:
    ..\..\..\EPOC32\BUILD\src\example\group\MyDLL\ARMV5\MyDll{000a0000}.def(7) : _ZThn12_N7Derived3fooEv @6
    This shows a problem with a frozen DEF file: the export at ordinal 2 is missing, and a new unfrozen export has been added at ordinal 6. When we compare the two symbols, they look suspiciously similar to each other, and to a third symbol in the DEF file:
            _ZN7Derived3fooEv @1
      _ZThn8_N7Derived3fooEv @2 // this one is missing
      _ZThn12_N7Derived3fooEv @6 // this one has appeared
      The exports beginning with _ZTh are compiler generated functions called "thunks", and the information between ZTh and the next underscore is the "offset" associated with the thunk. Our problem is that for some reason, the offset associated with the thunk has changed from "n8" to "n12".
      These generated functions are a feature of the ARM EABI (amongst others), hence the name "EABI Thunk Offset Problem".

      What causes this problem?

      To cut a long story short, the problem is caused by adding member data to a base class.
      You need something else as well (multiple inheritance with virtual functions in more than one of the base classes), but the problem is always due to adding member data to a base class. This is always a Binary Compatibility break, but the EABI Thunk Offset Problem is that it shows up as a change to symbols which can appear in DEF files.


      How do I fix it?

      You have three choices:

      The first option is to refreeze the DEF file: this would be OK if you aren't maintaining a frozen interface, and your customers will in any case need to rebuild because of the Binary Compatibility break. The easiest way to refreeze is to delete all of the exports from your existing DEF file, build again, and then use "abld freeze armv5" to update the DEF file. After updating the DEF file, build again: this time it should build cleanly.

      The second option is to use the attached script to fix the EABI Thunk Offsets. It expects to read a build log containing the MAKEDEF errors and warnings, and will modify the DEF file to replace each missing export with the corresponding unfrozen export. Run the script with no arguments to get further details.



      After fixing the DEF file, you will need to rebuild the DLL which uses the DEF file.

      The last option is that you could change your mind about adding that extra member data... This will only be an option if it is your change which causes the problem: if your supplier has changed the size of a class that they own and caused this problem, then you are forced to change your DEF file.

      If you do own the class which has the extra member data, it's worth noting that this change is likely to affect your customers as well: they will have to rebuild because of the BC break, but they will also see the EABI Thunk Offset Problem if they derive from your class. This includes simple inheritance from a class which shows the problem, if it reimplements any of the virtual functions which require thunks. When Symbian breaks compatibility in a way likely to cause this problem, the corresponding entry in the Compatibility Break spreadsheet will say "BC+ Break: Rebuild & Check/Fix Def-File EABI Thunk Offsets".


      Tell me the full details: What is a thunk? What causes its offset to change?

      In a C++ class hierarchy involving both virtual functions and multiple inheritance, objects can be accessed as though they were several different types. A typical Symbian OS example would be a CBase-derived class which also derives from an M-class, perhaps to provide an "observer" interface: for example CCoeControl, which derives from both CBase and MObjectProvider.

      The virtual functions which can be called on an object depends on the type it currently appears to be: a CCoeControl object can be viewed as a CBase object, in which case it has one set of virtual functions, or as an MObjectProvider, in which case it has another. The compiler constructs separate "vtables" for each of the possible interfaces, and these tables contain information about how to convert back to the underlying CCoeControl object. When converting from a CCoeControl pointer to an MObjectProvider pointer, the compiler will adjust the value of the pointer, so that it points to the "MObjectProvider" part of the object, and not the full CCoeControl object.

      The MObjectProvider class defines a pure virtual function MopSupplyObject, which is implemented in CCoeControl. Even when the object is presenting it's MObjectProvider interface, the vtable must use the correct implementation of MopSupplyObject, which expects to be used in the context of a CCoeControl. The solution used by the compiler is to create a "virtual function override thunk" function which makes any necessary adjustments between the calling context (a pointer to an MObjectProvider) and the execution context (a pointer to a CCoeControl). This could have been implemented using the names of the two contexts, but instead the EABI uses the amount by which the "this" pointer needs to be adjusted to make the switch - this is the "offset" encoded in the name.

      Here's a small example:



      Compile this with "armcc -S eabi_thunk_offset_problem.cpp" to get an assembly listing. Compile it again with an extra argument "-DCOUNT=2" to change the size of the base class, and compare the two files: there will be various differences in the code, but also differences in the _ZTh symbols - including the differences used in the "typical symptom" above.

      If you use virtual inheritance, then you may see another version of the problem. With virtual inheritance, there are two offsets involved and the thunk symbols will begin with _ZTv. The same symbol may appear in several thunks, each with different offsets.

      For more details on the EABI, see http://www.arm.com/products/DevTools/ABI.html.