xtensa: fix PR ld/25861

Message ID 20200421101309.19304-1-jcmvbkbc@gmail.com
State New
Headers show
Series
  • xtensa: fix PR ld/25861
Related show

Commit Message

Alan Modra via Binutils April 21, 2020, 10:13 a.m.
Introduce new relaxations XTENSA_PDIFF{8,16,32} for positive differences
(subtracted symbol precedes diminished symbol) and XTENSA_NDIFF{8,16,32}
for negative differences (subtracted symbol follows diminished symbol).
Don't generate XTENSA_DIFF relocations in the assembler, generate
XTENSA_PDIFF or XTENSA_NDIFF based on relative symbol position.

Handle XTENSA_DIFF in BFD for compatibility with old object files.
Handle XTENSA_PDIFF and XTENSA_NDIFF in BFD, treating difference value
as unsigned.

2020-04-21  Max Filippov  <jcmvbkbc@gmail.com>
bfd/
	* bfd-in2.h: Regenerated.
	* elf32-xtensa.c (elf_howto_table): New entries for
	R_XTENSA_PDIFF{8,16,32} and R_XTENSA_NDIFF{8,16,32}.
	(elf_xtensa_reloc_type_lookup, elf_xtensa_do_reloc)
	(relax_section): Add cases for R_XTENSA_PDIFF{8,16,32} and
       	R_XTENSA_NDIFF{8,16,32}.
	* libbfd.h (bfd_reloc_code_real_names): Add names for
	BFD_RELOC_XTENSA_PDIFF{8,16,32} and
       	BFD_RELOC_XTENSA_NDIFF{8,16,32}.
	* reloc.c: Add documentation for BFD_RELOC_XTENSA_PDIFF{8,16,32}
       	and BFD_RELOC_XTENSA_NDIFF{8,16,32}.

binutils/
	* readelf.c (is_none_reloc): Recognize
	BFD_RELOC_XTENSA_PDIFF{8,16,32} and
       	BFD_RELOC_XTENSA_NDIFF{8,16,32}.

gas/
	* config/tc-xtensa.c (md_apply_fix): Replace
	BFD_RELOC_XTENSA_DIFF{8,16,32} generation with
	BFD_RELOC_XTENSA_PDIFF{8,16,32} and
        BFD_RELOC_XTENSA_NDIFF{8,16,32} generation.
	* testsuite/gas/xtensa/loc.d: Replace BFD_RELOC_XTENSA_DIFF16
       	with BFD_RELOC_XTENSA_PDIFF16 in the expected output.

include/
	* elf/xtensa.h (elf_xtensa_reloc_type): New entries for
	R_XTENSA_PDIFF{8,16,32} and R_XTENSA_NDIFF{8,16,32}.

ld/
	* testsuite/ld-xtensa/relax-loc.d: New test definition.
	* testsuite/ld-xtensa/relax-loc.s: New test source.
	* testsuite/ld-xtensa/xtensa.exp (relax-loc): New test.
---
 bfd/bfd-in2.h                      | 20 ++++++-
 bfd/elf32-xtensa.c                 | 89 +++++++++++++++++++++++++++++-
 bfd/libbfd.h                       |  6 ++
 bfd/reloc.c                        | 24 ++++++++
 binutils/readelf.c                 |  8 ++-
 gas/config/tc-xtensa.c             | 12 +++-
 gas/testsuite/gas/xtensa/loc.d     |  2 +-
 include/elf/xtensa.h               |  6 ++
 ld/testsuite/ld-xtensa/relax-loc.d |  7 +++
 ld/testsuite/ld-xtensa/relax-loc.s | 15 +++++
 ld/testsuite/ld-xtensa/xtensa.exp  |  1 +
 11 files changed, 183 insertions(+), 7 deletions(-)
 create mode 100644 ld/testsuite/ld-xtensa/relax-loc.d
 create mode 100644 ld/testsuite/ld-xtensa/relax-loc.s

