[PATCH] aarch64: Add support for %dtprel(var) and R_AARCH64_TLS_DTPREL64
Shivam Gupta
shivam98.tkg@gmail.com
Fri Mar 27 17:10:36 GMT 2026
Hello,
Gentle Ping!
I am not sure that I am correctly intersecting the flow at s_aarch64_cons
for this new syntax. Let me know if there is better to handle that.
Thanks,
Shivam
On Wed, Mar 18, 2026 at 11:27 AM Shivam Gupta <shivam98.tkg@gmail.com>
wrote:
> Hello,
>
> Apologise if I CCed wrong people for this patch to review.
>
> I think Binutils side of this commit is prerequisite for llvm/lld side of
> same work so PTAL.
>
> Thanks,
> Shivam
>
>
> On Sat, Mar 14, 2026 at 2:12 AM Shivam Gupta <shivam98.tkg@gmail.com>
> wrote:
>
>> 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.
>>
>> gold/
>> * aarch64-reloc-property.h (code_to_array_index): Handle
>> R_AARCH64_TLS_DTPREL64.
>> * aarch64.cc (Relocate::relocate): Handle R_AARCH64_TLS_DTPREL64.
>>
>> ld/
>> * testsuite/ld-aarch64/tls-debug.s: New test.
>> * testsuite/ld-aarch64/tls-debug.d: Run the test.
>>
>> Signed-off-by: Shivam Gupta <shivam98.tkg@gmail.com>
>> ---
>> bfd/elfnn-aarch64.c | 12 +++++++
>> gas/config/tc-aarch64.c | 44 +++++++++++++++++++++++++
>> gas/testsuite/gas/aarch64/tls-debug.d | 10 ++++++
>> gas/testsuite/gas/aarch64/tls-debug.s | 9 +++++
>> gold/aarch64-reloc-property.h | 2 ++
>> gold/aarch64.cc | 8 ++++-
>> ld/testsuite/ld-aarch64/aarch64-elf.exp | 1 +
>> ld/testsuite/ld-aarch64/tls-debug.d | 9 +++++
>> ld/testsuite/ld-aarch64/tls-debug.s | 9 +++++
>> 9 files changed, 103 insertions(+), 1 deletion(-)
>> create mode 100644 gas/testsuite/gas/aarch64/tls-debug.d
>> create mode 100644 gas/testsuite/gas/aarch64/tls-debug.s
>> create mode 100644 ld/testsuite/ld-aarch64/tls-debug.d
>> create mode 100644 ld/testsuite/ld-aarch64/tls-debug.s
>>
>> diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
>> index 66049c81..acf207dd 100644
>> --- a/bfd/elfnn-aarch64.c
>> +++ b/bfd/elfnn-aarch64.c
>> @@ -6496,6 +6496,18 @@ elfNN_aarch64_final_link_relocate
>> (reloc_howto_type *howto,
>> *unresolved_reloc_p = false;
>> break;
>>
>> + case BFD_RELOC_AARCH64_TLS_DTPREL:
>> + /* Handle R_AARCH64_TLS_DTPREL64 in non-alloc sections */
>> + if (!(input_section->flags & SEC_ALLOC))
>> + {
>> + 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 cd761634..6cc7481a 100644
>> --- a/gas/config/tc-aarch64.c
>> +++ b/gas/config/tc-aarch64.c
>> @@ -2229,6 +2229,40 @@ s_aarch64_cons (int nbytes)
>> {
>> struct reloc_table_entry *reloc;
>>
>> + /* Check for %dtprel(var) syntax */
>> + if (*input_line_pointer == '%')
>> + {
>> + char *p = ++input_line_pointer; /* skip '%' */
>> +
>> + /* Look for "dtprel" */
>> + if (strncmp (p, "dtprel", 6) == 0 && p[6] == '(')
>> + {
>> + input_line_pointer = p + 7; /* Skip "dtprel(" */
>> +
>> + /* Parse the symbol inside the parentheses */
>> + expression (&exp);
>> +
>> + /* Ensure we have a closing parenthesis */
>> + if (*input_line_pointer == ')')
>> + input_line_pointer++;
>> + else
>> + as_bad (_("missing ')' after %%dtprel(...)"));
>> +
>> + /* Create the fixup using your DTPREL ID */
>> + 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 %%%s"), p);
>> + }
>> + }
>> +
>> expression (&exp);
>>
>> if (exp.X_op != O_symbol)
>> @@ -3292,6 +3326,15 @@ static struct reloc_table_entry reloc_table[] =
>> 0,
>> 0},
>>
>> + /* TLS relative offset. */
>> + {"dtprel", 0,
>> + 0, /* adr_type */
>> + 0,
>> + 0,
>> + 0,
>> + 0,
>> + BFD_RELOC_AARCH64_TLS_DTPREL},
>> +
>> /* Lower 16 bit offset into GOT entry for a symbol */
>> {"tlsdesc_off_g0_nc", 0,
>> 0, /* adr_type */
>> @@ -10114,6 +10157,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 00000000..a64ff67f
>> --- /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 00000000..9590ad40
>> --- /dev/null
>> +++ b/gas/testsuite/gas/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)
>> diff --git a/gold/aarch64-reloc-property.h b/gold/aarch64-reloc-property.h
>> index 986adf9d..c1ce0033 100644
>> --- a/gold/aarch64-reloc-property.h
>> +++ b/gold/aarch64-reloc-property.h
>> @@ -220,6 +220,8 @@ class AArch64_reloc_property_table
>> code_to_array_index(unsigned int code) const
>> {
>> if (code == 0) return 0;
>> + if (code == elfcpp::R_AARCH64_TLS_DTPREL64)
>> + return 0;
>> if (!((code >= elfcpp::R_AARCH64_ABS64 &&
>> code <= elfcpp::R_AARCH64_LD64_GOTPAGE_LO15)
>> || (code >= elfcpp::R_AARCH64_TLSGD_ADR_PREL21 &&
>> diff --git a/gold/aarch64.cc b/gold/aarch64.cc
>> index 9ef5df79..5575f78b 100644
>> --- a/gold/aarch64.cc
>> +++ b/gold/aarch64.cc
>> @@ -7330,13 +7330,19 @@ Target_aarch64<size,
>> big_endian>::Relocate::relocate(
>> gsym, psymval, view, address);
>> break;
>>
>> + case elfcpp::R_AARCH64_TLS_DTPREL64:
>> + {
>> + uint64_t val = psymval->value (object, 0) + rela.get_r_addend ();
>> + elfcpp::Swap<64, big_endian>::writeval (view, val);
>> + break;
>> + }
>> +
>> // These are dynamic relocations, which are unexpected when linking.
>> case elfcpp::R_AARCH64_COPY:
>> case elfcpp::R_AARCH64_GLOB_DAT:
>> case elfcpp::R_AARCH64_JUMP_SLOT:
>> case elfcpp::R_AARCH64_RELATIVE:
>> case elfcpp::R_AARCH64_IRELATIVE:
>> - case elfcpp::R_AARCH64_TLS_DTPREL64:
>> case elfcpp::R_AARCH64_TLS_DTPMOD64:
>> case elfcpp::R_AARCH64_TLS_TPREL64:
>> case elfcpp::R_AARCH64_TLSDESC:
>> diff --git a/ld/testsuite/ld-aarch64/aarch64-elf.exp
>> b/ld/testsuite/ld-aarch64/aarch64-elf.exp
>> index a0a8867d..096f5f9f 100644
>> --- a/ld/testsuite/ld-aarch64/aarch64-elf.exp
>> +++ b/ld/testsuite/ld-aarch64/aarch64-elf.exp
>> @@ -252,6 +252,7 @@ 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-desc-ie"
>> +run_dump_test "tls-debug"
>> run_dump_test "tls-desc-ie-ilp32"
>> run_dump_test "tls-relax-gdesc-le-2"
>> run_dump_test "tls-relax-gdesc-le-2-ilp32"
>> diff --git a/ld/testsuite/ld-aarch64/tls-debug.d
>> b/ld/testsuite/ld-aarch64/tls-debug.d
>> new file mode 100644
>> index 00000000..4344b02e
>> --- /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 00000000..9590ad40
>> --- /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)
>> --
>> 2.34.1
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://sourceware.org/pipermail/binutils/attachments/20260327/0f843f50/attachment-0001.htm>
More information about the Binutils
mailing list