Peter Collingbourne | 31fda09 | 2019-05-29 03:29:01 | [diff] [blame] | 1 | Partitions |
| 2 | ========== |
| 3 | |
| 4 | .. warning:: |
| 5 | |
Peter Collingbourne | 8cfb14f | 2019-06-07 19:23:19 | [diff] [blame] | 6 | This feature is currently experimental, and its interface is subject |
| 7 | to change. |
Peter Collingbourne | 31fda09 | 2019-05-29 03:29:01 | [diff] [blame] | 8 | |
| 9 | LLD's partitioning feature allows a program (which may be an executable |
| 10 | or a shared library) to be split into multiple pieces, or partitions. A |
| 11 | partitioned program consists of a main partition together with a number of |
| 12 | loadable partitions. The loadable partitions depend on the main partition |
| 13 | in a similar way to a regular ELF shared object dependency, but unlike a |
| 14 | shared object, the main partition and the loadable partitions share a virtual |
| 15 | address space at link time, and each loadable partition is assigned a fixed |
| 16 | offset from the main partition. This allows the loadable partitions to refer |
| 17 | to code and data in the main partition directly without the binary size and |
| 18 | performance overhead of PLTs, GOTs or symbol table entries. |
| 19 | |
| 20 | Usage |
| 21 | ----- |
| 22 | |
| 23 | A program that uses the partitioning feature must decide which symbols are |
| 24 | going to be used as the "entry points" for each partition. An entry point |
| 25 | could, for example, be the equivalent of the partition's ``main`` function, or |
| 26 | there could be a group of functions that expose the functionality implemented |
| 27 | by the partition. The intent is that in order to use a loadable partition, |
| 28 | the program will use ``dlopen``/``dlsym`` or similar functions to dynamically |
| 29 | load the partition at its assigned address, look up an entry point by name |
| 30 | and call it. Note, however, that the standard ``dlopen`` function does not |
| 31 | allow specifying a load address. On Android, the ``android_dlopen_ext`` |
| 32 | function may be used together with the ``ANDROID_DLEXT_RESERVED_ADDRESS`` |
| 33 | flag to load a shared object at a specific address. |
| 34 | |
| 35 | Once the entry points have been decided, the translation unit(s) |
| 36 | containing the entry points should be compiled using the Clang compiler flag |
| 37 | ``-fsymbol-partition=<soname>``, where ``<soname>`` is the intended soname |
| 38 | of the partition. The resulting object files are passed to the linker in |
| 39 | the usual way. |
| 40 | |
| 41 | The linker will then use these entry points to automatically split the program |
| 42 | into partitions according to which sections of the program are reachable from |
| 43 | which entry points, similarly to how ``--gc-sections`` removes unused parts of |
| 44 | a program. Any sections that are only reachable from a loadable partition's |
| 45 | entry point are assigned to that partition, while all other sections are |
| 46 | assigned to the main partition, including sections only reachable from |
| 47 | loadable partitions. |
| 48 | |
| 49 | The following diagram illustrates how sections are assigned to partitions. Each |
| 50 | section is colored according to its assigned partition. |
| 51 | |
| 52 | .. image:: partitions.svg |
| 53 | |
| 54 | The result of linking a program that uses partitions is essentially an |
| 55 | ELF file with all of the partitions concatenated together. This file is |
| 56 | referred to as a combined output file. To extract a partition from the |
| 57 | combined output file, the ``llvm-objcopy`` tool should be used together |
| 58 | with the flag ``--extract-main-partition`` to extract the main partition, or |
| 59 | ``-extract-partition=<soname>`` to extract one of the loadable partitions. |
| 60 | An example command sequence is shown below: |
| 61 | |
| 62 | .. code-block:: shell |
| 63 | |
| 64 | # Compile the main program. |
| 65 | clang -ffunction-sections -fdata-sections -c main.c |
| 66 | |
| 67 | # Compile a feature to be placed in a loadable partition. |
| 68 | # Note that this is likely to be a separate build step to the main partition. |
| 69 | clang -ffunction-sections -fdata-sections -fsymbol-partition=libfeature.so -c feature.c |
| 70 | |
| 71 | # Link the combined output file. |
| 72 | clang main.o feature.o -fuse-ld=lld -shared -o libcombined.so -Wl,-soname,libmain.so -Wl,--gc-sections |
| 73 | |
| 74 | # Extract the partitions. |
| 75 | llvm-objcopy libcombined.so libmain.so --extract-main-partition |
| 76 | llvm-objcopy libcombined.so libfeature.so --extract-partition=libfeature.so |
| 77 | |
| 78 | In order to allow a program to discover the names of its loadable partitions |
| 79 | and the locations of their reserved regions, the linker creates a partition |
| 80 | index, which is an array of structs with the following definition: |
| 81 | |
| 82 | .. code-block:: c |
| 83 | |
| 84 | struct partition_index_entry { |
| 85 | int32_t name_offset; |
| 86 | int32_t addr_offset; |
| 87 | uint32_t size; |
| 88 | }; |
| 89 | |
| 90 | The ``name_offset`` field is a relative pointer to a null-terminated string |
| 91 | containing the soname of the partition, the ``addr_offset`` field is a |
| 92 | relative pointer to its load address and the ``size`` field contains the |
| 93 | size of the region reserved for the partition. To derive an absolute pointer |
| 94 | from the relative pointer fields in this data structure, the address of the |
| 95 | field should be added to the value stored in the field. |
| 96 | |
| 97 | The program may discover the location of the partition index using the |
| 98 | linker-defined symbols ``__part_index_begin`` and ``__part_index_end``. |
| 99 | |
| 100 | Restrictions |
| 101 | ------------ |
| 102 | |
| 103 | This feature is currently only supported in the ELF linker. |
| 104 | |
| 105 | The partitioning feature may not currently be used together with the |
| 106 | ``SECTIONS`` or ``PHDRS`` linker script features, nor may it be used with the |
| 107 | ``--section-start``, ``-Ttext``, ``-Tdata`` or ``-Tbss`` flags. All of these |
| 108 | features assume a single set of output sections and/or program headers, which |
| 109 | makes their semantics ambiguous in the presence of more than one partition. |
| 110 | |
| 111 | The partitioning feature may not currently be used on the MIPS architecture |
| 112 | because it is unclear whether the MIPS multi-GOT ABI is compatible with |
| 113 | partitions. |
| 114 | |
| 115 | The current implementation only supports creating up to 254 partitions due |
| 116 | to implementation limitations. This limit may be relaxed in the future. |