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