-- 
2.20.1

Comments

Alan Modra via Binutils April 23, 2020, 12:15 a.m. | #1
On Tue, Apr 21, 2020 at 3:13 AM Max Filippov <jcmvbkbc@gmail.com> wrote:
> 2020-04-21  Max Filippov  <jcmvbkbc@gmail.com>

> bfd/

>         * bfd-in2.h: Regenerated.

>         * elf32-xtensa.c (elf_howto_table): New entries for

>         R_XTENSA_PDIFF{8,16,32} and R_XTENSA_NDIFF{8,16,32}.

>         (elf_xtensa_reloc_type_lookup, elf_xtensa_do_reloc)

>         (relax_section): Add cases for R_XTENSA_PDIFF{8,16,32} and

>         R_XTENSA_NDIFF{8,16,32}.

>         * libbfd.h (bfd_reloc_code_real_names): Add names for

>         BFD_RELOC_XTENSA_PDIFF{8,16,32} and

>         BFD_RELOC_XTENSA_NDIFF{8,16,32}.

>         * reloc.c: Add documentation for BFD_RELOC_XTENSA_PDIFF{8,16,32}

>         and BFD_RELOC_XTENSA_NDIFF{8,16,32}.

>

> binutils/

>         * readelf.c (is_none_reloc): Recognize

>         BFD_RELOC_XTENSA_PDIFF{8,16,32} and

>         BFD_RELOC_XTENSA_NDIFF{8,16,32}.

>

> gas/

>         * config/tc-xtensa.c (md_apply_fix): Replace

>         BFD_RELOC_XTENSA_DIFF{8,16,32} generation with

>         BFD_RELOC_XTENSA_PDIFF{8,16,32} and

>         BFD_RELOC_XTENSA_NDIFF{8,16,32} generation.

>         * testsuite/gas/xtensa/loc.d: Replace BFD_RELOC_XTENSA_DIFF16

>         with BFD_RELOC_XTENSA_PDIFF16 in the expected output.

>

> include/

>         * elf/xtensa.h (elf_xtensa_reloc_type): New entries for

>         R_XTENSA_PDIFF{8,16,32} and R_XTENSA_NDIFF{8,16,32}.

>

> ld/

>         * testsuite/ld-xtensa/relax-loc.d: New test definition.

>         * testsuite/ld-xtensa/relax-loc.s: New test source.

>         * testsuite/ld-xtensa/xtensa.exp (relax-loc): New test.


This is ok.
Alan Modra via Binutils April 23, 2020, 1:49 a.m. | #2
On Wed, Apr 22, 2020 at 5:15 PM augustine.sterling@gmail.com
<augustine.sterling@gmail.com> wrote:
> On Tue, Apr 21, 2020 at 3:13 AM Max Filippov <jcmvbkbc@gmail.com> wrote:

> > 2020-04-21  Max Filippov  <jcmvbkbc@gmail.com>

> > bfd/

> >         * bfd-in2.h: Regenerated.

> >         * elf32-xtensa.c (elf_howto_table): New entries for

> >         R_XTENSA_PDIFF{8,16,32} and R_XTENSA_NDIFF{8,16,32}.

> >         (elf_xtensa_reloc_type_lookup, elf_xtensa_do_reloc)

> >         (relax_section): Add cases for R_XTENSA_PDIFF{8,16,32} and

> >         R_XTENSA_NDIFF{8,16,32}.

> >         * libbfd.h (bfd_reloc_code_real_names): Add names for

> >         BFD_RELOC_XTENSA_PDIFF{8,16,32} and

> >         BFD_RELOC_XTENSA_NDIFF{8,16,32}.

> >         * reloc.c: Add documentation for BFD_RELOC_XTENSA_PDIFF{8,16,32}

> >         and BFD_RELOC_XTENSA_NDIFF{8,16,32}.

> >

> > binutils/

