[05/10] ld: Initial DT_RELR support

Message ID 20220107190631.309790-6-hjl.tools@gmail.com
State Superseded
Headers
Series ld: Implement DT_RELR for x86 |

Checks

Context Check Description
dj/TryBot-apply_patch fail Patch failed to apply to master at the time it was sent

Commit Message

H.J. Lu Jan. 7, 2022, 7:06 p.m. UTC
  Add a -z pack-relative-relocs option to enable DT_RELR and create a
relr.dyn section for DT_RELR.

-z pack-relative-relocs implies -z combreloc and --relax.  --no-relax
and -z nocombreloc imply -z nopack-relative-relocs.

-z pack-relative-relocs is chosen over the similar option in lld,
--pack-dyn-relocs=relr, to implement a glibc binary lockout mechanism
with a special glibc version symbol, to avoid random crashes of DT_RELR
binaries with the existing glibc binaries.

bfd/

	* elf-bfd.h (elf_link_hash_table): Add srelrdyn.
	* elflink.c (_bfd_elf_link_create_dynamic_sections): Create a
	.relr.dyn section for DT_RELR.

include/

	* bfdlink.h (bfd_link_info): Add enable_dt_relr.

ld/

	* News: Mention -z pack-relative-relocs and
	-z nopack-relative-relocs.
	* ld.texi: Document -z pack-relative-relocs and
	-z nopack-relative-relocs.
	* ldelf.c (ldelf_after_parse): Disable DT_RELR if not building
	PIE nor shared library.  Add 3 spare dynamic tags for DT_RELR,
	DT_RELRSZ and DT_RELRENT.
	* lexsup.c (parse_args): Disable DT_RELR for --no-relax.
	* emulparams/elf32_x86_64.sh: Source dt-relr.sh.
	* emulparams/elf_i386.sh: Likewise.
	* emulparams/elf_x86_64.sh: Likewise.
	* emulparams/dt-relr.sh: New file.
	* emultempl/elf.em (gld${EMULATION_NAME}_handle_option): Disable
	DT_RELR for -z nocombreloc.
	* scripttempl/elf.sc: Support .relr.dyn.
---
 bfd/elf-bfd.h                 |  1 +
 bfd/elflink.c                 | 11 +++++++++++
 include/bfdlink.h             |  4 ++++
 ld/NEWS                       |  3 +++
 ld/emulparams/dt-relr.sh      | 21 +++++++++++++++++++++
 ld/emulparams/elf32_x86_64.sh |  1 +
 ld/emulparams/elf_i386.sh     |  1 +
 ld/emulparams/elf_x86_64.sh   |  1 +
 ld/emultempl/elf.em           |  5 ++++-
 ld/ld.texi                    | 14 +++++++++++++-
 ld/ldelf.c                    | 13 +++++++++++++
 ld/lexsup.c                   |  1 +
 ld/scripttempl/elf.sc         |  4 ++++
 13 files changed, 78 insertions(+), 2 deletions(-)
 create mode 100644 ld/emulparams/dt-relr.sh
  

Comments

Fangrui Song Jan. 8, 2022, 2:10 a.m. UTC | #1
On 2022-01-07, H.J. Lu via Binutils wrote:
>Add a -z pack-relative-relocs option to enable DT_RELR and create a
>relr.dyn section for DT_RELR.
>
>-z pack-relative-relocs implies -z combreloc and --relax.  --no-relax
>and -z nocombreloc imply -z nopack-relative-relocs.
>
>-z pack-relative-relocs is chosen over the similar option in lld,
>--pack-dyn-relocs=relr, to implement a glibc binary lockout mechanism
>with a special glibc version symbol, to avoid random crashes of DT_RELR
>binaries with the existing glibc binaries.

Why does --no-relax suppress  -z nopack-relative-relocs?

My mental model is that --relax is for GOTPCRELX/TLS optimization/RISC-V
relaxation/AArch64 GOT optimization/(hopefully PowerPC64 TOC
optimization)/etc. It should be orthogonal to RELR. It is true that
both RISC-V relaxation/RELR need to compute the layouts more than once,
but other passes technically don't need to be coupled with layout
computation.

People specifying --no-relax may work around potential bugs, but they
may not want to lose the benefit of RELR.

