-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Description
Zig Version
0.14.1
Steps to Reproduce and Observed Behavior
It seems like threadlocal
variables when compiled for aarch64-linux-android
produce code that uses TPIDR_EL0
to access thread local storage, when I believe it should be using emulated TLS via __emutls_get_address
like Clang/LLVM does. This is fine for newer Android devices, but causes crashes on earlier Android devices, like a Samsung Galaxy S8 running Android 9 or a Moto G71 running Android 12 (Moto isn't 100% confirmed to be the same root cause). I see TLS emulation already in Zig with code to export the relevant functions for Android - not sure what's missing.
The following minimal snippet reproduces the issue:
threadlocal var tl: u32 = 0;
export fn getValue() u32
{
return tl;
}
export fn setValue(v: u32) void
{
tl = v;
}
I'm compiling this with zigup run 0.14.1 build-lib .\sample.zig -target aarch64-linux-android -dynamic -O ReleaseFast
. I'm using ReleaseFast
to keep the output assembly short, though it still happens on Debug builds. This is the output assembly:
000000000001038c <getValue>:
1038c: a9bf7bfd stp x29, x30, [sp,#-16]!
10390: 910003fd mov x29, sp
10394: 90000080 adrp x0, 20000 <setValue+0xfc4c>
10398: f9425801 ldr x1, [x0,#1200]
1039c: 9112c000 add x0, x0, #0x4b0
103a0: d63f0020 blr x1
103a4: d53bd048 mrs x8, tpidr_el0
103a8: b8606900 ldr w0, [x8,x0]
103ac: a8c17bfd ldp x29, x30, [sp],#16
103b0: d65f03c0 ret
00000000000103b4 <setValue>:
103b4: a9bf7bfd stp x29, x30, [sp,#-16]!
103b8: 910003fd mov x29, sp
103bc: 2a0003e8 mov w8, w0
103c0: 90000080 adrp x0, 20000 <setValue+0xfc4c>
103c4: f9425801 ldr x1, [x0,#1200]
103c8: 9112c000 add x0, x0, #0x4b0
103cc: d63f0020 blr x1
103d0: d53bd049 mrs x9, tpidr_el0
103d4: b8206928 str w8, [x9,x0]
103d8: a8c17bfd ldp x29, x30, [sp],#16
103dc: d65f03c0 ret
Notice the use of tpidr_el0
. My current workaround is just to avoid threadlocal
variables, which is hard because it includes some stuff in the Zig standard library.
EDIT: I've also tried creating a libc.txt
that points to the Android NDK, passing --libc libc.txt
to the build-lib
command. Also tried ways to tell Zig "compile for Android API 21" but not sure where to do that. Clearly emulated TLS was happening at some point per #5921, maybe even from Zig stdlib code. Not sure what changed.
Expected Behavior
Compare the output above with the equivalent C++ snippet:
thread_local int tl = 0;
extern "C" int getValue()
{
return tl;
}
extern "C" int setValue(int v)
{
tl = v;
}
Compiled similarly with zigup run 0.14.1 build-lib .\sample.cpp -target aarch64-linux-android -dynamic -O ReleaseFast
, which produces the following more backwards-compatible assembly:
00000000000103f4 <getValue>:
103f4: a9bf7bfd stp x29, x30, [sp,#-16]!
103f8: 910003fd mov x29, sp
103fc: 90000080 adrp x0, 20000 <__emutls_get_address@plt+0xfbc0>
10400: f942b000 ldr x0, [x0,#1376]
10404: 9400000f bl 10440 <__emutls_get_address@plt>
10408: b9400000 ldr w0, [x0]
1040c: a8c17bfd ldp x29, x30, [sp],#16
10410: d65f03c0 ret
Disassembly of section .plt:
0000000000010420 <__emutls_get_address@plt-0x20>:
10420: a9bf7bf0 stp x16, x30, [sp,#-16]!
10424: 90000090 adrp x16, 20000 <__emutls_get_address@plt+0xfbc0>
10428: f942be11 ldr x17, [x16,#1400]
1042c: 9115e210 add x16, x16, #0x578
10430: d61f0220 br x17
10434: d503201f nop
10438: d503201f nop
1043c: d503201f nop
0000000000010440 <__emutls_get_address@plt>:
10440: 90000090 adrp x16, 20000 <__emutls_get_address@plt+0xfbc0>
10444: f942c211 ldr x17, [x16,#1408]
10448: 91160210 add x16, x16, #0x580
1044c: d61f0220 br x17
I'd expect Zig to generate code that uses __emutls_get_address
, since that's more backward-compatible and it will cause crashes on real Android devices if you ship an app with native Zig code.