[PATCH 3/3] RISC-V: Added DT_RELR support

Nelson Chu nelson@rivosinc.com
Sat Jun 7 08:36:41 GMT 2025


Porting by refering aarch64 and loongarch implementations.

1. RISC-V and loongarch both have relaxations, so there is also the same thing
that it's not safe to do relxations when updating the section layouts for relr.

2. RISC-V does not usually pre-fill values for R_RISCV_RELATIVE relocation, but
relr needs, so added *.d test cases to make sure the contents of relr are
pre-filled (relocated).

3. For relr readelf, added is_riscv_special_symbol_name to filter following
special symbols:
* mapping symbols
* __DATA_BEGIN__, __SDATA_BEGIN__ and __BSS_END__, which are only used for
counting gp in riscv.
---
 bfd/elfnn-riscv.c                             | 512 +++++++++++++++++-
 binutils/readelf.c                            |  17 +
 binutils/testsuite/lib/binutils-common.exp    |   3 +-
 ld/emulparams/elf32lriscv.sh                  |   1 +
 ld/emulparams/elf64lriscv.sh                  |   1 +
 ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp    |  51 ++
 .../ld-riscv-elf/relr-align-rv32-pic.d        |  23 +
 .../ld-riscv-elf/relr-align-rv32-pic.rd       |  18 +
 .../ld-riscv-elf/relr-align-rv64-pic.d        |  41 ++
 .../ld-riscv-elf/relr-align-rv64-pic.rd       |  18 +
 ld/testsuite/ld-riscv-elf/relr-align.s        | 114 ++++
 .../ld-riscv-elf/relr-data-rv32-pic.d         |  22 +
 .../ld-riscv-elf/relr-data-rv32-pic.rd        |  14 +
 .../ld-riscv-elf/relr-data-rv32-pie.d         |  22 +
 .../ld-riscv-elf/relr-data-rv32-pie.rd        |  14 +
 .../ld-riscv-elf/relr-data-rv64-pic.d         |  22 +
 .../ld-riscv-elf/relr-data-rv64-pic.rd        |  14 +
 .../ld-riscv-elf/relr-data-rv64-pie.d         |  22 +
 .../ld-riscv-elf/relr-data-rv64-pie.rd        |  14 +
 ld/testsuite/ld-riscv-elf/relr-data.s         |  79 +++
 ld/testsuite/ld-riscv-elf/relr-discard-pic.d  |  14 +
 ld/testsuite/ld-riscv-elf/relr-discard-pie.d  |  11 +
 ld/testsuite/ld-riscv-elf/relr-got-rv32-pic.d |  21 +
 .../ld-riscv-elf/relr-got-rv32-pic.rd         |  11 +
 ld/testsuite/ld-riscv-elf/relr-got-rv32-pie.d |  21 +
 .../ld-riscv-elf/relr-got-rv32-pie.rd         |  11 +
 ld/testsuite/ld-riscv-elf/relr-got-rv64-pic.d |  23 +
 .../ld-riscv-elf/relr-got-rv64-pic.rd         |  11 +
 ld/testsuite/ld-riscv-elf/relr-got-rv64-pie.d |  23 +
 .../ld-riscv-elf/relr-got-rv64-pie.rd         |  11 +
 ld/testsuite/ld-riscv-elf/relr-got.s          |  31 ++
 ld/testsuite/ld-riscv-elf/relr-relocs.ld      |  23 +
 ld/testsuite/ld-riscv-elf/relr-text-pic.d     |  14 +
 ld/testsuite/ld-riscv-elf/relr-text-pie.d     |  14 +
 ld/testsuite/ld-riscv-elf/relr-text.s         |  10 +
 35 files changed, 1251 insertions(+), 20 deletions(-)
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-align-rv32-pic.d
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-align-rv32-pic.rd
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-align-rv64-pic.d
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-align-rv64-pic.rd
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-align.s
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-data-rv32-pic.d
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-data-rv32-pic.rd
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-data-rv32-pie.d
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-data-rv32-pie.rd
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-data-rv64-pic.d
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-data-rv64-pic.rd
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-data-rv64-pie.d
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-data-rv64-pie.rd
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-data.s
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-discard-pic.d
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-discard-pie.d
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-got-rv32-pic.d
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-got-rv32-pic.rd
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-got-rv32-pie.d
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-got-rv32-pie.rd
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-got-rv64-pic.d
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-got-rv64-pic.rd
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-got-rv64-pie.d
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-got-rv64-pie.rd
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-got.s
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-relocs.ld
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-text-pic.d
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-text-pie.d
 create mode 100644 ld/testsuite/ld-riscv-elf/relr-text.s

diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 2341447c421..4f29774f325 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -77,21 +77,27 @@
        && (H)->type == STT_GNU_IFUNC \
        && ((SEC)->flags & SEC_CODE) == 0))
 
-/* True if dynamic relocation should be generated.  */
-#define RISCV_GENERATE_DYNAMIC_RELOC(PCREL, INFO, H, RESOLVED_TO_ZERO) \
-  ((bfd_link_pic (INFO) \
-    && ((H) == NULL \
-	|| (ELF_ST_VISIBILITY ((H)->other) == STV_DEFAULT && !(RESOLVED_TO_ZERO)) \
-	|| (H)->root.type != bfd_link_hash_undefweak) \
-    && (!(PCREL) \
-	|| !SYMBOL_CALLS_LOCAL ((INFO), (H)))) \
-   || (!bfd_link_pic (INFO) \
-       && (H) != NULL \
-       && (H)->dynindx != -1 \
-       && !(H)->non_got_ref \
-       && (((H)->def_dynamic && !(H)->def_regular) \
-	   || (H)->root.type == bfd_link_hash_undefweak \
-	   || (H)->root.type == bfd_link_hash_undefined)))
+/* True if dynamic relocation should be generated when generating a shared
+   library or PIE.  */
+#define RISCV_GENERATE_DYNAMIC_RELOC_FOR_PIC(PCREL, INFO, H, RESOLVED_TO_ZERO) \
+  (bfd_link_pic (INFO) \
+   && ((H) == NULL \
+       || (ELF_ST_VISIBILITY ((H)->other) == STV_DEFAULT && !(RESOLVED_TO_ZERO)) \
+       || (H)->root.type != bfd_link_hash_undefweak) \
+   && (!(PCREL) \
+       || !SYMBOL_CALLS_LOCAL ((INFO), (H))))
+
+/* True if dynamic relocation should be generated when generating an
+   executable.  We may need to keep relocations for symbols satisfied
+   by a dynamic library if we manage to avoid.  */
+#define RISCV_GENERATE_DYNAMIC_RELOC_FOR_EXE(INFO, H) \
+  (!bfd_link_pic (INFO) \
+   && (H) != NULL \
+   && (H)->dynindx != -1 \
+   && !(H)->non_got_ref \
+   && (((H)->def_dynamic && !(H)->def_regular) \
+	 || (H)->root.type == bfd_link_hash_undefweak \
+	 || (H)->root.type == bfd_link_hash_undefined))
 
 /* True if this input relocation should be copied to output.  H->dynindx
    may be -1 if this symbol was marked to become local.  */
@@ -200,6 +206,39 @@ elfNN_riscv_mkobject (bfd *abfd)
 				  sizeof (struct _bfd_riscv_elf_obj_tdata));
 }
 
+struct relr_entry
+{
+  asection *sec;
+  bfd_vma off;
+};
+
+typedef struct _riscv_elf_section_data
+{
+  struct bfd_elf_section_data elf;
+
+  /* Handle interactions between DT_RELR and relaxation.  */
+  struct relr_entry *relr;
+} _riscv_elf_section_data;
+
+#define riscv_elf_section_data(sec) \
+  ((_riscv_elf_section_data *) elf_section_data (sec))
+
+/* Allocate target specific section data.  */
+
+static bool
+elfNN_riscv_new_section_hook (bfd *abfd, asection *sec)
+{
+  if (!sec->used_by_bfd)
+    {
+      struct _riscv_elf_section_data *sdata;
+      sdata = bfd_zalloc (abfd, sizeof (*sdata));
+      if (sdata == NULL)
+	return false;
+      sec->used_by_bfd = sdata;
+    }
+  return _bfd_elf_new_section_hook (abfd, sec);
+}
+
 #include "elf/common.h"
 #include "elf/internal.h"
 
@@ -232,6 +271,17 @@ struct riscv_elf_link_hash_table
 
   /* Relocations for variant CC symbols may be present.  */
   int variant_cc;
+
+  /* Array of RELATIVE relocs to be emitted in DT_RELR format.  */
+  bfd_size_type relr_alloc;
+  bfd_size_type relr_count;
+  struct relr_entry *relr;
+  /* Sorted output addresses of above RELATIVE relocs.  */
+  bfd_vma *relr_sorted;
+  /* Layout recomputation count.  */
+  bfd_size_type relr_layout_iter;
+  /* The section layouts are updating for relr.  */
+  bool layout_mutating_for_relr;
 };
 
 /* Instruction access functions. */
@@ -1499,6 +1549,369 @@ allocate_local_ifunc_dynrelocs (void **slot, void *inf)
   return allocate_ifunc_dynrelocs (h, inf);
 }
 
