[llvm] [bolt] AArch64: Fix TLSDESC to LE relaxation by mold (PR #190370)
Hemant Kulkarni via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 3 10:33:27 PDT 2026
https://github.com/awshkulkar created https://github.com/llvm/llvm-project/pull/190370
mold linker creates relaxation stub from TLSDESC to LE, (lld makes it IE) using sequence as NOP+NOP+MOVZ+MOVK. This in itself is not an issue, when --emit-relocs is added the relocs R_AARCH64_TLSDESC_ADD_LO12 and R_AARCH64_TLSDESC_CALL are associated with useful MOVW instructions. However bolt does not check for R_AARCH64_TLSDESC_ADD_LO12 in adjustRelocation() when disassembling the file. This later triggers a bug when reloc is patched as movk is patched with S_LO12 type fixup kind which is invalid.
Refer to bug: https://github.com/llvm/llvm-project/issues/190366 for details.
>From 7eef585826b2e3be1400471cc9567ed7dfc45ba8 Mon Sep 17 00:00:00 2001
From: Hemant Kulkarni <hkulkar at amazon.com>
Date: Fri, 3 Apr 2026 15:07:11 +0000
Subject: [PATCH] BOLT: Support alternative TLSDEC to LE relaxation.
Linker other than LLD or BFD sometimes relax TLSDEC
sequence as NOP+NOP+MOVZ+MOVK. The MOVK instruction lands
in place where reloc emitted emit-relocs is R_AARCH64_TLSDESC_ADD_LO12.
Bolt should add this reloc to adjustRelocation to check for validity
of MOVW class of instructions.
---
.../Target/AArch64/AArch64MCSymbolizer.cpp | 1 +
.../AArch64/Inputs/tls-desc-le-relax.yaml | 330 ++++++++++++++++++
.../tls-desc-le-relaxation-alternative.test | 11 +
3 files changed, 342 insertions(+)
create mode 100644 bolt/test/AArch64/Inputs/tls-desc-le-relax.yaml
create mode 100644 bolt/test/AArch64/tls-desc-le-relaxation-alternative.test
diff --git a/bolt/lib/Target/AArch64/AArch64MCSymbolizer.cpp b/bolt/lib/Target/AArch64/AArch64MCSymbolizer.cpp
index 28b4fc0705eaf..7bbfb1429e37b 100644
--- a/bolt/lib/Target/AArch64/AArch64MCSymbolizer.cpp
+++ b/bolt/lib/Target/AArch64/AArch64MCSymbolizer.cpp
@@ -104,6 +104,7 @@ AArch64MCSymbolizer::adjustRelocation(const Relocation &Rel,
default:
break;
case ELF::R_AARCH64_TLSDESC_LD64_LO12:
+ case ELF::R_AARCH64_TLSDESC_ADD_LO12:
case ELF::R_AARCH64_TLSDESC_ADR_PAGE21:
case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
diff --git a/bolt/test/AArch64/Inputs/tls-desc-le-relax.yaml b/bolt/test/AArch64/Inputs/tls-desc-le-relax.yaml
new file mode 100644
index 0000000000000..f7783c41b6d88
--- /dev/null
+++ b/bolt/test/AArch64/Inputs/tls-desc-le-relax.yaml
@@ -0,0 +1,330 @@
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_AARCH64
+ProgramHeaders:
+ - Type: PT_PHDR
+ Flags: [ PF_R ]
+ VAddr: 0x200040
+ Align: 0x8
+ Offset: 0x40
+ - Type: PT_LOAD
+ Flags: [ PF_R ]
+ FirstSec: .eh_frame
+ LastSec: .eh_frame_hdr
+ VAddr: 0x200000
+ Align: 0x10000
+ Offset: 0x0
+ - Type: PT_LOAD
+ Flags: [ PF_X, PF_R ]
+ FirstSec: .text
+ LastSec: .text
+ VAddr: 0x2102F0
+ Align: 0x10000
+ Offset: 0x2F0
+ - Type: PT_LOAD
+ Flags: [ PF_W, PF_R ]
+ FirstSec: .tbss
+ LastSec: .relro_padding
+ VAddr: 0x2203B0
+ Align: 0x10000
+ Offset: 0x3B0
+ - Type: PT_LOAD
+ Flags: [ PF_W, PF_R ]
+ FirstSec: .got.plt
+ LastSec: .got.plt
+ VAddr: 0x2303B8
+ Align: 0x10000
+ Offset: 0x3B8
+ - Type: PT_TLS
+ Flags: [ PF_R ]
+ FirstSec: .tbss
+ LastSec: .tbss
+ VAddr: 0x2203B0
+ Align: 0x4
+ Offset: 0x3B0
+ - Type: PT_GNU_EH_FRAME
+ Flags: [ PF_R ]
+ FirstSec: .eh_frame_hdr
+ LastSec: .eh_frame_hdr
+ VAddr: 0x2002C4
+ Align: 0x4
+ Offset: 0x2C4
+ - Type: PT_GNU_STACK
+ Flags: [ PF_W, PF_R ]
+ Offset: 0x0
+ - Type: PT_GNU_RELRO
+ Flags: [ PF_R ]
+ FirstSec: .tbss
+ LastSec: .relro_padding
+ VAddr: 0x2203B0
+ Offset: 0x3B0
+Sections:
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ Address: 0x200238
+ AddressAlign: 0x8
+ Content: 1000000000000000017A5200017C1E011B0C1F0018000000180000009C0001002800000000480C1D109E029D040000001800000034000000A800010038000000004C0C1D109E029D040000001800000050000000C40001002C00000000480C1D109E029D040000001C0000006C000000D400010028000000004C0C1D109E029D040000000000000000000000
+ - Name: .eh_frame_hdr
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC ]
+ Address: 0x2002C4
+ AddressAlign: 0x4
+ Content: 011B033B70FFFFFF040000002C00010088FFFFFF54000100A4FFFFFF8C000100C0FFFFFFB8000100DCFFFFFF
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ Address: 0x2102F0
+ AddressAlign: 0x4
+ Content: FD7BBFA9FD0300911F2003D51F2003D50000A0D2000280F248D03BD5006960B8FD7BC1A8C0035FD6FF8300D1FD7B01A9FD430091A0C31FB8A8C35FB81F2003D51F2003D50000A0D2000280F249D03BD5286920B8FD7B41A9FF830091C0035FD6FD7BBFA9FD0300911F2003D51F2003D50000A0D2000280F248D03BD5086960B80001080BFD7BC1A8C0035FD6FF8300D1FD7B01A9FD430091BFC31FB880008052E2FFFF97EFFFFF97FD7B41A9FF830091C0035FD6007D20D4007D20D4007D20D4
+ - Name: .tbss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+ Address: 0x2203B0
+ AddressAlign: 0x4
+ Size: 0x4
+ - Name: .got
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x2203B0
+ AddressAlign: 0x8
+ Content: '0000000000000000'
+ - Name: .relro_padding
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x2203B8
+ AddressAlign: 0x1
+ Size: 0xFC48
+ - Name: .got.plt
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Address: 0x2303B8
+ AddressAlign: 0x8
+ Content: '000000000000000000000000000000000000000000000000'
+ - Name: .comment
+ Type: SHT_PROGBITS
+ Flags: [ SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x1
+ EntSize: 0x1
+ Content: 005562756E747520636C616E672076657273696F6E2031342E302E302D317562756E7475312E31006D6F6C6420322E34302E342028666339366331623965666536643330623465303666653361396437383937333562636534353130653B20636F6D70617469626C65207769746820474E55206C642900
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Link: .symtab
+ AddressAlign: 0x8
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x200254
+ Symbol: .text
+ Type: R_AARCH64_PREL32
+ - Offset: 0x200270
+ Symbol: .text
+ Type: R_AARCH64_PREL32
+ Addend: 40
+ - Offset: 0x20028C
+ Symbol: .text
+ Type: R_AARCH64_PREL32
+ Addend: 96
+ - Offset: 0x2002A8
+ Symbol: .text
+ Type: R_AARCH64_PREL32
+ Addend: 140
+ - Name: .rela.text
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Link: .symtab
+ AddressAlign: 0x8
+ Info: .text
+ Relocations:
+ - Offset: 0x2102F8
+ Symbol: tls_var
+ Type: R_AARCH64_TLSDESC_ADR_PAGE21
+ - Offset: 0x2102FC
+ Symbol: tls_var
+ Type: R_AARCH64_TLSDESC_LD64_LO12
+ - Offset: 0x210300
+ Symbol: tls_var
+ Type: R_AARCH64_TLSDESC_ADD_LO12
+ - Offset: 0x210304
+ Symbol: tls_var
+ Type: R_AARCH64_TLSDESC_CALL
+ - Offset: 0x21032C
+ Symbol: tls_var
+ Type: R_AARCH64_TLSDESC_ADR_PAGE21
+ - Offset: 0x210330
+ Symbol: tls_var
+ Type: R_AARCH64_TLSDESC_LD64_LO12
+ - Offset: 0x210334
+ Symbol: tls_var
+ Type: R_AARCH64_TLSDESC_ADD_LO12
+ - Offset: 0x210338
+ Symbol: tls_var
+ Type: R_AARCH64_TLSDESC_CALL
+ - Offset: 0x210358
+ Symbol: tls_var
+ Type: R_AARCH64_TLSDESC_ADR_PAGE21
+ - Offset: 0x21035C
+ Symbol: tls_var
+ Type: R_AARCH64_TLSDESC_LD64_LO12
+ - Offset: 0x210360
+ Symbol: tls_var
+ Type: R_AARCH64_TLSDESC_ADD_LO12
+ - Offset: 0x210364
+ Symbol: tls_var
+ Type: R_AARCH64_TLSDESC_CALL
+ - Offset: 0x210390
+ Symbol: set_tls
+ Type: R_AARCH64_CALL26
+ - Offset: 0x210394
+ Symbol: get_tls_twice
+ Type: R_AARCH64_CALL26
+Symbols:
+ - Name: .eh_frame
+ Type: STT_SECTION
+ Section: .eh_frame
+ Value: 0x200238
+ - Name: .eh_frame_hdr
+ Type: STT_SECTION
+ Section: .eh_frame_hdr
+ Value: 0x2002C4
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ Value: 0x2102F0
+ - Name: .tbss
+ Type: STT_SECTION
+ Section: .tbss
+ Value: 0x2203B0
+ - Name: .got
+ Type: STT_SECTION
+ Section: .got
+ Value: 0x2203B0
+ - Name: .relro_padding
+ Type: STT_SECTION
+ Section: .relro_padding
+ Value: 0x2203B8
+ - Name: .got.plt
+ Type: STT_SECTION
+ Section: .got.plt
+ Value: 0x2303B8
+ - Name: .comment
+ Type: STT_SECTION
+ Section: .comment
+ - Name: .rela.eh_frame
+ Type: STT_SECTION
+ Section: .rela.eh_frame
+ - Name: .shstrtab
+ Type: STT_SECTION
+ Section: .shstrtab
+ - Name: .strtab
+ Type: STT_SECTION
+ Section: .strtab
+ - Name: .symtab
+ Type: STT_SECTION
+ Section: .symtab
+ - Name: .rela.text
+ Type: STT_SECTION
+ Section: .rela.text
+ - Name: tls-desc.c
+ Type: STT_FILE
+ Index: SHN_ABS
+ - Name: '$x.0'
+ Section: .text
+ Value: 0x2102F0
+ - Name: '$d.1'
+ Section: .tbss
+ Value: 0x2203B0
+ - Name: '$d.2'
+ Section: .comment
+ - Name: get_tls
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x2102F0
+ Size: 0x28
+ - Name: tls_var
+ Type: STT_TLS
+ Section: .tbss
+ Size: 0x4
+ - Name: set_tls
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x210318
+ Size: 0x38
+ - Name: get_tls_twice
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x210350
+ Size: 0x2C
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x21037C
+ Size: 0x28
+ - Name: __ehdr_start
+ Section: .eh_frame
+ Value: 0x200000
+ - Name: __init_array_start
+ Section: .symtab
+ - Name: __init_array_end
+ Section: .symtab
+ - Name: __fini_array_start
+ Section: .symtab
+ - Name: __fini_array_end
+ Section: .symtab
+ - Name: __preinit_array_start
+ Section: .symtab
+ - Name: __preinit_array_end
+ Section: .symtab
+ - Name: _DYNAMIC
+ Section: .symtab
+ - Name: _GLOBAL_OFFSET_TABLE_
+ Section: .got
+ Value: 0x2203B0
+ - Name: _PROCEDURE_LINKAGE_TABLE_
+ - Name: __bss_start
+ Section: .symtab
+ - Name: _end
+ Section: .got.plt
+ Value: 0x2303D0
+ - Name: _etext
+ Section: .text
+ Value: 0x2103B0
+ - Name: _edata
+ Section: .got.plt
+ Value: 0x2303D0
+ - Name: __executable_start
+ Section: .eh_frame
+ Value: 0x200000
+ - Name: __rela_iplt_start
+ - Name: __rela_iplt_end
+ - Name: __GNU_EH_FRAME_HDR
+ Section: .eh_frame_hdr
+ Value: 0x2002C4
+ - Name: end
+ Section: .got.plt
+ Value: 0x2303D0
+ - Name: etext
+ Section: .text
+ Value: 0x2103B0
+ - Name: edata
+ Section: .got.plt
+ Value: 0x2303D0
+ - Name: __dso_handle
+ Section: .eh_frame
+ Value: 0x200238
+ - Name: _TLS_MODULE_BASE_
+ Type: STT_TLS
+ Section: .eh_frame
+ Value: 0x2203B0
+ - Name: __start_EHDR
+ Section: .symtab
+ - Name: __stop_EHDR
+ Section: .symtab
+ - Name: __start_PHDR
+ Section: .symtab
+ - Name: __stop_PHDR
+ Section: .symtab
+...
diff --git a/bolt/test/AArch64/tls-desc-le-relaxation-alternative.test b/bolt/test/AArch64/tls-desc-le-relaxation-alternative.test
new file mode 100644
index 0000000000000..ab66ad8dfc88a
--- /dev/null
+++ b/bolt/test/AArch64/tls-desc-le-relaxation-alternative.test
@@ -0,0 +1,11 @@
+# Check that BOLT handles case when TLSDESC is relaxed to LE
+# with NOP+NOP+MOVZ+MOVK layout (as produced by some linkers like mold).
+# The TLSDESC_ADD_LO12 relocation lands on a MOVZ instruction, which is
+# not a valid target for the S_LO12 specifier.
+
+RUN: yaml2obj %S/Inputs/tls-desc-le-relax.yaml -o %t.exe
+RUN: llvm-bolt %t.exe -o %t.bolt 2>&1 | FileCheck %s
+
+CHECK: BOLT-INFO: Target architecture: aarch64
+CHECK-DAG: BOLT-INFO: Starting stub-insertion pass
+CHECK-DAG: BOLT-INFO: setting _end
More information about the llvm-commits
mailing list