> >         * readelf.c (is_none_reloc): Recognize

> >         BFD_RELOC_XTENSA_PDIFF{8,16,32} and

> >         BFD_RELOC_XTENSA_NDIFF{8,16,32}.

> >

> > gas/

> >         * config/tc-xtensa.c (md_apply_fix): Replace

> >         BFD_RELOC_XTENSA_DIFF{8,16,32} generation with

> >         BFD_RELOC_XTENSA_PDIFF{8,16,32} and

> >         BFD_RELOC_XTENSA_NDIFF{8,16,32} generation.

> >         * testsuite/gas/xtensa/loc.d: Replace BFD_RELOC_XTENSA_DIFF16

> >         with BFD_RELOC_XTENSA_PDIFF16 in the expected output.

> >

> > include/

> >         * elf/xtensa.h (elf_xtensa_reloc_type): New entries for

> >         R_XTENSA_PDIFF{8,16,32} and R_XTENSA_NDIFF{8,16,32}.

> >

> > ld/

> >         * testsuite/ld-xtensa/relax-loc.d: New test definition.

> >         * testsuite/ld-xtensa/relax-loc.s: New test source.

> >         * testsuite/ld-xtensa/xtensa.exp (relax-loc): New test.

>

> This is ok.


Thanks, applied to master.

-- Max

Patch

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 37114607b515..be6a30f57955 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -5217,7 +5217,9 @@  to one of its own internal functions or data structures.  */
 PLT entries.  Otherwise, this is just a generic 32-bit relocation.  */
   BFD_RELOC_XTENSA_PLT,
 
-/* Xtensa relocations to mark the difference of two local symbols.
+/* Xtensa relocations for backward compatibility.  These have been replaced
+by BFD_RELOC_XTENSA_PDIFF and BFD_RELOC_XTENSA_NDIFF.
+Xtensa relocations to mark the difference of two local symbols.
 These are only needed to support linker relaxation and can be ignored
 when not relaxing.  The field is set to the value of the difference
 assuming no relaxation.  The relocation encodes the position of the
@@ -5291,6 +5293,22 @@  BFD_RELOC_XTENSA_ASM_EXPAND.  */
   BFD_RELOC_XTENSA_TLS_ARG,
   BFD_RELOC_XTENSA_TLS_CALL,
 
+/* Xtensa relocations to mark the difference of two local symbols.
+These are only needed to support linker relaxation and can be ignored
+when not relaxing.  The field is set to the value of the difference
+assuming no relaxation.  The relocation encodes the position of the
+subtracted symbol so the linker can determine whether to adjust the field
+value.  PDIFF relocations are used for positive differences, NDIFF
+relocations are used for negative differences.  The difference value
+is treated as unsigned with these relocation types, giving full
+8/16 value ranges.  */
+  BFD_RELOC_XTENSA_PDIFF8,
+  BFD_RELOC_XTENSA_PDIFF16,
+  BFD_RELOC_XTENSA_PDIFF32,
+  BFD_RELOC_XTENSA_NDIFF8,
+  BFD_RELOC_XTENSA_NDIFF16,
+  BFD_RELOC_XTENSA_NDIFF32,
+
 /* 8 bit signed offset in (ix+d) or (iy+d).  */
   BFD_RELOC_Z80_DISP8,
 
diff --git a/bfd/elf32-xtensa.c b/bfd/elf32-xtensa.c
index 473a9d76f289..fded42d52a9a 100644
--- a/bfd/elf32-xtensa.c
+++ b/bfd/elf32-xtensa.c
@@ -325,6 +325,20 @@  static reloc_howto_type elf_howto_table[] =
   HOWTO (R_XTENSA_TLS_CALL, 0, 0, 0, FALSE, 0, complain_overflow_dont,
 	 bfd_elf_xtensa_reloc, "R_XTENSA_TLS_CALL",
 	 FALSE, 0, 0, FALSE),
