Skip to content

Startup crash in 11.4.1 on x86_64 (Android 9 / Chromebook ARC++): UnsatisfiedLinkError "unknown reloc type 16" — TLS DTPMOD64 still present (related to #445) #458

@daentech

Description

@daentech

Bug report

librive-android.so for the x86_64 ABI in app.rive:rive-android:11.4.1 still contains a general-dynamic TLS relocation (R_X86_64_DTPMOD64, relocation type 16) and imports __tls_get_addr. Android's bionic dynamic linker does not support dynamic-TLS relocations in a dlopen()-ed shared library before API 29, so Rive.init()System.loadLibrary aborts at startup on x86_64 devices running Android ≤ 9.

This appears to be the x86_64 counterpart of #445 (armeabi-v7a, "unknown reloc type 17"), which was reported fixed in 11.4.1 by adapting the libhydrogen TLS fix — but the x86_64 build of 11.4.1 still carries the TLS relocation. This is consistent with the post-close report on #445 that crashes persist on Android 9.

Versions

Affected devices

  • ABI: x86_64
  • Android 9 (API 28)
  • Reproduced on x86_64 Chromebooks (Android-on-ChromeOS / ARC++): Intel Apollo Lake / Braswell-class boards (e.g. coral). ARM phones are unaffected — they load the arm64-v8a build.

Crash

java.lang.UnsatisfiedLinkError: dlopen failed: unknown reloc type 16 @ 0x... (11982)
    at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
    at java.lang.System.loadLibrary(System.java:1669)
    at app.rive.runtime.kotlin.core.Rive$NativeLoader.loadWithSystemLoader(Rive.kt)
    at app.rive.runtime.kotlin.core.Rive$NativeLoader.loadLibrary(Rive.kt:11)
    at app.rive.runtime.kotlin.core.Rive.init(Rive.kt:31)

Evidence

The readelf/objdump TLS check (the one requested in #445), run against lib/x86_64/librive-android.so extracted from the 11.4.1 artifact:

# relocation-type histogram
   11982  R_X86_64_RELATIVE
    6757  R_X86_64_64
    2077  R_X86_64_JUMP_SLOT
     535  R_X86_64_GLOB_DAT
       1  R_X86_64_DTPMOD64        <-- relocation type 16 == "unknown reloc type 16"

# general-dynamic TLS marker (undefined import)
*UND*  __tls_get_addr

# TLS program header present
TLS  ...  memsz 0x40  flags r--

R_X86_64_DTPMOD64 is relocation type 16 on x86_64 — exactly the "unknown reloc type 16" in the crash. The single DTPMOD64 plus the __tls_get_addr import indicate one thread_local compiled with the general/local-dynamic TLS model.

Why x86_64 specifically

arm64-v8a uses R_AARCH64_TLSDESC (TLS-descriptor model), which modern bionic supports, so phones load fine. The x86_64 (and likely x86) build emits general-dynamic TLS (DTPMOD64 + __tls_get_addr), which bionic's linker rejects on API < 29.

Suggested fix

Same family as the libhydrogen fix in #445, but the x86/x86_64 builds appear to have been missed. Build the affected native libraries with emulated TLS (-femulated-tls) or force the initial-exec model (-ftls-model=initial-exec), so the thread_local no longer emits general-dynamic relocations / __tls_get_addr and instead resolves via __emutls_get_address (supported on all API levels). This matches the NDK guidance for supporting API < 29 with thread_local.

Happy to re-run the TLS check on a fixed build.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions