Language Standard Flags and ABI Compatibility
Installing a compiler is insufficient for C++23 development. By default, compilers often default to Older standards (C++14 or C++17) to maintain backward compatibility. This module details the Invocation flags required to enable C++23 features and analyzes the critical concept of Application Binary Interface (ABI) compatibility across different standard library implementations.
Compiler Invocation Standards
Section titled “Compiler Invocation Standards”To utilize C++23 features (such as std::expected``std::printOr std::ranges::to), specific Flags must be passed to the compiler driver.
ISO Standard Flags
Section titled “ISO Standard Flags”The following table outlines the flags required to enable strict C++23 support.
| Compiler | Flag | Description |
|---|---|---|
| Clang 16+ | -std=c++23 | Enables ISO C++23 standard features. |
| GCC 13+ | -std=c++23 | Enables ISO C++23 standard features. |
| MSVC (VS2022) | /std:c++latest | Enables the latest working draft features. (Note: /std:c++23 is available in recent builds but may require specific VS updates). |
Extension Flags vs. Strict ISO
Section titled “Extension Flags vs. Strict ISO”Compilers often provide two modes: strict ISO compliance and GNU/MSVC extensions.
-std=c++23: Strict ISO mode. Recommended for cross-platform portability.-std=gnu++23: ISO C++23 plus GNU extensions (e.g., Statement Expressions, Variable Length Arrays). This is the default behavior if-stdis omitted in GCC, but targeting a lower standard version./Permissive-(MSVC): Disables non-standard behavior. This is implicitly enabled by/std:c++20and later, but explicitly adding it ensures strict conformance.
Best Practice: Always explicitly define -std=c++23 (or /std:c++latest) and disable Extensions to prevent vendor lock-in.
Standard Library Implementations
Section titled “Standard Library Implementations”The C++ “compiler” consists of the frontend (syntax parsing) and the Standard Library implementation (headers and runtime binaries). These are distinct components and can be mixed in specific Configurations.
The Three Major Implementations
Section titled “The Three Major Implementations”- libstdc++ (The GNU Standard C++ Library)
- Primary Platform: Linux (Default).
- Maintainer: Free Software Foundation (GCC).
- Characteristics: Monolithic, extremely stable ABI.
- libc++ (LLVM C++ Standard Library)
- Primary Platform: macOS (Default), Android, FreeBSD.
- Maintainer: LLVM Project.
- Characteristics: Modular, faster compile times, modern codebase. It does not aim for binary compatibility with
libstdc++.
- MSVC STL
- Primary Platform: Windows (MSVC).
- Maintainer: Microsoft.
- Characteristics: Tightly coupled with the Windows UCRT.
Switching Implementations (Clang)
Section titled “Switching Implementations (Clang)”Clang allows switching the underlying standard library using the -stdlib flag. This is common when Testing for portability or using Clang on Linux.
# Link against LLVM's libc++ (Requires libc++-dev installed)clang++ -std=c++23 -stdlib=libc++ main.cpp
# Link against GNU's libstdc++ (Default on Linux)clang++ -std=c++23 -stdlib=libstdc++ main.cpp:::caution Library Availability On Linux, using -stdlib=libc++ requires the installation of Specific library packages (e.g., libc++-dev and libc++abi-dev on Debian/Ubuntu). If these are Missing, the linker will fail to find symbols. :::
Application Binary Interface (ABI)
Section titled “Application Binary Interface (ABI)”The Application Binary Interface (ABI) defines how data structures and routines are accessed in Machine code. Unlike the API (Source Compatibility), which deals with code syntax, the ABI deals With:
- Data Layout: The size, alignment, and padding of classes (e.g.,
sizeof(std::string)). - Calling Convention: How arguments are passed in registers/stack (e.g., x64 System V ABI vs. Microsoft x64 calling convention).
- Name Mangling: How C++ symbol names are encoded into unique strings for the linker (e.g.,
_ZNK3MapI...).
The Itanium C++ ABI [Itanium ABI] is the specification used by GCC and Clang on all non-Windows Platforms. It governs vtable layout, the order of base class subobjects, the construction and Destruction semantics of virtual bases, and the name mangling algorithm. Understanding this Specification is necessary for diagnosing ABI breakage.
The Linkage Rule
Section titled “The Linkage Rule”Rule: All object files (.o``.obj) and static libraries (.a``.lib) linked into a single Executable must be compiled with a compatible ABI.
Violating this results in Linker Errors (best case) or runtime memory corruption (worst case).
Proof of Binary Incompatibility
Section titled “Proof of Binary Incompatibility”Consider two translation units compiled with different ABIs. Unit A uses libstdc++ and Unit B uses libc++. Both define a function that takes std::string by value:
// unit_a.cpp — compiled with -stdlib=libstdc++#include <string>#include <cstddef>
extern "C" std::size_t get_string_size_libstdcxx(std::string s) { return s.size();}// unit_b.cpp — compiled with -stdlib=libc++#include <string>#include <iostream>#include <cstddef>
extern "C" std::size_t get_string_size_libstdcxx(std::string s);
int main() { std::string msg = "hello"; // The caller (libc++) constructs a std::string with sizeof=24 (libc++ SSO buffer is 22 bytes) // The callee (libstdc++) expects sizeof=32 (libstdc++ SSO buffer is 15 bytes) // The callee reads 32 bytes from the stack, but only 24 were written. // This reads 8 bytes of stack garbage, causing undefined behavior. std::cout << get_string_size_libstdcxx(msg) << "\n"; return 0;}This compiles and links without error because extern "C" suppresses name mangling. However, at Runtime, get_string_size_libstdcxx interprets the stack according to libstdc++’s std::string Layout, which differs from libc++’s layout. The size() call reads from the wrong offset and Returns garbage. This is undefined behavior [N4950 §6.9].
Theorem: Two object files compiled against different C++ standard library implementations are Binary-incompatible even when the source-level API is identical.
Proof sketch:
- Each standard library implementation defines its own
std::stringlayout (member order, SSO buffer size, alignment padding). - The C++ calling convention passes non—copyable class types by value via memory (caller allocates space, callee reads from that space).
- If
sizeof(std::string)differs between implementations, the callee reads bytes that were never written by the caller, violating memory safety. - Even when
sizeofis coincidentally equal, the internal layout (offset of size field, offset of data pointer) differs, causing the callee to interpret data fields incorrectly.
No correct program can be formed by linking object files from different standard Library ABIs.
Common ABI Hazards
Section titled “Common ABI Hazards”1. The GCC Dual ABI (_GLIBCXX_USE_CXX11_ABI)
Section titled “1. The GCC Dual ABI (_GLIBCXX_USE_CXX11_ABI)”In GCC 5.1, std::string and std::list were rewritten to comply with C++11 standards (forbidding Copy-On-Write implementations). To maintain backward compatibility with older binaries, libstdc++ Contains two versions of these symbols.
std::__cxx11::string(Modern, SSO-optimized).std::string(Legacy, Copy-On-Write).
This is controlled via a preprocessor macro:
-D_GLIBCXX_USE_CXX11_ABI=1(Default on modern Linux distros).-D_GLIBCXX_USE_CXX11_ABI=0(Legacy mode).
Hazard: Linking a library built with ABI=0 against an application built with ABI=1 will fail to Link because the symbol names for std::string are mangled differently. This is explained in Further detail in the Standard Library Implementation Section.
The root cause is that C++11 prohibited Copy-On-Write semantics for std::basic_string [N4950 §23.4.5]. The legacy libstdc++ implementation used COW, which means iterators could be invalidated By non-const operations on aliased strings. The new ABI uses Small String Optimization (SSO) Instead, eliminating this class of bugs at the cost of breaking binary compatibility.
2. MSVC vs. MinGW vs. Clang (Windows)
Section titled “2. MSVC vs. MinGW vs. Clang (Windows)”Windows has two distinct ecosystem ABIs:
- MSVC ABI: Used by Visual Studio.
- Itanium/GNU ABI: Used by MinGW-w64.
Hazard: You cannot generally link a C++ static library built with MinGW (libfoo.a) into an MSVC project (project.exe). They use different name mangling and exception handling mechanisms (table-based vs. DWARF/SJLJ).
Clang on Windows Exception: Clang on Windows can simulate either ABI depending on the driver:
clang++.exe(MinGW-style): Targets GNU ABI.clang-cl.exe: Targets MSVC ABI (acts as a drop-in replacement forcl.exe).
Verification Strategy
Section titled “Verification Strategy”To determine which ABI and Standard Library your environment is using, compile and run the following Inspection code.
#include <iostream>#include <vector>
int main() { std::cout << "Compiler and ABI Inspection:\n";
// 1. Check Standard Version std::cout << "Standard (__cplusplus): " << __cplusplus << "\n";
// 2. Check Standard Library#if defined(_LIBCPP_VERSION) std::cout << "Library: libc++ (Version " << _LIBCPP_VERSION << ")\n";#elif defined(__GLIBCXX__) std::cout << "Library: libstdc++ (Timestamp " << __GLIBCXX__ << ")\n";#elif defined(_MSVC_STL_VERSION) std::cout << "Library: MSVC STL (Version " << _MSVC_STL_VERSION << ")\n";#else std::cout << "Library: Unknown\n";#endif
// 3. Check GCC Dual ABI Status (Linux/MinGW only)#if defined(_GLIBCXX_USE_CXX11_ABI) std::cout << "GLIBCXX ABI: " << _GLIBCXX_USE_CXX11_ABI << "\n";#endif
return 0;}CMake Integration
Section titled “CMake Integration”In this course, we abstract these flags using CMake to ensure cross-platform consistency. Do not Manually type -std=c++23 in the terminal during development. Configure your CMakeLists.txt as Follows:
cmake_minimum_required(VERSION 3.25)project(Cpp23Architecture)
# Force C++23 Standardset(CMAKE_CXX_STANDARD 23)set(CMAKE_CXX_STANDARD_REQUIRED ON)set(CMAKE_CXX_EXTENSIONS OFF) # Disables GNU extensions (Strict ISO)
add_executable(app main.cpp)This configuration automatically translates to:
-std=c++23on GCC/Clang./std:c++latest(or/std:c++23) on MSVC.
Detailed C++ Standard Feature Overview
Section titled “Detailed C++ Standard Feature Overview”C++11 — The Modern C++ Foundation
Section titled “C++11 — The Modern C++ Foundation”C++11 introduced the most significant set of changes since the original standard. Key features:
autotype deduction, range-based for loops,nullptr``enum class- Move semantics (
std::move``std::forwardRvalue references) - Smart pointers (
std::unique_ptr``std::shared_ptr``std::weak_ptr) - Lambda expressions,
std::function``std::bind constexpr``static_assert``decltype- Variadic templates, template aliases
<thread>``<mutex>``<condition_variable>``<future>- Uniform initialization (
{}syntax),std::initializer_list
C++14 — Bug Fixes and Refinements
Section titled “C++14 — Bug Fixes and Refinements”Incremental improvements over C++11:
- Generic lambdas (
autoparameters), captured-by-move lambdas std::make_unique``std::exchange``std::integer_sequence- Return type deduction (
auto f() { return 42; }) - Relaxed
constexpr(allows loops, local variables) [[deprecated]]attribute, variable templates
C++17 — Major New Features
Section titled “C++17 — Major New Features”- Structured bindings (
auto [a, b] = pair;) std::optional``std::variant``std::anystd::filesystem``std::string_viewif constexprFold expressions,std::apply- Guaranteed copy elision (prvalues are not objects until materialized)
std::invoke``std::byteNested namespaces (A::B::C)__has_include``<charconv>(std::from_chars``std::to_chars)
C++20 — The “Big Four”
Section titled “C++20 — The “Big Four””- Concepts (
template<std::integral T>), requires clauses - Ranges (
std::views::filter``std::views::transformRange adapters) - Coroutines (
co_await``co_yield``co_return) - Modules (
export module foo;``import foo;)
Also: Three-way comparison (<=>), std::formatDesignated initializers, std::span std::jthreadCalendar/time zone libraries.
C++23 — Refinements and Completeness
Section titled “C++23 — Refinements and Completeness”std::print``std::println(free-function formatting)std::expected<T, E>(error handling without exceptions)std::flat_map``std::flat_set(sorted associative containers using contiguous storage)std::mdspan(multidimensional view)std::move_only_function#embeddirective (binary resource inclusion)autoin function parameters, deducingthis
C++26 Preview (as of 2025)
Section titled “C++26 Preview (as of 2025)”std::reflection(compile-time reflection)std::text_encoding(text encoding detection)- Patches for contracts,
std::expectedmonadic operations - Linear algebra (
std::linalg) - Hazard pointers and RCU (lock-free data structures)
Compiler Version Support Matrix
Section titled “Compiler Version Support Matrix”| Feature | GCC Min | Clang Min | MSVC Min |
|---|---|---|---|
| C++11 | 4.8 | 3.3 | VS 2013 |
| C++14 | 5.0 | 3.4 | VS 2015 |
| C++17 | 7.0 | 5.0 | VS 2017 |
| C++20 | 10.0 | 10.0 | VS 2019 |
| C++23 | 13.0 | 16.0 | VS 2022 |
Feature-Level Support Details
Section titled “Feature-Level Support Details”Different compilers achieve “full” C++23 support at different versions. The table above shows the Minimum version for basic support, but some features require newer versions:
| C++23 Feature | GCC Min | Clang Min | MSVC Min | Notes |
|---|---|---|---|---|
std::print | 14.0 | 18.0 | 19.40 | Requires OS-level terminal support |
std::expected | 13.0 | 16.0 | 19.38 | Widely available |
std::flat_map | 14.0 | 17.0 | 19.40 | Requires sorted associative container |
std::mdspan | 14.0 | 18.0 | 19.40 | Multidimensional view |
std::move_only_function | 13.0 | 18.0 | 19.38 | Move-only callable wrapper |
std::generator | 14.0 | 18.0 | N/A | Coroutine-based generator |
std::ranges::to | 14.0 | 18.0 | 19.40 | Range-to-container conversion |
#embed | N/A | 19.0 | N/A | Resource embedding |
deducing this | N/A | 18.0 | N/A | Explicit object member functions |
auto in parameters | N/A | N/A | N/A | Not yet implemented in any major compiler |
std::format full spec | 14.0 | 17.0 | 19.38 | Many format specifiers added in C++23 |
ABI Stability Between Compiler Versions
Section titled “ABI Stability Between Compiler Versions”What Changes Between ABI Versions
Section titled “What Changes Between ABI Versions”An ABI break occurs when the binary interface of a compiled entity changes in a way that is Incompatible with previously compiled code. Common causes:
- Name mangling changes. GCC 5.1 changed the mangling of
std::stringandstd::list(the dual ABI issue described above). - Layout changes. Adding virtual functions changes the vtable layout. Changing member order or size changes the object layout.
- Calling convention changes. Rare, but possible when new register classes are added (e.g., AVX-512 register passing).
- Standard library changes. Adding members to standard library types (e.g.,
std::vectorgrew additional member variables in some implementations).
ABI-Breaking Changes Across Standards
Section titled “ABI-Breaking Changes Across Standards”The following table catalogs known ABI-breaking changes introduced by various C++ standards in libstdc++ and libc++.
| Change | Standard | Implementation | Effect |
|---|---|---|---|
std::string COW to SSO | C++11 | libstdc++ | Dual ABI; sizeof(std::string) changed |
std::list size field removal | C++11 | libstdc++ | Dual ABI; O(1) size() required node count |
std::vector bool specialization | C++20 | libstdc++ | Minor layout changes in some configurations |
std::optional union member | C++23 | libc++ | ABI version bump via _LIBCPP_ABI_VERSION |
std::function small buffer | C++14 | libc++ | Layout change in libc++ ABI v2 |
std::shared_ptr control block | C++20 | MSVC STL | Debug-only layout change (IDL sensitive) |
std::locale::facet refcount | C++11 | libstdc++ | Atomic refcount changed layout |
std::type_info / RTTI | C++11 | All | vtable changes for virtual bases |
ABI Breakage Examples
Section titled “ABI Breakage Examples”// v1 of library (libfoo.so):struct Config { int timeout = 30; bool verbose = false;};
// v2 of library (libfoo.so):struct Config { int timeout = 30; bool verbose = false; int retries = 3; // NEW FIELD — changes sizeof(Config)};
// Application compiled against v1, linked against v2:// - If application passes Config by value, the callee reads past the allocated memory// - If application accesses retries, it reads garbage from adjacent stack/heap// This is an ABI break even though the source API "looks" compatible.This is a concrete instance of the One Definition Rule (ODR) violation at the binary level [N4950 §6.3]. The ODR requires that every entity with external linkage have exactly one definition across All translation units. When the definition of Config changes between library version v1 and v2, But the consumer was compiled against v1, the binary contains two incompatible definitions of Config in the same program. The linker does not detect this because the struct has no mangled Symbol (it is not a function or global variable).
The -fabi-version Flags (GCC)
Section titled “The -fabi-version Flags (GCC)”GCC provides flags to control the ABI version used during compilation. These are relevant when Building code that must interoperate with older binaries.
# GCC 5+: default is ABI version 11 (dual ABI with CXX11 ABI enabled)g++ -std=c++23 -fabi-version=11 code.cpp
# Force legacy ABI (equivalent to -D_GLIBCXX_USE_CXX11_ABI=0)g++ -std=c++23 -fabi-version=10 code.cpp
# Check the current ABI versionecho | g++ -dM -E - | grep __GXX_ABI_VERSION# Output: #define __GXX_ABI_VERSION 1017ABI version 10 corresponds to the pre-C++11 ABI (COW std::string). ABI version 11 is the modern C++11 ABI. There is no ABI version 12 or higher as of GCC 14; GCC has maintained ABI version 11 Stability since GCC 5.1.
Cross-Compiler ABI Compatibility Matrix
Section titled “Cross-Compiler ABI Compatibility Matrix”| Scenario | Compatible? | Notes |
|---|---|---|
GCC 13 GCC 14 (same -std) | Yes | Same libstdc++ ABI |
Clang 16 GCC 13 (Linux, libstdc++) | Must use same libstdc++ version and -std flag | |
Clang 16 (libc++) GCC 13 (libstdc++) | No | Different standard library ABIs |
| MSVC 2022 MinGW-w64 (Windows) | No | Different name mangling, exception handling, C++ ABI |
GCC Linux Clang Linux (libstdc++) | Same libstdc++.so must be used at runtime | |
| MSVC 2019 MSVC 2022 | MSVC STL aims for ABI stability, but not guaranteed |
:::caution Mixing Clang and GCC on Linux with the same libstdc++ is generally safe for the same C++ standard version. However, some ABI-affecting flags (like -D_GLIBCXX_USE_CXX11_ABI) must be Consistent across all object files in the final binary. :::
MSVC ABI Differences
Section titled “MSVC ABI Differences”MSVC uses a different C++ ABI from the Itanium ABI used by GCC/Clang. Key differences:
- Name mangling. MSVC uses a different mangling scheme (decorated names like
??0Config@@QAE@XZvs. GCC’s_ZN6ConfigC1Ev). - Exception handling. MSVC uses table-based exception handling (similar to DWARF) for C++ exceptions on x64, not Structured Exception Handling (SEH). GCC/Clang use DWARF (Linux) or SjLj (some platforms).
sizeofdifferences. Some types have different sizes across ABIs (e.g.,longis 4 bytes on Windows, 8 bytes on Linux x86-64).- vtable layout. The vtable structure, RTTI layout, and thunk mechanisms differ.
- Debug iterator support. MSVC STL includes debug iterator checks in debug builds that change iterator sizes.
#include <iostream>
int main() { std::cout << "sizeof(long): " << sizeof(long) << "\n"; std::cout << "sizeof(pointer): " << sizeof(void*) << "\n"; // On Windows (MSVC): sizeof(long) = 4, sizeof(pointer) = 8 // On Linux x86-64 (GCC/Clang): sizeof(long) = 8, sizeof(pointer) = 8}The sizeof(long) difference is a consequence of the different data models: Windows uses the LLP64 Model (long is 32 bits, long long is 64 bits), while Linux uses the LP64 model (long is 64 Bits). This is defined by the System V AMD64 ABI specification [System V ABI] and the Microsoft x64 Calling convention [MSVC x64 ABI] respectively.
Common Pitfalls
Section titled “Common Pitfalls”- Defaulting to an older standard. GCC defaults to C++14 (or C++17 in newer versions), Clang defaults to C++14. Always explicitly set
-std=c++23in your build system. - Mixing
-std=c++23and-std=c++17object files. While the ABI is backward compatible (C++23 builds can link C++17 objects), the reverse is not guaranteed. - Using GNU extensions unconditionally.
-std=gnu++23enables extensions like VLAs and statement expressions that are not portable. Use-std=c++23for strict ISO compliance. - Assuming
sizeof(long)is portable. It is 4 bytes on Windows, 8 bytes on Linux. Useint64_torlong longfor fixed-width types. - Forgetting to set
CMAKE_CXX_EXTENSIONS OFF. Without this, CMake defaults to GNU extensions, which may introduce non-portable constructs. - Passing C++ types across
extern "C"boundaries.extern "C"suppresses name mangling but does not change the calling convention for C++ class types. Passingstd::string``std::vectoror any non-POD type through anextern "C"function is undefined behavior if the caller and callee use different standard library ABIs. Use opaque handles or plain C types at ABI boundaries. - ABI version drift in long-lived projects. If a library is compiled once with GCC 5 and never recompiled, but the application is upgraded to GCC 14, the two may have incompatible ABI assumptions. Rebuild all dependencies when upgrading the toolchain.
ABI and Inline Namespace Versioning
Section titled “ABI and Inline Namespace Versioning”The C++ Standard Library uses inline namespaces to embed ABI version information directly into Symbol names without changing the user-facing API. This is how libstdc++ and libc++ manage ABI Evolution without breaking existing binaries.
How Inline Namespaces Work
Section titled “How Inline Namespaces Work”An inline namespace [N4950 S9.8.2] is a nested namespace whose members are automatically accessible From the enclosing namespace. However, the mangled symbol name includes the inline namespace name, Providing ABI versioning without API changes:
#include <iostream>
int main() { // User code sees std::string // But the mangled symbol is std::__cxx11::basic_string<char, ...> std::string s = "hello"; std::cout << s << "\n";}The _GLIBCXX_USE_CXX11_ABI macro controls whether the old ABI namespace or the new ABI namespace Is selected. When =1 (default), std::string resolves to std::__cxx11::basic_string. When =0 It resolves to the legacy std::basic_string with Copy-On-Write semantics.
libc++ ABI Versioning
Section titled “libc++ ABI Versioning”Libc++ uses _LIBCPP_ABI_VERSION for similar purposes. When libc++ changes the layout of a standard Type (e.g., std::optional grew a union member in a newer version), the ABI version is bumped, and The new layout is placed in a new inline namespace. Old binaries continue to link against the old Inline namespace symbols.
# Inspect the inline namespaces in libc++nm -C /usr/lib/libc++.so | grep basic_string# Output includes: std::__1::basic_string<char, ...># The __1 is the inline namespace (ABI version 1)Inline Namespace Mechanics: Formal Treatment
Section titled “Inline Namespace Mechanics: Formal Treatment”Consider the following simplified representation of how libstdc++ implements the dual ABI:
// Inside <string> (simplified):namespace std { // Legacy ABI (inline namespace removed, so symbols mangle as std::basic_string) inline namespace __cxx11 { template<typename CharT, ...> class basic_string { /* SSO implementation */ }; }}When _GLIBCXX_USE_CXX11_ABI=1``basic_string is defined inside std::__cxx11. The mangled name For std::string becomes _ZNSt7__cxx11basic_stringIcSt11char_traitsIcESaIcEE (includes the __cxx11 tag). When _GLIBCXX_USE_CXX11_ABI=0The basic_string definition is placed directly in stdAnd the mangled name omits the __cxx11 component.
The linker treats these as entirely different symbols. An object file compiled with ABI=0 references _ZStplIcSt11char_traitsIcESaIcEENSt7__cxx11basic_stringIT_T0_T1_EERKS8_S9_ while an object file Compiled with ABI=1 references the same function but without the __cxx11 inline namespace Qualifier. The linker reports “undefined reference” because it cannot find a match.
Practical Implications
Section titled “Practical Implications”- Never mix ABI versions in the same binary. If one library was compiled with
_GLIBCXX_USE_CXX11_ABI=0and another with=1The linker sees two distinctstd::stringtypes and will report “undefined reference” or “multiple definition” errors. - System libraries are compiled with the distro’s default ABI. On Ubuntu 22.04, system libraries use ABI=1. Recompiling your own code with ABI=0 and linking against system
.sofiles will fail. - ABI version is embedded in the symbol name. You can verify ABI compatibility by inspecting symbol names with
nm -Corobjdump -T.
ABI Inspecting Tools
Section titled “ABI Inspecting Tools”Verifying ABI compatibility is an essential diagnostic skill. The following tools allow you to Inspect the binary interface of compiled artifacts.
nm: Symbol Table Inspection
Section titled “nm: Symbol Table Inspection”# List symbols in a shared library (demangled)nm -DC /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep basic_string
# Show undefined symbols in an object filenm -u app.o
# Show defined symbolsnm app.o | grep " T "objdump: ELF Section and Symbol Inspection
Section titled “objdump: ELF Section and Symbol Inspection”# Show all dynamic symbols with their versionsobjdump -T /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | head -30
# Show the dynamic relocation entriesobjdump -R app
# Disassemble a specific functionobjdump -d -M intel app | grep -A20 "<main>:"readelf: Structured ELF Inspection
Section titled “readelf: Structured ELF Inspection”# Show the program headers (including INTERP for dynamic linker)readelf -l app
# Show the dynamic section (DT_NEEDED entries)readelf -d app
# Show symbol version requirementsreadelf -V app
# Show section headers (verify .text, .rodata, .data sizes)readelf -S appabi-compliance-checker (Advanced)
Section titled “abi-compliance-checker (Advanced)”For library maintainers, the abi-compliance-checker tool from the ABI Compliance Checker suite can Automatically detect ABI breaks between two versions of a library:
# Installsudo apt install abi-compliance-checker abi-dumper
# Dump ABI descriptors for two versionsabi-dumper libfoo.so.1 -o abi1.xml -lver 1.0abi-dumper libfoo.so.2 -o abi2.xml -lver 2.0
# Compareabi-compliance-checker -l libfoo -old abi1.xml -new abi2.xmlThis tool checks for:
- Added/removed symbols
- Changed symbol visibility
- Modified vtable layout
- Changed type sizes
- Modified function signatures
C++ Standard Header ABI Differences
Section titled “C++ Standard Header ABI Differences”Different C++ standard library implementations may implement the same header with different internal Types. The following table shows the sizeof differences for key types across implementations:
| Type | libstdc++ (64-bit) | libc++ (64-bit) | MSVC STL (64-bit) |
|---|---|---|---|
sizeof(std::string) | 32 | 24 | 32 |
sizeof(std::vector<T>) | 24 | 24 | 24 |
sizeof(std::optional<T>) (no-value) | 24 (for int) | 16 (for int) | 16 (for int) |
sizeof(std::shared_ptr<T>) | 16 | 16 | 16 |
sizeof(std::unique_ptr<T>) | 8 | 8 | 8 |
sizeof(std::function<void()>) | 32 | 32 | 48 |
The std::function size difference is particularly notable: MSVC STL allocates 48 bytes for the Small buffer optimization (SBO), while libstdc++ and libc++ allocate 32 bytes. A std::function That captures more state than fits in the SBO buffer triggers heap allocation, so the threshold Differs between implementations.
Cross-Platform ABI Checklist
Section titled “Cross-Platform ABI Checklist”When distributing a C++ library that must work across platforms, verify the following:
- All object files use the same C++ standard version (or compatible versions).
- All object files use the same standard library implementation (
libstdc++``libc++Or MSVC STL). - The
_GLIBCXX_USE_CXX11_ABImacro is consistent across all compilation units (GCC only). - No GNU extensions are used in public headers (or extensions are enabled uniformly).
- The struct layout is identical across platforms (verify with
static_assert(sizeof(T) == N)). - The calling convention matches (System V AMD64 ABI on Linux, Microsoft x64 on Windows).
- Exception handling mechanism matches (DWARF/SJLJ/LSDA on GCC/Clang, table-based on MSVC x64).
See Also
Section titled “See Also”- Installing a Compiler
- Standard Library Implementation
- Cross-compilation Toolchains
- Linker Configuration
Further Reading
Section titled “Further Reading”- Itanium C++ ABI — The formal specification of the C++ ABI used by GCC and Clang on non-Windows platforms. This document defines name mangling, vtable layout, exception handling tables, and class layout rules. Understanding this specification is essential for debugging ABI breakage.
- System V AMD64 ABI — The calling convention specification for x86-64 Linux systems. Defines register usage, stack frame layout, and argument passing rules.
- N4950 — The C++23 working draft standard. The authoritative reference for language and library behavior.
- Compiler Explorer (godbolt.org) — Online tool for inspecting compiler output (assembly, AST, preprocessed source) across multiple compilers. Essential for verifying that compiler flags produce the expected code generation.
Summary
Section titled “Summary”This topic covers the core concepts of language standard flags and abi compatibility, including underlying theory, practical implementation, and key applications.
Key concepts include:
- command-line fundamentals
- file permissions and ownership
- process management
- shell scripting with bash
- package management
Understanding these concepts thoroughly is essential for both examinations and practical programming, and requires both theoretical knowledge and hands-on practice.
Worked Examples
Section titled “Worked Examples”Worked examples demonstrating the application of key concepts are covered in the detailed sub-pages linked above.