>bfd/
>
>	* elf-bfd.h (elf_link_hash_table): Add srelrdyn.
>	* elflink.c (_bfd_elf_link_create_dynamic_sections): Create a
>	.relr.dyn section for DT_RELR.
>
>include/
>
>	* bfdlink.h (bfd_link_info): Add enable_dt_relr.
>
>ld/
>
>	* News: Mention -z pack-relative-relocs and
>	-z nopack-relative-relocs.
>	* ld.texi: Document -z pack-relative-relocs and
>	-z nopack-relative-relocs.
>	* ldelf.c (ldelf_after_parse): Disable DT_RELR if not building
>	PIE nor shared library.  Add 3 spare dynamic tags for DT_RELR,
>	DT_RELRSZ and DT_RELRENT.
>	* lexsup.c (parse_args): Disable DT_RELR for --no-relax.
>	* emulparams/elf32_x86_64.sh: Source dt-relr.sh.
>	* emulparams/elf_i386.sh: Likewise.
>	* emulparams/elf_x86_64.sh: Likewise.
>	* emulparams/dt-relr.sh: New file.
>	* emultempl/elf.em (gld${EMULATION_NAME}_handle_option): Disable
>	DT_RELR for -z nocombreloc.
>	* scripttempl/elf.sc: Support .relr.dyn.
>---
> bfd/elf-bfd.h                 |  1 +
> bfd/elflink.c                 | 11 +++++++++++
> include/bfdlink.h             |  4 ++++
> ld/NEWS                       |  3 +++
> ld/emulparams/dt-relr.sh      | 21 +++++++++++++++++++++
> ld/emulparams/elf32_x86_64.sh |  1 +
> ld/emulparams/elf_i386.sh     |  1 +
> ld/emulparams/elf_x86_64.sh   |  1 +
> ld/emultempl/elf.em           |  5 ++++-
> ld/ld.texi                    | 14 +++++++++++++-
> ld/ldelf.c                    | 13 +++++++++++++
> ld/lexsup.c                   |  1 +
> ld/scripttempl/elf.sc         |  4 ++++
> 13 files changed, 78 insertions(+), 2 deletions(-)
> create mode 100644 ld/emulparams/dt-relr.sh
>
>diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
>index c4d2ef00d6b..4e73d79ee77 100644
>--- a/bfd/elf-bfd.h
>+++ b/bfd/elf-bfd.h
>@@ -707,6 +707,7 @@ struct elf_link_hash_table
>   asection *irelplt;
>   asection *irelifunc;
>   asection *dynsym;
>+  asection *srelrdyn;
> };
>
> /* Returns TRUE if the hash table is a struct elf_link_hash_table.  */
>diff --git a/bfd/elflink.c b/bfd/elflink.c
>index bea413ec24e..d51b00b6c10 100644
>--- a/bfd/elflink.c
>+++ b/bfd/elflink.c
>@@ -359,6 +359,17 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
> 	elf_section_data (s)->this_hdr.sh_entsize = 4;
>     }
>
>+  if (info->enable_dt_relr)
>+    {
>+      s = bfd_make_section_anyway_with_flags (abfd, ".relr.dyn",
>+					      (bed->dynamic_sec_flags
>+					       | SEC_READONLY));
>+      if (s == NULL
>+	  || !bfd_set_section_alignment (s, bed->s->log_file_align))
>+	return false;
>+      elf_hash_table (info)->srelrdyn = s;
>+    }
>+
>   /* Let the backend create the rest of the sections.  This lets the
>      backend set the right flags.  The backend will normally create
>      the .got and .plt sections.  */
>diff --git a/include/bfdlink.h b/include/bfdlink.h
>index 01f57c22edf..92e3e32360b 100644
>--- a/include/bfdlink.h
>+++ b/include/bfdlink.h
>@@ -413,6 +413,10 @@ struct bfd_link_info
>   /* TRUE if PT_GNU_RELRO segment should be created.  */
>   unsigned int relro: 1;
>
>+  /* TRUE if DT_RELR should be enabled for compact relative
>+     relocations.  */
>+  unsigned int enable_dt_relr: 1;
>+
>   /* TRUE if separate code segment should be created.  */
>   unsigned int separate_code: 1;
>
>diff --git a/ld/NEWS b/ld/NEWS
>index 5d3d80dbbba..77c716b577d 100644
>--- a/ld/NEWS
>+++ b/ld/NEWS
>@@ -1,5 +1,8 @@
> -*- text -*-
>
>+* Add -z pack-relative-relocs/-z no pack-relative-relocs to x86 ELF
>+  linker to pack relative relocations in the DT_RELR section.
>+
> * Add support for the LoongArch architecture.
>
> * Add -z indirect-extern-access/-z noindirect-extern-access to x86 ELF
>diff --git a/ld/emulparams/dt-relr.sh b/ld/emulparams/dt-relr.sh
>new file mode 100644
>index 00000000000..ed93ee2b5c2
>--- /dev/null
>+++ b/ld/emulparams/dt-relr.sh
>@@ -0,0 +1,21 @@
>+HAVE_DT_RELR=yes
>+PARSE_AND_LIST_OPTIONS_PACK_RELATIVE_RELOCS='
>+  fprintf (file, _("\
>+  -z pack-relative-relocs     Pack relative relocations\n"));
>+  fprintf (file, _("\
>+  -z nopack-relative-relocs   Do not pack relative relocations (default)\n"));
>+'
>+
>+PARSE_AND_LIST_ARGS_CASE_Z_PACK_RELATIVE_RELOCS='
>+      else if (strcmp (optarg, "pack-relative-relocs") == 0)
>+	{
>+	  link_info.enable_dt_relr = true;
>+	  link_info.combreloc = true;
>+	}
>+      else if (strcmp (optarg, "nopack-relative-relocs") == 0)
>+	link_info.enable_dt_relr = false;
>+'
>+
>+
>+PARSE_AND_LIST_OPTIONS="$PARSE_AND_LIST_OPTIONS $PARSE_AND_LIST_OPTIONS_PACK_RELATIVE_RELOCS"
>+PARSE_AND_LIST_ARGS_CASE_Z="$PARSE_AND_LIST_ARGS_CASE_Z $PARSE_AND_LIST_ARGS_CASE_Z_PACK_RELATIVE_RELOCS"
>diff --git a/ld/emulparams/elf32_x86_64.sh b/ld/emulparams/elf32_x86_64.sh
>index ac0a7aa6dcf..4bff41287c1 100644
>--- a/ld/emulparams/elf32_x86_64.sh
>+++ b/ld/emulparams/elf32_x86_64.sh
>@@ -7,6 +7,7 @@ source_sh ${srcdir}/emulparams/cet.sh
> source_sh ${srcdir}/emulparams/x86-report-relative.sh
> source_sh ${srcdir}/emulparams/x86-64-level.sh
> source_sh ${srcdir}/emulparams/static.sh
>+source_sh ${srcdir}/emulparams/dt-relr.sh
> SCRIPT_NAME=elf
> ELFSIZE=32
> OUTPUT_FORMAT="elf32-x86-64"
>diff --git a/ld/emulparams/elf_i386.sh b/ld/emulparams/elf_i386.sh
>index 98532e5edbc..ae17bb4b3f7 100644
>--- a/ld/emulparams/elf_i386.sh
>+++ b/ld/emulparams/elf_i386.sh
>@@ -6,6 +6,7 @@ source_sh ${srcdir}/emulparams/cet.sh
> source_sh ${srcdir}/emulparams/x86-report-relative.sh
> source_sh ${srcdir}/emulparams/x86-64-level.sh
> source_sh ${srcdir}/emulparams/static.sh
>+source_sh ${srcdir}/emulparams/dt-relr.sh
> SCRIPT_NAME=elf
> OUTPUT_FORMAT="elf32-i386"
> NO_RELA_RELOCS=yes
>diff --git a/ld/emulparams/elf_x86_64.sh b/ld/emulparams/elf_x86_64.sh
>index 48d0974711b..5f2743ed409 100644
>--- a/ld/emulparams/elf_x86_64.sh
>+++ b/ld/emulparams/elf_x86_64.sh
>@@ -8,6 +8,7 @@ source_sh ${srcdir}/emulparams/x86-report-relative.sh
> source_sh ${srcdir}/emulparams/x86-64-level.sh
> source_sh ${srcdir}/emulparams/x86-64-lam.sh
> source_sh ${srcdir}/emulparams/static.sh
>+source_sh ${srcdir}/emulparams/dt-relr.sh
> SCRIPT_NAME=elf
> ELFSIZE=64
> OUTPUT_FORMAT="elf64-x86-64"
>diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
>index 59775260b06..7a32a4cc4d4 100644
>--- a/ld/emultempl/elf.em
>+++ b/ld/emultempl/elf.em
>@@ -822,7 +822,10 @@ fragment <<EOF
>       else if (strcmp (optarg, "combreloc") == 0)
> 	link_info.combreloc = true;
>       else if (strcmp (optarg, "nocombreloc") == 0)
>-	link_info.combreloc = false;
>+	{
>+	  link_info.combreloc = false;
>+	  link_info.enable_dt_relr = false;
>+	}
>       else if (strcmp (optarg, "nocopyreloc") == 0)
> 	link_info.nocopyreloc = true;
> EOF
>diff --git a/ld/ld.texi b/ld/ld.texi
>index edcf1772855..457089ec06a 100644
>--- a/ld/ld.texi
>+++ b/ld/ld.texi
>@@ -1242,6 +1242,7 @@ Supported for Linux/i386 and Linux/x86_64.
> @itemx nocombreloc
> Combine multiple dynamic relocation sections and sort to improve
> dynamic symbol lookup caching.  Do not do this if @samp{nocombreloc}.
>+@samp{nocombreloc} implies @samp{nopack-relative-relocs}.
>
> @item common
> @itemx nocommon
>@@ -1430,6 +1431,16 @@ called.
> @item origin
> Specify that the object requires @samp{$ORIGIN} handling in paths.
>
>+@item pack-relative-relocs
>+@itemx nopack-relative-relocs
>+Generate compact relative relocation in position-independent executable
>+and shared library.  It adds @code{DT_RELR}, @code{DT_RELRSZ} and
>+@code{DT_RELRENT} entries to the dynamic section.  It is ignored when
>+building position-dependent executable and relocatable output.  This
>+option also implies @option{combreloc} and @option{--relax}.
>+@option{nopack-relative-relocs} is the default, which disables
>+compact relative relocation.  Supported for i386 and x86-64.
>+
> @item relro
> @itemx norelro
> Create an ELF @code{PT_GNU_RELRO} segment header in the object.  This
>@@ -2215,7 +2226,8 @@ family of processors.
> @end ifset
>
> On platforms where the feature is supported, the option
>-@option{--no-relax} will disable it.
>+@option{--no-relax} will disable it and also imply
>+@option{-z nopack-relative-relocs}.
>
> On platforms where the feature is not supported, both @option{--relax}
> and @option{--no-relax} are accepted, but ignored.
>diff --git a/ld/ldelf.c b/ld/ldelf.c
>index d15f027e91a..1978ac477f5 100644
>--- a/ld/ldelf.c
>+++ b/ld/ldelf.c
>@@ -71,6 +71,19 @@ ldelf_after_parse (void)
> 	einfo (_("%P: warning: -z dynamic-undefined-weak ignored\n"));
>       link_info.dynamic_undefined_weak = 0;
>     }
>+
>+  /* Disable DT_RELR if not building PIE nor shared library.  */
>+  if (!bfd_link_pic (&link_info))
>+    link_info.enable_dt_relr = 0;
>+
>+  if (link_info.enable_dt_relr)
>+    {
>+      ENABLE_RELAXATION;
>+
>+      /* Add 3 spare tags for DT_RELR, DT_RELRSZ and DT_RELRENT.  */
>+      link_info.spare_dynamic_tags += 3;
>+    }
>+
>   after_parse_default ();
>   if (link_info.commonpagesize > link_info.maxpagesize)
>     einfo (_("%F%P: common page size (0x%v) > maximum page size (0x%v)\n"),
>diff --git a/ld/lexsup.c b/ld/lexsup.c
>index 5acc47ed5a0..3942716963a 100644
>--- a/ld/lexsup.c
>+++ b/ld/lexsup.c
>@@ -1229,6 +1229,7 @@ parse_args (unsigned argc, char **argv)
> 	  break;
> 	case OPTION_NO_RELAX:
> 	  DISABLE_RELAXATION;
>+	  link_info.enable_dt_relr = false;
> 	  break;
> 	case OPTION_RELAX:
> 	  ENABLE_RELAXATION;
>diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
>index a9a39ad402c..f3552a4a554 100644
>--- a/ld/scripttempl/elf.sc
>+++ b/ld/scripttempl/elf.sc
>@@ -10,6 +10,7 @@
> #		empty.
> #	HAVE_NOINIT - Include a .noinit output section in the script.
> #	HAVE_PERSISTENT - Include a .persistent output section in the script.
>+#	HAVE_DT_RELR - Include a .relr.dyn output section in the script.
> #	SMALL_DATA_CTOR - .ctors contains small data.
> #	SMALL_DATA_DTOR - .dtors contains small data.
> #	DATA_ADDR - if end-of-text-plus-one-page isn't right for data start
>@@ -520,6 +521,9 @@ emit_dyn()
>     fi
>   fi
>   rm -f ldscripts/dyntmp.$$
>+  if test -n "${COMBRELOC}" && test -n "${HAVE_DT_RELR}"; then
>+    echo "  .relr.dyn : { *(.relr.dyn) }"
>+  fi
> }
>
> test -n "${NON_ALLOC_DYN}${SEPARATE_CODE}" || emit_dyn
>-- 
>2.33.1
>
  