+
+  HOWTO (R_XTENSA_PDIFF8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield,
+	 bfd_elf_xtensa_reloc, "R_XTENSA_PDIFF8", FALSE, 0, 0xff, FALSE),
+  HOWTO (R_XTENSA_PDIFF16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield,
+	 bfd_elf_xtensa_reloc, "R_XTENSA_PDIFF16", FALSE, 0, 0xffff, FALSE),
+  HOWTO (R_XTENSA_PDIFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
+	 bfd_elf_xtensa_reloc, "R_XTENSA_PDIFF32", FALSE, 0, 0xffffffff, FALSE),
+
+  HOWTO (R_XTENSA_NDIFF8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield,
+	 bfd_elf_xtensa_reloc, "R_XTENSA_NDIFF8", FALSE, 0, 0xff, FALSE),
+  HOWTO (R_XTENSA_NDIFF16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield,
+	 bfd_elf_xtensa_reloc, "R_XTENSA_NDIFF16", FALSE, 0, 0xffff, FALSE),
+  HOWTO (R_XTENSA_NDIFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
+	 bfd_elf_xtensa_reloc, "R_XTENSA_NDIFF32", FALSE, 0, 0xffffffff, FALSE),
 };
 
 #if DEBUG_GEN_RELOC
@@ -364,6 +378,30 @@  elf_xtensa_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       TRACE ("BFD_RELOC_XTENSA_DIFF32");
       return &elf_howto_table[(unsigned) R_XTENSA_DIFF32 ];
 
+    case BFD_RELOC_XTENSA_PDIFF8:
+      TRACE ("BFD_RELOC_XTENSA_PDIFF8");
+      return &elf_howto_table[(unsigned) R_XTENSA_PDIFF8 ];
+
+    case BFD_RELOC_XTENSA_PDIFF16:
+      TRACE ("BFD_RELOC_XTENSA_PDIFF16");
+      return &elf_howto_table[(unsigned) R_XTENSA_PDIFF16 ];
+
+    case BFD_RELOC_XTENSA_PDIFF32:
+      TRACE ("BFD_RELOC_XTENSA_PDIFF32");
+      return &elf_howto_table[(unsigned) R_XTENSA_PDIFF32 ];
+
+    case BFD_RELOC_XTENSA_NDIFF8:
+      TRACE ("BFD_RELOC_XTENSA_NDIFF8");
+      return &elf_howto_table[(unsigned) R_XTENSA_NDIFF8 ];
+
+    case BFD_RELOC_XTENSA_NDIFF16:
+      TRACE ("BFD_RELOC_XTENSA_NDIFF16");
+      return &elf_howto_table[(unsigned) R_XTENSA_NDIFF16 ];
+
+    case BFD_RELOC_XTENSA_NDIFF32:
+      TRACE ("BFD_RELOC_XTENSA_NDIFF32");
+      return &elf_howto_table[(unsigned) R_XTENSA_NDIFF32 ];
+
     case BFD_RELOC_XTENSA_RTLD:
       TRACE ("BFD_RELOC_XTENSA_RTLD");
       return &elf_howto_table[(unsigned) R_XTENSA_RTLD ];
