[v3] aarch64: Add support for %dtprel(var) and R_AARCH64_TLS_DTPREL64

Message ID 20260408101538.16958-1-shivam98.tkg@gmail.com
State Committed
Headers
Series [v3] aarch64: Add support for %dtprel(var) and R_AARCH64_TLS_DTPREL64 |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 fail Patch failed to apply
linaro-tcwg-bot/tcwg_binutils_check--master-arm fail Patch failed to apply

Commit Message

Shivam Gupta April 8, 2026, 10:15 a.m. UTC
  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 <shivam98.tkg@gmail.com>

---

Notes :
    Changes in v3:
      - Combine multiple %dtprel relocations into a single line in test
      - Simplify %dtprel parsing logic
      - Simplify unknown relocation operator error message

 bfd/elfnn-aarch64.c                     | 11 ++++++++
 gas/config/tc-aarch64.c                 | 37 +++++++++++++++++++++++++
 gas/testsuite/gas/aarch64/tls-debug.d   | 10 +++++++
 gas/testsuite/gas/aarch64/tls-debug.s   |  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 ++++++
 7 files changed, 85 insertions(+)
 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
  

Comments

Alice Carlotti April 9, 2026, 2:38 p.m. UTC | #1
On Wed, Apr 08, 2026 at 03:45:38PM +0530, Shivam Gupta 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.
> 
> 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 <shivam98.tkg@gmail.com>
> 
> ---
> 
> Notes :
>     Changes in v3:
>       - Combine multiple %dtprel relocations into a single line in test
>       - Simplify %dtprel parsing logic
>       - Simplify unknown relocation operator error message

Thanks - I've committed this for you.

Alice

> 
>  bfd/elfnn-aarch64.c                     | 11 ++++++++
>  gas/config/tc-aarch64.c                 | 37 +++++++++++++++++++++++++
>  gas/testsuite/gas/aarch64/tls-debug.d   | 10 +++++++
>  gas/testsuite/gas/aarch64/tls-debug.s   |  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 ++++++
>  7 files changed, 85 insertions(+)
>  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..117e1498 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 cd761634..73b549a1 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 00000000..1dd4df17
> --- /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..c45507ed
> --- /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 24c73d53..fa802105 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 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
>
  
Shivam Gupta April 9, 2026, 2:51 p.m. UTC | #2
Perfect, thanks a lot!
It is an honor to have a contribution to GNU Binutils.

Shivam

On Thu, Apr 9, 2026 at 8:09 PM Alice Carlotti <alice.carlotti@arm.com>
wrote:

> On Wed, Apr 08, 2026 at 03:45:38PM +0530, Shivam Gupta 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.
> >
> > 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 <shivam98.tkg@gmail.com>
> >
> > ---
> >
> > Notes :
> >     Changes in v3:
> >       - Combine multiple %dtprel relocations into a single line in test
> >       - Simplify %dtprel parsing logic
> >       - Simplify unknown relocation operator error message
>
> Thanks - I've committed this for you.
>
> Alice
>
> >
> >  bfd/elfnn-aarch64.c                     | 11 ++++++++
> >  gas/config/tc-aarch64.c                 | 37 +++++++++++++++++++++++++
> >  gas/testsuite/gas/aarch64/tls-debug.d   | 10 +++++++
> >  gas/testsuite/gas/aarch64/tls-debug.s   |  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 ++++++
> >  7 files changed, 85 insertions(+)
> >  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..117e1498 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 cd761634..73b549a1 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 00000000..1dd4df17
> > --- /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..c45507ed
> > --- /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 24c73d53..fa802105 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 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
> >
>
  

Patch

diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 66049c81..117e1498 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 cd761634..73b549a1 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 00000000..1dd4df17
--- /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..c45507ed
--- /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 24c73d53..fa802105 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 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)