H.J. Lu Jan. 8, 2022, 2:42 a.m. UTC | #2
On Fri, Jan 7, 2022 at 6:10 PM Fangrui Song <i@maskray.me> wrote:
>
> On 2022-01-07, H.J. Lu via Binutils wrote:
> >Add a -z pack-relative-relocs option to enable DT_RELR and create a
> >relr.dyn section for DT_RELR.
> >
> >-z pack-relative-relocs implies -z combreloc and --relax.  --no-relax
> >and -z nocombreloc imply -z nopack-relative-relocs.
> >
> >-z pack-relative-relocs is chosen over the similar option in lld,
> >--pack-dyn-relocs=relr, to implement a glibc binary lockout mechanism
> >with a special glibc version symbol, to avoid random crashes of DT_RELR
> >binaries with the existing glibc binaries.
>
> Why does --no-relax suppress  -z nopack-relative-relocs?

-z nopack-relative-relocs uses the linker relaxation.  It is
possible to do it with --no-relax.  But it requires a major change
in the linker relaxation.

> My mental model is that --relax is for GOTPCRELX/TLS optimization/RISC-V
> relaxation/AArch64 GOT optimization/(hopefully PowerPC64 TOC
> optimization)/etc. It should be orthogonal to RELR. It is true that
> both RISC-V relaxation/RELR need to compute the layouts more than once,
> but other passes technically don't need to be coupled with layout
> computation.

