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