From: Shivam Gupta Date: Wed, 8 Apr 2026 10:15:38 +0000 (+0530) Subject: aarch64: Add support for %dtprel(var) and R_AARCH64_TLS_DTPREL64 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ed71fa9a44511cb8d933073f892ea041c3ff9107;p=thirdparty%2Fbinutils-gdb.git aarch64: Add support for %dtprel(var) and R_AARCH64_TLS_DTPREL64 This patch allows R_AARCH64_TLS_DTPREL64 relocations in non-allocated sections, which is required for DWARF debug information when using Thread Local Storage. This matches the behavior in LLD. Also a new syntax to parse dtprel operator use to describe tls location in debug information. Please see the reference 3 below. References: - https://github.com/llvm/llvm-project/pull/146572 [AArch64] Support TLS variables in debug info - https://github.com/llvm/llvm-project/pull/183962 [LLD][AArch64] Handle R_AARCH64_TLS_DTPREL64 in non-alloc sections - https://github.com/ARM-software/abi-aa/pull/330 [AAELF64] Allow R_AARCH64_TLS_DTPREL to be used statically. bfd/ * elfnn-aarch64.c (elfNN_aarch64_final_link_relocate): Handle BFD_RELOC_AARCH64_TLS_DTPREL. gas/ * config/tc-aarch64.c (s_aarch64_cons): Parse %dtprel(var) syntax. * testsuite/gas/aarch64/tls-debug.s: New test. * testsuite/gas/aarch64/tls-debug.d: Run the test. ld/ * testsuite/ld-aarch64/tls-debug.s: New test. * testsuite/ld-aarch64/tls-debug.d: Run the test. Bug: https://sourceware.org/PR28351 Signed-off-by: Shivam Gupta --- diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c index 66049c81edf..117e149866c 100644 --- a/bfd/elfnn-aarch64.c +++ b/bfd/elfnn-aarch64.c @@ -6496,6 +6496,17 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, *unresolved_reloc_p = false; break; + case BFD_RELOC_AARCH64_TLS_DTPREL: + if (input_section->flags & SEC_ALLOC) + return bfd_reloc_notsupported; + value -= dtpoff_base (info); + value += rel->r_addend; + + bfd_put_64 (output_bfd, value, contents + rel->r_offset); + + *unresolved_reloc_p = false; + break; + case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC: case BFD_RELOC_AARCH64_TLSDESC_OFF_G1: if (globals->root.sgot == NULL) diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c index cd76163488c..73b549a16c9 100644 --- a/gas/config/tc-aarch64.c +++ b/gas/config/tc-aarch64.c @@ -2229,6 +2229,42 @@ s_aarch64_cons (int nbytes) { struct reloc_table_entry *reloc; + /* Check for %dtprel(var) syntax */ + if (*input_line_pointer == '%') + { + if (strncmp (input_line_pointer, "%dtprel(", 8) == 0) + { + input_line_pointer += 8; + + expression (&exp); + + /* Ensure we have a closing parenthesis */ + if (*input_line_pointer == ')') + input_line_pointer++; + else + { + as_bad (_("missing ')' after %%dtprel")); + ignore_rest_of_line (); + return; + } + + addressT where = frag_now_fix (); + fix_new_exp (frag_now, where, nbytes, &exp, 0, + BFD_RELOC_AARCH64_TLS_DTPREL); + + char *dest = frag_more (nbytes); + memset (dest, 0, nbytes); + continue; + } + + else + { + as_bad (_("unknown relocation operator")); + ignore_rest_of_line (); + return; + } + } + expression (&exp); if (exp.X_op != O_symbol) @@ -10114,6 +10150,7 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg) case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1: case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC: case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2: + case BFD_RELOC_AARCH64_TLS_DTPREL: S_SET_THREAD_LOCAL (fixP->fx_addsy); /* Should always be exported to object file, see aarch64_force_relocation(). */ diff --git a/gas/testsuite/gas/aarch64/tls-debug.d b/gas/testsuite/gas/aarch64/tls-debug.d new file mode 100644 index 00000000000..1dd4df17542 --- /dev/null +++ b/gas/testsuite/gas/aarch64/tls-debug.d @@ -0,0 +1,10 @@ +#as: +#objdump: -r +#target: aarch64*-*-* + +#... +RELOCATION RECORDS FOR \[\.debug_info\]: +OFFSET +TYPE +VALUE +0*0 R_AARCH64_TLS_DTPREL64 +var +0*8 R_AARCH64_TLS_DTPREL64 +var\+0x0+1 +#... diff --git a/gas/testsuite/gas/aarch64/tls-debug.s b/gas/testsuite/gas/aarch64/tls-debug.s new file mode 100644 index 00000000000..c45507ed110 --- /dev/null +++ b/gas/testsuite/gas/aarch64/tls-debug.s @@ -0,0 +1,8 @@ +.section .tdata,"awT",@progbits +.skip 8 // Force var to have an offset of 8 +.globl var +var: + .word 0 + +.section .debug_info,"",@progbits + .xword %dtprel(var), %dtprel(var+1) diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp b/ld/testsuite/ld-aarch64/aarch64-elf.exp index 24c73d530dc..fa80210500e 100644 --- a/ld/testsuite/ld-aarch64/aarch64-elf.exp +++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp @@ -261,6 +261,7 @@ run_dump_test "tls-relax-ld-le-small" run_dump_test "tls-relax-ld-le-small-ilp32" run_dump_test "tls-relax-ld-le-tiny" run_dump_test "tls-relax-ld-le-tiny-ilp32" +run_dump_test "tls-debug" run_dump_test "tls-desc-ie" run_dump_test "tls-desc-ie-ilp32" run_dump_test "tls-relax-gdesc-le-2" diff --git a/ld/testsuite/ld-aarch64/tls-debug.d b/ld/testsuite/ld-aarch64/tls-debug.d new file mode 100644 index 00000000000..4344b02e794 --- /dev/null +++ b/ld/testsuite/ld-aarch64/tls-debug.d @@ -0,0 +1,9 @@ +#source: tls-debug.s +#ld: -shared -T relocs.ld -e0 +#objdump: -s -j .debug_info + +#... +Contents of section .debug_info: +#... + [0-9a-f]+ 08000000 00000000 09000000 00000000 .* +#... diff --git a/ld/testsuite/ld-aarch64/tls-debug.s b/ld/testsuite/ld-aarch64/tls-debug.s new file mode 100644 index 00000000000..9590ad409f9 --- /dev/null +++ b/ld/testsuite/ld-aarch64/tls-debug.s @@ -0,0 +1,9 @@ +.section .tdata,"awT",@progbits +.skip 8 // Force var to have an offset of 8 +.globl var +var: + .word 0 + +.section .debug_info,"",@progbits + .xword %dtprel(var) + .xword %dtprel(var+1)