I will look into it after the initial DT_RELR work is checked in.

> People specifying --no-relax may work around potential bugs, but they
> may not want to lose the benefit of RELR.
>
> >bfd/
> >
> >       * elf-bfd.h (elf_link_hash_table): Add srelrdyn.
> >       * elflink.c (_bfd_elf_link_create_dynamic_sections): Create a
> >       .relr.dyn section for DT_RELR.
> >
> >include/
> >
> >       * bfdlink.h (bfd_link_info): Add enable_dt_relr.
> >
> >ld/
> >
> >       * News: Mention -z pack-relative-relocs and
> >       -z nopack-relative-relocs.
> >       * ld.texi: Document -z pack-relative-relocs and
> >       -z nopack-relative-relocs.
> >       * ldelf.c (ldelf_after_parse): Disable DT_RELR if not building
> >       PIE nor shared library.  Add 3 spare dynamic tags for DT_RELR,
> >       DT_RELRSZ and DT_RELRENT.
> >       * lexsup.c (parse_args): Disable DT_RELR for --no-relax.
> >       * emulparams/elf32_x86_64.sh: Source dt-relr.sh.
> >       * emulparams/elf_i386.sh: Likewise.
> >       * emulparams/elf_x86_64.sh: Likewise.
> >       * emulparams/dt-relr.sh: New file.
> >       * emultempl/elf.em (gld${EMULATION_NAME}_handle_option): Disable
> >       DT_RELR for -z nocombreloc.
> >       * scripttempl/elf.sc: Support .relr.dyn.
> >---
> > bfd/elf-bfd.h                 |  1 +
> > bfd/elflink.c                 | 11 +++++++++++
> > include/bfdlink.h             |  4 ++++
> > ld/NEWS                       |  3 +++
> > ld/emulparams/dt-relr.sh      | 21 +++++++++++++++++++++
> > ld/emulparams/elf32_x86_64.sh |  1 +
> > ld/emulparams/elf_i386.sh     |  1 +
> > ld/emulparams/elf_x86_64.sh   |  1 +
> > ld/emultempl/elf.em           |  5 ++++-
> > ld/ld.texi                    | 14 +++++++++++++-
> > ld/ldelf.c                    | 13 +++++++++++++
> > ld/lexsup.c                   |  1 +
> > ld/scripttempl/elf.sc         |  4 ++++
> > 13 files changed, 78 insertions(+), 2 deletions(-)
> > create mode 100644 ld/emulparams/dt-relr.sh
> >
> >diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
> >index c4d2ef00d6b..4e73d79ee77 100644
> >--- a/bfd/elf-bfd.h
> >+++ b/bfd/elf-bfd.h
> >@@ -707,6 +707,7 @@ struct elf_link_hash_table
> >   asection *irelplt;
> >   asection *irelifunc;
> >   asection *dynsym;
> >+  asection *srelrdyn;
> > };
> >
> > /* Returns TRUE if the hash table is a struct elf_link_hash_table.  */
> >diff --git a/bfd/elflink.c b/bfd/elflink.c
> >index bea413ec24e..d51b00b6c10 100644
> >--- a/bfd/elflink.c
> >+++ b/bfd/elflink.c
> >@@ -359,6 +359,17 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
> >       elf_section_data (s)->this_hdr.sh_entsize = 4;
> >     }
> >
> >+  if (info->enable_dt_relr)
> >+    {
> >+      s = bfd_make_section_anyway_with_flags (abfd, ".relr.dyn",
> >+                                            (bed->dynamic_sec_flags
> >+                                             | SEC_READONLY));
> >+      if (s == NULL
> >+        || !bfd_set_section_alignment (s, bed->s->log_file_align))
> >+      return false;
> >+      elf_hash_table (info)->srelrdyn = s;
> >+    }
> >+
> >   /* Let the backend create the rest of the sections.  This lets the
> >      backend set the right flags.  The backend will normally create
> >      the .got and .plt sections.  */
> >diff --git a/include/bfdlink.h b/include/bfdlink.h
> >index 01f57c22edf..92e3e32360b 100644
> >--- a/include/bfdlink.h
> >+++ b/include/bfdlink.h
> >@@ -413,6 +413,10 @@ struct bfd_link_info
> >   /* TRUE if PT_GNU_RELRO segment should be created.  */
> >   unsigned int relro: 1;
> >
> >+  /* TRUE if DT_RELR should be enabled for compact relative
> >+     relocations.  */
> >+  unsigned int enable_dt_relr: 1;
> >+
> >   /* TRUE if separate code segment should be created.  */
> >   unsigned int separate_code: 1;
> >
> >diff --git a/ld/NEWS b/ld/NEWS
> >index 5d3d80dbbba..77c716b577d 100644
> >--- a/ld/NEWS
> >+++ b/ld/NEWS
> >@@ -1,5 +1,8 @@
> > -*- text -*-
> >
> >+* Add -z pack-relative-relocs/-z no pack-relative-relocs to x86 ELF
> >+  linker to pack relative relocations in the DT_RELR section.
> >+
> > * Add support for the LoongArch architecture.
> >
> > * Add -z indirect-extern-access/-z noindirect-extern-access to x86 ELF
> >diff --git a/ld/emulparams/dt-relr.sh b/ld/emulparams/dt-relr.sh
> >new file mode 100644
> >index 00000000000..ed93ee2b5c2
> >--- /dev/null
> >+++ b/ld/emulparams/dt-relr.sh
> >@@ -0,0 +1,21 @@
> >+HAVE_DT_RELR=yes
> >+PARSE_AND_LIST_OPTIONS_PACK_RELATIVE_RELOCS='
> >+  fprintf (file, _("\
> >+  -z pack-relative-relocs     Pack relative relocations\n"));
> >+  fprintf (file, _("\
> >+  -z nopack-relative-relocs   Do not pack relative relocations (default)\n"));
> >+'
> >+
> >+PARSE_AND_LIST_ARGS_CASE_Z_PACK_RELATIVE_RELOCS='
> >+      else if (strcmp (optarg, "pack-relative-relocs") == 0)
> >+      {
> >+        link_info.enable_dt_relr = true;
> >+        link_info.combreloc = true;
> >+      }
> >+      else if (strcmp (optarg, "nopack-relative-relocs") == 0)
> >+      link_info.enable_dt_relr = false;
> >+'
> >+
> >+
> >+PARSE_AND_LIST_OPTIONS="$PARSE_AND_LIST_OPTIONS $PARSE_AND_LIST_OPTIONS_PACK_RELATIVE_RELOCS"
> >+PARSE_AND_LIST_ARGS_CASE_Z="$PARSE_AND_LIST_ARGS_CASE_Z $PARSE_AND_LIST_ARGS_CASE_Z_PACK_RELATIVE_RELOCS"
> >diff --git a/ld/emulparams/elf32_x86_64.sh b/ld/emulparams/elf32_x86_64.sh
> >index ac0a7aa6dcf..4bff41287c1 100644
> >--- a/ld/emulparams/elf32_x86_64.sh
> >+++ b/ld/emulparams/elf32_x86_64.sh
> >@@ -7,6 +7,7 @@ source_sh ${srcdir}/emulparams/cet.sh
> > source_sh ${srcdir}/emulparams/x86-report-relative.sh
> > source_sh ${srcdir}/emulparams/x86-64-level.sh
> > source_sh ${srcdir}/emulparams/static.sh
> >+source_sh ${srcdir}/emulparams/dt-relr.sh
> > SCRIPT_NAME=elf
> > ELFSIZE=32
> > OUTPUT_FORMAT="elf32-x86-64"
> >diff --git a/ld/emulparams/elf_i386.sh b/ld/emulparams/elf_i386.sh
> >index 98532e5edbc..ae17bb4b3f7 100644
> >--- a/ld/emulparams/elf_i386.sh
> >+++ b/ld/emulparams/elf_i386.sh
> >@@ -6,6 +6,7 @@ source_sh ${srcdir}/emulparams/cet.sh
> > source_sh ${srcdir}/emulparams/x86-report-relative.sh
> > source_sh ${srcdir}/emulparams/x86-64-level.sh
> > source_sh ${srcdir}/emulparams/static.sh
> >+source_sh ${srcdir}/emulparams/dt-relr.sh
> > SCRIPT_NAME=elf
> > OUTPUT_FORMAT="elf32-i386"
> > NO_RELA_RELOCS=yes
> >diff --git a/ld/emulparams/elf_x86_64.sh b/ld/emulparams/elf_x86_64.sh
> >index 48d0974711b..5f2743ed409 100644
> >--- a/ld/emulparams/elf_x86_64.sh
> >+++ b/ld/emulparams/elf_x86_64.sh
> >@@ -8,6 +8,7 @@ source_sh ${srcdir}/emulparams/x86-report-relative.sh
> > source_sh ${srcdir}/emulparams/x86-64-level.sh
> > source_sh ${srcdir}/emulparams/x86-64-lam.sh
> > source_sh ${srcdir}/emulparams/static.sh
> >+source_sh ${srcdir}/emulparams/dt-relr.sh
> > SCRIPT_NAME=elf
> > ELFSIZE=64
> > OUTPUT_FORMAT="elf64-x86-64"
> >diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
> >index 59775260b06..7a32a4cc4d4 100644
> >--- a/ld/emultempl/elf.em
> >+++ b/ld/emultempl/elf.em
> >@@ -822,7 +822,10 @@ fragment <<EOF
> >       else if (strcmp (optarg, "combreloc") == 0)
> >       link_info.combreloc = true;
> >       else if (strcmp (optarg, "nocombreloc") == 0)
> >-      link_info.combreloc = false;
> >+      {
> >+        link_info.combreloc = false;
> >+        link_info.enable_dt_relr = false;
> >+      }
> >       else if (strcmp (optarg, "nocopyreloc") == 0)
> >       link_info.nocopyreloc = true;
> > EOF
> >diff --git a/ld/ld.texi b/ld/ld.texi
> >index edcf1772855..457089ec06a 100644
> >--- a/ld/ld.texi
> >+++ b/ld/ld.texi
> >@@ -1242,6 +1242,7 @@ Supported for Linux/i386 and Linux/x86_64.
> > @itemx nocombreloc
> > Combine multiple dynamic relocation sections and sort to improve
> > dynamic symbol lookup caching.  Do not do this if @samp{nocombreloc}.
> >+@samp{nocombreloc} implies @samp{nopack-relative-relocs}.
> >
> > @item common
> > @itemx nocommon
> >@@ -1430,6 +1431,16 @@ called.
> > @item origin
> > Specify that the object requires @samp{$ORIGIN} handling in paths.
> >
> >+@item pack-relative-relocs
> >+@itemx nopack-relative-relocs
> >+Generate compact relative relocation in position-independent executable
> >+and shared library.  It adds @code{DT_RELR}, @code{DT_RELRSZ} and
> >+@code{DT_RELRENT} entries to the dynamic section.  It is ignored when
> >+building position-dependent executable and relocatable output.  This
> >+option also implies @option{combreloc} and @option{--relax}.
> >+@option{nopack-relative-relocs} is the default, which disables
> >+compact relative relocation.  Supported for i386 and x86-64.
> >+
> > @item relro
> > @itemx norelro
> > Create an ELF @code{PT_GNU_RELRO} segment header in the object.  This
> >@@ -2215,7 +2226,8 @@ family of processors.
> > @end ifset
> >
> > On platforms where the feature is supported, the option
> >-@option{--no-relax} will disable it.
> >+@option{--no-relax} will disable it and also imply
> >+@option{-z nopack-relative-relocs}.
> >
> > On platforms where the feature is not supported, both @option{--relax}
> > and @option{--no-relax} are accepted, but ignored.
> >diff --git a/ld/ldelf.c b/ld/ldelf.c
> >index d15f027e91a..1978ac477f5 100644
> >--- a/ld/ldelf.c
> >+++ b/ld/ldelf.c
> >@@ -71,6 +71,19 @@ ldelf_after_parse (void)
> >       einfo (_("%P: warning: -z dynamic-undefined-weak ignored\n"));
> >       link_info.dynamic_undefined_weak = 0;
> >     }
> >+
> >+  /* Disable DT_RELR if not building PIE nor shared library.  */
> >+  if (!bfd_link_pic (&link_info))
> >+    link_info.enable_dt_relr = 0;
> >+
> >+  if (link_info.enable_dt_relr)
> >+    {
> >+      ENABLE_RELAXATION;
> >+
> >+      /* Add 3 spare tags for DT_RELR, DT_RELRSZ and DT_RELRENT.  */
> >+      link_info.spare_dynamic_tags += 3;
> >+    }
> >+
> >   after_parse_default ();
> >   if (link_info.commonpagesize > link_info.maxpagesize)
> >     einfo (_("%F%P: common page size (0x%v) > maximum page size (0x%v)\n"),
> >diff --git a/ld/lexsup.c b/ld/lexsup.c
> >index 5acc47ed5a0..3942716963a 100644
> >--- a/ld/lexsup.c
> >+++ b/ld/lexsup.c
> >@@ -1229,6 +1229,7 @@ parse_args (unsigned argc, char **argv)
> >         break;
> >       case OPTION_NO_RELAX:
> >         DISABLE_RELAXATION;
> >+        link_info.enable_dt_relr = false;
> >         break;
> >       case OPTION_RELAX:
> >         ENABLE_RELAXATION;
> >diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
> >index a9a39ad402c..f3552a4a554 100644
> >--- a/ld/scripttempl/elf.sc
> >+++ b/ld/scripttempl/elf.sc
> >@@ -10,6 +10,7 @@
> > #             empty.
> > #     HAVE_NOINIT - Include a .noinit output section in the script.
> > #     HAVE_PERSISTENT - Include a .persistent output section in the script.
> >+#     HAVE_DT_RELR - Include a .relr.dyn output section in the script.
> > #     SMALL_DATA_CTOR - .ctors contains small data.
> > #     SMALL_DATA_DTOR - .dtors contains small data.
> > #     DATA_ADDR - if end-of-text-plus-one-page isn't right for data start
> >@@ -520,6 +521,9 @@ emit_dyn()
> >     fi
> >   fi
> >   rm -f ldscripts/dyntmp.$$
> >+  if test -n "${COMBRELOC}" && test -n "${HAVE_DT_RELR}"; then
> >+    echo "  .relr.dyn : { *(.relr.dyn) }"
> >+  fi
> > }
> >
> > test -n "${NON_ALLOC_DYN}${SEPARATE_CODE}" || emit_dyn
> >--
> >2.33.1
> >
  
