[PATCH 2/2] xtensa: implement R_XTENSA_32_ABS

Alexey Lapshin alexey.lapshin@espressif.com
Wed Sep 23 16:59:23 GMT 2026


Implement R_XTENSA_32_ABS, a 32-bit absolute address computed as S + A.
Its howto is not partial_inplace, so the addend lives in r_addend alone
and the contents of the relocated word do not contribute to the result,
as the generic ABI requires for SHT_RELA.  This is the form LLVM emits
for 32-bit absolute data.

Treat R_XTENSA_32_ABS like R_XTENSA_32 wherever the latter is handled,
both when applying relocations and when relaxing, so that objects using
either relocation can be linked together.  Also allow literals using the
two to be coalesced: r_reloc_init already folds the in-place addend of
R_XTENSA_32 into target_offset, so equal offsets mean equal addresses.
Likewise, when reading and merging property table entries, add the
relocated word to r_addend only for R_XTENSA_32.

The assembler keeps emitting R_XTENSA_32 by default, because loaders of
relocatable objects, such as the Linux kernel module loader, may not
know the new relocation.  The new --abs32-rela option makes it emit
R_XTENSA_32_ABS for 32-bit absolute data instead, --no-abs32-rela
selects R_XTENSA_32, and configuring with --enable-r-xtensa-32-abs makes
R_XTENSA_32_ABS the default.

For more details see discussion
https://discourse.llvm.org/t/rfc-add-xtensa-support-to-lld-elf-static-linking-for-embedded-targets/91608

bfd/
	* reloc.c (BFD_RELOC_XTENSA_32_ABS): New relocation code.
	* bfd-in2.h, libbfd.h: Regenerate.
	* elf32-xtensa.c (elf_howto_table): Add R_XTENSA_32_ABS.
	(elf_xtensa_reloc_type_lookup): Handle BFD_RELOC_XTENSA_32_ABS.
	(elf_xtensa_do_reloc): Handle R_XTENSA_32_ABS.
	(xtensa_reloc_addend): New function.
	(xtensa_read_table_entries, relax_property_section): Accept
	R_XTENSA_32_ABS.  Use xtensa_reloc_addend.
	(elf_xtensa_check_relocs, elf_xtensa_relocate_section)
	(compute_removed_literals, shrink_dynamic_reloc_sections): Treat
	R_XTENSA_32_ABS like R_XTENSA_32.
	(literal_reloc_type): New function.
	(literal_value_equal): Use it, so that R_XTENSA_32 and
	R_XTENSA_32_ABS literals can be coalesced.

binutils/
	* readelf.c (is_32bit_abs_reloc): Accept R_XTENSA_32_ABS.

gas/
	* configure.ac: Add --enable-r-xtensa-32-abs.  Define
	DEFAULT_R_XTENSA_32_ABS.
	* configure, config.in: Regenerate.
	* config/tc-xtensa.c (use_abs32_rela): New variable.
	(option_abs32_rela, option_no_abs32_rela): New options.
	(md_longopts, md_parse_option, md_show_usage): Handle them.
	(tc_gen_reloc): Emit BFD_RELOC_XTENSA_32_ABS in place of
	BFD_RELOC_32 if use_abs32_rela.
	* doc/as.texi, doc/c-xtensa.texi: Document --[no-]abs32-rela.
	* testsuite/gas/xtensa/reloc-abs32.s,
	* testsuite/gas/xtensa/reloc-abs32.d,
	* testsuite/gas/xtensa/reloc-abs32-no-rela.d: New tests.
	* testsuite/gas/xtensa/pdiff-uleb128-norelax.d: Accept either
	relocation on .xt.prop.

ld/
	* testsuite/ld-xtensa/reloc-abs32-1.s,
	* testsuite/ld-xtensa/reloc-abs32-2.s,
	* testsuite/ld-xtensa/reloc-abs32-3.s,
	* testsuite/ld-xtensa/reloc-abs32.t,
	* testsuite/ld-xtensa/reloc-abs32.d,
	* testsuite/ld-xtensa/reloc-abs32-r.d: New tests, linking objects
	using R_XTENSA_32_ABS together with one using R_XTENSA_32.
	* testsuite/ld-xtensa/reloc-coalesce-abs32-1.s,
	* testsuite/ld-xtensa/reloc-coalesce-abs32-2.s,
	* testsuite/ld-xtensa/reloc-coalesce-abs32.d: New test.
	* testsuite/ld-xtensa/reloc-prop-abs32.s,
	* testsuite/ld-xtensa/reloc-prop-abs32.t,
	* testsuite/ld-xtensa/reloc-prop-abs32.d: New test.
	* testsuite/ld-xtensa/xtensa.exp: Run them.
