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