Fangrui Song Jan. 8, 2022, 8:30 a.m. UTC | #3
On 2022-01-07, H.J. Lu via Binutils wrote:
>Add a -z pack-relative-relocs option to enable DT_RELR and create a
>relr.dyn section for DT_RELR.
>
>-z pack-relative-relocs implies -z combreloc and --relax.  --no-relax
>and -z nocombreloc imply -z nopack-relative-relocs.
>
>-z pack-relative-relocs is chosen over the similar option in lld,
>--pack-dyn-relocs=relr, to implement a glibc binary lockout mechanism
>with a special glibc version symbol, to avoid random crashes of DT_RELR
>binaries with the existing glibc binaries.

I think -z pack-relative-relocs is orthogonal to -z combreloc.
-z combreloc affects how .rela.dyn is sorted and whether RELACOUNT is
generated. It has nothing to do with .relr.dyn, which is a different section.
  
H.J. Lu Jan. 8, 2022, 1:19 p.m. UTC | #4
On Sat, Jan 8, 2022 at 12:30 AM Fangrui Song <i@maskray.me> wrote:
>
> On 2022-01-07, H.J. Lu via Binutils wrote:
> >Add a -z pack-relative-relocs option to enable DT_RELR and create a
> >relr.dyn section for DT_RELR.
> >
> >-z pack-relative-relocs implies -z combreloc and --relax.  --no-relax
> >and -z nocombreloc imply -z nopack-relative-relocs.
> >
> >-z pack-relative-relocs is chosen over the similar option in lld,
> >--pack-dyn-relocs=relr, to implement a glibc binary lockout mechanism
> >with a special glibc version symbol, to avoid random crashes of DT_RELR
> >binaries with the existing glibc binaries.
>
> I think -z pack-relative-relocs is orthogonal to -z combreloc.
> -z combreloc affects how .rela.dyn is sorted and whether RELACOUNT is
> generated. It has nothing to do with .relr.dyn, which is a different section.

