[lld] [lld][AArch64] Support R_AARCH64_TLSLE_ADD_TPREL_LO12 (PR #227173)
dong jianqiang via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 29 18:15:16 PDT 2026
https://github.com/dongjianqiang2 updated https://github.com/llvm/llvm-project/pull/227173
>From eb99dcb93610af950fb725f60be0bec33847feac Mon Sep 17 00:00:00 2001
From: Dong JianQiang <dongjianqiang2 at huawei.com>
Date: Tue, 29 Sep 2026 09:58:40 +0800
Subject: [PATCH] [lld][AArch64] Support R_AARCH64_TLSLE_ADD_TPREL_LO12
AArch64 local-exec TLS code sequences compiled with -mtls-size=12 use
the non-NC R_AARCH64_TLSLE_ADD_TPREL_LO12 relocation (emitted for
'add xN, xN, :tprel_lo12:sym'), but lld only handles the _NC variant,
so linking such objects fails with 'unknown relocation'.
Add the relocation to the TLS LE group in scanSectionImpl (R_TPREL,
same group as the other TLSLE relocations, so it is also rejected for
-shared) and resolve it like the _NC variant, but with an unsigned
12-bit range check as the non-NC form requires the full offset to fit
into the imm12 field.
---
lld/ELF/Arch/AArch64.cpp | 5 +++++
lld/test/ELF/aarch64-tls-le-12.s | 34 ++++++++++++++++++++++++++++++++
lld/test/ELF/aarch64-tls-le.s | 18 ++++++++++++++---
3 files changed, 54 insertions(+), 3 deletions(-)
create mode 100644 lld/test/ELF/aarch64-tls-le-12.s
diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 5a9f306e9b47e..1d24084d82762 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -335,6 +335,7 @@ void AArch64::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels,
// TLS LE relocations:
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
+ case R_AARCH64_TLSLE_ADD_TPREL_LO12:
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
@@ -830,6 +831,10 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
}
write32Imm12(loc, val >> 12);
break;
+ case R_AARCH64_TLSLE_ADD_TPREL_LO12:
+ checkUInt(ctx, loc, val, 12, rel);
+ write32Imm12(loc, val);
+ break;
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
case R_AARCH64_TLSDESC_ADD_LO12:
case R_AARCH64_AUTH_TLSDESC_ADD_LO12:
diff --git a/lld/test/ELF/aarch64-tls-le-12.s b/lld/test/ELF/aarch64-tls-le-12.s
new file mode 100644
index 0000000000000..2850464b7fd9d
--- /dev/null
+++ b/lld/test/ELF/aarch64-tls-le-12.s
@@ -0,0 +1,34 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn %t | FileCheck %s
+
+## The non-NC R_AARCH64_TLSLE_ADD_TPREL_LO12 relocation requires the full
+## offset from the thread pointer to fit into an unsigned 12-bit immediate.
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %s -defsym=OOR=1 -o %t.bad.o
+# RUN: not ld.lld %t.bad.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=OOR --implicit-check-not=error:
+
+# OOR: error: {{.*}}:(.text+0x4): relocation R_AARCH64_TLSLE_ADD_TPREL_LO12 out of range: 4096 is not in [0, 4095]; references 'v1'
+
+.globl _start
+_start:
+ mrs x0, TPIDR_EL0
+ add x0, x0, :tprel_lo12:v1
+
+#CHECK: Disassembly of section .text:
+#CHECK: <_start>:
+#CHECK-NEXT: mrs x0, TPIDR_EL0
+#CHECK-NEXT: add x0, x0, #32
+
+.section .tbss,"awT", at nobits
+.ifdef OOR
+.space (0x1000 - 0x10)
+.else
+.space 0x10
+.endif
+
+.type v1, at object
+.globl v1
+v1:
+.word 0
+.size v1, 4
diff --git a/lld/test/ELF/aarch64-tls-le.s b/lld/test/ELF/aarch64-tls-le.s
index feb269c30b2ab..91c52525b9422 100644
--- a/lld/test/ELF/aarch64-tls-le.s
+++ b/lld/test/ELF/aarch64-tls-le.s
@@ -15,6 +15,7 @@
# ERR: error: relocation R_AARCH64_TLSLE_ADD_TPREL_HI12 against v1 cannot be used with -shared
# ERR: error: relocation R_AARCH64_TLSLE_ADD_TPREL_LO12_NC against v1 cannot be used with -shared
+# ERR: error: relocation R_AARCH64_TLSLE_ADD_TPREL_LO12 against v3 cannot be used with -shared
# ERR: error: relocation R_AARCH64_TLSLE_ADD_TPREL_HI12 against v2 cannot be used with -shared
# ERR: error: relocation R_AARCH64_TLSLE_ADD_TPREL_LO12_NC against v2 cannot be used with -shared
# ERR: error: relocation R_AARCH64_TLSLE_ADD_TPREL_HI12 against v1 cannot be used with -shared
@@ -27,6 +28,8 @@ _start:
add x0, x0, :tprel_hi12:v1
add x0, x0, :tprel_lo12_nc:v1
mrs x0, TPIDR_EL0
+ add x0, x0, :tprel_lo12:v3
+ mrs x0, TPIDR_EL0
add x0, x0, :tprel_hi12:v2
add x0, x0, :tprel_lo12_nc:v2
add x2, x1, :tprel_hi12:v1
@@ -41,6 +44,8 @@ _start:
#NORELAX-NEXT: add x0, x0, #0, lsl #12
#CHECK-NEXT: add x0, x0, #16
#CHECK-NEXT: mrs x0, TPIDR_EL0
+#CHECK-NEXT: add x0, x0, #20
+#CHECK-NEXT: mrs x0, TPIDR_EL0
#CHECK-NEXT: add x0, x0, #4095, lsl #12
#CHECK-NEXT: add x0, x0, #4088
#CHECK-NEXT: add x2, x1, #0, lsl #12
@@ -57,9 +62,16 @@ v1:
.word 0
.size v1, 4
-# The current offset from the thread pointer is 20. Raise it to just below the
-# 24-bit limit.
-.space (0xfffff8 - 20)
+.type v3, at object
+.globl v3
+.p2align 2
+v3:
+.word 0
+.size v3, 4
+
+## The current offset from the thread pointer is 24. Raise it to just below the
+## 24-bit limit.
+.space (0xfffff8 - 24)
.type v2, at object
.globl v2
More information about the llvm-commits
mailing list