+/* Record a relative relocation that will be emitted packed (DT_RELR).
+   Called after relocation sections are sized, so undo the size accounting
+   for this relocation.  */
+
+static bool
+record_relr (struct riscv_elf_link_hash_table *htab, asection *sec,
+	     bfd_vma off, asection *sreloc)
+{
+  struct relr_entry **sec_relr = &riscv_elf_section_data (sec)->relr;
+
+  /* Undo the relocation section size accounting.  */
+  BFD_ASSERT (sreloc->size >= sizeof (ElfNN_External_Rela));
+  sreloc->size -= sizeof (ElfNN_External_Rela);
+
+  /* The packing format uses the last bit of the address so that
+     must be aligned.  We don't pack relocations that may not be
+     aligned even though the final output address could end up
+     aligned, to avoid complex sizing logic for a rare case.  */
+  BFD_ASSERT (off % 2 == 0 && sec->alignment_power > 0);
+  if (htab->relr_count >= htab->relr_alloc)
+    {
+      if (htab->relr_alloc == 0)
+	htab->relr_alloc = 4096;
+      else
+	htab->relr_alloc *= 2;
+      htab->relr = bfd_realloc (htab->relr,
+				htab->relr_alloc * sizeof (*htab->relr));
+      if (htab->relr == NULL)
+	return false;
+    }
+
+  htab->relr[htab->relr_count].sec = sec;
+  htab->relr[htab->relr_count].off = off;
+  if (*sec_relr == NULL)
+    *sec_relr = &htab->relr[htab->relr_count];
+  htab->relr_count++;
+  return true;
+}
+
+/* Follow allocate_dynrelocs, but only record relative relocations against the
+   GOT and undo their previous size accounting.  */
+
+static bool
+record_relr_dyn_got_relocs (struct elf_link_hash_entry *h, void *inf)
+{
+  if (h->root.type == bfd_link_hash_indirect)
+    return true;
+  if (h->type == STT_GNU_IFUNC && h->def_regular)
+    return true;
+  if (h->got.refcount <= 0)
+    return true;
+  if (riscv_elf_hash_entry (h)->tls_type
+      & (GOT_TLS_GD | GOT_TLS_IE | GOT_TLSDESC))
+    return true;
+
+  struct bfd_link_info *info = (struct bfd_link_info *) inf;
+  struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info);
+
+  /* Need to make sure gp is output as a dynamic symbol for pde?  */
+
+  if (bfd_link_pic (info) && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+    {
+      /* Check got relocs in riscv_elf_relocate_section.  */
+      bool relative_reloc = SYMBOL_REFERENCES_LOCAL (info, h)
+			    && !bfd_is_abs_symbol (&h->root);
+      if (relative_reloc)
+	if (!record_relr (htab, htab->elf.sgot, h->got.offset,
+			  htab->elf.srelgot))
+	  return false;
+    }
+  return true;
+}
+
+/* Record packed relative relocs against the GOT for local symbols.
+   Undo the size accounting of riscv_elf_late_size_sections.  */
+
+static bool
+record_relr_local_got_relocs (bfd *input_bfd, struct bfd_link_info *info)
+{
+  bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (input_bfd);
+  bfd_vma *local_got_offsets = elf_local_got_offsets (input_bfd);
+  char *local_tls_type = _bfd_riscv_elf_local_got_tls_type (input_bfd);
+
+  if (!bfd_link_pic (info)
+      || !local_got_refcounts
+      || !local_got_offsets
+      || !local_tls_type)
+    return true;
+
+  Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (input_bfd);
+  struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info);
+  for (unsigned int i = 0; i < symtab_hdr->sh_info; i++)
+    {
+      if (local_got_refcounts[i] <= 0)
+	continue;
+      if ((local_tls_type[i] & GOT_NORMAL) == 0)
+	continue;
+
+      bfd_vma off = local_got_offsets[i];
+
+      /* FIXME: If the local symbol is in SHN_ABS then emitting
+	 a relative relocation is not correct, but it seems to
+	 be wrong in riscv_elf_relocate_section too.  */
+      if (!record_relr (htab, htab->elf.sgot, off, htab->elf.srelgot))
+	return false;
+    }
+  return true;
+}
+
+/* Follows the logic of riscv_elf_relocate_section to decide which
+   relocations will become relative and possible to pack.  Ignore
+   relocations against the GOT, those are handled separately per-symbol.
+   Undo the size accounting of the packed relocations and record them
+   so the relr section can be sized later.  */
+
+static bool
+record_relr_non_got_relocs (bfd *input_bfd, struct bfd_link_info *info,
+			    asection *sec)
+{
+  if (sec->reloc_count == 0)
+    return true;
+  if ((sec->flags & (SEC_RELOC | SEC_ALLOC | SEC_DEBUGGING))
+      != (SEC_RELOC | SEC_ALLOC))
+    return true;
+  if (sec->alignment_power == 0)
+    return true;
+  if (discarded_section (sec))
+    return true;
+  asection *sreloc = elf_section_data (sec)->sreloc;
+  if (sreloc == NULL)
+    return true;
+
+  struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info);
+  Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (input_bfd);
+  struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd);
+  const Elf_Internal_Rela * relocs =
+	_bfd_elf_link_info_read_relocs (input_bfd, info, sec, NULL, NULL,
+					info->keep_memory);
+  BFD_ASSERT (relocs != NULL);
+
+  const Elf_Internal_Rela *rel = relocs;
+  const Elf_Internal_Rela *rel_end = relocs + sec->reloc_count;
+  for (; rel < rel_end; rel++)
+    {
+      unsigned int r_symndx = ELFNN_R_SYM (rel->r_info);
+      unsigned int r_type = ELFNN_R_TYPE (rel->r_info);
+
+      /* Handle relocs that can become R_RISCV_RELATIVE,
+	 but not ones against the GOT as those are handled
+	 separately per-symbol.  */
+      if (r_type != R_RISCV_32 && r_type != R_RISCV_64)
+	continue;
+      /* Can only pack relocation against an aligned address.  */
+      if (rel->r_offset % 2 != 0)
+	continue;
+
+      struct elf_link_hash_entry *h = NULL;
+      asection *def_sec = NULL;
+      bool resolved_to_zero = false;
+      if (r_symndx < symtab_hdr->sh_info)
+	{
+	  /* A local symbol.  */
+	  Elf_Internal_Sym *isym;
+	  isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
+					input_bfd, r_symndx);
+	  BFD_ASSERT (isym != NULL);
+
+	  if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
+	    continue;
+
+	  def_sec = bfd_section_from_elf_index (input_bfd, isym->st_shndx);
+	}
+      else
+	{
+	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+	  while (h->root.type == bfd_link_hash_indirect
+		 || h->root.type == bfd_link_hash_warning)
+	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+	  /* Filter out symbols that cannot have a relative reloc.  */
+	  if (h->dyn_relocs == NULL)
+	    continue;
+	  if (bfd_is_abs_symbol (&h->root))
+	    continue;
+	  if (h->type == STT_GNU_IFUNC)
+	    continue;
+
+	  if (h->root.type == bfd_link_hash_defined
+	      || h->root.type == bfd_link_hash_defweak)
+	    def_sec = h->root.u.def.section;
+
+	  resolved_to_zero = UNDEFWEAK_NO_DYNAMIC_RELOC (info, h);
+	}
+
+      if (def_sec != NULL && discarded_section (def_sec))
+	continue;
+
+      /* Same logic as in riscv_elf_relocate_section, for R_RISCV_32/64.
+	 Except conditionals trimmed that cannot result a reltive reloc.  */
+      reloc_howto_type *howto = riscv_elf_rtype_to_howto (input_bfd, r_type);
+      if (RISCV_GENERATE_DYNAMIC_RELOC_FOR_PIC (howto->pc_relative, info, h,
+						resolved_to_zero))
+	{
+	  if (RISCV_COPY_INPUT_RELOC (info, h))
+	    continue;
+
+	  if (!record_relr (htab, sec, rel->r_offset, sreloc))
+	    return false;
+	}
+    }
+  return true;
+}
+
+static int
+cmp_relr_addr (const void *p, const void *q)
+{
+  const bfd_vma *a = p;
+  const bfd_vma *b = q;
+  return *a < *b ? -1 : *a > *b ? 1 : 0;
+}
+
+/* Produce a malloc'd sorted array of reloc addresses in htab->relr_sorted.
+   Returns false on allocation failure.  */
+
+static bool
+sort_relr (struct bfd_link_info *info,
+	   struct riscv_elf_link_hash_table *htab)
+{
+  if (htab->relr_count == 0)
+    return true;
+
+  bfd_vma *addr = htab->relr_sorted;
+  if (addr == NULL)
+    {
+      addr = bfd_malloc (htab->relr_count * sizeof (*addr));
+      if (addr == NULL)
+	return false;
+      htab->relr_sorted = addr;
+    }
+
+  for (bfd_size_type i = 0; i < htab->relr_count; i++)
+    {
+      bfd_vma off = _bfd_elf_section_offset (info->output_bfd, info,
+					     htab->relr[i].sec,
+					     htab->relr[i].off);
+      addr[i] = htab->relr[i].sec->output_section->vma
+		+ htab->relr[i].sec->output_offset
+		+ off;
+    }
+  qsort (addr, htab->relr_count, sizeof (*addr), cmp_relr_addr);
+  return true;
+}
+
+/* Size of a relr entry and a relocated location.  */
+#define RELR_SZ (ARCH_SIZE / 8)
+/* Number of consecutive locations a relr bitmap entry references.  */
+#define RELR_N (ARCH_SIZE - 1)
+
+/* Size .relr.dyn whenever the layout changes, the number of packed
+   relocs are unchanged but the packed representation can.  */
+
+static bool
+riscv_elf_size_relative_relocs (struct bfd_link_info *info,
+				bool *need_layout)
+{
+  struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info);
+  asection *srelrdyn = htab->elf.srelrdyn;
+  *need_layout = false;
+
+  if (!sort_relr (info, htab))
+    return false;
+  bfd_vma *addr = htab->relr_sorted;
+
+  BFD_ASSERT (srelrdyn != NULL);
+  bfd_size_type oldsize = srelrdyn->size;
+  srelrdyn->size = 0;
+  for (bfd_size_type i = 0; i < htab->relr_count; )
+    {
+      bfd_vma base = addr[i];
+      i++;
+      srelrdyn->size += RELR_SZ;
+      base += RELR_SZ;
+      for (;;)
+	{
+	  bfd_size_type start_i = i;
+	  while (i < htab->relr_count
+		 && addr[i] - base < RELR_N * RELR_SZ
+		 && (addr[i] - base) % RELR_SZ == 0)
+	    i++;
+	  if (i == start_i)
+	    break;
+	  srelrdyn->size += RELR_SZ;
+	  base += RELR_N * RELR_SZ;
+	}
+    }
+  if (srelrdyn->size != oldsize)
+    {
+      *need_layout = true;
+      /* Stop after a few iterations in case the layout does not converge,
+	 we can do this when the size would shrink.  */
+      if (htab->relr_layout_iter++ > 5 && srelrdyn->size < oldsize)
+	{
+	  srelrdyn->size = oldsize;
+	  *need_layout = false;
+	}
+    }
+  htab->layout_mutating_for_relr = *need_layout;
+  return true;
+}
+
+/* Emit the .relr.dyn section after it is sized and the layout is fixed.  */
+
+static bool
+riscv_elf_finish_relative_relocs (struct bfd_link_info *info)
+{
+  struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info);
+  asection *srelrdyn = htab->elf.srelrdyn;
+  bfd *dynobj = htab->elf.dynobj;
+
+  if (srelrdyn == NULL || srelrdyn->size == 0)
+    return true;
+  srelrdyn->contents = bfd_alloc (dynobj, srelrdyn->size);
+  if (srelrdyn->contents == NULL)
+    return false;
+  srelrdyn->alloced = 1;
+  bfd_vma *addr = htab->relr_sorted;
+  bfd_byte *loc = srelrdyn->contents;
+  for (bfd_size_type i = 0; i < htab->relr_count; )
+    {
+      bfd_vma base = addr[i];
+      i++;
+      bfd_put_NN (dynobj, base, loc);
+      loc += RELR_SZ;
+      base += RELR_SZ;
+      for (;;)
+	{
+	  bfd_vma bits = 0;
+	  while (i < htab->relr_count)
+	    {
+	      bfd_vma delta = addr[i] - base;
+	      if (delta >= RELR_N * RELR_SZ || delta % RELR_SZ != 0)
+		break;
+	      bits |= (bfd_vma) 1 << (delta / RELR_SZ);
+	      i++;
+	    }
+	  if (bits == 0)
+	    break;
+	  bfd_put_NN (dynobj, (bits << 1) | 1, loc);
+	  loc += RELR_SZ;
+	  base += RELR_N * RELR_SZ;
+	}
+    }
+  free (addr);
+  htab->relr_sorted = NULL;
+  /* Pad any excess with 1's, a do-nothing encoding.  */
+  while (loc < srelrdyn->contents + srelrdyn->size)
+    {
+      bfd_put_NN (dynobj, 1, loc);
+      loc += RELR_SZ;
+    }
+  return true;
+}
+
 static bool
 riscv_elf_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
 {
@@ -1648,6 +2061,27 @@ riscv_elf_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
 	htab->elf.sgotplt->size = 0;
     }
 
