[lld] [ELF] Range-check the x86-64 GD-to-IE TLS optimizations (PR #225228)
Farid Zakaria via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 21 15:57:37 PDT 2026
https://github.com/fzakaria created https://github.com/llvm/llvm-project/pull/225228
Add range-checks to relaxTlsGdToIe so that they fail when the PC-relative displacement is larger than 32-bit (signed). The un-relaxed paths in X86_64::relocate already do this via checkInt()
Assisted-By: Opus 5
>From 4da852c1579b372e84be7fe6161bf2732869eeb5 Mon Sep 17 00:00:00 2001
From: Farid Zakaria <fmzakari at meta.com>
Date: Mon, 21 Sep 2026 15:55:28 -0700
Subject: [PATCH] [ELF] Range-check the x86-64 GD-to-IE TLS optimizations
Add range-checks to relaxTlsGdToIe so that they fail when the PC-relative
displacement is larger than 32-bit (signed). The un-relaxed paths in
X86_64::relocate already do this via checkInt()
Assisted-By: Opus 5
---
lld/ELF/Arch/X86_64.cpp | 3 +++
lld/test/ELF/x86-64-tls-gdie.s | 9 +++++++++
lld/test/ELF/x86-64-tls-pltoff64.s | 13 +++++++++++++
lld/test/ELF/x86-64-tlsdesc-gd.s | 9 +++++++++
4 files changed, 34 insertions(+)
diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp
index f172080dc2b6a6..c1d1db1d0133c8 100644
--- a/lld/ELF/Arch/X86_64.cpp
+++ b/lld/ELF/Arch/X86_64.cpp
@@ -866,6 +866,7 @@ void X86_64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
memcpy(loc - 3, inst, sizeof(inst));
// Both code sequences are PC relatives, but since we are moving the
// constant forward by 9 bytes we have to subtract the value by 9.
+ checkInt(ctx, loc, val - 9, 32, rel);
write32le(loc + 9, val - 9);
return;
}
@@ -885,6 +886,7 @@ void X86_64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
// Both code sequences are PC relatives, but since we are moving the
// constant forward by 8 bytes we have to subtract the value by 8.
+ checkInt(ctx, loc, val - 8, 32, rel);
write32le(loc + 8, val - 8);
} else if (rel.type == R_X86_64_GOTPC32_TLSDESC ||
rel.type == R_X86_64_CODE_4_GOTPC32_TLSDESC) {
@@ -899,6 +901,7 @@ void X86_64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
return;
}
loc[-2] = 0x8b;
+ checkInt(ctx, loc, val, 32, rel);
write32le(loc, val);
}
}
diff --git a/lld/test/ELF/x86-64-tls-gdie.s b/lld/test/ELF/x86-64-tls-gdie.s
index ad67e79043798e..04d828994d7f83 100644
--- a/lld/test/ELF/x86-64-tls-gdie.s
+++ b/lld/test/ELF/x86-64-tls-gdie.s
@@ -7,6 +7,15 @@
// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=RELOC %s
// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn %t1 | FileCheck --check-prefix=DISASM %s
+/// The optimized sequence reaches the GOT with a 32-bit PC-relative
+/// displacement, so it has the same range limit as an unrelaxed GOTTPOFF.
+// RUN: echo 'SECTIONS { .text 0x100000 : { *(.text) } .got 0x80200000 : { *(.got) } }' > %t.lds
+// RUN: not ld.lld %t.o %t.so -T %t.lds -o /dev/null 2>&1 | \
+// RUN: FileCheck --check-prefix=RANGE %s --implicit-check-not=error:
+
+// RANGE: error: {{.*}}.o:(.text+0x4): relocation R_X86_64_TLSGD out of range: 2148532208 is not in [-2147483648, 2147483647]; references 'tlsshared0'
+// RANGE: error: {{.*}}.o:(.text+0x14): relocation R_X86_64_TLSGD out of range: 2148532200 is not in [-2147483648, 2147483647]; references 'tlsshared1'
+
// SEC: .got PROGBITS 00000000002023a8 0003a8 000010 00 WA 0 0 8
//RELOC: Relocations [
diff --git a/lld/test/ELF/x86-64-tls-pltoff64.s b/lld/test/ELF/x86-64-tls-pltoff64.s
index 9c2aef215d1470..314afcdf96e443 100644
--- a/lld/test/ELF/x86-64-tls-pltoff64.s
+++ b/lld/test/ELF/x86-64-tls-pltoff64.s
@@ -15,6 +15,13 @@
# RUN: llvm-readelf -r out.so | FileCheck %s --check-prefix=SDYN
# RUN: llvm-objdump -d --no-show-raw-insn --no-print-imm-hex out.so | FileCheck %s --check-prefix=SHARED
+## The GD-to-IE optimization reaches the GOT with a 32-bit PC-relative
+## displacement, so it has the same range limit as an unrelaxed GOTTPOFF.
+# RUN: not ld.lld a.o b.so -T lds -o /dev/null 2>&1 | \
+# RUN: FileCheck %s --check-prefix=RANGE --implicit-check-not=error:
+
+# RANGE: error: a.o:(.text+0x19): relocation R_X86_64_TLSGD out of range: 2148532186 is not in [-2147483648, 2147483647]; references 'y'
+
# SEC: .got PROGBITS 00000000002023c8
# SEC: Relocation section '.rela.dyn' {{.*}} contains 1 entries:
# SEC-NEXT: Offset
@@ -96,3 +103,9 @@ x2: .zero 4
.section .tbss,"awT", at nobits
.globl y
y: .zero 4
+
+#--- lds
+SECTIONS {
+ .text 0x100000 : { *(.text) }
+ .got 0x80200000 : { *(.got) }
+}
diff --git a/lld/test/ELF/x86-64-tlsdesc-gd.s b/lld/test/ELF/x86-64-tlsdesc-gd.s
index 433c2b2723463b..798e62d6126d26 100644
--- a/lld/test/ELF/x86-64-tlsdesc-gd.s
+++ b/lld/test/ELF/x86-64-tlsdesc-gd.s
@@ -18,6 +18,15 @@
# RUN: llvm-readobj -r %t | FileCheck --check-prefix=IE-REL %s
# RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn %t | FileCheck --check-prefix=IE %s
+## The optimized sequence reaches the GOT with a 32-bit PC-relative
+## displacement, so it has the same range limit as an unrelaxed GOTTPOFF.
+# RUN: echo 'SECTIONS { .text 0x100000 : { *(.text) } .got 0x80200000 : { *(.got) } }' > %t.lds
+# RUN: not ld.lld %t.o %t1.so -T %t.lds -o /dev/null 2>&1 | \
+# RUN: FileCheck --check-prefix=IE-RANGE %s --implicit-check-not=error:
+
+# IE-RANGE: error: {{.*}}.o:(.text+0x1e): relocation R_X86_64_GOTPC32_TLSDESC out of range: 2148532190 is not in [-2147483648, 2147483647]; references 'c'
+# IE-RANGE: error: {{.*}}.o:(.text+0x2e): relocation R_X86_64_CODE_4_GOTPC32_TLSDESC out of range: 2148532174 is not in [-2147483648, 2147483647]; references 'c'
+
# GD-RELA: .rela.dyn {
# GD-RELA-NEXT: 0x23E0 R_X86_64_TLSDESC - 0xB
# GD-RELA-NEXT: 0x23C0 R_X86_64_TLSDESC a 0x0
More information about the llvm-commits
mailing list