---
 bfd/bfd-in2.h                                 |  6 ++
 bfd/elf32-xtensa.c                            | 78 +++++++++++++++----
 bfd/libbfd.h                                  |  1 +
 bfd/reloc.c                                   |  8 ++
 binutils/readelf.c                            |  3 +-
 gas/config.in                                 |  4 +
 gas/config/tc-xtensa.c                        | 36 ++++++++-
 gas/configure                                 | 29 ++++++-
 gas/configure.ac                              | 20 +++++
 gas/doc/as.texi                               |  1 +
 gas/doc/c-xtensa.texi                         | 11 +++
 .../gas/xtensa/pdiff-uleb128-norelax.d        |  2 +-
 .../gas/xtensa/reloc-abs32-no-rela.d          | 20 +++++
 gas/testsuite/gas/xtensa/reloc-abs32.d        | 18 +++++
 gas/testsuite/gas/xtensa/reloc-abs32.s        | 13 ++++
 ld/testsuite/ld-xtensa/reloc-abs32-1.s        | 15 ++++
 ld/testsuite/ld-xtensa/reloc-abs32-2.s        |  6 ++
 ld/testsuite/ld-xtensa/reloc-abs32-3.s        | 11 +++
 ld/testsuite/ld-xtensa/reloc-abs32-r.d        | 23 ++++++
 ld/testsuite/ld-xtensa/reloc-abs32.d          | 16 ++++
 ld/testsuite/ld-xtensa/reloc-abs32.t          |  5 ++
 .../ld-xtensa/reloc-coalesce-abs32-1.s        | 18 +++++
 .../ld-xtensa/reloc-coalesce-abs32-2.s        | 14 ++++
 ld/testsuite/ld-xtensa/reloc-coalesce-abs32.d | 21 +++++
 ld/testsuite/ld-xtensa/reloc-prop-abs32.d     | 13 ++++
 ld/testsuite/ld-xtensa/reloc-prop-abs32.s     | 19 +++++
 ld/testsuite/ld-xtensa/reloc-prop-abs32.t     |  5 ++
 ld/testsuite/ld-xtensa/xtensa.exp             |  5 ++
 28 files changed, 397 insertions(+), 24 deletions(-)
 create mode 100644 gas/testsuite/gas/xtensa/reloc-abs32-no-rela.d
 create mode 100644 gas/testsuite/gas/xtensa/reloc-abs32.d
 create mode 100644 gas/testsuite/gas/xtensa/reloc-abs32.s
 create mode 100644 ld/testsuite/ld-xtensa/reloc-abs32-1.s
 create mode 100644 ld/testsuite/ld-xtensa/reloc-abs32-2.s
 create mode 100644 ld/testsuite/ld-xtensa/reloc-abs32-3.s
 create mode 100644 ld/testsuite/ld-xtensa/reloc-abs32-r.d
 create mode 100644 ld/testsuite/ld-xtensa/reloc-abs32.d
 create mode 100644 ld/testsuite/ld-xtensa/reloc-abs32.t
 create mode 100644 ld/testsuite/ld-xtensa/reloc-coalesce-abs32-1.s
 create mode 100644 ld/testsuite/ld-xtensa/reloc-coalesce-abs32-2.s
 create mode 100644 ld/testsuite/ld-xtensa/reloc-coalesce-abs32.d
 create mode 100644 ld/testsuite/ld-xtensa/reloc-prop-abs32.d
 create mode 100644 ld/testsuite/ld-xtensa/reloc-prop-abs32.s
 create mode 100644 ld/testsuite/ld-xtensa/reloc-prop-abs32.t

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 711006471d1..abb0d30f2e3 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -6178,6 +6178,12 @@ enum bfd_reloc_code_real
      for virtually every function.  */
   BFD_RELOC_XTENSA_PDIFF_ULEB128,
 
+  /* Xtensa 32-bit absolute address, computed as S + A with the addend taken
+     only from the r_addend field.  Unlike R_XTENSA_32, to which BFD_RELOC_32
+     maps and which is partial_inplace, the contents of the relocated word do
+     not contribute to the result.  */
+  BFD_RELOC_XTENSA_32_ABS,
+
   /* 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 2c279bcbe95..d6b77c7c2c7 100644
--- a/bfd/elf32-xtensa.c
+++ b/bfd/elf32-xtensa.c
@@ -348,6 +348,13 @@ static reloc_howto_type elf_howto_table[] =
 	 bfd_elf_xtensa_reloc, "R_XTENSA_NDIFF32", false, 0, 0xffffffff, false),
   HOWTO (R_XTENSA_PDIFF_ULEB128, 0, 0, 0, false, 0, complain_overflow_dont,
 	 bfd_elf_xtensa_reloc, "R_XTENSA_PDIFF_ULEB128", false, 0, 0, false),
+
+  /* Absolute 32-bit address with the addend taken only from r_addend.
+     Unlike R_XTENSA_32 this is not partial_inplace, so the contents of
+     the relocated word do not contribute to the result.  */
+  HOWTO (R_XTENSA_32_ABS, 0, 4, 32, false, 0, complain_overflow_bitfield,
+	 bfd_elf_xtensa_reloc, "R_XTENSA_32_ABS",
+	 false, 0, 0xffffffff, false),
 };
 
 #if DEBUG_GEN_RELOC
@@ -415,6 +422,10 @@ elf_xtensa_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       TRACE ("BFD_RELOC_XTENSA_PDIFF_ULEB128");
       return &elf_howto_table[(unsigned) R_XTENSA_PDIFF_ULEB128 ];
 
+    case BFD_RELOC_XTENSA_32_ABS:
+      TRACE ("BFD_RELOC_XTENSA_32_ABS");
+      return &elf_howto_table[(unsigned) R_XTENSA_32_ABS ];
+
     case BFD_RELOC_XTENSA_RTLD:
       TRACE ("BFD_RELOC_XTENSA_RTLD");
       return &elf_howto_table[(unsigned) R_XTENSA_RTLD ];
@@ -854,6 +865,23 @@ property_table_matches (const void *ap, const void *bp)
 }
 
 
