1 | ============== |
2 | LTO Visibility |
3 | ============== |
4 | |
5 | *LTO visibility* is a property of an entity that specifies whether it can be |
6 | referenced from outside the current LTO unit. A *linkage unit* is a set of |
7 | translation units linked together into an executable or DSO, and a linkage |
8 | unit's *LTO unit* is the subset of the linkage unit that is linked together |
9 | using link-time optimization; in the case where LTO is not being used, the |
10 | linkage unit's LTO unit is empty. Each linkage unit has only a single LTO unit. |
11 | |
12 | The LTO visibility of a class is used by the compiler to determine which |
13 | classes the whole-program devirtualization (``-fwhole-program-vtables``) and |
14 | control flow integrity (``-fsanitize=cfi-vcall`` and ``-fsanitize=cfi-mfcall``) |
15 | features apply to. These features use whole-program information, so they |
16 | require the entire class hierarchy to be visible in order to work correctly. |
17 | |
18 | If any translation unit in the program uses either of the whole-program |
19 | devirtualization or control flow integrity features, it is effectively an ODR |
20 | violation to define a class with hidden LTO visibility in multiple linkage |
21 | units. A class with public LTO visibility may be defined in multiple linkage |
22 | units, but the tradeoff is that the whole-program devirtualization and |
23 | control flow integrity features can only be applied to classes with hidden LTO |
24 | visibility. A class's LTO visibility is treated as an ODR-relevant property |
25 | of its definition, so it must be consistent between translation units. |
26 | |
27 | In translation units built with LTO, LTO visibility is based on the |
28 | class's symbol visibility as expressed at the source level (i.e. the |
29 | ``__attribute__((visibility("...")))`` attribute, or the ``-fvisibility=`` |
30 | flag) or, on the Windows platform, the dllimport and dllexport attributes. When |
31 | targeting non-Windows platforms, classes with a visibility other than hidden |
32 | visibility receive public LTO visibility. When targeting Windows, classes |
33 | with dllimport or dllexport attributes receive public LTO visibility. All |
34 | other classes receive hidden LTO visibility. Classes with internal linkage |
35 | (e.g. classes declared in unnamed namespaces) also receive hidden LTO |
36 | visibility. |
37 | |
38 | A class defined in a translation unit built without LTO receives public |
39 | LTO visibility regardless of its object file visibility, linkage or other |
40 | attributes. |
41 | |
42 | This mechanism will produce the correct result in most cases, but there are |
43 | two cases where it may wrongly infer hidden LTO visibility. |
44 | |
45 | 1. As a corollary of the above rules, if a linkage unit is produced from a |
46 | combination of LTO object files and non-LTO object files, any hidden |
47 | visibility class defined in both a translation unit built with LTO and |
48 | a translation unit built without LTO must be defined with public LTO |
49 | visibility in order to avoid an ODR violation. |
50 | |
51 | 2. Some ABIs provide the ability to define an abstract base class without |
52 | visibility attributes in multiple linkage units and have virtual calls |
53 | to derived classes in other linkage units work correctly. One example of |
54 | this is COM on Windows platforms. If the ABI allows this, any base class |
55 | used in this way must be defined with public LTO visibility. |
56 | |
57 | Classes that fall into either of these categories can be marked up with the |
58 | ``[[clang::lto_visibility_public]]`` attribute. To specifically handle the |
59 | COM case, classes with the ``__declspec(uuid())`` attribute receive public |
60 | LTO visibility. On Windows platforms, clang-cl's ``/MT`` and ``/MTd`` |
61 | flags statically link the program against a prebuilt standard library; |
62 | these flags imply public LTO visibility for every class declared in the |
63 | ``std`` and ``stdext`` namespaces. |
64 | |
65 | Example |
66 | ======= |
67 | |
68 | The following example shows how LTO visibility works in practice in several |
69 | cases involving two linkage units, ``main`` and ``dso.so``. |
70 | |
71 | .. code-block:: none |
72 | |
73 | +-----------------------------------------------------------+ +----------------------------------------------------+ |
74 | | main (clang++ -fvisibility=hidden): | | dso.so (clang++ -fvisibility=hidden): | |
75 | | | | | |
76 | | +-----------------------------------------------------+ | | struct __attribute__((visibility("default"))) C { | |
77 | | | LTO unit (clang++ -fvisibility=hidden -flto): | | | virtual void f(); | |
78 | | | | | | } | |
79 | | | struct A { ... }; | | | void C::f() {} | |
80 | | | struct [[clang::lto_visibility_public]] B { ... }; | | | struct D { | |
81 | | | struct __attribute__((visibility("default"))) C { | | | virtual void g() = 0; | |
82 | | | virtual void f(); | | | }; | |
83 | | | }; | | | struct E : D { | |
84 | | | struct [[clang::lto_visibility_public]] D { | | | virtual void g() { ... } | |
85 | | | virtual void g() = 0; | | | }; | |
86 | | | }; | | | __attribute__(visibility("default"))) D *mkE() { | |
87 | | | | | | return new E; | |
88 | | +-----------------------------------------------------+ | | } | |
89 | | | | | |
90 | | struct B { ... }; | +----------------------------------------------------+ |
91 | | | |
92 | +-----------------------------------------------------------+ |
93 | |
94 | We will now describe the LTO visibility of each of the classes defined in |
95 | these linkage units. |
96 | |
97 | Class ``A`` is not defined outside of ``main``'s LTO unit, so it can have |
98 | hidden LTO visibility. This is inferred from the object file visibility |
99 | specified on the command line. |
100 | |
101 | Class ``B`` is defined in ``main``, both inside and outside its LTO unit. The |
102 | definition outside the LTO unit has public LTO visibility, so the definition |
103 | inside the LTO unit must also have public LTO visibility in order to avoid |
104 | an ODR violation. |
105 | |
106 | Class ``C`` is defined in both ``main`` and ``dso.so`` and therefore must |
107 | have public LTO visibility. This is correctly inferred from the ``visibility`` |
108 | attribute. |
109 | |
110 | Class ``D`` is an abstract base class with a derived class ``E`` defined |
111 | in ``dso.so``. This is an example of the COM scenario; the definition of |
112 | ``D`` in ``main``'s LTO unit must have public LTO visibility in order to be |
113 | compatible with the definition of ``D`` in ``dso.so``, which is observable |
114 | by calling the function ``mkE``. |
115 | |