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