+/* Addend of relocation IREL.  R_XTENSA_32 is the only partial_inplace
+   relocation, so only for it does the relocated word in CONTENTS
+   contribute.  Other relocations, such as R_XTENSA_32_ABS, take the
+   addend from r_addend alone.  */
+
+static bfd_vma
+xtensa_reloc_addend (bfd *abfd, bfd_byte *contents,
+		     const Elf_Internal_Rela *irel)
+{
+  bfd_vma addend = irel->r_addend;
+
+  if (ELF32_R_TYPE (irel->r_info) == R_XTENSA_32)
+    addend += bfd_get_32 (abfd, contents + irel->r_offset);
+  return addend;
+}
+
+
 /* Get the literal table or property table entries for the given
    section.  Sets TABLE_P and returns the number of entries.  On
    error, returns a negative value.  */
@@ -952,14 +980,16 @@ xtensa_read_table_entries (bfd *abfd,
 	{
 	  bfd_vma sym_off;
 	  unsigned long r_symndx = ELF32_R_SYM (irel->r_info);
-	  BFD_ASSERT (ELF32_R_TYPE (irel->r_info) == R_XTENSA_32);
+	  BFD_ASSERT (ELF32_R_TYPE (irel->r_info) == R_XTENSA_32
+		      || ELF32_R_TYPE (irel->r_info) == R_XTENSA_32_ABS);
 
 	  if (get_elf_r_symndx_section (abfd, r_symndx) != section)
 	    continue;
 
 	  sym_off = get_elf_r_symndx_offset (abfd, r_symndx);
 	  BFD_ASSERT (sym_off == 0);
-	  address += (section_addr + sym_off + irel->r_addend);
+	  address = (section_addr + sym_off
+		     + xtensa_reloc_addend (abfd, table_data, irel));
 	}
       else
 	{
@@ -1148,6 +1178,7 @@ elf_xtensa_check_relocs (bfd *abfd,
 	  break;
 
 	case R_XTENSA_32:
+	case R_XTENSA_32_ABS:
 	  tls_type = GOT_NORMAL;
 	  is_got = true;
 	  break;
@@ -1951,6 +1982,7 @@ elf_xtensa_do_reloc (reloc_howto_type *howto,
       bfd_put_32 (abfd, relocation - self_address, contents + address);
       return bfd_reloc_ok;
 
+    case R_XTENSA_32_ABS:
     case R_XTENSA_PLT:
     case R_XTENSA_TLSDESC_FN:
     case R_XTENSA_TLSDESC_ARG:
@@ -2783,6 +2815,7 @@ elf_xtensa_relocate_section (struct bfd_link_info *info,
       switch (r_type)
 	{
 	case R_XTENSA_32:
+	case R_XTENSA_32_ABS:
 	case R_XTENSA_PLT:
 	  if (elf_hash_table (info)->dynamic_sections_created
 	      && (input_section->flags & SEC_ALLOC) != 0
@@ -2828,7 +2861,7 @@ elf_xtensa_relocate_section (struct bfd_link_info *info,
 		      outrel.r_addend = rel->r_addend;
 		      rel->r_addend = 0;
 
-		      if (r_type == R_XTENSA_32)
+		      if (r_type == R_XTENSA_32 || r_type == R_XTENSA_32_ABS)
 			{
 			  outrel.r_info =
 			    ELF32_R_INFO (h->dynindx, R_XTENSA_GLOB_DAT);
@@ -5202,6 +5235,19 @@ init_literal_value (literal_value *lit,
 }
 
 
+/* R_XTENSA_32 and R_XTENSA_32_ABS literals with the same target_offset hold
+   the same address, because r_reloc_init folds the in-place addend of
+   R_XTENSA_32 into target_offset.  */
+
+static unsigned
+literal_reloc_type (const r_reloc *r_rel)
+{
+  unsigned r_type = ELF32_R_TYPE (r_rel->rela.r_info);
+
+  return r_type == R_XTENSA_32_ABS ? R_XTENSA_32 : r_type;
+}
+
+
 static bool
 literal_value_equal (const literal_value *src1,
 		     const literal_value *src2,
@@ -5215,8 +5261,7 @@ literal_value_equal (const literal_value *src1,
   if (r_reloc_is_const (&src1->r_rel))
     return (src1->value == src2->value);
 
-  if (ELF32_R_TYPE (src1->r_rel.rela.r_info)
-      != ELF32_R_TYPE (src2->r_rel.rela.r_info))
+  if (literal_reloc_type (&src1->r_rel) != literal_reloc_type (&src2->r_rel))
     return false;
 
   if (src1->r_rel.target_offset != src2->r_rel.target_offset)
@@ -8847,10 +8892,11 @@ compute_removed_literals (bfd *abfd,
       irel = get_irel_at_offset (sec, internal_relocs,
 				 rel->r_rel.target_offset);
 
-      /* If the relocation on this is not a simple R_XTENSA_32 or
-	 R_XTENSA_PLT then do not consider it.  This may happen when
-	 the difference of two symbols is used in a literal.  */
+      /* If the relocation on this is not a simple R_XTENSA_32,
+	 R_XTENSA_32_ABS or R_XTENSA_PLT then do not consider it.  This may
+	 happen when the difference of two symbols is used in a literal.  */
       if (irel && (ELF32_R_TYPE (irel->r_info) != R_XTENSA_32
+		   && ELF32_R_TYPE (irel->r_info) != R_XTENSA_32_ABS
 		   && ELF32_R_TYPE (irel->r_info) != R_XTENSA_PLT))
 	continue;
 
@@ -10321,7 +10367,8 @@ shrink_dynamic_reloc_sections (struct bfd_link_info *info,
 
   dynamic_symbol = elf_xtensa_dynamic_symbol_p (h, info);
 
-  if ((r_type == R_XTENSA_32 || r_type == R_XTENSA_PLT)
+  if ((r_type == R_XTENSA_32 || r_type == R_XTENSA_32_ABS
+       || r_type == R_XTENSA_PLT)
       && (input_section->flags & SEC_ALLOC) != 0
       && (dynamic_symbol
 	  || (bfd_link_pic (info)
@@ -10787,19 +10834,18 @@ relax_property_section (bfd *abfd,
 		remove_this_rel = true;
 	    }
 	  else if (offset_rel
-		   && ELF32_R_TYPE (offset_rel->r_info) == R_XTENSA_32)
+		   && (ELF32_R_TYPE (offset_rel->r_info) == R_XTENSA_32
+		       || ELF32_R_TYPE (offset_rel->r_info) == R_XTENSA_32_ABS))
 	    {
 	      if (last_irel)
 		{
 		  flagword old_flags;
 		  bfd_vma old_size =
 		    bfd_get_32 (abfd, &contents[last_irel->r_offset + 4]);
-		  bfd_vma old_address =
-		    (last_irel->r_addend
-		     + bfd_get_32 (abfd, &contents[last_irel->r_offset]));
-		  bfd_vma new_address =
-		    (offset_rel->r_addend
-		     + bfd_get_32 (abfd, &contents[actual_offset]));
+		  bfd_vma old_address = xtensa_reloc_addend (abfd, contents,
+							    last_irel);
+		  bfd_vma new_address = xtensa_reloc_addend (abfd, contents,
+							    offset_rel);
 		  if (is_full_prop_section)
 		    old_flags = bfd_get_32
 		      (abfd, &contents[last_irel->r_offset + 8]);
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index c3fa76125e2..038f2b56c65 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2797,6 +2797,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_XTENSA_NDIFF16",
   "BFD_RELOC_XTENSA_NDIFF32",
   "BFD_RELOC_XTENSA_PDIFF_ULEB128",
+  "BFD_RELOC_XTENSA_32_ABS",
   "BFD_RELOC_Z80_DISP8",
   "BFD_RELOC_Z80_BYTE0",
   "BFD_RELOC_Z80_BYTE1",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 555028bdf19..c7c611fb844 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -6043,6 +6043,14 @@ ENUMDOC
   by such a difference, which DWARF 5 location and range lists produce
   for virtually every function.
 
+ENUM
+  BFD_RELOC_XTENSA_32_ABS
+ENUMDOC
+  Xtensa 32-bit absolute address, computed as S + A with the addend taken
+  only from the r_addend field.  Unlike R_XTENSA_32, to which BFD_RELOC_32
+  maps and which is partial_inplace, the contents of the relocated word do
+  not contribute to the result.
+
 ENUM
   BFD_RELOC_Z80_DISP8
 ENUMDOC
diff --git a/binutils/readelf.c b/binutils/readelf.c
index b86bf3eb294..97965d633e8 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -15700,7 +15700,8 @@ is_32bit_abs_reloc (Filedata * filedata, unsigned int reloc_type)
       return reloc_type == 1; /* R_XSTROMY16_32.  */
     case EM_XTENSA_OLD:
     case EM_XTENSA:
-      return reloc_type == 1; /* R_XTENSA_32.  */
+      /* R_XTENSA_32 or R_XTENSA_32_ABS.  */
+      return reloc_type == 1 || reloc_type == 64;
     case EM_Z80:
       return reloc_type == 6; /* R_Z80_32.  */
     default:
diff --git a/gas/config.in b/gas/config.in
index ae5f41f7058..563c79bd47a 100644
--- a/gas/config.in
+++ b/gas/config.in
@@ -57,6 +57,10 @@
 /* Define default value for RISC-V -mpriv-spec */
 #undef DEFAULT_RISCV_PRIV_SPEC
 
+/* Define to 1 if you want to emit R_XTENSA_32_ABS for 32-bit absolute data
+   by default. */
+#undef DEFAULT_R_XTENSA_32_ABS
+
 /* Define to 1 if you want to emit SFrames by default. */
 #undef DEFAULT_SFRAME
 
diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c
index f76067d5bb2..e642ce03ac3 100644
--- a/gas/config/tc-xtensa.c
+++ b/gas/config/tc-xtensa.c
@@ -494,6 +494,10 @@ static fixS *xg_append_jump (fragS *fragP, symbolS *sym, offsetT offset);
 static void xtensa_maybe_create_literal_pool_frag (bool, bool);
 static bool auto_litpools = false;
 static int auto_litpool_limit = 0;
+/* Loaders of relocatable objects, such as kernel module loaders, may only
+   know R_XTENSA_32, so R_XTENSA_32_ABS is the default only when configured
+   with --enable-r-xtensa-32-abs.  */
+static bool use_abs32_rela = DEFAULT_R_XTENSA_32_ABS;
 static bool xtensa_is_init_fini (segT seg);
 
 /* Alignment Functions.  */
@@ -733,6 +737,9 @@ enum
 
   option_abi_windowed,
   option_abi_call0,
+
+  option_abs32_rela,
+  option_no_abs32_rela,
 };
 
 const char md_shortopts[] = "";
@@ -817,6 +824,9 @@ const struct option md_longopts[] =
   { "abi-windowed", no_argument, NULL, option_abi_windowed },
   { "abi-call0", no_argument, NULL, option_abi_call0 },
 
+  { "abs32-rela", no_argument, NULL, option_abs32_rela },
+  { "no-abs32-rela", no_argument, NULL, option_no_abs32_rela },
+
   { NULL, no_argument, NULL, 0 }
 };
 
@@ -1052,6 +1062,14 @@ md_parse_option (int c, const char *arg)
       elf32xtensa_abi = XTHAL_ABI_CALL0;
       return 1;
 
+    case option_abs32_rela:
+      use_abs32_rela = true;
+      return 1;
+
+    case option_no_abs32_rela:
+      use_abs32_rela = false;
+      return 1;
+
     default:
       return 0;
     }
@@ -1086,7 +1104,12 @@ Xtensa options:\n\
   --[no-]separate-prop-tables\n\
                           [Do not] place Xtensa property records into\n\
                           individual property sections for each section.\n\
-                          Default is to generate single property section.\n", stream);
+                          Default is to generate single property section.\n\
+  --[no-]abs32-rela       [Do not] emit R_XTENSA_32_ABS rather than\n\
+                          R_XTENSA_32 for 32-bit absolute data.\n", stream);
+  fprintf (stream, "\
+                          Default is %s.\n",
+	   DEFAULT_R_XTENSA_32_ABS ? "R_XTENSA_32_ABS" : "R_XTENSA_32");
 }
 
 
@@ -6160,6 +6183,7 @@ arelent *
 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
 {
   arelent *reloc;
+  bfd_reloc_code_real_type r_type;
 
   reloc = notes_alloc (sizeof (arelent));
   reloc->sym_ptr_ptr = notes_alloc (sizeof (asymbol *));
@@ -6172,18 +6196,22 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
 
   reloc->addend = fixp->fx_offset;
 
-  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
+  r_type = fixp->fx_r_type;
+  if (r_type == BFD_RELOC_32 && use_abs32_rela)
+    r_type = BFD_RELOC_XTENSA_32_ABS;
+
+  reloc->howto = bfd_reloc_type_lookup (stdoutput, r_type);
   if (reloc->howto == NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
 		    _("cannot represent `%s' relocation in object file"),
-		    bfd_get_reloc_code_name (fixp->fx_r_type));
+		    bfd_get_reloc_code_name (r_type));
       return NULL;
     }
 
   if (!fixp->fx_pcrel != !reloc->howto->pc_relative)
     as_fatal (_("internal error; cannot generate `%s' relocation"),
-	      bfd_get_reloc_code_name (fixp->fx_r_type));
+	      bfd_get_reloc_code_name (r_type));
 
   return reloc;
 }
diff --git a/gas/configure b/gas/configure
index 8afaf2729ed..6b5128475e9 100755
--- a/gas/configure
+++ b/gas/configure
@@ -826,6 +826,7 @@ enable_generate_build_notes
 enable_mips_fix_loongson3_llsc
 enable_x86_used_note
 enable_default_riscv_attribute
+enable_r_xtensa_32_abs
 enable_werror
 enable_build_warnings
 with_cpu
@@ -1507,6 +1508,9 @@ Optional Features:
   --enable-x86-used-note  generate GNU x86 used ISA and feature properties
   --enable-default-riscv-attribute
                           generate RISC-V arch attribute by default
+  --enable-r-xtensa-32-abs
+                          emit R_XTENSA_32_ABS for 32-bit absolute data by
+                          default
   --enable-werror         treat compile warnings as errors
   --enable-build-warnings enable build-time compiler warnings
   --disable-nls           do not use Native Language Support
@@ -11152,7 +11156,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11155 "configure"
+#line 11159 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11258,7 +11262,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11261 "configure"
+#line 11265 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12034,6 +12038,18 @@ if test "${enable_default_riscv_attribute+set}" = set; then :
 esac
 fi
 
+# Decide if the Xtensa assembler should default to emitting R_XTENSA_32_ABS
+# rather than R_XTENSA_32 for 32-bit absolute data.
+ac_default_r_xtensa_32_abs=unset
+# Provide a configuration option to override the default.
+# Check whether --enable-r-xtensa-32-abs was given.
+if test "${enable_r_xtensa_32_abs+set}" = set; then :
+  enableval=$enable_r_xtensa_32_abs; case "${enableval}" in
+  yes)  ac_default_r_xtensa_32_abs=1 ;;
+  no)   ac_default_r_xtensa_32_abs=0 ;;
+esac
+fi
+
 using_cgen=no
 
 
@@ -13127,6 +13143,15 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
+if test ${ac_default_r_xtensa_32_abs} = unset; then
+  ac_default_r_xtensa_32_abs=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_R_XTENSA_32_ABS $ac_default_r_xtensa_32_abs
+_ACEOF
+
+
 if test ${ac_default_mips_fix_loongson3_llsc} = unset; then
   ac_default_mips_fix_loongson3_llsc=0
 fi
diff --git a/gas/configure.ac b/gas/configure.ac
index 4dc7c019ce2..9d68bdb1c85 100644
--- a/gas/configure.ac
+++ b/gas/configure.ac
@@ -172,6 +172,18 @@ AC_ARG_ENABLE(default-riscv-attribute,
   no)   ac_default_generate_riscv_attr=0 ;;
 esac])dnl
 
+# Decide if the Xtensa assembler should default to emitting R_XTENSA_32_ABS
+# rather than R_XTENSA_32 for 32-bit absolute data.
+ac_default_r_xtensa_32_abs=unset
+# Provide a configuration option to override the default.
+AC_ARG_ENABLE(r-xtensa-32-abs,
+	      AS_HELP_STRING([--enable-r-xtensa-32-abs],
+	      [emit R_XTENSA_32_ABS for 32-bit absolute data by default]),
+[case "${enableval}" in
+  yes)  ac_default_r_xtensa_32_abs=1 ;;
+  no)   ac_default_r_xtensa_32_abs=0 ;;
+esac])dnl
+
 using_cgen=no
 
 AM_BINUTILS_WARNINGS
@@ -778,6 +790,14 @@ AC_DEFINE_UNQUOTED(DEFAULT_RISCV_ATTR,
   $ac_default_generate_riscv_attr,
   [Define to 1 if you want to generate RISC-V arch attribute by default.])
 
+if test ${ac_default_r_xtensa_32_abs} = unset; then
+  ac_default_r_xtensa_32_abs=0
+fi
+AC_DEFINE_UNQUOTED(DEFAULT_R_XTENSA_32_ABS,
+  $ac_default_r_xtensa_32_abs,
+  [Define to 1 if you want to emit R_XTENSA_32_ABS for 32-bit absolute data
+   by default.])
+
 if test ${ac_default_mips_fix_loongson3_llsc} = unset; then
   ac_default_mips_fix_loongson3_llsc=0
 fi
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index 070ead47246..c43d48b000f 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -651,6 +651,7 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}.
  [@b{--rename-section} @var{oldname}=@var{newname}]
  [@b{--[no-]trampolines}]
  [@b{--abi-windowed}|@b{--abi-call0}]
+ [@b{--[no-]abs32-rela}]
 @end ifset
 @ifset Z80
 
diff --git a/gas/doc/c-xtensa.texi b/gas/doc/c-xtensa.texi
index 02913621c63..2e571ea03a6 100644
--- a/gas/doc/c-xtensa.texi
+++ b/gas/doc/c-xtensa.texi
@@ -130,6 +130,17 @@ Choose ABI tag written to the @code{.xtensa.info} section.  ABI tag
 indicates ABI of the assembly code.  A warning is issued by the linker
 on an attempt to link object files with inconsistent ABI tags.
 Default ABI is chosen by the Xtensa core configuration.
+
+@item --abs32-rela | --no-abs32-rela
+@kindex --abs32-rela
+@kindex --no-abs32-rela
+Choose the relocation emitted for 32-bit absolute data.
+@samp{--abs32-rela} emits @code{R_XTENSA_32_ABS}, which keeps the whole
+addend in the relocation and is the form produced by LLVM.
+@samp{--no-abs32-rela} emits @code{R_XTENSA_32}, which may also keep the
+addend in the relocated word and is understood by older linkers and by
+loaders of relocatable objects.  The default is @samp{--no-abs32-rela},
+unless the assembler was configured with @samp{--enable-r-xtensa-32-abs}.
 @end table
 
 @c man end
diff --git a/gas/testsuite/gas/xtensa/pdiff-uleb128-norelax.d b/gas/testsuite/gas/xtensa/pdiff-uleb128-norelax.d
index dcd4641083f..19a64feca91 100644
--- a/gas/testsuite/gas/xtensa/pdiff-uleb128-norelax.d
+++ b/gas/testsuite/gas/xtensa/pdiff-uleb128-norelax.d
@@ -11,7 +11,7 @@
 
 RELOCATION RECORDS FOR \[.xt.prop\]:
 OFFSET +TYPE +VALUE
-0+ R_XTENSA_32 +.text.*
+0+ R_XTENSA_32(_ABS)? +.text.*
 
 Contents of section .debug_info:
  0000 c801.*
diff --git a/gas/testsuite/gas/xtensa/reloc-abs32-no-rela.d b/gas/testsuite/gas/xtensa/reloc-abs32-no-rela.d
new file mode 100644
index 00000000000..54af2a41eb5
--- /dev/null
+++ b/gas/testsuite/gas/xtensa/reloc-abs32-no-rela.d
@@ -0,0 +1,20 @@
+#as: --no-abs32-rela
+#source: reloc-abs32.s
+#objdump: -r -s -j .rodata
+#name: 32-bit absolute relocations with --no-abs32-rela
+
+# R_XTENSA_32 is partial_inplace, so the addends of references to the
+# section symbol are held in the relocated words.  Both byte orders are
+# accepted.
+
+.*: +file format .*xtensa.*
+
+RELOCATION RECORDS FOR \[\.rodata\]:
+OFFSET +TYPE +VALUE
+0+00 R_XTENSA_32 +\.text
+0+04 R_XTENSA_32 +\.text
+0+08 R_XTENSA_32 +gsym
+0+0c R_XTENSA_32 +gsym\+0x0+8
+
+Contents of section \.rodata:
+ 0000 (00000002 00000012|02000000 12000000) 00000000 00000000 .*
diff --git a/gas/testsuite/gas/xtensa/reloc-abs32.d b/gas/testsuite/gas/xtensa/reloc-abs32.d
new file mode 100644
index 00000000000..f55369f5f98
--- /dev/null
+++ b/gas/testsuite/gas/xtensa/reloc-abs32.d
@@ -0,0 +1,18 @@
+#as: --abs32-rela
+#objdump: -r -s -j .rodata
+#name: 32-bit absolute relocations with --abs32-rela
+
+# R_XTENSA_32_ABS keeps the addend in r_addend and leaves the relocated word
+# zero.
+
+.*: +file format .*xtensa.*
+
+RELOCATION RECORDS FOR \[\.rodata\]:
+OFFSET +TYPE +VALUE
+0+00 R_XTENSA_32_ABS +\.text\+0x0+2
+0+04 R_XTENSA_32_ABS +\.text\+0x0+12
+0+08 R_XTENSA_32_ABS +gsym
+0+0c R_XTENSA_32_ABS +gsym\+0x0+8
+
+Contents of section \.rodata:
+ 0000 00000000 00000000 00000000 00000000 .*
diff --git a/gas/testsuite/gas/xtensa/reloc-abs32.s b/gas/testsuite/gas/xtensa/reloc-abs32.s
new file mode 100644
index 00000000000..80a5430c505
--- /dev/null
+++ b/gas/testsuite/gas/xtensa/reloc-abs32.s
@@ -0,0 +1,13 @@
+	.text
+	.global gsym
+	.skip 2
+lsym:
+	.skip 2
+gsym:
+	.skip 2
+
+	.section .rodata
+	.word lsym
+	.word lsym + 16
+	.word gsym
+	.word gsym + 8
diff --git a/ld/testsuite/ld-xtensa/reloc-abs32-1.s b/ld/testsuite/ld-xtensa/reloc-abs32-1.s
new file mode 100644
index 00000000000..4abf9c79430
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/reloc-abs32-1.s
@@ -0,0 +1,15 @@
+	.text
+	.global _start
+	.global target
+_start:
+	.skip 2
+target:
+	.skip 2
+
+	# Relocations as LLVM emits them: R_XTENSA_32_ABS with the addend in
+	# r_addend and a zero relocated word.
+	.section .rodata
+	.reloc ., R_XTENSA_32_ABS, target
+	.word 0
+	.reloc ., R_XTENSA_32_ABS, target + 8
+	.word 0
diff --git a/ld/testsuite/ld-xtensa/reloc-abs32-2.s b/ld/testsuite/ld-xtensa/reloc-abs32-2.s
new file mode 100644
index 00000000000..9560d9fdaf3
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/reloc-abs32-2.s
@@ -0,0 +1,6 @@
+	# GNU as emits R_XTENSA_32, which is partial_inplace, so the addend
+	# may be held in the relocated word rather than in r_addend.
+	.section .rodata
+legacy:
+	.word 8
+	.reloc legacy, R_XTENSA_32, target
diff --git a/ld/testsuite/ld-xtensa/reloc-abs32-3.s b/ld/testsuite/ld-xtensa/reloc-abs32-3.s
new file mode 100644
index 00000000000..19d0a08f9ac
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/reloc-abs32-3.s
@@ -0,0 +1,11 @@
+	# A local label is referenced through the section symbol, so a
+	# relocatable link must rebase the addend by the output offset of
+	# this .text and keep the result in r_addend.
+	.text
+	.skip 4
+.Llocal:
+	.skip 4
+
+	.section .rodata
+	.reloc ., R_XTENSA_32_ABS, .Llocal + 4
+	.word 0
diff --git a/ld/testsuite/ld-xtensa/reloc-abs32-r.d b/ld/testsuite/ld-xtensa/reloc-abs32-r.d
new file mode 100644
index 00000000000..26088adcf30
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/reloc-abs32-r.d
@@ -0,0 +1,23 @@
+#source: reloc-abs32-1.s
+#source: reloc-abs32-2.s
+#source: reloc-abs32-3.s
+#ld: -r
+#objdump: -r -s -j .rodata
+#name: 32-bit absolute relocations, relocatable link
+
+# R_XTENSA_32_ABS keeps its addend in r_addend and leaves the relocated word
+# zero, including the reference to .text whose addend is rebased by the 4
+# bytes of .text that precede it.  The partial_inplace R_XTENSA_32 keeps its
+# addend of 8 in the relocated word.  Both byte orders are accepted.
+
+.*: +file format .*xtensa.*
+
+RELOCATION RECORDS FOR \[\.rodata\]:
+OFFSET +TYPE +VALUE
+0+00 R_XTENSA_32_ABS +target
+0+04 R_XTENSA_32_ABS +target\+0x0+8
+0+08 R_XTENSA_32 +target
+0+0c R_XTENSA_32_ABS +\.text\+0x0+c
+
+Contents of section \.rodata:
+ 0000 00000000 00000000 (00000008|08000000) 00000000 .*
diff --git a/ld/testsuite/ld-xtensa/reloc-abs32.d b/ld/testsuite/ld-xtensa/reloc-abs32.d
new file mode 100644
index 00000000000..170a2b5421b
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/reloc-abs32.d
@@ -0,0 +1,16 @@
+#source: reloc-abs32-1.s
+#source: reloc-abs32-2.s
+#source: reloc-abs32-3.s
+#ld: -T reloc-abs32.t
+#objdump: -s -j .rodata
+#name: 32-bit absolute relocations
+
+# target is at 0x1002 and local at 0x1008.  The first two words and the
+# last one use R_XTENSA_32_ABS and take their addends from r_addend; the
+# third uses the partial_inplace R_XTENSA_32 and takes its addend of 8 from
+# the relocated word.  Both byte orders are accepted.
+
+.*: +file format .*xtensa.*
+
+Contents of section \.rodata:
+ 100c (00001002 0000100a 0000100a 0000100c|02100000 0a100000 0a100000 0c100000).*
diff --git a/ld/testsuite/ld-xtensa/reloc-abs32.t b/ld/testsuite/ld-xtensa/reloc-abs32.t
new file mode 100644
index 00000000000..b4d18b24a1c
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/reloc-abs32.t
@@ -0,0 +1,5 @@
+SECTIONS
+{
+  .text 0x00001000 : { *(.literal .text) }
+  .rodata : { *(.rodata) }
+}
diff --git a/ld/testsuite/ld-xtensa/reloc-coalesce-abs32-1.s b/ld/testsuite/ld-xtensa/reloc-coalesce-abs32-1.s
new file mode 100644
index 00000000000..cd1515f9f86
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/reloc-coalesce-abs32-1.s
@@ -0,0 +1,18 @@
+	.global foo
+	.data
+	.global g_name
+	.align 4
+g_name:
+.Lg_name:
+	.word 0xffffffff
+	.text
+	.global main
+	.align 4
+main:
+	entry a5,16
+	movi a5,20000
+	# Through the section symbol, so R_XTENSA_32 holds the addend in the
+	# literal word.
+	movi a6,.Lg_name+4
+	call8 foo
+	ret
diff --git a/ld/testsuite/ld-xtensa/reloc-coalesce-abs32-2.s b/ld/testsuite/ld-xtensa/reloc-coalesce-abs32-2.s
new file mode 100644
index 00000000000..3728ad8ba12
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/reloc-coalesce-abs32-2.s
@@ -0,0 +1,14 @@
+	# A literal as LLVM emits it: R_XTENSA_32_ABS with the addend in
+	# r_addend and a zero literal word.
+	.text
+	.global foo
+	.global g_name
+	.align 4
+	.literal .Lg_name, 0
+	.reloc .Lg_name, R_XTENSA_32_ABS, g_name + 4
+foo:
+	entry a5,16
+	movi a5,20000
+	l32r a6,.Lg_name
+	movi a7,50000
+	ret
diff --git a/ld/testsuite/ld-xtensa/reloc-coalesce-abs32.d b/ld/testsuite/ld-xtensa/reloc-coalesce-abs32.d
new file mode 100644
index 00000000000..ac27c83facc
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/reloc-coalesce-abs32.d
@@ -0,0 +1,21 @@
+#source: reloc-coalesce-abs32-1.s
+#source: reloc-coalesce-abs32-2.s
+#as: --no-abs32-rela
+#ld: -T coalesce.t
+#objdump: -d
+#name: coalesce R_XTENSA_32 and R_XTENSA_32_ABS literals
+
+# Both objects load g_name + 4, one through R_XTENSA_32 with the addend in
+# the literal word and one through R_XTENSA_32_ABS with the addend in
+# r_addend.  The two literals must be coalesced, leaving three literals
+# before main, and both loads must still see g_name + 4.
+
+#...
+0000000c <main>:
+#...
+ +[0-9a-f]+:	[0-9a-f]+ +	l32r	a6, 4 <main-0x8> \([0-9a-f]+ <g_name\+0x4>\)
+#...
+[0-9a-f]+ <foo>:
+#...
+ +[0-9a-f]+:	[0-9a-f]+ +	l32r	a6, 4 <main-0x8> \([0-9a-f]+ <g_name\+0x4>\)
+#pass
diff --git a/ld/testsuite/ld-xtensa/reloc-prop-abs32.d b/ld/testsuite/ld-xtensa/reloc-prop-abs32.d
new file mode 100644
index 00000000000..eda00cccf38
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/reloc-prop-abs32.d
@@ -0,0 +1,13 @@
+#source: reloc-prop-abs32.s
+#ld: -T reloc-prop-abs32.t
+#objdump: -s -j .xt.prop
+#name: R_XTENSA_32_ABS property merge ignores relocated word
+
+# The addends alone place the ranges at .text+0 and .text+4, so they are
+# adjacent and must merge into one entry of size 8 at 0x1000.  Both byte
+# orders are accepted.
+
+.*: +file format .*xtensa.*
+
+Contents of section \.xt\.prop:
+ 1008 (00001000 00000008 00000002|00100000 08000000 02000000).*
diff --git a/ld/testsuite/ld-xtensa/reloc-prop-abs32.s b/ld/testsuite/ld-xtensa/reloc-prop-abs32.s
new file mode 100644
index 00000000000..1de962ac1c1
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/reloc-prop-abs32.s
@@ -0,0 +1,19 @@
+	# Two adjacent instruction ranges.  R_XTENSA_32_ABS keeps the address in
+	# r_addend; the relocated words are non-zero and must not be added.
+	# Adding them makes the ranges non-adjacent, so the linker will not
+	# merge the entries.
+	.section .xt.prop
+	.reloc ., R_XTENSA_32_ABS, .text
+	.word 0x10
+	.word 4
+	.word 2			# XTENSA_PROP_INSN
+
+	.reloc ., R_XTENSA_32_ABS, .text + 4
+	.word 0x20
+	.word 4
+	.word 2			# XTENSA_PROP_INSN
+
+	.text
+	.global _start
+_start:
+	.skip 8
diff --git a/ld/testsuite/ld-xtensa/reloc-prop-abs32.t b/ld/testsuite/ld-xtensa/reloc-prop-abs32.t
new file mode 100644
index 00000000000..b89e47c8c69
--- /dev/null
+++ b/ld/testsuite/ld-xtensa/reloc-prop-abs32.t
@@ -0,0 +1,5 @@
+SECTIONS
+{
+  .text 0x1000 : { *(.text) }
+  .xt.prop : { *(.xt.prop) }
+}
diff --git a/ld/testsuite/ld-xtensa/xtensa.exp b/ld/testsuite/ld-xtensa/xtensa.exp
index 66a6b7a60da..bccd8a2b8f3 100644
--- a/ld/testsuite/ld-xtensa/xtensa.exp
+++ b/ld/testsuite/ld-xtensa/xtensa.exp
@@ -44,4 +44,9 @@ run_dump_test "relax-undef-weak-local-pie"
 run_dump_test "relax-undef-weak-shared"
 run_dump_test "relax-undef-weak-local-shared"
 
+run_dump_test "reloc-abs32"
+run_dump_test "reloc-abs32-r"
+run_dump_test "reloc-coalesce-abs32"
+run_dump_test "reloc-prop-abs32"
+
 run_dump_test "startstop"
-- 
2.55.0



More information about the Binutils mailing list