With -z nocombreloc, ld can generate:

$ readelf -r tmpdir/pr25754-3ba

Relocation section '.rela.data.rel.ro' at offset 0x540 contains 1 entry:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000003de8  000000000008 R_X86_64_RELATIVE                    3de8

Relocation section '.rela.got' at offset 0x558 contains 5 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000003fd0  000100000006 R_X86_64_GLOB_DAT 0000000000000000
__libc_start_main@GLIBC_2.34 + 0
000000003fd8  000200000006 R_X86_64_GLOB_DAT 0000000000000000
_ITM_deregisterTM[...] + 0
000000003fe8  000400000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
000000003ff0  000500000006 R_X86_64_GLOB_DAT 0000000000000000
_ITM_registerTMCl[...] + 0
000000003ff8  000600000006 R_X86_64_GLOB_DAT 0000000000000000
__cxa_finalize@GLIBC_2.2.5 + 0

Relocation section '.rela.fini_array' at offset 0x5d0 contains 1 entry:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000003de0  000000000008 R_X86_64_RELATIVE                    10f0

Relocation section '.rela.init_array' at offset 0x5e8 contains 1 entry:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000003dd8  000000000008 R_X86_64_RELATIVE                    1130

Relocation section '.rela.plt' at offset 0x600 contains 1 entry:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000004018  000300000007 R_X86_64_JUMP_SLO 0000000000000000
puts@GLIBC_2.2.5 + 0