+  /* Record the relative relocations that will be packed and undo the
+     size allocation for them in .rela.*. The size of .relr.dyn will be
+     computed later iteratively since it depends on the final layout.  */
+  if (info->enable_dt_relr && !bfd_link_relocatable (info))
+    {
+      elf_link_hash_traverse (&htab->elf, record_relr_dyn_got_relocs, info);
+
+      for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+	{
+	  if (!is_riscv_elf (ibfd))
+	    continue;
+
+	  for (s = ibfd->sections; s != NULL; s = s->next)
+	    if (!record_relr_non_got_relocs (ibfd, info, s))
+	      return false;
+
+	  if (!record_relr_local_got_relocs (ibfd, info))
+	    return false;
+	}
+    }
+
   /* The check_relocs and adjust_dynamic_symbol entry points have
      determined the sizes of the various dynamic sections.  Allocate
      memory for them.  */
@@ -1677,6 +2111,15 @@ riscv_elf_late_size_sections (bfd *output_bfd, struct bfd_link_info *info)
 	      s->reloc_count = 0;
 	    }
 	}
+      else if (s == htab->elf.srelrdyn)
+	{
+	  /* Remove .relr.dyn based on relr_count, not size, since
+	     it is not sized yet.  */
+	  if (htab->relr_count == 0)
+	    s->flags |= SEC_EXCLUDE;
+	  /* Allocate contents later.  */
+	  continue;
+	}
       else
 	{
 	  /* It's not one of our sections.  */
@@ -2701,7 +3144,7 @@ riscv_elf_relocate_section (bfd *output_bfd,
 		off &= ~1;
 	      else
 		{
-		  if (bfd_link_pic (info))
+		  if (bfd_link_pic (info) && !info->enable_dt_relr)
 		    {
 		      asection *s;
 		      Elf_Internal_Rela outrel;
@@ -2950,8 +3393,9 @@ riscv_elf_relocate_section (bfd *output_bfd,
 	  if ((input_section->flags & SEC_ALLOC) == 0)
 	    break;
 
-	  if (RISCV_GENERATE_DYNAMIC_RELOC (howto->pc_relative, info, h,
-					    resolved_to_zero))
+	  if (RISCV_GENERATE_DYNAMIC_RELOC_FOR_PIC (howto->pc_relative, info,
+						    h, resolved_to_zero)
+	      || RISCV_GENERATE_DYNAMIC_RELOC_FOR_EXE (info, h))
 	    {
 	      Elf_Internal_Rela outrel;
 	      asection *sreloc;
@@ -2991,6 +3435,14 @@ riscv_elf_relocate_section (bfd *output_bfd,
 		  outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type);
 		  outrel.r_addend = rel->r_addend;
 		}
+	      else if (info->enable_dt_relr
+		       && input_section->alignment_power != 0
+		       && rel->r_offset % 2 == 0)
+		{
+		  /* Don't emit a relative relocation that is packed, only
+		     apply the addend.  */
+		  goto do_relocation;
+		}
 	      else
 		{
 		  /* This symbol is local, or marked to become local.  */
@@ -3462,6 +3914,10 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
 
 	  BFD_ASSERT ((h->got.offset & 1) != 0);  */
 
+	  /* Don't emit relative relocs if they are packed.  */
+	  if (info->enable_dt_relr)
+	    goto skip_got_reloc;
+
 	  asection *sec = h->root.u.def.section;
 	  rela.r_info = ELFNN_R_INFO (0, R_RISCV_RELATIVE);
 	  rela.r_addend = (h->root.u.def.value
@@ -3498,6 +3954,8 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
 	}
     }
 
+ skip_got_reloc:
+
   if (h->needs_copy)
     {
       Elf_Internal_Rela rela;
@@ -4578,6 +5036,16 @@ _riscv_relax_delete_bytes (bfd *abfd,
 	}
     }
 
+  /* Adjust the offsets for all record relr in this section.  */
+  struct relr_entry *relr = riscv_elf_section_data (sec)->relr;
+  struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (link_info);
+  struct relr_entry *relr_end = NULL;
+  if (htab->relr_count)
+    relr_end = htab->relr + htab->relr_count;
+  for (; relr && relr < relr_end && relr->sec == sec; relr++)
+    if (relr->off > addr && relr->off < toaddr)
+      relr->off -= count;
+
   return true;
 }
 
@@ -5214,7 +5682,10 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
 	  && info->relax_pass == 0)
       /* The exp_seg_relro_adjust is enum phase_enum (0x4),
 	 and defined in ld/ldexp.h.  */
-      || *(htab->data_segment_phase) == 4)
+      || *(htab->data_segment_phase) == 4
+      /* It's not safe to do relaxations when relr are updating the section
+	 layouts.  */
+      || htab->layout_mutating_for_relr)
     return true;
 
   /* Record the first relax section, so that we can reset the
@@ -5798,10 +6269,13 @@ riscv_elf_merge_symbol_attribute (struct elf_link_hash_entry *h,
 #define elf_info_to_howto			riscv_info_to_howto_rela
 #define bfd_elfNN_bfd_relax_section		_bfd_riscv_relax_section
 #define bfd_elfNN_mkobject			elfNN_riscv_mkobject
+#define bfd_elfNN_new_section_hook		elfNN_riscv_new_section_hook
 #define elf_backend_additional_program_headers \
   riscv_elf_additional_program_headers
 #define elf_backend_modify_segment_map		riscv_elf_modify_segment_map
 #define elf_backend_merge_symbol_attribute	riscv_elf_merge_symbol_attribute
+#define elf_backend_size_relative_relocs	riscv_elf_size_relative_relocs
+#define elf_backend_finish_relative_relocs	riscv_elf_finish_relative_relocs
 
 #define elf_backend_init_index_section		_bfd_elf_init_1_index_section
 
diff --git a/binutils/readelf.c b/binutils/readelf.c
index dd1871d8c75..ab904664231 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -1663,6 +1663,20 @@ is_aarch64_special_symbol_name (const char *name)
   return name[2] == 0 || name[2] == '.';
 }
 
+/* See riscv_elf_is_mapping_symbols.  */
+
+static bool
+is_riscv_special_symbol_name (const char *name)
+{
+  return (!strcmp (name, "$d")
+	  || !strcmp (name, "$x")
+	  || !strncmp (name, "$xrv", 4)
+	  /* Only used for counting gp in risc-v.  */
+	  || !strcmp (name, "__DATA_BEGIN__")
+	  || !strcmp (name, "__SDATA_BEGIN__")
+	  || !strcmp (name, "__BSS_END__"));
+}
+
 static bool
 is_special_symbol_name (Filedata * filedata, const char * s)
 {
@@ -1671,6 +1685,9 @@ is_special_symbol_name (Filedata * filedata, const char * s)
     case EM_AARCH64:
       return is_aarch64_special_symbol_name (s);
 
+    case EM_RISCV:
+      return is_riscv_special_symbol_name (s);
+
     default:
       return false;
     }
diff --git a/binutils/testsuite/lib/binutils-common.exp b/binutils/testsuite/lib/binutils-common.exp
index 41d94d256ec..4cc75f6edaf 100644
--- a/binutils/testsuite/lib/binutils-common.exp
+++ b/binutils/testsuite/lib/binutils-common.exp
@@ -472,7 +472,8 @@ proc supports_dt_relr {} {
 	  || [istarget i?86-*-*]
 	  || [istarget powerpc64*-*-*]
 	  || [istarget aarch64*-*-*]
-	  || [istarget loongarch64*-*-*])
+	  || [istarget loongarch64*-*-*]
+	  || [istarget riscv*-*-*])
 	 && ([istarget *-*-linux*]
 	     || [istarget *-*-gnu*]) } {
 	return 1
diff --git a/ld/emulparams/elf32lriscv.sh b/ld/emulparams/elf32lriscv.sh
index da0d7cf54f4..c85cf179b6d 100644
--- a/ld/emulparams/elf32lriscv.sh
+++ b/ld/emulparams/elf32lriscv.sh
@@ -1,6 +1,7 @@
 # RV32 code using ILP32D ABI.
 # ABI not in emulation name to avoid breaking backward compatibility.
 source_sh ${srcdir}/emulparams/elf32lriscv-defs.sh
+source_sh ${srcdir}/emulparams/dt-relr.sh
 OUTPUT_FORMAT="elf32-littleriscv"
 
 # On Linux, first look for 32 bit ILP32D target libraries in /lib/ilp32d as per
diff --git a/ld/emulparams/elf64lriscv.sh b/ld/emulparams/elf64lriscv.sh
index e07a0648735..1ea5b7fc637 100644
--- a/ld/emulparams/elf64lriscv.sh
+++ b/ld/emulparams/elf64lriscv.sh
@@ -1,6 +1,7 @@
 # RV64 code using LP64D ABI.
 # ABI not in emulation name to avoid breaking backward compatibility.
 source_sh ${srcdir}/emulparams/elf64lriscv-defs.sh
+source_sh ${srcdir}/emulparams/dt-relr.sh
 OUTPUT_FORMAT="elf64-littleriscv"
 
 # On Linux, first look for 64 bit LP64D target libraries in /lib64/lp64d as per
diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index d68a9145dcd..2b31d54ac1e 100644
--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
@@ -78,6 +78,41 @@ proc run_dump_test_ifunc { name target output} {
 	      "$name-$target.$ext"]]
 }
 