@@ -1851,6 +1889,12 @@  elf_xtensa_do_reloc (reloc_howto_type *howto,
     case R_XTENSA_DIFF8:
     case R_XTENSA_DIFF16:
     case R_XTENSA_DIFF32:
+    case R_XTENSA_PDIFF8:
+    case R_XTENSA_PDIFF16:
+    case R_XTENSA_PDIFF32:
+    case R_XTENSA_NDIFF8:
+    case R_XTENSA_NDIFF16:
+    case R_XTENSA_NDIFF32:
     case R_XTENSA_TLS_FUNC:
     case R_XTENSA_TLS_ARG:
     case R_XTENSA_TLS_CALL:
@@ -9604,7 +9648,13 @@  relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info)
 
 	      if (r_type == R_XTENSA_DIFF8
 		  || r_type == R_XTENSA_DIFF16
-		  || r_type == R_XTENSA_DIFF32)
+		  || r_type == R_XTENSA_DIFF32
+		  || r_type == R_XTENSA_PDIFF8
+		  || r_type == R_XTENSA_PDIFF16
+		  || r_type == R_XTENSA_PDIFF32
+		  || r_type == R_XTENSA_NDIFF8
+		  || r_type == R_XTENSA_NDIFF16
+		  || r_type == R_XTENSA_NDIFF32)
 		{
 		  bfd_signed_vma diff_value = 0;
 		  bfd_vma new_end_offset, diff_mask = 0;
@@ -9631,8 +9681,27 @@  relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info)
 		      diff_value =
 			bfd_get_signed_32 (abfd, &contents[old_source_offset]);
 		      break;
+		    case R_XTENSA_PDIFF8:
+		    case R_XTENSA_NDIFF8:
+		      diff_value =
+			bfd_get_8 (abfd, &contents[old_source_offset]);
+		      break;
+		    case R_XTENSA_PDIFF16:
+		    case R_XTENSA_NDIFF16:
+		      diff_value =
+			bfd_get_16 (abfd, &contents[old_source_offset]);
+		      break;
+		    case R_XTENSA_PDIFF32:
+		    case R_XTENSA_NDIFF32:
+		      diff_value =
+			bfd_get_32 (abfd, &contents[old_source_offset]);
+		      break;
 		    }
 
+		  if (r_type >= R_XTENSA_NDIFF8
+		      && r_type <= R_XTENSA_NDIFF32)
+		    diff_value = -diff_value;
+
 		  new_end_offset = offset_with_removed_text_map
 		    (&target_relax_info->action_list,
 		     r_rel.target_offset + diff_value);
@@ -9655,6 +9724,24 @@  relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info)
 		      bfd_put_signed_32 (abfd, diff_value,
 				  &contents[old_source_offset]);
 		      break;
+		    case R_XTENSA_PDIFF8:
+		    case R_XTENSA_NDIFF8:
+		      diff_mask = 0xff;
+		      bfd_put_8 (abfd, diff_value,
+				 &contents[old_source_offset]);
+		      break;
+		    case R_XTENSA_PDIFF16:
+		    case R_XTENSA_NDIFF16:
+		      diff_mask = 0xffff;
+		      bfd_put_16 (abfd, diff_value,
+				  &contents[old_source_offset]);
+		      break;
+		    case R_XTENSA_PDIFF32:
+		    case R_XTENSA_NDIFF32:
+		      diff_mask = 0xffffffff;
+		      bfd_put_32 (abfd, diff_value,
+				  &contents[old_source_offset]);
+		      break;
 		    }
 
 		  /* Check for overflow. Sign bits must be all zeroes or all ones */
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 3c184fcadadf..989f4bc0b595 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2919,6 +2919,12 @@  static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_XTENSA_TLS_FUNC",
   "BFD_RELOC_XTENSA_TLS_ARG",
   "BFD_RELOC_XTENSA_TLS_CALL",
+  "BFD_RELOC_XTENSA_PDIFF8",
+  "BFD_RELOC_XTENSA_PDIFF16",
+  "BFD_RELOC_XTENSA_PDIFF32",
+  "BFD_RELOC_XTENSA_NDIFF8",
+  "BFD_RELOC_XTENSA_NDIFF16",
+  "BFD_RELOC_XTENSA_NDIFF32",
   "BFD_RELOC_Z80_DISP8",
   "BFD_RELOC_Z80_BYTE0",
   "BFD_RELOC_Z80_BYTE1",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index c4dec86d1d46..f5df8e2ab3eb 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -6556,6 +6556,8 @@  ENUMX
 ENUMX
   BFD_RELOC_XTENSA_DIFF32
 ENUMDOC
