Skip to content

Commit c5aa263

Browse files
committed
[libc++] Document our ABI guarantees and what ABI flags exist to modify these guarantees
1 parent 72768d9 commit c5aa263

File tree

2 files changed

+228
-101
lines changed

2 files changed

+228
-101
lines changed
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
=======================
2+
libc++'s ABI Guarantees
3+
=======================
4+
5+
libc++ provides multiple types ABI guarantees. These include stability of the layout of structs, the linking of TUs
6+
built against different versions and configurations of the library, and more. This document describes what guarantees
7+
libc++ provides in these different fields as well as what options exist for users and vendors to affect these
8+
guarantees.
9+
10+
Note that all of the guarantees listed below come with an asterisk that there may be circumstances where we deem it
11+
worth it to break that guarantee. These breaks are communicated to vendors by CCing #libcxx-vendors on GitHub. If you
12+
are a vendor, please ask to be added to that group to be notified about changes that potentially affect you.
13+
14+
15+
Stability of the Layout of Structs
16+
==================================
17+
18+
The layout of any struct that is observable by the user is kept stable across versions of the library and any options
19+
users are allowed to change. There are a lot of structs that have internal names, but are none the less observable by
20+
users; for example through public aliases to these types or because they affect the layout of other types.
21+
22+
There are multiple ABI flags which affect the layout of certain structs:
23+
24+
``_LIBCPP_ABI_ALTERNATE_STRING_LAYOUT``
25+
---------------------------------------
26+
This changes the internal layout of ``basic_string`` to move the section that is used for the internal buffer to the
27+
front, making it eight byte aligned instead of being unaligned, improving the performance of some operations
28+
significantly.
29+
30+
``_LIBCPP_ABI_NO_ITERATOR_BASES``
31+
---------------------------------
32+
This removes the ``std::iterator`` base class from ``back_insert_iterator``, ``front_insert_iterator``,
33+
``insert_iterator``, ``istream_iterator``, ``ostream_iterator``, ``ostreambuf_itreator``, ``reverse_iterator``, and
34+
``raw_storage_iterator``. This doesn't directly affect the layout of these types in most cases, but may result in more
35+
padding being used when they are used in combination, for example ``reverse_iterator<reverse_iterator<T>>``.
36+
37+
- ``_LIBCPP_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION``
38+
-------------------------------------------------
39+
This changes the index type used inside ``std::variant`` to the smallest required type to reduce the datasize of
40+
variants in most cases.
41+
42+
``_LIBCPP_ABI_OPTIMIZED_FUNCTION``
43+
----------------------------------
44+
This significantly restructures how `std::function` is written to provide better performance, but is currently not ABI
45+
stable.
46+
47+
``_LIBCPP_ABI_NO_RANDOM_DEVICE_COMPATIBILITY_LAYOUT``
48+
-----------------------------------------------------
49+
This changes the layout of ``std::random_device`` to only holds state with an implementation that gets entropy from a
50+
file (see ``_LIBCPP_USING_DEV_RANDOM``). When switching from this implementation to another one on a platform that has
51+
already shipped ``std::random_device``, one needs to retain the same object layout to remain ABI compatible. This flag
52+
removes these workarounds for platforms that don't care about ABI compatibility.
53+
54+
55+
``_LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING``
56+
------------------------------------------
57+
This removes artifical padding from ``_LIBCPP_COMPRESSED_PAIR`` and ``_LIBCPP_COMPRESSED_TRIPLE``. These macros are used
58+
inside the associative and unordered containers, ``deque``, ``forward_list``, ``future``, ``list``, ``basic_string``,
59+
``function``, ``shared_ptr``, ``unique_ptr``, and ``vector`` to stay ABI compatible with the legacy
60+
``__compressed_pair`` type. This has historically been used to reduce storage requirements in the case of empty types,
61+
but has been replaced by ``[[no_unique_address]]``. ``[[no_unique_address]]`` is significantly lighter in terms of
62+
compile time and debug information, and also improves the layout of structs further. However, to keep ABI stability, the
63+
additional improvements in layout had to be reverted by introducing artificial padding.
64+
65+
``_LIBCPP_ABI_IOS_ALLOW_ARBITRARY_FILL_VALUE``
66+
----------------------------------------------
67+
``basic_ios`` uses ``WEOF`` to indicate that the fill value is uninitialized. However, on platforms where the size of
68+
``char_type`` is equal to or greater than the size of ``int_type`` and ``char_type`` is unsigned,
69+
``char_traits<char_type>::eq_int_type()`` cannot distinguish between ``WEOF`` and ``WCHAR_MAX``. This flag changes
70+
``basic_ios`` to instead track whether the fill value has been initialized using a separate boolean.
71+
72+
73+
Linking TUs which have been compiled against different releases of libc++
74+
=========================================================================
75+
libc++ supports linking TUs which have beeen compiled against different releases of libc++ by marking symbols with
76+
hidden visibility and changing the mangling of header-only functions in every release. This guarantee can be disabled
77+
via ``_LIBCPP_NO_ABI_TAG``, but it is not recommended to do so.
78+
79+
80+
Linking TUs which have been compiled with different flags affecting code gen
81+
============================================================================
82+
There are a lot of compiler (and library) flags which change the code generated for functions. This includes flags like
83+
``-O1``, which are guaranteed by the compiler to not change the observable behaviour of a correct program, as well as
84+
flags like ``-fexceptions``, which **do** change the observable behaviour. libc++ allows linking of TUs which have been
85+
compiled whith specific flags only and makes no guarantees for any of the flags not listed below.
86+
87+
The flags allowed (in any combination) are:
88+
- ``-f[no-]exceptions``
89+
- ``-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE{_FAST,_EXTENSIVE,_DEBUG,_NONE}``
90+
91+
Note that this does not provide any guarantees about user-defined functions, but only that the libc++ functions linked
92+
behave as the flags say.
93+
94+
95+
Availability of symbols in the built library (both static and shared)
96+
=====================================================================
97+
In general, libc++ does not make any guarantees about forwards-compability. That is, a TU compiled against new headers
98+
may not work with an older library. Vendors who require such support can leverage the availability markups. On the other
99+
hand, backwards compatibility is generally guaranteed.
100+
101+
There are multiple ABI flags that change the symbols exported from the built library:
102+
103+
``_LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON``
104+
-------------------------------------------------
105+
This removes ``__basic_string_common<true>::__throw_length_error()`` and
106+
``__basic_string_common<true>::__throw_out_of_range()``. These symbols have been used by ``basic_string`` in the past,
107+
but are not referenced from the headers anymore.
108+
109+
``_LIBCPP_ABI_DO_NOT_EXPORT_VECTOR_BASE_COMMON``
110+
------------------------------------------------
111+
This removes ``__vector_base_common<true>::__throw_length_error()`` and
112+
``__vector_base_common<true>::__throw_out_of_range()``. These symbols have been used by ``vector`` in the past, but are
113+
not referenced from the headers anymore.
114+
115+
``_LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10``
116+
----------------------------------------------
117+
This removes ``__itoa::__u32toa()`` and ``__iota::__u64toa``. These symbols have been used by ``to_chars`` in the past,
118+
but are not referenced from the headers anymore.
119+
120+
``_LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION``
121+
-------------------------------------------------------
122+
This replaces the symbols that are exported for ``basic_string`` to avoid exporting functions which are likely to be
123+
inlined as well as explicitly moving paths to the built library which are slow, improving fast-path inlining of multiple
124+
functions. This flag is currently unstable.
125+
126+
127+
Stability of the traits of a type
128+
=================================
129+
Whether a particular trait of a type is kept stable depends heavily on the type in question and the trait. The most
130+
important trait of a type to keep stable is the triviality for the purpose of calls, since that directly affects the
131+
function call ABI. Which types are considered non-trivial for the purpose of calls is defined in the
132+
`Itanium ABI <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions>`_.
133+
``is_trivially_copyable`` should also be kept stable usually, since many programs depend on this trait for their own
134+
layouting. This isn't rigit as the previous requirement though.
135+
136+
There are multiple ABI flags that change traits of a struct:
137+
138+
``_LIBCPP_ABI_ENABLE_UNIQUE_PTR_TRIVIAL_ABI``
139+
---------------------------------------------
140+
This flag adds ``[[clang::trivial_abi]]`` to ``unique_ptr``, which makes it trivial for the purpose of calls.
141+
142+
``_LIBCPP_ABI_ENABLE_SHARED_PTR_TRIVIAL_ABI``
143+
---------------------------------------------
144+
This flag adds ``[[clang::trivial_abi]]`` to ``shared_ptr``, which makes it trivial for the purpose of calls.
145+
146+
147+
Types that public aliases reference
148+
===================================
149+
There are a lot of aliases that reference types with library internal names. For example, containers contain an
150+
``iterator`` alias to a type with a library internal name. These have to always reference the same type, since the
151+
mangling of user-defined function overloads would change otherwise. A notable exception to this are the alias templates
152+
to type traits. There doesn't seem to be anybody who relies on these names staying the same, so it is OK to change what
153+
these aliases actually reference.
154+
155+
There are multiple ABI flags which change which type an alias references:
156+
157+
``_LIBCPP_ABI_INCOMPLETE_TYPES_IN_DEQUE``
158+
-----------------------------------------
159+
This changes ``deque::iterator`` to avoid requring complete types for ``deque``.
160+
161+
``_LIBCPP_ABI_FIX_UNORDERED_CONTAINER_SIZE_TYPE``
162+
-------------------------------------------------
163+
This changes the unordered container's ``size_types`` aliases.
164+
165+
``_LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY`` and ``_LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW``
166+
-----------------------------------------------------------------------------------------------
167+
This changes the ``iterator`` and ``const_iterator`` of ``array`` and ``string_view`` respectively to reference
168+
``__wrap_iter`` instead, which makes it less likely for users to depend on non-portable implementation details. This is
169+
especially useful because enabling bounded iterators hardening requires code not to make these assumptions.
170+
171+
``_LIBCPP_ABI_BOUNDED_ITERATORS``, ``_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STRING``, ``_LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR``, and ``_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY``
172+
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
173+
These flags change the ``iterator`` member of various classes to reference hardened iterators instead. See the
174+
:ref:`hardening documentation <_hardening>` for more details.
175+
176+
177+
Meaning of values
178+
=================
179+
The meaning of specific values can usually not be changed, since programs compiled against older versions of the headers
180+
may check for these values. These specific values don't have to be hard-coded, but can also depend on user input.
181+
182+
There are multiple ABI flags that change the meaning of particular values:
183+
184+
``_LIBCPP_ABI_REGEX_CONSTANTS_NONZERO``
185+
---------------------------------------
186+
This changes the value of ``regex_constants::syntax_option-type::ECMAScript`` to be standards-conforming.
187+
188+
``_LIBCPP_ABI_FIX_CITYHASH_IMPLEMENTATION``
189+
-------------------------------------------
190+
This flag fixes the implementation of CityHash used for ``hash<fundamental-type>``. The incorrect implementation of
191+
CityHash has the roblem that it drops some bits on the floor.
192+
193+
inline namespaces
194+
=================
195+
Inline namespaces which contain types that are ovservable by the user need to be kept the same, since they affect
196+
mangling. libc++ has almost all symbols inside an inline namespace. By default that namespace is ``__1``, but can be
197+
changed by the vendor by setting `LIBCXX_ABI_NAMESPACE` during CMake configuration. There is also
198+
``_LIBCPP_ABI_NO_FILESYSTEM_INLINE_NAMESPACE`` to remove the ``__fs``namespace from surrounding the ``filesystem``
199+
namespace. This shortens the mangling of the filesystem symbols a bit.

0 commit comments

Comments
 (0)