3 R_X86_64_RELATIVEs are 3 different .rela sections.
If they are put in a single section, they are combined.
  
H.J. Lu Jan. 8, 2022, 6:32 p.m. UTC | #5
On Fri, Jan 7, 2022 at 6:42 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Fri, Jan 7, 2022 at 6:10 PM Fangrui Song <i@maskray.me> wrote:
> >
> > On 2022-01-07, H.J. Lu via Binutils wrote:
> > >Add a -z pack-relative-relocs option to enable DT_RELR and create a
> > >relr.dyn section for DT_RELR.
> > >
> > >-z pack-relative-relocs implies -z combreloc and --relax.  --no-relax
> > >and -z nocombreloc imply -z nopack-relative-relocs.
> > >
> > >-z pack-relative-relocs is chosen over the similar option in lld,
> > >--pack-dyn-relocs=relr, to implement a glibc binary lockout mechanism
> > >with a special glibc version symbol, to avoid random crashes of DT_RELR
> > >binaries with the existing glibc binaries.
> >
> > Why does --no-relax suppress  -z nopack-relative-relocs?
>
> -z nopack-relative-relocs uses the linker relaxation.  It is
> possible to do it with --no-relax.  But it requires a major change
> in the linker relaxation.
>

It turns out to be a simple change.  Fixed in the v2 patch.


H.J.
  

Patch

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index c4d2ef00d6b..4e73d79ee77 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -707,6 +707,7 @@  struct elf_link_hash_table
   asection *irelplt;
   asection *irelifunc;
   asection *dynsym;
+  asection *srelrdyn;
 };
 
 /* Returns TRUE if the hash table is a struct elf_link_hash_table.  */
diff --git a/bfd/elflink.c b/bfd/elflink.c
index bea413ec24e..d51b00b6c10 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -359,6 +359,17 @@  _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 	elf_section_data (s)->this_hdr.sh_entsize = 4;
     }
 
+  if (info->enable_dt_relr)
+    {
+      s = bfd_make_section_anyway_with_flags (abfd, ".relr.dyn",
+					      (bed->dynamic_sec_flags
+					       | SEC_READONLY));
+      if (s == NULL
+	  || !bfd_set_section_alignment (s, bed->s->log_file_align))
+	return false;
+      elf_hash_table (info)->srelrdyn = s;
+    }
+
   /* Let the backend create the rest of the sections.  This lets the
      backend set the right flags.  The backend will normally create
      the .got and .plt sections.  */
diff --git a/include/bfdlink.h b/include/bfdlink.h
index 01f57c22edf..92e3e32360b 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -413,6 +413,10 @@  struct bfd_link_info
   /* TRUE if PT_GNU_RELRO segment should be created.  */
   unsigned int relro: 1;
 
+  /* TRUE if DT_RELR should be enabled for compact relative
+     relocations.  */
+  unsigned int enable_dt_relr: 1;
+
   /* TRUE if separate code segment should be created.  */
   unsigned int separate_code: 1;
 
diff --git a/ld/NEWS b/ld/NEWS
index 5d3d80dbbba..77c716b577d 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,8 @@ 
 -*- text -*-
 
+* Add -z pack-relative-relocs/-z no pack-relative-relocs to x86 ELF
+  linker to pack relative relocations in the DT_RELR section.
+
 * Add support for the LoongArch architecture.
 
 * Add -z indirect-extern-access/-z noindirect-extern-access to x86 ELF
diff --git a/ld/emulparams/dt-relr.sh b/ld/emulparams/dt-relr.sh
new file mode 100644
index 00000000000..ed93ee2b5c2
--- /dev/null
+++ b/ld/emulparams/dt-relr.sh
@@ -0,0 +1,21 @@ 
+HAVE_DT_RELR=yes
+PARSE_AND_LIST_OPTIONS_PACK_RELATIVE_RELOCS='
+  fprintf (file, _("\
+  -z pack-relative-relocs     Pack relative relocations\n"));
+  fprintf (file, _("\
+  -z nopack-relative-relocs   Do not pack relative relocations (default)\n"));
+'
+
+PARSE_AND_LIST_ARGS_CASE_Z_PACK_RELATIVE_RELOCS='
+      else if (strcmp (optarg, "pack-relative-relocs") == 0)
+	{
+	  link_info.enable_dt_relr = true;
+	  link_info.combreloc = true;
+	}
+      else if (strcmp (optarg, "nopack-relative-relocs") == 0)
+	link_info.enable_dt_relr = false;
+'
+
+
+PARSE_AND_LIST_OPTIONS="$PARSE_AND_LIST_OPTIONS $PARSE_AND_LIST_OPTIONS_PACK_RELATIVE_RELOCS"
+PARSE_AND_LIST_ARGS_CASE_Z="$PARSE_AND_LIST_ARGS_CASE_Z $PARSE_AND_LIST_ARGS_CASE_Z_PACK_RELATIVE_RELOCS"
diff --git a/ld/emulparams/elf32_x86_64.sh b/ld/emulparams/elf32_x86_64.sh
index ac0a7aa6dcf..4bff41287c1 100644
--- a/ld/emulparams/elf32_x86_64.sh
+++ b/ld/emulparams/elf32_x86_64.sh
@@ -7,6 +7,7 @@  source_sh ${srcdir}/emulparams/cet.sh
 source_sh ${srcdir}/emulparams/x86-report-relative.sh
 source_sh ${srcdir}/emulparams/x86-64-level.sh
 source_sh ${srcdir}/emulparams/static.sh
+source_sh ${srcdir}/emulparams/dt-relr.sh
 SCRIPT_NAME=elf
 ELFSIZE=32
 OUTPUT_FORMAT="elf32-x86-64"
