Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mixing separately compiled objects

Tags:

c++

gcc

Let's I have a class class Drawable. It could have many members, member functions, parent classes, or could be very simple. For the sake of this example that is not important. Also, let's say it is some kind of GUI element.

Then, let's assume I have a rendering engine, which is provided as a GCC library engine.a. That library contains class Screen, which has method void Screen::add(const Drawable & child). All I have are headers and library itself. In my application I instantiate Screen, create few Drawable objects and add them to Screen.

My question:
Could my GCC toolchain (or my GCC toolchain's version) create different memory layout for Drawable objects than in compiled engine.a? Standard does not define it and it is an implementation detail. Either way it will link perfectly. How can I know that and how can I be sure about correct behaviour?

P. S. I mostly use ARM GCC toolchain for Cortex-M architecture. But my question is not limited to that.

P. P. S. If you have any thoughts related, but not related to GCC specifically, please feel free to share.

Thank you.

EDIT
This question is about compiler internals ONLY.

like image 392
Karolis Milieška Avatar asked Mar 03 '23 05:03

Karolis Milieška


2 Answers

Could my GCC toolchain (or my GCC toolchain's version) create different memory layout for Drawable objects than in compiled engine.a?

Yes. Consider the following silly example:

struct Drawable
{
   #ifdef ENABLE_COUNTERS
   int counter = 0;
   #endif

  // ...
};

Perhaps one person compiled with -DENABLE_COUNTERS and someone else didn't. This violates the One Definition Rule. Or perhaps one toolchain was compiled where integers were 32 bits and another where they were 64 bits.

The linker, in order to be fast, will not complain; it will just throw away all but one definition, which could wreak all kinds of havoc (virtual function calls especially could get weird as the offsets become wrong).

How can I know that and how can I be sure about correct behaviour?

gcc has flto-odr-type-merging and -Wodr that can help you out when you compile.

Google's ASAN can also examine memory layouts to ensure they're identical.


Regarding your edit on compiler internals only.

Please refer to GCC's guidance on ABI stability: https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html

Roughly speaking. Each major compiler version has a new ABI. Later minor releases with the same major release almost always are compatible.

You can control which ABI you target with -fabi-version

like image 117
AndyG Avatar answered Mar 16 '23 01:03

AndyG


The memory layout, along with a lot of other things, is part of the ABI. One of the other things is the name mangling scheme. Although you should only link together object compiled for the same ABI, ABI designers try to use different mangling scheme so that accidentally linking objects compiled with different ABI usually result in unresolved symbols.

GCC has a command line flag to control the ABI: -fabi-version but the ABI depends also of some other options like -fno-exceptions and obviously the standard library implementation for the standard types.

like image 20
AProgrammer Avatar answered Mar 16 '23 02:03

AProgrammer