+
+proc run_dump_test_relr { name target output} {
+    # TODO: big-endian for *.d test cases?
+    set asflags "-mlittle-endian"
+    set ldflags "-z pack-relative-relocs -T relr-relocs.ld"
+    switch -- $output {
+	pie {
+	    set ext "pie"
+	    set ldflags "$ldflags -pie"
+	}
+	pic {
+	    set ext "so"
+	    set ldflags "$ldflags -shared"
+	}
+    }
+    switch -- $target {
+	rv32 {
+	    set asflags "$asflags -march=rv32i -mabi=ilp32"
+	    set ldflags "$ldflags -m[riscv_choose_ilp32_emul]"
+	}
+	rv64 {
+	    set asflags "$asflags -march=rv64i -mabi=lp64 -defsym __64_bit__=1"
+	    set ldflags "$ldflags -m[riscv_choose_lp64_emul]"
+	}
+    }
+    run_ld_link_tests [list \
+	[list "$name ($target-$output)" \
+	      "$ldflags" "" \
+	      "$asflags" \
+	      [list "$name.s"] \
+	      [concat [list "readelf -rW  $name-$target-$output.rd"] \
+		      [list "objdump -dsw $name-$target-$output.d"]] \
+	      "$name-$target.$ext"]]
+}
+
 proc run_relax_twice_test {} {
     global as
     global ld
@@ -230,6 +265,22 @@ if [istarget "riscv*-*-*"] {
     run_dump_test "discard-pie"
     run_dump_test "discard-pic"
 
+    # RELR
+    run_dump_test_relr "relr-data" rv32 pie
+    run_dump_test_relr "relr-data" rv32 pic
+    run_dump_test_relr "relr-got" rv32 pie
+    run_dump_test_relr "relr-got" rv32 pic
+    run_dump_test_relr "relr-align" rv32 pic
+    run_dump_test_relr "relr-data" rv64 pie
+    run_dump_test_relr "relr-data" rv64 pic
+    run_dump_test_relr "relr-got" rv64 pie
+    run_dump_test_relr "relr-got" rv64 pic
+    run_dump_test_relr "relr-align" rv64 pic
+    run_dump_test "relr-text-pie"
+    run_dump_test "relr-text-pic"
+    run_dump_test "relr-discard-pie"
+    run_dump_test "relr-discard-pic"
+
     # IFUNC testcases.
     # Check IFUNC by single type relocs.
     run_dump_test_ifunc "ifunc-reloc-call-01" rv32 exe
diff --git a/ld/testsuite/ld-riscv-elf/relr-align-rv32-pic.d b/ld/testsuite/ld-riscv-elf/relr-align-rv32-pic.d
new file mode 100644
index 00000000000..31eea11c42f
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-align-rv32-pic.d
@@ -0,0 +1,23 @@
+#...
+Contents of section .data:
+ 12340000 00000100 00000100 00000000 00000000.*
+ 12340010 00000000 01000000 01000000 00000000.*
+ 12340020 00000100 00000000 00000000 01000000.*
+ 12340030 00000000 00000100 01000000 02000000.*
+ 12340040 03000000 04000000 05000000 06000000.*
+ 12340050 07000000 08000000 09000000 0a000000.*
+ 12340060 0b000000 0c000000 0d000000 0e000000.*
+ 12340070 0f000000 10000000 11000000 12000000.*
+ 12340080 13000000 14000000 15000000 16000000.*
+ 12340090 17000000 18000000 19000000 1a000000.*
+ 123400a0 1b000000 1c000000 1d000000 1e000000.*
+ 123400b0 1f000000 20000100 21000000 22000000.*
+ 123400c0 23000000 24000000 25000000 26000000.*
+ 123400d0 27000000 28000000 29000000 2a000000.*
+ 123400e0 2b000000 2c000000 2d000000 2e000000.*
+ 123400f0 2f000000 30000000 31000000 32000000.*
+ 12340100 33000000 34000000 35000000 36000000.*
+ 12340110 37000000 38000000 39000000 3a000000.*
+ 12340120 3b000000 3c000000 3d000000 3e000000.*
+ 12340130 3f000100 40000100.*
+#...
diff --git a/ld/testsuite/ld-riscv-elf/relr-align-rv32-pic.rd b/ld/testsuite/ld-riscv-elf/relr-align-rv32-pic.rd
new file mode 100644
index 00000000000..01a08671d3c
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-align-rv32-pic.rd
@@ -0,0 +1,18 @@
+Relocation section '\.rela\.dyn'.*contains 3 entries:
+[ 	]+Offset[ 	]+Info[ 	]+Type[ 	]+.*
+12340009[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+10000
+1234000d[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+10000
+12340025[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+10000
+
+Relocation section '\.relr\.dyn'.*contains 10 entries which relocate 10 locations:
+Index:[ 	]+Entry[ 	]+Address[ 	]+Symbolic Address
+0000:[ 	]+12340000[ 	]+12340000[ 	]+double_0
+0001:[ 	]+00000003[ 	]+12340004[ 	]+double_0 \+ 0x4
+0002:[ 	]+12340012[ 	]+12340012[ 	]+double_2
+0003:[ 	]+00000003[ 	]+12340016[ 	]+double_2 \+ 0x4
+0004:[ 	]+12340020[ 	]+12340020[ 	]+single_0
+0005:[ 	]+1234002a[ 	]+1234002a[ 	]+single_2
+0006:[ 	]+12340034[ 	]+12340034[ 	]+big
+0007:[ 	]+123400b4[ 	]+123400b4[ 	]+big \+ 0x80
+0008:[ 	]+80000001[ 	]+12340130[ 	]+big \+ 0xfc
+0009:[ 	]+00000003[ 	]+12340134[ 	]+big \+ 0x100
diff --git a/ld/testsuite/ld-riscv-elf/relr-align-rv64-pic.d b/ld/testsuite/ld-riscv-elf/relr-align-rv64-pic.d
new file mode 100644
index 00000000000..38d81f8da5c
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-align-rv64-pic.d
@@ -0,0 +1,41 @@
+#...
+Contents of section .data:
+ 12340000 00000100 00000000 00000100 00000000.*
+ 12340010 00000000 00000000 00000000 00000000.*
+ 12340020 00000000 01000000 00000000 01000000.*
+ 12340030 00000000 00000000 00000100 00000000.*
+ 12340040 00000000 00000000 00000000 01000000.*
+ 12340050 00000000 00000000 00000100 00000000.*
+ 12340060 01000000 00000000 02000000 00000000.*
+ 12340070 03000000 00000000 04000000 00000000.*
+ 12340080 05000000 00000000 06000000 00000000.*
+ 12340090 07000000 00000000 08000000 00000000.*
+ 123400a0 09000000 00000000 0a000000 00000000.*
+ 123400b0 0b000000 00000000 0c000000 00000000.*
+ 123400c0 0d000000 00000000 0e000000 00000000.*
+ 123400d0 0f000000 00000000 10000000 00000000.*
+ 123400e0 11000000 00000000 12000000 00000000.*
+ 123400f0 13000000 00000000 14000000 00000000.*
+ 12340100 15000000 00000000 16000000 00000000.*
+ 12340110 17000000 00000000 18000000 00000000.*
+ 12340120 19000000 00000000 1a000000 00000000.*
+ 12340130 1b000000 00000000 1c000000 00000000.*
+ 12340140 1d000000 00000000 1e000000 00000000.*
+ 12340150 1f000000 00000000 20000100 00000000.*
+ 12340160 21000000 00000000 22000000 00000000.*
+ 12340170 23000000 00000000 24000000 00000000.*
+ 12340180 25000000 00000000 26000000 00000000.*
+ 12340190 27000000 00000000 28000000 00000000.*
+ 123401a0 29000000 00000000 2a000000 00000000.*
+ 123401b0 2b000000 00000000 2c000000 00000000.*
+ 123401c0 2d000000 00000000 2e000000 00000000.*
+ 123401d0 2f000000 00000000 30000000 00000000.*
+ 123401e0 31000000 00000000 32000000 00000000.*
+ 123401f0 33000000 00000000 34000000 00000000.*
+ 12340200 35000000 00000000 36000000 00000000.*
+ 12340210 37000000 00000000 38000000 00000000.*
+ 12340220 39000000 00000000 3a000000 00000000.*
+ 12340230 3b000000 00000000 3c000000 00000000.*
+ 12340240 3d000000 00000000 3e000000 00000000.*
+ 12340250 3f000100 00000000 40000100 00000000.*
+#...
diff --git a/ld/testsuite/ld-riscv-elf/relr-align-rv64-pic.rd b/ld/testsuite/ld-riscv-elf/relr-align-rv64-pic.rd
new file mode 100644
index 00000000000..97a4d8c290e
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-align-rv64-pic.rd
@@ -0,0 +1,18 @@
+Relocation section '\.rela\.dyn'.*contains 3 entries:
+[ 	]+Offset[ 	]+Info[ 	]+Type[ 	]+.*
+0000000012340011[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+10000
+0000000012340019[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+10000
+0000000012340041[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+10000
+
+Relocation section '\.relr\.dyn'.*contains 9 entries which relocate 10 locations:
+Index:[ 	]+Entry[ 	]+Address[ 	]+Symbolic Address
+0000:[ 	]+0000000012340000[ 	]+0000000012340000[ 	]+double_0
+0001:[ 	]+0000000000000003[ 	]+0000000012340008[ 	]+double_0 \+ 0x8
+0002:[ 	]+0000000012340022[ 	]+0000000012340022[ 	]+double_2
+0003:[ 	]+0000000000000003[ 	]+000000001234002a[ 	]+double_2 \+ 0x8
+0004:[ 	]+0000000012340038[ 	]+0000000012340038[ 	]+single_0
+0005:[ 	]+000000001234004a[ 	]+000000001234004a[ 	]+single_2
+0006:[ 	]+0000000012340058[ 	]+0000000012340058[ 	]+big
+0007:[ 	]+8000000100000001[ 	]+0000000012340158[ 	]+big \+ 0x100
+[ 	]+0000000012340250[ 	]+big \+ 0x1f8
+0008:[ 	]+0000000000000003[ 	]+0000000012340258[ 	]+big \+ 0x200
diff --git a/ld/testsuite/ld-riscv-elf/relr-align.s b/ld/testsuite/ld-riscv-elf/relr-align.s
new file mode 100644
index 00000000000..9b19f88f5ec
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-align.s
@@ -0,0 +1,114 @@
+# Test DT_RELR with differently aligned relative relocs.
+
+.macro data value
+.ifdef __64_bit__
+	.quad \value
+.else
+	.long \value
+.endif
+.endm
+
+.text
+.global _start
+_start:
+foo:
+
+.data
+.p2align 3
+double_0:
+data foo
+data foo
+.byte 0
+double_1:
+data foo
+data foo
+.byte 0
+double_2:
+data foo
+data foo
+.byte 0
+.byte 0
+.byte 0
+.byte 0
+.byte 0
+.byte 0
+single_0:
+data foo
+.byte 0
+single_1:
+data foo
+.byte 0
+single_2:
+data foo
+.byte 0
+.byte 0
+.byte 0
+.byte 0
+.byte 0
+.byte 0
+big:
+data foo
+data 1
+data 2
+data 3
+data 4
+data 5
+data 6
+data 7
+data 8
+data 9
+data 10
+data 11
+data 12
+data 13
+data 14
+data 15
+data 16
+data 17
+data 18
+data 19
+data 20
+data 21
+data 22
+data 23
+data 24
+data 25
+data 26
+data 27
+data 28
+data 29
+data 30
+data 31
+data foo + 32
+data 33
+data 34
+data 35
+data 36
+data 37
+data 38
+data 39
+data 40
+data 41
+data 42
+data 43
+data 44
+data 45
+data 46
+data 47
+data 48
+data 49
+data 50
+data 51
+data 52
+data 53
+data 54
+data 55
+data 56
+data 57
+data 58
+data 59
+data 60
+data 61
+data 62
+data foo + 63
+data foo + 64
diff --git a/ld/testsuite/ld-riscv-elf/relr-data-rv32-pic.d b/ld/testsuite/ld-riscv-elf/relr-data-rv32-pic.d
new file mode 100644
index 00000000000..4af2318123a
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-data-rv32-pic.d
@@ -0,0 +1,22 @@
+#...
+Contents of section .data.unaligned_local:
+ 12340000 00000000.*
+Contents of section .data.unaligned_hidden:
+ 12340004 00000000.*
+Contents of section .data.unaligned_global:
+ 12340008 00000000.*
+Contents of section .data.unaligned_DYNAMIC:
+ 1234000c 00000000.*
+Contents of section .data.aligned_local:
+ 12340010 04000100.*
+Contents of section .data.aligned_hidden:
+ 12340014 08000100.*
+Contents of section .data.aligned_global:
+ 12340018 00000000.*
+Contents of section .data.aligned_global_abs:
+ 1234001c 2a000000.*
+Contents of section .data.aligned_weak_undef:
+ 12340020 00000000.*
+Contents of section .data.aligned_DYNAMIC:
+ 12340024 28003412.*
+#...
diff --git a/ld/testsuite/ld-riscv-elf/relr-data-rv32-pic.rd b/ld/testsuite/ld-riscv-elf/relr-data-rv32-pic.rd
new file mode 100644
index 00000000000..45da4525ba8
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-data-rv32-pic.rd
@@ -0,0 +1,14 @@
+Relocation section '\.rela\.dyn'.*contains 6 entries:
+[ 	]+Offset[ 	]+Info[ 	]+Type[ 	]+.*
+12340000[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+10004
+12340004[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+10008
+1234000c[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+12340028
+12340008[ 	]+[0-9a-f]+[ 	]+R_RISCV_32[ 	]+0001000c[ 	]+sym_global \+ 0
+12340018[ 	]+[0-9a-f]+[ 	]+R_RISCV_32[ 	]+0001000c[ 	]+sym_global \+ 0
+12340020[ 	]+[0-9a-f]+[ 	]+R_RISCV_32[ 	]+00000000[ 	]+sym_weak_undef \+ 0
+
+Relocation section '\.relr\.dyn'.*contains 2 entries which relocate 3 locations:
+Index:[ 	]+Entry[ 	]+Address[ 	]+Symbolic Address
+0000:[ 	]+12340010[ 	]+12340010[ 	]+aligned_local
+0001:[ 	]+00000023[ 	]+12340014[ 	]+aligned_hidden
+[ 	]+12340024[ 	]+aligned_DYNAMIC
diff --git a/ld/testsuite/ld-riscv-elf/relr-data-rv32-pie.d b/ld/testsuite/ld-riscv-elf/relr-data-rv32-pie.d
new file mode 100644
index 00000000000..71e081ccdca
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-data-rv32-pie.d
@@ -0,0 +1,22 @@
+#...
+Contents of section .data.unaligned_local:
+ 12340000 00000000.*
+Contents of section .data.unaligned_hidden:
+ 12340004 00000000.*
+Contents of section .data.unaligned_global:
+ 12340008 00000000.*
+Contents of section .data.unaligned_DYNAMIC:
+ 1234000c 00000000.*
+Contents of section .data.aligned_local:
+ 12340010 04000100.*
+Contents of section .data.aligned_hidden:
+ 12340014 08000100.*
+Contents of section .data.aligned_global:
+ 12340018 0c000100.*
+Contents of section .data.aligned_global_abs:
+ 1234001c 2a000000.*
+Contents of section .data.aligned_weak_undef:
+ 12340020 00000000.*
+Contents of section .data.aligned_DYNAMIC:
+ 12340024 28003412.*
+#...
diff --git a/ld/testsuite/ld-riscv-elf/relr-data-rv32-pie.rd b/ld/testsuite/ld-riscv-elf/relr-data-rv32-pie.rd
new file mode 100644
index 00000000000..99e733f93c2
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-data-rv32-pie.rd
@@ -0,0 +1,14 @@
+Relocation section '\.rela\.dyn'.*contains 5 entries:
+[ 	]+Offset[ 	]+Info[ 	]+Type[ 	]+.*
+12340000[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+10004
+12340004[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+10008
+12340008[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+1000c
+1234000c[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+12340028
+12340020[ 	]+[0-9a-f]+[ 	]+R_RISCV_32[ 	]+00000000[ 	]+sym_weak_undef \+ 0
+
+Relocation section '\.relr\.dyn'.*contains 2 entries which relocate 4 locations:
+Index:[ 	]+Entry[ 	]+Address[ 	]+Symbolic Address
+0000:[ 	]+12340010[ 	]+12340010[ 	]+aligned_local
+0001:[ 	]+00000027[ 	]+12340014[ 	]+aligned_hidden
+[ 	]+12340018[ 	]+aligned_global
+[ 	]+12340024[ 	]+aligned_DYNAMIC
diff --git a/ld/testsuite/ld-riscv-elf/relr-data-rv64-pic.d b/ld/testsuite/ld-riscv-elf/relr-data-rv64-pic.d
new file mode 100644
index 00000000000..0e3e1627dc5
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-data-rv64-pic.d
@@ -0,0 +1,22 @@
+#...
+Contents of section .data.unaligned_local:
+ 12340000 00000000 00000000.*
+Contents of section .data.unaligned_hidden:
+ 12340008 00000000 00000000.*
+Contents of section .data.unaligned_global:
+ 12340010 00000000 00000000.*
+Contents of section .data.unaligned_DYNAMIC:
+ 12340018 00000000 00000000.*
+Contents of section .data.aligned_local:
+ 12340020 04000100 00000000.*
+Contents of section .data.aligned_hidden:
+ 12340028 08000100 00000000.*
+Contents of section .data.aligned_global:
+ 12340030 00000000 00000000.*
+Contents of section .data.aligned_global_abs:
+ 12340038 2a000000 00000000.*
+Contents of section .data.aligned_weak_undef:
+ 12340040 00000000 00000000.*
+Contents of section .data.aligned_DYNAMIC:
+ 12340048 50003412 00000000.*
+#...
diff --git a/ld/testsuite/ld-riscv-elf/relr-data-rv64-pic.rd b/ld/testsuite/ld-riscv-elf/relr-data-rv64-pic.rd
new file mode 100644
index 00000000000..8bbd2e45a5e
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-data-rv64-pic.rd
@@ -0,0 +1,14 @@
+Relocation section '\.rela\.dyn'.*contains 6 entries:
+[ 	]+Offset[ 	]+Info[ 	]+Type[ 	]+.*
+0000000012340000[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+10004
+0000000012340008[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+10008
+0000000012340018[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+12340050
+0000000012340010[ 	]+[0-9a-f]+[ 	]+R_RISCV_64[ 	]+000000000001000c[ 	]+sym_global \+ 0
+0000000012340030[ 	]+[0-9a-f]+[ 	]+R_RISCV_64[ 	]+000000000001000c[ 	]+sym_global \+ 0
+0000000012340040[ 	]+[0-9a-f]+[ 	]+R_RISCV_64[ 	]+0000000000000000[ 	]+sym_weak_undef \+ 0
+
+Relocation section '\.relr\.dyn'.*contains 2 entries which relocate 3 locations:
+Index:[ 	]+Entry[ 	]+Address[ 	]+Symbolic Address
+0000:[ 	]+0000000012340020[ 	]+0000000012340020[ 	]+aligned_local
+0001:[ 	]+0000000000000023[ 	]+0000000012340028[ 	]+aligned_hidden
+[ 	]+0000000012340048[ 	]+aligned_DYNAMIC
diff --git a/ld/testsuite/ld-riscv-elf/relr-data-rv64-pie.d b/ld/testsuite/ld-riscv-elf/relr-data-rv64-pie.d
new file mode 100644
index 00000000000..0f940b325a8
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-data-rv64-pie.d
@@ -0,0 +1,22 @@
+#...
+Contents of section .data.unaligned_local:
+ 12340000 00000000 00000000.*
+Contents of section .data.unaligned_hidden:
+ 12340008 00000000 00000000.*
+Contents of section .data.unaligned_global:
+ 12340010 00000000 00000000.*
+Contents of section .data.unaligned_DYNAMIC:
+ 12340018 00000000 00000000.*
+Contents of section .data.aligned_local:
+ 12340020 04000100 00000000.*
+Contents of section .data.aligned_hidden:
+ 12340028 08000100 00000000.*
+Contents of section .data.aligned_global:
+ 12340030 0c000100 00000000.*
+Contents of section .data.aligned_global_abs:
+ 12340038 2a000000 00000000.*
+Contents of section .data.aligned_weak_undef:
+ 12340040 00000000 00000000.*
+Contents of section .data.aligned_DYNAMIC:
+ 12340048 50003412 00000000.*
+#...
diff --git a/ld/testsuite/ld-riscv-elf/relr-data-rv64-pie.rd b/ld/testsuite/ld-riscv-elf/relr-data-rv64-pie.rd
new file mode 100644
index 00000000000..6a7b8875133
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-data-rv64-pie.rd
@@ -0,0 +1,14 @@
+Relocation section '\.rela\.dyn'.*contains 5 entries:
+[ 	]+Offset[ 	]+Info[ 	]+Type[ 	]+.*
+0000000012340000[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+10004
+0000000012340008[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+10008
+0000000012340010[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+1000c
+0000000012340018[ 	]+[0-9a-f]+[ 	]+R_RISCV_RELATIVE[ 	]+12340050
+0000000012340040[ 	]+[0-9a-f]+[ 	]+R_RISCV_64[ 	]+0000000000000000[ 	]+sym_weak_undef \+ 0
+
+Relocation section '\.relr\.dyn'.*contains 2 entries which relocate 4 locations:
+Index:[ 	]+Entry[ 	]+Address[ 	]+Symbolic Address
+0000:[ 	]+0000000012340020[ 	]+0000000012340020[ 	]+aligned_local
+0001:[ 	]+0000000000000027[ 	]+0000000012340028[ 	]+aligned_hidden
+[ 	]+0000000012340030[ 	]+aligned_global
+[ 	]+0000000012340048[ 	]+aligned_DYNAMIC
diff --git a/ld/testsuite/ld-riscv-elf/relr-data.s b/ld/testsuite/ld-riscv-elf/relr-data.s
new file mode 100644
index 00000000000..1198a730226
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-data.s
@@ -0,0 +1,79 @@
+# Test symbol references in .data when used with DT_RELR.
+# Relocations for unaligned sections are currently not packed.
+
+.macro data value
+.ifdef __64_bit__
+	.quad \value
+.else
+	.long \value
+.endif
+.endm
+
+.text
+.global _start
+_start:
+	nop
+
+sym_local:
+	nop
+
+.global sym_hidden
+.hidden sym_hidden
+sym_hidden:
+	nop
+
+.global sym_global
+sym_global:
+	nop
+
+.global sym_global_abs
+.set sym_global_abs, 42
+
+.global sym_weak_undef
+.weak sym_weak_undef
+
+.section .data.unaligned_local
+unaligned_local:
+data sym_local
+
+.section .data.unaligned_hidden
+unaligned_hidden:
+data sym_hidden
+
+.section .data.unaligned_global
+unaligned_global:
+data sym_global
+
+.section .data.unaligned_DYNAMIC
+unaligned_DYNAMIC:
+data _DYNAMIC
+
+.section .data.aligned_local
+.p2align 1
+aligned_local:
+data sym_local
+
+.section .data.aligned_hidden
+.p2align 1
+aligned_hidden:
+data sym_hidden
+
+.section .data.aligned_global
+.p2align 1
+aligned_global:
+data sym_global
+
+.section .data.aligned_global_abs
+.p2align 1
+aligned_global_abs:
+data sym_global_abs
+
+.section .data.aligned_weak_undef
+.p2align 1
+aligned_weak_undef:
+data sym_weak_undef
+
+.section .data.aligned_DYNAMIC
+.p2align 1
+aligned_DYNAMIC:
+data _DYNAMIC
diff --git a/ld/testsuite/ld-riscv-elf/relr-discard-pic.d b/ld/testsuite/ld-riscv-elf/relr-discard-pic.d
new file mode 100644
index 00000000000..d45420b93bd
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-discard-pic.d
@@ -0,0 +1,14 @@
+#source: discard.s
+#as: -march=rv64i
+#ld: -shared -T discard.ld -melf64lriscv -z pack-relative-relocs
+#readelf: -rW
+
+Relocation section '\.rela\.dyn'.*
+[ 	]+Offset[ 	]+Info[ 	]+Type.*
+0000000000020018[ 	]+[0-9a-f]+[ 	]+R_RISCV_64[ 	]+000000000001000c[ 	]+sym_global \+ 0
+0000000000020020[ 	]+[0-9a-f]+[ 	]+R_RISCV_64[ 	]+000000000001000c[ 	]+sym_global_keep \+ 0
+
+Relocation section '\.relr\.dyn'.*
+Index:[ 	]+Entry[ 	]+Address[ 	]+Symbolic Address
+0000:[ 	]+0000000000020008[ 	]+0000000000020008[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x8
+0001:[ 	]+0000000000000003[ 	]+0000000000020010[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x10
diff --git a/ld/testsuite/ld-riscv-elf/relr-discard-pie.d b/ld/testsuite/ld-riscv-elf/relr-discard-pie.d
new file mode 100644
index 00000000000..1137a7de56e
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-discard-pie.d
@@ -0,0 +1,11 @@
+#source: discard.s
+#as: -march=rv64i
+#ld: -pie -T discard.ld -melf64lriscv -z pack-relative-relocs
+#readelf: -rW
+
+Relocation section '\.relr\.dyn'.*
+Index:[ 	]+Entry[ 	]+Address[ 	]+Symbolic Address
+0000:[ 	]+0000000000020008[ 	]+0000000000020008[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x8
+0001:[ 	]+000000000000000f[ 	]+0000000000020010[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x10
+[ 	]+0000000000020018[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x18
+[ 	]+0000000000020020[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x20
diff --git a/ld/testsuite/ld-riscv-elf/relr-got-rv32-pic.d b/ld/testsuite/ld-riscv-elf/relr-got-rv32-pic.d
new file mode 100644
index 00000000000..843953f3d38
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-got-rv32-pic.d
@@ -0,0 +1,21 @@
+#...
+Contents of section .got:
+ 20000 00003412 30000100 34000100 00003412.*
+ 20010 00000000 00000000.*
+#...
+Disassembly of section .text:
+
+00010000 <_start>:
+[ 	]+10000:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+10004:[ 	]+[0-9a-f]+[ 	]+lw[ 	]+.*# 20004 <.*>
+[ 	]+10008:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+1000c:[ 	]+[0-9a-f]+[ 	]+lw[ 	]+.*# 20008 <.*>
+[ 	]+10010:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+10014:[ 	]+[0-9a-f]+[ 	]+lw[ 	]+.*# 20010 <.*>
+[ 	]+10018:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+1001c:[ 	]+[0-9a-f]+[ 	]+lw[ 	]+.*# 20014 <.*>
+[ 	]+10020:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+10024:[ 	]+[0-9a-f]+[ 	]+lw[ 	]+.*# 20018 <.*>
+[ 	]+10028:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+1002c:[ 	]+[0-9a-f]+[ 	]+lw[ 	]+.*# 2000c <.*>
+#...
diff --git a/ld/testsuite/ld-riscv-elf/relr-got-rv32-pic.rd b/ld/testsuite/ld-riscv-elf/relr-got-rv32-pic.rd
new file mode 100644
index 00000000000..22a8888ade1
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-got-rv32-pic.rd
@@ -0,0 +1,11 @@
+Relocation section '\.rela\.dyn'.*contains 3 entries:
+[ 	]+Offset[ 	]+Info[ 	]+Type[ 	]+.*
+00020010[ 	]+[0-9a-f]+[ 	]+R_RISCV_32[ 	]+00010038[ 	]+sym_global \+ 0
+00020014[ 	]+[0-9a-f]+[ 	]+R_RISCV_32[ 	]+0000002a[ 	]+sym_global_abs \+ 0
+00020018[ 	]+[0-9a-f]+[ 	]+R_RISCV_32[ 	]+00000000[ 	]+sym_weak_undef \+ 0
+
+Relocation section '\.relr\.dyn'.*contains 2 entries which relocate 3 locations:
+Index:[ 	]+Entry[ 	]+Address[ 	]+Symbolic Address
+0000:[ 	]+00020004[ 	]+00020004[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x4
+0001:[ 	]+00000007[ 	]+00020008[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x8
+[ 	]+0002000c[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0xc
diff --git a/ld/testsuite/ld-riscv-elf/relr-got-rv32-pie.d b/ld/testsuite/ld-riscv-elf/relr-got-rv32-pie.d
new file mode 100644
index 00000000000..432620d4395
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-got-rv32-pie.d
@@ -0,0 +1,21 @@
+#...
+Contents of section .got:
+ 20000 00003412 30000100 34000100 00003412.*
+ 20010 38000100 2a000000.*
+#...
+Disassembly of section .text:
+
+00010000 <_start>:
+[ 	]+10000:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+10004:[ 	]+[0-9a-f]+[ 	]+lw[ 	]+.*# 20004 <.*>
+[ 	]+10008:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+1000c:[ 	]+[0-9a-f]+[ 	]+lw[ 	]+.*# 20008 <.*>
+[ 	]+10010:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+10014:[ 	]+[0-9a-f]+[ 	]+lw[ 	]+.*# 20010 <.*>
+[ 	]+10018:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+1001c:[ 	]+[0-9a-f]+[ 	]+lw[ 	]+.*# 20014 <.*>
+[ 	]+10020:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+10024:[ 	]+[0-9a-f]+[ 	]+lw[ 	]+.*# 20018 <.*>
+[ 	]+10028:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+1002c:[ 	]+[0-9a-f]+[ 	]+lw[ 	]+.*# 2000c <.*>
+#...
diff --git a/ld/testsuite/ld-riscv-elf/relr-got-rv32-pie.rd b/ld/testsuite/ld-riscv-elf/relr-got-rv32-pie.rd
new file mode 100644
index 00000000000..b0138b16139
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-got-rv32-pie.rd
@@ -0,0 +1,11 @@
+Relocation section '\.rela\.dyn'.*contains 2 entries:
+[ 	]+Offset[ 	]+Info[ 	]+Type[ 	]+.*
+00000000[ 	]+[0-9a-f]+[ 	]+R_RISCV_NONE[ 	]+0
+00020018[ 	]+[0-9a-f]+[ 	]+R_RISCV_32[ 	]+00000000[ 	]+sym_weak_undef \+ 0
+
+Relocation section '\.relr\.dyn'.*contains 2 entries which relocate 4 locations:
+Index:[ 	]+Entry[ 	]+Address[ 	]+Symbolic Address
+0000:[ 	]+00020004[ 	]+00020004[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x4
+0001:[ 	]+0000000f[ 	]+00020008[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x8
+[ 	]+0002000c[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0xc
+[ 	]+00020010[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x10
diff --git a/ld/testsuite/ld-riscv-elf/relr-got-rv64-pic.d b/ld/testsuite/ld-riscv-elf/relr-got-rv64-pic.d
new file mode 100644
index 00000000000..30216ede4c4
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-got-rv64-pic.d
@@ -0,0 +1,23 @@
+#...
+Contents of section .got:
+ 20000 00003412 00000000 30000100 00000000.*
+ 20010 34000100 00000000 00003412 00000000.*
+ 20020 00000000 00000000 00000000 00000000.*
+ 20030 00000000 00000000.*
+#...
+Disassembly of section .text:
+
+0000000000010000 <_start>:
+[ 	]+10000:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+10004:[ 	]+[0-9a-f]+[ 	]+ld[ 	]+.*# 20008 <.*>
+[ 	]+10008:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+1000c:[ 	]+[0-9a-f]+[ 	]+ld[ 	]+.*# 20010 <.*>
+[ 	]+10010:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+10014:[ 	]+[0-9a-f]+[ 	]+ld[ 	]+.*# 20020 <.*>
+[ 	]+10018:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+1001c:[ 	]+[0-9a-f]+[ 	]+ld[ 	]+.*# 20028 <.*>
+[ 	]+10020:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+10024:[ 	]+[0-9a-f]+[ 	]+ld[ 	]+.*# 20030 <.*>
+[ 	]+10028:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+1002c:[ 	]+[0-9a-f]+[ 	]+ld[ 	]+.*# 20018 <.*>
+#...
diff --git a/ld/testsuite/ld-riscv-elf/relr-got-rv64-pic.rd b/ld/testsuite/ld-riscv-elf/relr-got-rv64-pic.rd
new file mode 100644
index 00000000000..39d4dc999f4
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-got-rv64-pic.rd
@@ -0,0 +1,11 @@
+Relocation section '\.rela\.dyn'.*contains 3 entries:
+[ 	]+Offset[ 	]+Info[ 	]+Type[ 	]+.*
+0000000000020020[ 	]+[0-9a-f]+[ 	]+R_RISCV_64[ 	]+0000000000010038[ 	]+sym_global \+ 0
+0000000000020028[ 	]+[0-9a-f]+[ 	]+R_RISCV_64[ 	]+000000000000002a[ 	]+sym_global_abs \+ 0
+0000000000020030[ 	]+[0-9a-f]+[ 	]+R_RISCV_64[ 	]+0000000000000000[ 	]+sym_weak_undef \+ 0
+
+Relocation section '\.relr\.dyn'.*contains 2 entries which relocate 3 locations:
+Index:[ 	]+Entry[ 	]+Address[ 	]+Symbolic Address
+0000:[ 	]+0000000000020008[ 	]+0000000000020008[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x8
+0001:[ 	]+0000000000000007[ 	]+0000000000020010[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x10
+[ 	]+0000000000020018[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x18
diff --git a/ld/testsuite/ld-riscv-elf/relr-got-rv64-pie.d b/ld/testsuite/ld-riscv-elf/relr-got-rv64-pie.d
new file mode 100644
index 00000000000..43da91dfb29
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-got-rv64-pie.d
@@ -0,0 +1,23 @@
+#...
+Contents of section .got:
+ 20000 00003412 00000000 30000100 00000000.*
+ 20010 34000100 00000000 00003412 00000000.*
+ 20020 38000100 00000000 2a000000 00000000.*
+ 20030 00000000 00000000.*
+#...
+Disassembly of section .text:
+
+0000000000010000 <_start>:
+[ 	]+10000:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+10004:[ 	]+[0-9a-f]+[ 	]+ld[ 	]+.*# 20008 <.*>
+[ 	]+10008:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+1000c:[ 	]+[0-9a-f]+[ 	]+ld[ 	]+.*# 20010 <.*>
+[ 	]+10010:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+10014:[ 	]+[0-9a-f]+[ 	]+ld[ 	]+.*# 20020 <.*>
+[ 	]+10018:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+1001c:[ 	]+[0-9a-f]+[ 	]+ld[ 	]+.*# 20028 <.*>
+[ 	]+10020:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+10024:[ 	]+[0-9a-f]+[ 	]+ld[ 	]+.*# 20030 <.*>
+[ 	]+10028:[ 	]+[0-9a-f]+[ 	]+auipc.*
+[ 	]+1002c:[ 	]+[0-9a-f]+[ 	]+ld[ 	]+.*# 20018 <.*>
+#...
diff --git a/ld/testsuite/ld-riscv-elf/relr-got-rv64-pie.rd b/ld/testsuite/ld-riscv-elf/relr-got-rv64-pie.rd
new file mode 100644
index 00000000000..6776d438cb3
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-got-rv64-pie.rd
@@ -0,0 +1,11 @@
+Relocation section '\.rela\.dyn'.*contains 2 entries:
+[ 	]+Offset[ 	]+Info[ 	]+Type[ 	]+.*
+0000000000000000[ 	]+[0-9a-f]+[ 	]+R_RISCV_NONE[ 	]+0
+0000000000020030[ 	]+[0-9a-f]+[ 	]+R_RISCV_64[ 	]+0000000000000000[ 	]+sym_weak_undef \+ 0
+
+Relocation section '\.relr\.dyn'.*contains 2 entries which relocate 4 locations:
+Index:[ 	]+Entry[ 	]+Address[ 	]+Symbolic Address
+0000:[ 	]+0000000000020008[ 	]+0000000000020008[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x8
+0001:[ 	]+000000000000000f[ 	]+0000000000020010[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x10
+[ 	]+0000000000020018[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x18
+[ 	]+0000000000020020[ 	]+_GLOBAL_OFFSET_TABLE_ \+ 0x20
diff --git a/ld/testsuite/ld-riscv-elf/relr-got.s b/ld/testsuite/ld-riscv-elf/relr-got.s
new file mode 100644
index 00000000000..5f98340b5b6
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-got.s
@@ -0,0 +1,31 @@
+# Test GOT relocations with DT_RELR.
+
+.text
+.option norelax
+.option pic
+.global _start
+_start:
+	la	x1, sym_local
+	la	x1, sym_hidden
+	la	x1, sym_global
+	la	x1, sym_global_abs
+	la	x1, sym_weak_undef
+	la	x1, _DYNAMIC
+
+sym_local:
+	nop
+
+.global sym_hidden
+.hidden sym_hidden
+sym_hidden:
+	nop
+
+.global sym_global
+sym_global:
+	nop
+
+.global sym_global_abs
+.set sym_global_abs, 42
+
+.global sym_weak_undef
+.weak sym_weak_undef
diff --git a/ld/testsuite/ld-riscv-elf/relr-relocs.ld b/ld/testsuite/ld-riscv-elf/relr-relocs.ld
new file mode 100644
index 00000000000..2010568190e
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-relocs.ld
@@ -0,0 +1,23 @@
+/* Script for ld testsuite */
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  PROVIDE (__executable_start = 0x8000); . = 0x10000;
+  .text           :
+  {
+    *(.before)
+    *(.text)
+    *(.after)
+  } =0
+  . = 0x20000;
+  .got            : { *(.got) *(.got.plt)}
+  . = 0x12340000;
+  .far : { *(.far) }
+  .riscv.attributes 0 : { *(.ARM.atttributes) }
+  /* Providing a .data section triggers a non-executable segment to be
+     generated, which gives somewhere else for the linker to put the TLS
+     segment without creating a RWX permissioned one. */
+  .data : { *(.data) }
+}
diff --git a/ld/testsuite/ld-riscv-elf/relr-text-pic.d b/ld/testsuite/ld-riscv-elf/relr-text-pic.d
new file mode 100644
index 00000000000..bc151e2f128
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-text-pic.d
@@ -0,0 +1,14 @@
+#source: relr-text.s
+#ld: -shared -z pack-relative-relocs -T relr-relocs.ld
+#readelf: -drW
+
+#...
+.*\(TEXTREL\)[ 	]+0x0
+#...
+.*\(RELR\).*
+.*\(RELRSZ\)[ 	]+(4|8) \(bytes\)
+.*\(RELRENT\)[ 	]+(4|8) \(bytes\)
+#...
+Relocation section '\.relr\.dyn' .* contains 1 entry which relocates 1 location:
+Index:[ 	]+Entry[ 	]+Address[ 	]+Symbolic Address
+0000:[ 	]+(00000000|)00010000[ 	]+(00000000|)00010000[ 	]+_start
diff --git a/ld/testsuite/ld-riscv-elf/relr-text-pie.d b/ld/testsuite/ld-riscv-elf/relr-text-pie.d
new file mode 100644
index 00000000000..65ef1de775f
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-text-pie.d
@@ -0,0 +1,14 @@
+#source: relr-text.s
+#ld: -pie -z pack-relative-relocs -T relr-relocs.ld
+#readelf: -drW
+
+#...
+.*\(TEXTREL\)[ 	]+0x0
+#...
+.*\(RELR\).*
+.*\(RELRSZ\)[ 	]+(4|8) \(bytes\)
+.*\(RELRENT\)[ 	]+(4|8) \(bytes\)
+#...
+Relocation section '\.relr\.dyn' .* contains 1 entry which relocates 1 location:
+Index:[ 	]+Entry[ 	]+Address[ 	]+Symbolic Address
+0000:[ 	]+(00000000|)00010000[ 	]+(00000000|)00010000[ 	]+_start
diff --git a/ld/testsuite/ld-riscv-elf/relr-text.s b/ld/testsuite/ld-riscv-elf/relr-text.s
new file mode 100644
index 00000000000..7e0eecbc527
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/relr-text.s
@@ -0,0 +1,10 @@
+# Test DT_RELR with DT_TEXTREL.
+
+.text
+.p2align 3
+.global _start
+_start:
+.global foo
+.hidden foo
+foo:
+.quad foo
-- 
2.39.5 (Apple Git-154)



More information about the Binutils mailing list