+  Xtensa relocations for backward compatibility.  These have been replaced
+  by BFD_RELOC_XTENSA_PDIFF and BFD_RELOC_XTENSA_NDIFF.
   Xtensa relocations to mark the difference of two local symbols.
   These are only needed to support linker relaxation and can be ignored
   when not relaxing.  The field is set to the value of the difference
@@ -6668,6 +6670,28 @@  ENUMX
   BFD_RELOC_XTENSA_TLS_CALL
 ENUMDOC
   Xtensa TLS relocations.
+ENUM
+  BFD_RELOC_XTENSA_PDIFF8
+ENUMX
+  BFD_RELOC_XTENSA_PDIFF16
+ENUMX
+  BFD_RELOC_XTENSA_PDIFF32
+ENUMX
+  BFD_RELOC_XTENSA_NDIFF8
+ENUMX
+  BFD_RELOC_XTENSA_NDIFF16
+ENUMX
+  BFD_RELOC_XTENSA_NDIFF32
+ENUMDOC
+  Xtensa relocations to mark the difference of two local symbols.
+  These are only needed to support linker relaxation and can be ignored
+  when not relaxing.  The field is set to the value of the difference
+  assuming no relaxation.  The relocation encodes the position of the
+  subtracted symbol so the linker can determine whether to adjust the field
+  value.  PDIFF relocations are used for positive differences, NDIFF
+  relocations are used for negative differences.  The difference value
+  is treated as unsigned with these relocation types, giving full
+  8/16 value ranges.
 
 ENUM
   BFD_RELOC_Z80_DISP8
diff --git a/binutils/readelf.c b/binutils/readelf.c
index d4756c93b345..800918f901c8 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -13262,7 +13262,13 @@  is_none_reloc (Filedata * filedata, unsigned int reloc_type)
       return (reloc_type == 0      /* R_XTENSA_NONE.  */
 	      || reloc_type == 17  /* R_XTENSA_DIFF8.  */
 	      || reloc_type == 18  /* R_XTENSA_DIFF16.  */
-	      || reloc_type == 19  /* R_XTENSA_DIFF32.  */);
+	      || reloc_type == 19  /* R_XTENSA_DIFF32.  */
+	      || reloc_type == 57  /* R_XTENSA_PDIFF8.  */
+	      || reloc_type == 58  /* R_XTENSA_PDIFF16.  */
+	      || reloc_type == 59  /* R_XTENSA_PDIFF32.  */
+	      || reloc_type == 60  /* R_XTENSA_NDIFF8.  */
+	      || reloc_type == 61  /* R_XTENSA_NDIFF16.  */
+	      || reloc_type == 62  /* R_XTENSA_NDIFF32.  */);
     }
   return FALSE;
 }
diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c
index 71d4d94a8d7d..ee75c13548ff 100644
--- a/gas/config/tc-xtensa.c
+++ b/gas/config/tc-xtensa.c
@@ -5974,18 +5974,24 @@  md_apply_fix (fixS *fixP, valueT *valP, segT seg)
     case BFD_RELOC_8:
       if (fixP->fx_subsy)
 	{
+	  bfd_boolean neg = S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
+	    < S_GET_VALUE (fixP->fx_subsy);
+
 	  switch (fixP->fx_r_type)
 	    {
 	    case BFD_RELOC_8:
-	      fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF8;
+	      fixP->fx_r_type = neg
+		? BFD_RELOC_XTENSA_NDIFF8 : BFD_RELOC_XTENSA_PDIFF8;
 	      fixP->fx_signed = 0;
 	      break;
 	    case BFD_RELOC_16:
-	      fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF16;
+	      fixP->fx_r_type = neg
+		? BFD_RELOC_XTENSA_NDIFF16 : BFD_RELOC_XTENSA_PDIFF16;
 	      fixP->fx_signed = 0;
 	      break;
 	    case BFD_RELOC_32:
-	      fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF32;
+	      fixP->fx_r_type = neg
+		? BFD_RELOC_XTENSA_NDIFF32 : BFD_RELOC_XTENSA_PDIFF32;
 	      fixP->fx_signed = 0;
 	      break;
 	    default:
diff --git a/gas/testsuite/gas/xtensa/loc.d b/gas/testsuite/gas/xtensa/loc.d
index 71983cc90055..8fb3425999d5 100644
--- a/gas/testsuite/gas/xtensa/loc.d
+++ b/gas/testsuite/gas/xtensa/loc.d
@@ -6,5 +6,5 @@ 
 
 RELOCATION RECORDS FOR \[\.debug_line\]:
 #...
-.*R_XTENSA_DIFF16.*\.text\+0x00009c42
+.*R_XTENSA_PDIFF16.*\.text\+0x00009c42
 #...
diff --git a/include/elf/xtensa.h b/include/elf/xtensa.h
index 2eb5e4e52941..bd5c80d13777 100644
--- a/include/elf/xtensa.h
+++ b/include/elf/xtensa.h
@@ -87,6 +87,12 @@  START_RELOC_NUMBERS (elf_xtensa_reloc_type)
      RELOC_NUMBER (R_XTENSA_TLS_FUNC, 54)
      RELOC_NUMBER (R_XTENSA_TLS_ARG, 55)
      RELOC_NUMBER (R_XTENSA_TLS_CALL, 56)
+     RELOC_NUMBER (R_XTENSA_PDIFF8, 57)
+     RELOC_NUMBER (R_XTENSA_PDIFF16, 58)
+     RELOC_NUMBER (R_XTENSA_PDIFF32, 59)
+     RELOC_NUMBER (R_XTENSA_NDIFF8, 60)
+     RELOC_NUMBER (R_XTENSA_NDIFF16, 61)
+     RELOC_NUMBER (R_XTENSA_NDIFF32, 62)
 END_RELOC_NUMBERS (R_XTENSA_max)
 
 /* Processor-specific flags for the ELF header e_flags field.  */
diff --git a/ld/testsuite/ld-xtensa/relax-loc.d b/ld/testsuite/ld-xtensa/relax-loc.d
new file mode 100644
index 000000000000..3c8d673732ff
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/relax-loc.d
@@ -0,0 +1,7 @@ 
+#as: --text-section-literals
+#ld:
+#objdump: --dwarf=decodedline
+#...
+relax-loc.s[ 	]+1[ 	]+0x400054[ 	]+.*
+relax-loc.s[ 	]+2[ 	]+0x40005c[ 	]+.*
+#...
diff --git a/ld/testsuite/ld-xtensa/relax-loc.s b/ld/testsuite/ld-xtensa/relax-loc.s
new file mode 100644
index 000000000000..d768470e287a
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/relax-loc.s
@@ -0,0 +1,15 @@ 
+	.file	1 "relax-loc.s"
+	.globl	_start
+	.globl	_ResetVector
+	.text
+_ResetVector:
+_start:
+	.loc	1 1
+	j	1f
+	.literal_position
+1:
+	.loc	1 2
+
+	.rep	10000
+	movi	a2, 0x12345678
+	.endr
diff --git a/ld/testsuite/ld-xtensa/xtensa.exp b/ld/testsuite/ld-xtensa/xtensa.exp
index 9b2235b2151b..de39887936ad 100644
--- a/ld/testsuite/ld-xtensa/xtensa.exp
+++ b/ld/testsuite/ld-xtensa/xtensa.exp
@@ -27,6 +27,7 @@  run_dump_test "call_overflow"
 run_dump_test "coalesce"
 run_dump_test "diff_overflow"
 run_dump_test "lcall"
+run_dump_test "relax-loc"
 
 run_dump_test "relax-static-pie"
 run_dump_test "relax-static-local-pie"