1# Android linker changes for NDK developers 2 3This document details important changes related to native code 4loading in various Android releases. 5 6See also [bionic status](docs/status.md) for general libc/libm/libdl 7behavior changes. 8 9Required tools: the NDK has an _arch_-linux-android-readelf binary 10(e.g. arm-linux-androideabi-readelf or i686-linux-android-readelf) 11for each architecture (under toolchains/), but you can use readelf for 12any architecture, as we will be doing basic inspection only. On Linux 13you need to have the “binutils” package installed for readelf, 14and “pax-utils” for scanelf. 15 16 17## How we manage incompatible changes 18 19Our general practice with dynamic linker behavior changes is that they 20will be tied to an app's target API level: 21 22* Below the affected API level we'll preserve the old behavior or issue 23a warning, as appropriate. 24 25* At the affected API level and above, we’ll refuse to load the library. 26 27* Warnings about any behavior change that will affect a library if you 28increase your target API level will appear in logcat when that library 29is loaded, even if you're not yet targeting that API level. 30 31* On a developer preview build, dynamic linker warnings will also show up 32as toasts. Experience has shown that many developers don’t habitually 33check logcat for warnings until their app stops functioning, so the 34toasts help bring some visibility to the issues before it's too late. 35 36## Changes to library dependency resolution 37 38Until it was [fixed](https://issuetracker.google.com/36950617) in 39JB-MR2, Android didn't include the application library directory 40on the dynamic linker's search path. This meant that apps 41had to call `dlopen` or `System.loadLibrary` on all transitive 42dependencies before loading their main library. Worse, until it was 43[fixed](https://issuetracker.google.com/36935779) in JB-MR2, the 44dynamic linker's caching code cached failures too, so it was necessary 45to topologically sort your libraries and load them in reverse order. 46 47If you need to support Android devices running OS 48versions older than JB-MR2, you might want to consider 49[ReLinker](https://github.com/KeepSafe/ReLinker) which claims to solve 50these problems automatically. 51 52Alternatively, if you don't have too many dependencies, it can be easiest to 53simply link all of your code into one big library and sidestep the details of 54library and symbol lookup changes on all past (and future) Android versions. 55 56## Changes to library search order 57 58We have made various fixes to library search order when resolving symbols. 59 60With API 22, load order switched from depth-first to breadth-first to 61fix dlsym(3). 62 63Before API 23, the default search order was to try the main executable, 64LD_PRELOAD libraries, the library itself, and its DT_NEEDED libraries 65in that order. For API 23 and later, for any given library, the dynamic 66linker divides other libraries into the global group and the local 67group. The global group is shared by all libraries and contains the main 68executable, LD_PRELOAD libraries, and any library with the DF_1_GLOBAL 69flag set (by passing “-z global” to ld(1)). The local group is 70the breadth-first transitive closure of the library and its DT_NEEDED 71libraries. The M dynamic linker searches the global group followed by 72the local group. This allows ASAN, for example, to ensure that it can 73intercept any symbol. 74 75 76## LD_PRELOAD and 32/64 bit 77 78LD_PRELOAD applies to both 32- and 64-bit processes. This means that you 79should avoid saying something like `/system/lib/libfoo.so` and just say 80`libfoo.so` instead, letting the dynamic linker find the correct library 81on its search path. 82 83 84## RTLD_LOCAL (Available in API level >= 23) 85 86The dlopen(3) RTLD_LOCAL flag used to be ignored but is implemented 87correctly in API 23 and later. Note that RTLD_LOCAL is the default, 88so even calls to dlopen(3) that didn’t explicitly use RTLD_LOCAL will 89be affected (unless they explicitly used RTLD_GLOBAL). With RTLD_LOCAL, 90symbols will not be made available to libraries loaded by later calls 91to dlopen(3) (as opposed to being referenced by DT_NEEDED entries). 92 93 94## GNU hashes (Availible in API level >= 23) 95 96The GNU hash style available with --hash-style=gnu allows faster 97symbol lookup and is now supported by the dynamic linker in API 23 and 98above. (Use --hash-style=both if you want to build code that uses this 99feature >= Android M but still works on older releases.) 100 101 102## Correct soname/path handling (Available in API level >= 23) 103 104The dynamic linker now understands the difference 105between a library’s soname and its path (public bug 106https://code.google.com/p/android/issues/detail?id=6670). API level 23 107is the first release where search by soname is implemented. Earlier 108releases would assume that the basename of the library was the soname, 109and used that to search for already-loaded libraries. For example, 110`dlopen("/this/directory/does/not/exist/libc.so", RTLD_NOW)` would 111find `/system/lib/libc.so` because it’s already loaded. This also meant 112that it was impossible to have two libraries `"dir1/libx.so"` and 113`"dir2/libx.so"` --- the dynamic linker couldn’t tell the difference 114and would always use whichever was loaded first, even if you explicitly 115tried to load both. This also applied to DT_NEEDED entries. 116 117Some apps have bad DT_NEEDED entries (usually absolute paths on the build 118machine’s file system) that used to work because we ignored everything 119but the basename. These apps will fail to load on API level 23 and above. 120 121 122## Symbol versioning (Available in API level >= 23) 123 124Symbol versioning allows libraries to provide better backwards 125compatibility. For example, if a library author knowingly changes 126the behavior of a function, they can provide two versions in the same 127library so that old code gets the old version and new code gets the new 128version. This is supported in API level 23 and above. 129 130 131## Opening shared libraries directly from an APK 132 133In API level 23 and above, it’s possible to open a .so file directly from 134your APK. Just use `System.loadLibrary("foo")` exactly as normal but set 135`android:extractNativeLibs="false"` in your `AndroidManifest.xml`. In 136older releases, the .so files were extracted from the APK file 137at install time. This meant that they took up space in your APK and 138again in your installation directory (and this was counted against you 139and reported to the user as space taken up by your app). Any .so file 140that you want to load directly from your APK must be page aligned 141(on a 4096-byte boundary) in the zip file and stored uncompressed. 142Current versions of the zipalign tool take care of alignment. 143 144Note that in API level 23 and above dlopen(3) will open a library from 145any zip file, not just your APK. Just give dlopen(3) a path of the form 146"my_zip_file.zip!/libs/libstuff.so". As with APKs, the library must be 147page-aligned and stored uncompressed for this to work. 148 149 150## Private API (Enforced for API level >= 24) 151 152Native libraries must use only public API, and must not link against 153non-NDK platform libraries. Starting with API 24 this rule is enforced and 154applications are no longer able to load non-NDK platform libraries. The 155rule is enforced by the dynamic linker, so non-public libraries 156are not accessible regardless of the way code tries to load them: 157System.loadLibrary, DT_NEEDED entries, and direct calls to dlopen(3) 158will all work exactly the same. 159 160Users should have a consistent app experience across updates, 161and developers shouldn't have to make emergency app updates to 162handle platform changes. For that reason, we recommend against using 163private C/C++ symbols. Private symbols aren't tested as part of the 164Compatibility Test Suite (CTS) that all Android devices must pass. They 165may not exist, or they may behave differently. This makes apps that use 166them more likely to fail on specific devices, or on future releases --- 167as many developers found when Android 6.0 Marshmallow switched from 168OpenSSL to BoringSSL. 169 170In order to reduce the user impact of this transition, we've identified 171a set of libraries that see significant use from Google Play's 172most-installed apps, and that are feasible for us to support in the 173short term (including libandroid_runtime.so, libcutils.so, libcrypto.so, 174and libssl.so). In order to give you more time to transition, we will 175temporarily support these libraries; so if you see a warning that means 176your code will not work in a future release -- please fix it now! 177 178In O and later, the system property `debug.ld.greylist_disabled` can be 179used to deny access to the greylist even to an app that would normally 180be allowed it. This allows you to test compatibility without bumping the 181app's `targetSdkVersion`. Use `setprop debug.ld.greylist_disabled true` 182to turn this on (any other value leaves the greylist enabled). 183 184``` 185$ readelf --dynamic libBroken.so | grep NEEDED 186 0x00000001 (NEEDED) Shared library: [libnativehelper.so] 187 0x00000001 (NEEDED) Shared library: [libutils.so] 188 0x00000001 (NEEDED) Shared library: [libstagefright_foundation.so] 189 0x00000001 (NEEDED) Shared library: [libmedia_jni.so] 190 0x00000001 (NEEDED) Shared library: [liblog.so] 191 0x00000001 (NEEDED) Shared library: [libdl.so] 192 0x00000001 (NEEDED) Shared library: [libz.so] 193 0x00000001 (NEEDED) Shared library: [libstdc++.so] 194 0x00000001 (NEEDED) Shared library: [libm.so] 195 0x00000001 (NEEDED) Shared library: [libc.so] 196``` 197 198*Potential problems*: starting from API 24 the dynamic linker will not 199load private libraries, preventing the application from loading. 200 201*Resolution*: rewrite your native code to rely only on public API. As a 202short term workaround, platform libraries without complex dependencies 203(libcutils.so) can be copied to the project. As a long term solution 204the relevant code must be copied to the project tree. SSL/Media/JNI 205internal/binder APIs should not be accessed from the native code. When 206necessary, native code should call appropriate public Java API methods. 207 208A complete list of public libraries is available within the NDK, under 209platforms/android-API/usr/lib. 210 211Note: SSL/crypto is a special case, applications must NOT use platform 212libcrypto and libssl libraries directly, even on older platforms. All 213applications should use GMS Security Provider to ensure they are protected 214from known vulnerabilities. 215 216 217## Missing Section Headers (Enforced for API level >= 24) 218 219Each ELF file has additional information contained in the section 220headers. These headers must be present now, because the dynamic linker 221uses them for sanity checking. Some developers strip them in an 222attempt to obfuscate the binary and prevent reverse engineering. (This 223doesn't really help because it is possible to reconstruct the stripped 224information using widely-available tools.) 225 226``` 227$ readelf --header libBroken.so | grep 'section headers' 228 Start of section headers: 0 (bytes into file) 229 Size of section headers: 0 (bytes) 230 Number of section headers: 0 231``` 232 233*Resolution*: remove the extra steps from your build that strip section 234headers. 235 236## Text Relocations (Enforced for API level >= 23) 237 238Starting with API 23, shared objects must not contain text 239relocations. That is, the code must be loaded as is and must not be 240modified. Such an approach reduces load time and improves security. 241 242The usual reason for text relocations is non-position independent 243hand-written assembler. This is not common. Use the scanelf tool as 244described in our documentation for further diagnostics: 245 246``` 247$ scanelf -qT libTextRel.so 248 libTextRel.so: (memory/data?) [0x15E0E2] in (optimized out: previous simd_broken_op1) [0x15E0E0] 249 libTextRel.so: (memory/data?) [0x15E3B2] in (optimized out: previous simd_broken_op2) [0x15E3B0] 250 ... 251``` 252 253If you have no scanelf tool available, it is possible to do a basic 254check with readelf instead, look for either a TEXTREL entry or the 255TEXTREL flag. Either alone is sufficient. (The value corresponding to the 256TEXTREL entry is irrelevant and typically 0 --- simply the presence of 257the TEXTREL entry declares that the .so contains text relocations). This 258example has both indicators present: 259 260``` 261$ readelf --dynamic libTextRel.so | grep TEXTREL 262 0x00000016 (TEXTREL) 0x0 263 0x0000001e (FLAGS) SYMBOLIC TEXTREL BIND_NOW 264``` 265 266Note: it is technically possible to have a shared object with the TEXTREL 267entry/flag but without any actual text relocations. This doesn't happen 268with the NDK, but if you're generating ELF files yourself make sure 269you're not generating ELF files that claim to have text relocations, 270because the Android dynamic linker trusts the entry/flag. 271 272*Potential problems*: Relocations enforce code pages being writable, and 273wastefully increase the number of dirty pages in memory. The dynamic 274linker has issued warnings about text relocations since Android K 275(API 19), but on API 23 and above it refuses to load code with text 276relocations. 277 278*Resolution*: rewrite assembler to be position independent to ensure 279no text relocations are necessary. The 280[Gentoo Textrels guide](https://wiki.gentoo.org/wiki/Hardened/Textrels_Guide) 281has instructions for fixing text relocations, and more detailed 282[scanelf documentation](https://wiki.gentoo.org/wiki/Hardened/PaX_Utilities). 283 284 285## Invalid DT_NEEDED Entries (Enforced for API level >= 23) 286 287While library dependencies (DT_NEEDED entries in the ELF headers) can be 288absolute paths, that doesn't make sense on Android because you have 289no control over where your library will be installed by the system. A 290DT_NEEDED entry should be the same as the needed library's SONAME, 291leaving the business of finding the library at runtime to the dynamic 292linker. 293 294Before API 23, Android's dynamic linker ignored the full path, and 295used only the basename (the part after the last ‘/') when looking 296up the required libraries. Since API 23 the runtime linker will honor 297the DT_NEEDED exactly and so it won't be able to load the library if 298it is not present in that exact location on the device. 299 300Even worse, some build systems have bugs that cause them to insert 301DT_NEEDED entries that point to a file on the build host, something that 302cannot be found on the device. 303 304``` 305$ readelf --dynamic libSample.so | grep NEEDED 306 0x00000001 (NEEDED) Shared library: [libm.so] 307 0x00000001 (NEEDED) Shared library: [libc.so] 308 0x00000001 (NEEDED) Shared library: [libdl.so] 309 0x00000001 (NEEDED) Shared library: 310[C:\Users\build\Android\ci\jni\libBroken.so] 311``` 312 313*Potential problems*: before API 23 the DT_NEEDED entry's basename was 314used, but starting from API 23 the Android runtime will try to load the 315library using the path specified, and that path won't exist on the 316device. There are broken third-party toolchains/build systems that use 317a path on a build host instead of the SONAME. 318 319*Resolution*: make sure all required libraries are referenced by SONAME 320only. It is better to let the runtime linker to find and load those 321libraries as the location may change from device to device. 322 323 324## Missing SONAME (Enforced for API level >= 23) 325 326Each ELF shared object (“native library”) must have a SONAME (Shared 327Object Name) attribute. The NDK toolchain adds this attribute by default, 328so its absence indicates either a misconfigured alternative toolchain 329or a misconfiguration in your build system. A missing SONAME may lead 330to runtime issues such as the wrong library being loaded: the filename 331is used instead when this attribute is missing. 332 333``` 334$ readelf --dynamic libWithSoName.so | grep SONAME 335 0x0000000e (SONAME) Library soname: [libWithSoName.so] 336``` 337 338*Potential problems*: namespace conflicts may lead to the wrong library 339being loaded at runtime, which leads to crashes when required symbols 340are not found, or you try to use an ABI-incompatible library that isn't 341the library you were expecting. 342 343*Resolution*: the current NDK generates the correct SONAME by 344default. Ensure you're using the current NDK and that you haven't 345configured your build system to generate incorrect SONAME entries (using 346the -soname linker option). 347 348## `__register_atfork` (Available in API level >= 23) 349 350To allow `atfork` and `pthread_atfork` handlers to be unregistered on 351`dlclose`, the implementation changed in API level 23. Unfortunately this 352requires a new libc function `__register_atfork`. Code using these functions 353that is built with a target API level >= 23 therefore will not load on earlier 354versions of Android, with an error referencing `__register_atfork`. 355 356*Resolution*: build your code with an NDK target API level that matches your 357app's minimum API level, or avoid using `atfork`/`pthread_atfork`. 358 359## DT_RUNPATH support (Available in API level >= 24) 360 361If an ELF file contains a DT_RUNPATH entry, the directories listed there 362will be searched to resolve DT_NEEDED entries. The string `${ORIGIN}` will 363be rewritten at runtime to the directory containing the ELF file. This 364allows the use of relative paths. The `${LIB}` and `${PLATFORM}` 365substitutions supported on some systems are not currently implemented on 366Android. 367 368 369## Writable and Executable Segments (Enforced for API level >= 26) 370 371Each segment in an ELF file has associated flags that tell the 372dynamic linker what permissions to give the corresponding page in 373memory. For security, data shouldn't be executable and code shouldn't be 374writable. This means that the W (for Writable) and E (for Executable) 375flags should be mutually exclusive. This wasn't historically enforced, 376but is now. 377 378``` 379$ readelf --program-headers -W libBadFlags.so | grep WE 380 LOAD 0x000000 0x00000000 0x00000000 0x4c01d 0x4c01d RWE 0x1000 381``` 382 383*Resolution*: we're aware of one middleware product that introduces these 384into your app. The middleware vendor is aware of the problem and has a fix 385available. 386 387## Invalid ELF header/section headers (Enforced for API level >= 26) 388 389In API level 26 and above the dynamic linker checks more values in 390the ELF header and section headers and fails if they are invalid. 391 392*Example error* 393``` 394dlopen failed: "/data/data/com.example.bad/lib.so" has unsupported e_shentsize: 0x0 (expected 0x28) 395``` 396 397*Resolution*: don't use tools that produce invalid/malformed 398ELF files. Note that using them puts application under high risk of 399being incompatible with future versions of Android. 400 401## Enable logging of dlopen/dlsym and library loading errors for apps (Available in Android O) 402 403Starting with Android O it is possible to enable logging of dynamic 404linker activity for debuggable apps by setting a property corresponding 405to the fully-qualified name of the specific app: 406``` 407adb shell setprop debug.ld.app.com.example.myapp dlerror,dlopen,dlsym 408adb logcat 409``` 410 411Any combination of `dlerror`, `dlopen`, and `dlsym` can be used. There's 412no separate `dlclose` option: `dlopen` covers both loading and unloading 413of libraries. Note also that `dlerror` doesn't correspond to actual 414calls of dlerror(3) but to any time the dynamic linker writes to its 415internal error buffer, so you'll see any errors the dynamic linker would 416have reported, even if the code you're debugging doesn't actually call 417dlerror(3) itself. 418 419On userdebug and eng builds it is possible to enable tracing for the 420whole system by using the `debug.ld.all` system property instead of 421app-specific one. For example, to enable logging of all dlopen(3) 422(and thus dclose(3)) calls, and all failures, but not dlsym(3) calls: 423``` 424adb shell setprop debug.ld.all dlerror,dlopen 425``` 426 427## dlclose interacts badly with thread local variables with non-trivial destructors 428 429Android allows `dlclose` to unload a library even if there are still 430thread-local variables with non-trivial destructors. This leads to 431crashes when a thread exits and attempts to call the destructor, the 432code for which has been unloaded (as in [issue 360], fixed in P). 433 434[issue 360]: https://github.com/android-ndk/ndk/issues/360 435 436Not calling `dlclose` or ensuring that your library has `RTLD_NODELETE` 437set (so that calls to `dlclose` don't actually unload the library) 438are possible workarounds. 439 440| | Pre-M | M+ | P+ | 441| ----------------- | -------------------------- | ------- | ----- | 442| No workaround | Works for static STL | Broken | Works | 443| `-Wl,-z,nodelete` | Works for static STL | Works | Works | 444| No `dlclose` | Works | Works | Works | 445 446## Use of IFUNC in libc (True for all API levels on devices running Q) 447 448Starting with Android Q (API level 29), libc uses 449[IFUNC](https://sourceware.org/glibc/wiki/GNU_IFUNC) functionality in 450the dynamic linker to choose optimized assembler routines at run time 451rather than at build time. This lets us use the same `libc.so` on all 452devices, and is similar to what other OSes already did. Because the zygote 453uses the C library, this decision is made long before we know what API 454level an app targets, so all code sees the new IFUNC-using C library. 455Most apps should be unaffected by this change, but apps that hook or try to 456detect hooking of C library functions might need to fix their code to cope 457with IFUNC relocations. The affected functions are from `<string.h>`, but 458may expand to include more functions (and more libraries) in future. 459 460## Relative relocations (RELR) 461 462Android added experimental support for RELR relative relocations 463in API level 28, but using `SHT_` and `DT_` constants in the space 464reserved for OS private use. 465 466API level 30 added support for ELF files using the official `SHT_` and 467`DT_` constants. 468 469The RELR encoding is unrelated to the earlier "packed relocations" 470format available from API level 23. 471 472There are no plans to remove support for ELF files using the older 473OS private use constants for RELR, nor for ELF files using packed 474relocations. 475