Jan 31, 2019

[C++][note] ABI compatibility and inline namespaces - Arvid Norberg

Quick note/refresh about ABI through Arvid Norberg's talk.




ABI is about linking.
Reference:
https://vsdmars.blogspot.com/2015/09/linking-notes.html


Calling convention

Reference:
https://en.wikipedia.org/wiki/X86_calling_conventions
The history of calling conventions series - Raymond Chen
https://blogs.msdn.microsoft.com/oldnewthing/20040102-00/?p=41213
https://blogs.msdn.microsoft.com/oldnewthing/20040107-00/?p=41183
https://blogs.msdn.microsoft.com/oldnewthing/20040108-00/?p=41163
https://blogs.msdn.microsoft.com/oldnewthing/20040114-00/?p=41053
https://www.codeproject.com/Articles/1388/Calling-Conventions-Demystified
https://www.agner.org/optimize/calling_conventions.pdf
x64 calling convention
https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2017
Stack frame layout on x86-64
https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/

- which registers to pass arguments in
- pass two 32bit arguments in 64bit registers
- split structs and pass fields in registers
- pass floats in special registers
- pass arguments in SIMD registers
- return value optimization
- how are exceptions thrown


Class layouts:

- vtable layout
- where/how we pad fields
- empty base class optimization
- std::pair (compressed_pair)
- std::string (SSO)


Across library boundaries:

- C++ version
- may affect layout
- name mangling
- calling convention
- defines
- may affect layout (e.g _GLIBCXX_USE_CXX11_ABI)
- any compiler flag alters layout or calling conventions


'#define' harms, beware of using it which breaks
the compile ABI.

In Golang, it simply asks you to recompile everything again
with same version of compiler.

In C++, we often have .so (SONAME) libraries.
This is where the trouble begins(Or solved).



Name mangling:

- Trouble in shared libraries.
- release mode library and debug mode client.
- C++98 library and C++11 client.
- Library headers is newer than library binary.



Solution:

- Auh, like Golang, recompile everything.
- Use a build system which ensures what we build is
link-compatible.
i.e
build system should give us separate library builds,
release build, debug build, etc.

If we tried to build release against debug library, build
system should fail us..



Inline namespaces come to the rescue:

Reference:
[C++] inline namespace compile time replacement trick.
https://vsdmars.blogspot.com/2016/02/c-inline-namespace-compile-time.html
C++11-FAQ-BS
http://www.stroustrup.com/C++11FAQ.html#inline-namespace

- inline namespaces let us inject information into the mangled
name(ABI), without altering the API.
i.e
for the caller always refers to the symbol inside the namespace function
regardless the namespace's internal inline namespace is.

This trick can go further since specialized temaplte can be defined
in the namespace which embeds the inline namespace's main template.

- inline namespaces affect the linker names of symbols,
While preserving the API.
From caller's perspective, the callee's name remains the same,
regardless where the name coming from different inlined namespace.



Forward declarations:

- A symbol's actual namespace is an implementation detail.
- Clients may not forward declare 3rd party symbols.
(because that symbol might be an inline namespace symbol,
which during a real linking stage, compile fails~~~)


Summary:

- Always build from the source (if there's no versioning .so, SONAME available)
- Use inline namespace for backward compatible upgrades to the ABI
(use with #define)
- Use inline namespace for ABI-safe build configurations
- Library authors, provide forward declaration headers (versioned, of course)


No comments:

Post a Comment

Note: Only a member of this blog may post a comment.