diff --git a/ld/emulparams/elf_i386.sh b/ld/emulparams/elf_i386.sh
index 98532e5edbc..ae17bb4b3f7 100644
--- a/ld/emulparams/elf_i386.sh
+++ b/ld/emulparams/elf_i386.sh
@@ -6,6 +6,7 @@  source_sh ${srcdir}/emulparams/cet.sh
 source_sh ${srcdir}/emulparams/x86-report-relative.sh
 source_sh ${srcdir}/emulparams/x86-64-level.sh
 source_sh ${srcdir}/emulparams/static.sh
+source_sh ${srcdir}/emulparams/dt-relr.sh
 SCRIPT_NAME=elf
 OUTPUT_FORMAT="elf32-i386"
 NO_RELA_RELOCS=yes
diff --git a/ld/emulparams/elf_x86_64.sh b/ld/emulparams/elf_x86_64.sh
index 48d0974711b..5f2743ed409 100644
--- a/ld/emulparams/elf_x86_64.sh
+++ b/ld/emulparams/elf_x86_64.sh
@@ -8,6 +8,7 @@  source_sh ${srcdir}/emulparams/x86-report-relative.sh
 source_sh ${srcdir}/emulparams/x86-64-level.sh
 source_sh ${srcdir}/emulparams/x86-64-lam.sh
 source_sh ${srcdir}/emulparams/static.sh
+source_sh ${srcdir}/emulparams/dt-relr.sh
 SCRIPT_NAME=elf
 ELFSIZE=64
 OUTPUT_FORMAT="elf64-x86-64"
diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
index 59775260b06..7a32a4cc4d4 100644
--- a/ld/emultempl/elf.em
+++ b/ld/emultempl/elf.em
@@ -822,7 +822,10 @@  fragment <<EOF
       else if (strcmp (optarg, "combreloc") == 0)
 	link_info.combreloc = true;
       else if (strcmp (optarg, "nocombreloc") == 0)
-	link_info.combreloc = false;
+	{
+	  link_info.combreloc = false;
+	  link_info.enable_dt_relr = false;
+	}
       else if (strcmp (optarg, "nocopyreloc") == 0)
 	link_info.nocopyreloc = true;
 EOF
diff --git a/ld/ld.texi b/ld/ld.texi
index edcf1772855..457089ec06a 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1242,6 +1242,7 @@  Supported for Linux/i386 and Linux/x86_64.
 @itemx nocombreloc
 Combine multiple dynamic relocation sections and sort to improve
 dynamic symbol lookup caching.  Do not do this if @samp{nocombreloc}.
+@samp{nocombreloc} implies @samp{nopack-relative-relocs}.
 
 @item common
 @itemx nocommon
@@ -1430,6 +1431,16 @@  called.
 @item origin
 Specify that the object requires @samp{$ORIGIN} handling in paths.
 
+@item pack-relative-relocs
+@itemx nopack-relative-relocs
+Generate compact relative relocation in position-independent executable
+and shared library.  It adds @code{DT_RELR}, @code{DT_RELRSZ} and
+@code{DT_RELRENT} entries to the dynamic section.  It is ignored when
+building position-dependent executable and relocatable output.  This
+option also implies @option{combreloc} and @option{--relax}.
+@option{nopack-relative-relocs} is the default, which disables
+compact relative relocation.  Supported for i386 and x86-64.
+
 @item relro
 @itemx norelro
 Create an ELF @code{PT_GNU_RELRO} segment header in the object.  This
@@ -2215,7 +2226,8 @@  family of processors.
 @end ifset
 
 On platforms where the feature is supported, the option
-@option{--no-relax} will disable it.
+@option{--no-relax} will disable it and also imply
+@option{-z nopack-relative-relocs}.
 
 On platforms where the feature is not supported, both @option{--relax}
 and @option{--no-relax} are accepted, but ignored.
diff --git a/ld/ldelf.c b/ld/ldelf.c
index d15f027e91a..1978ac477f5 100644
--- a/ld/ldelf.c
+++ b/ld/ldelf.c
@@ -71,6 +71,19 @@  ldelf_after_parse (void)
 	einfo (_("%P: warning: -z dynamic-undefined-weak ignored\n"));
       link_info.dynamic_undefined_weak = 0;
     }
+
+  /* Disable DT_RELR if not building PIE nor shared library.  */
+  if (!bfd_link_pic (&link_info))
+    link_info.enable_dt_relr = 0;
+
+  if (link_info.enable_dt_relr)
+    {
+      ENABLE_RELAXATION;
+
+      /* Add 3 spare tags for DT_RELR, DT_RELRSZ and DT_RELRENT.  */
+      link_info.spare_dynamic_tags += 3;
+    }
+
   after_parse_default ();
   if (link_info.commonpagesize > link_info.maxpagesize)
     einfo (_("%F%P: common page size (0x%v) > maximum page size (0x%v)\n"),
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 5acc47ed5a0..3942716963a 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -1229,6 +1229,7 @@  parse_args (unsigned argc, char **argv)
 	  break;
 	case OPTION_NO_RELAX:
 	  DISABLE_RELAXATION;
+	  link_info.enable_dt_relr = false;
 	  break;
 	case OPTION_RELAX:
 	  ENABLE_RELAXATION;
diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
index a9a39ad402c..f3552a4a554 100644
--- a/ld/scripttempl/elf.sc
+++ b/ld/scripttempl/elf.sc
@@ -10,6 +10,7 @@ 
 #		empty.
 #	HAVE_NOINIT - Include a .noinit output section in the script.
 #	HAVE_PERSISTENT - Include a .persistent output section in the script.
+#	HAVE_DT_RELR - Include a .relr.dyn output section in the script.
 #	SMALL_DATA_CTOR - .ctors contains small data.
 #	SMALL_DATA_DTOR - .dtors contains small data.
 #	DATA_ADDR - if end-of-text-plus-one-page isn't right for data start
@@ -520,6 +521,9 @@  emit_dyn()
     fi
   fi
   rm -f ldscripts/dyntmp.$$
+  if test -n "${COMBRELOC}" && test -n "${HAVE_DT_RELR}"; then
+    echo "  .relr.dyn : { *(.relr.dyn) }"
+  fi
 }
 
 test -n "${NON_ALLOC_DYN}${SEPARATE_CODE}" || emit_dyn