[PATCH 05/10] ld: Initial DT_RELR support

Fangrui Song i@maskray.me
Sat Jan 8 02:10:25 GMT 2022


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
>


More information about the Libc-alpha mailing list