Gcc Abi Compatibility

GCC ABI compatibility

The official ABI page points to an ABIcheck. This tool may do, what you want.

Standard library ABI compatibility

ABIs in practice are not linked to the standard, for example consider this following code compiled with gcc 4.9.4 and gcc 5.1
using the same flags:

-std=c++11 -O2

#include <string>
int main(){
return sizeof (std::string);
}

gcc 4.9.4 returns 8 from main, gcc 5.1 returns 32.

As for guarantees: it is complicated:

Nothing is guaranteed by the standard.

Practically MSVC used to break ABI compatability, they stopped (v140,v141,v142 use the same ABI), clang/gcc have a stable ABI for a long time.

For those interested in learning more:
For a broad discussion of ABI/C++ standard that is not directly related to this question you an look at this blog post.

_GLIBCXX_USE_CXX11_ABI, GCC 4.8 and ABI compatibility

It's possible to use the C++11 ABI with gcc 4.8.2, but it's a dangerous hack; you would be far better off if at all possible to ask your vendors to ship libraries compiled with the C++03 ABI (-D_GLIBCXX_USE_CXX11_ABI=0) or to upgrade to GCC 5 or above.

You would need to download and install gcc 5 so that you can use its libstdc++ headers and libraries, then direct gcc 4.8 to use those in preference to its own. In addition, because gcc 4.8 is missing some intrinsics required by the libstdc++ shipped with gcc 5, you would need to hack out their usage.

For example, to compile a simple single-file application that includes <string>:

/usr/local/gcc-4.8.2/bin/g++ \
-std=c++11 \
-D_GLIBCXX_USE_CXX11_ABI=1 \
-D'__is_trivially_copyable(...)=0' \
-D'__is_trivially_constructible(...)=0' \
-D'__is_trivially_assignable(...)=0' \
-nostdinc++ \
-isystem /usr/local/gcc-5.4.0/include/c++/5.4.0/ \
-isystem /usr/local/gcc-5.4.0/include/c++/5.4.0/x86_64-unknown-linux-gnu \
-L /usr/local/gcc-5.4.0/lib64
a.cpp

This is dangerous because the gcc 5.4 libstdc++ is not designed to work with gcc 4.8, and redefining the intrinsics used (__is_trivially_copyable etc.) could change the layout of structures or otherwise cause binary incompatibility between your programs and the vendor's libraries.

In order to run the resulting executable, you would also need to ensure that the dynamic linker finds a compatible libstdc++, for example by adding /usr/local/gcc-5.4.0/lib64 to /etc/ld.so.conf, or using -Wl,-rpath /usr/local/gcc-5.4.0/lib64.

Why is library API + compiler ABI enough to ensure compatibility between objects with different versions of gcc?

It seems like it is possible that gcc can change the header implementing std::string

It can't make arbitrary changes. That would (as you surmise) break things. But only some changes to std::string will affect the memory layout of the class, and those are the ones that matter.

For an example of an optimisation that wouldn't affect the memory layout: they could change the code inside

size_t string::find (const string& str, size_t pos = 0) const;

to use a more efficient algorithm. That wouldn't change the memory layout of the string.

In fact, if you temporarily ignore the fact that everything is templated and so has to be in header files, you can imagine string as being defined in a .h file and implemented in a .cpp file. The memory layout is determined only from the contents of the header file. Anything in the .cpp file could be safely changed.

An example of something they couldn't do is to add a new data member to string. That would definitely break things.

You mentioned the dual ABI case. What happened there is that they needed to make a breaking change, and so they had to introduce a new string class. One of the classes is std::string and the other std::_cxx11::string. (Messy things happen under the hood so most users don't realise they are using std::_cxx11::string on newer versions of the compiler/standard library.)

Please explain the C++ ABI

Although the C++ Standard doesn't prescribe any ABI, some actual implementations try hard to preserve ABI compatibility between versions of the toolchain. E.g. with GCC 4.x, it was possible to use a library linked against an older version of libstdc++, from a program that's compiled by a newer toolchain with a newer libstdc++. The older versions of the symbols expected by the library are provided by the newer libstdc++.so, and layouts of the classes defined in the C++ Standard Library are the same.

But when C++11 introduced the new requirements to std::string and std::list, these couldn't be implemented in libstdc++ without changing the layout of these classes. This means that, if you don't use the _GLIBCXX_USE_CXX11_ABI=0 kludge with GCC 5 and higher, you can't pass e.g. std::string objects between a GCC4-compiled library and a GCC5-compiled program. So the ABI was broken.

Some C++ implementations don't try that hard to have compatible ABI: e.g. MSVC++ doesn't provide such compatibility between major compiler releases (see this question), so one has to provide different versions of library to use with different versions of MSVC++.

So, in general, you can't mix and match libraries and executables compiled with different versions even of the same toolchain.

If clang++ and g++ are ABI incompatible, what is used for shared libraries in binary?

even for things as core as standard containers

Standard containers are not all that "core". (For typical implementations) they are implemented entirely in valid C++ in headers, and if you compile the same headers with G++ and Clang++ you'll get ABI compatible output. You should only get incompatibilities "even for things as core as standard containers" if you use different versions of the container headers, not just by using Clang instead of GCC.

Both GCC and Clang conform to a cross-vendor, cross-platform C++ ABI (originally developed for the Itanium architecture, but also used for x86, x86_64, SPARC etc.) The really core things such as class layout, name mangling, exception handling, vtables etc. are specified by that ABI and Clang and GCC both follow it.

So in other words, if you compile the same source with GCC and Clang you'll get ABI-compatible binaries.

If you want to understand this stuff better see my What's an ABI and why is it so complicated? slides.

ABI compatibility of different C/C++ language versions + GNU extensions

In general:

  • No you can't combine different language versions in the same program, this will cause "One Definition Rule" violations in many library headers.

You may find in limited cases that a few classes actually don't change with the language version. However this is rare, rvalue references are required by the C++11 Standard, and not available in C++03 mode at all.

As for versions with and without support for GNU extensions, you're likely to have more success, but you will still need to run each header through the preprocessor and verify that the exact same sequence of tokens is seen by the compiler using both options.

And that's completely apart from ABI changes, that could cause memory layout or name mangling to differ between compiler variants.

You can also avoid one-definition rule violations on your own public APIs by avoiding using any version and language-specific features. Essentially, this means a flat C API.



Related Topics



Leave a reply



Submit