| Android Dynamic Linker Design Notes |
| =================================== |
| |
| Introduction: |
| ------------- |
| |
| This document provides several notes related to the design of the Android |
| dynamic linker. |
| |
| |
| Prelinking: |
| ----------- |
| |
| System libraries in Android are internally prelinked, which means that |
| any internal relocations within them are stripped from the corresponding |
| shared object, in order to reduce size and speed up loading. |
| |
| Such libraries can only be loaded at the very specific virtual memory address |
| they have been prelinked to (during the build process). The list of prelinked |
| system libraries and their corresponding virtual memory address is found in |
| the file: |
| |
| build/core/prelink-linux-<arch>.map |
| |
| It should be updated each time a new system library is added to the |
| system. |
| |
| The prelink step happens at build time, and uses the 'soslim' and 'apriori' |
| tools: |
| |
| - 'apriori' is the real prelink tool which removes relocations from the |
| shared object, however, it must be given a list of symbols to remove |
| from the file. |
| |
| - 'soslim' is used to find symbols in an executable ELF file |
| and generate a list that can be passed to 'apriori'. |
| |
| By default, these tools are only used to remove internal symbols from |
| libraries, though they have been designed to allow more aggressive |
| optimizations (e.g. 'global' prelinking and symbol stripping, which |
| prevent replacing individual system libraries though). |
| |
| You can disable prelinking at build time by modifying your Android.mk with |
| a line like: |
| |
| LOCAL_PRELINK_MODULE := false |
| |
| |
| Initialization and Termination functions: |
| ----------------------------------------- |
| |
| The Unix Sys V Binary Interface standard states that an |
| executable can have the following entries in its .dynamic |
| section: |
| |
| DT_INIT |
| Points to the address of an initialization function |
| that must be called when the file is loaded. |
| |
| DT_INIT_ARRAY |
| Points to an array of function addresses that must be |
| called, in-order, to perform initialization. Some of |
| the entries in the array can be 0 or -1, and should |
| be ignored. |
| |
| Note: this is generally stored in a .init_array section |
| |
| DT_INIT_ARRAYSZ |
| The size of the DT_INITARRAY, if any |
| |
| DT_FINI |
| Points to the address of a finalization function which |
| must be called when the file is unloaded or the process |
| terminated. |
| |
| DT_FINI_ARRAY |
| Same as DT_INITARRAY but for finalizers. Note that the |
| functions must be called in reverse-order though |
| |
| Note: this is generally stored in a .fini_array section |
| |
| DT_FINI_ARRAYSZ |
| Size of FT_FINIARRAY |
| |
| DT_PREINIT_ARRAY |
| An array similar to DT_INIT_ARRAY which must *only* be |
| present in executables, not shared libraries, which contains |
| a list of functions that need to be called before any other |
| initialization function (i.e. DT_INIT and/or DT_INIT_ARRAY) |
| |
| Note: this is generally stored in a .preinit_array section |
| |
| DT_PREINIT_ARRAYSZ |
| The size of DT_PREINIT_ARRAY |
| |
| If both a DT_INIT and DT_INITARRAY entry are present, the DT_INIT |
| function must be called before the DT_INITARRAY functions. |
| |
| Consequently, the DT_FINIARRAY must be parsed in reverse order before |
| the DT_FINI function, if both are available. |
| |
| Note that the implementation of static C++ constructors is very |
| much processor dependent, and may use different ELF sections. |
| |
| On the ARM (see "C++ ABI for ARM" document), the static constructors |
| must be called explicitly from the DT_INIT_ARRAY, and each one of them |
| shall register a destructor by calling the special __eabi_atexit() |
| function (provided by the C library). The DT_FINI_ARRAY is not used |
| by static C++ destructors. |
| |
| On x86, the lists of constructors and destructors are placed in special |
| sections named ".ctors" and ".dtors", and the DT_INIT / DT_FINI functions |
| are in charge of calling them explicitly. |
| |
| |
| Debugging: |
| ---------- |
| |
| It is possible to enable debug output in the dynamic linker. To do so, |
| follow these steps: |
| |
| 1/ Modify the line in Android.mk that says: |
| |
| LOCAL_CFLAGS += -DLINKER_DEBUG=0 |
| |
| Into the following: |
| |
| LOCAL_CFLAGS += -DLINKER_DEBUG=1 |
| |
| 2/ Force-rebuild the dynamic linker: |
| |
| cd bionic/linker |
| mm -B |
| |
| 3/ Rebuild a new system image. |
| |
| You can increase the verbosity of debug traces by defining the DEBUG |
| environment variable to a numeric value from 0 to 2. This will only |
| affect new processes being launched. |
| |
| By default, traces are sent to logcat, with the "linker" tag. You can |
| change this to go to stdout instead by setting the definition of |
| LINKER_DEBUG_TO_LOG to 0 in "linker_debug.h". |