[PATCH 05/10] ld: Initial DT_RELR support

H.J. Lu hjl.tools@gmail.com
Sat Jan 8 02:42:16 GMT 2022


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
> >



-- 
H.J.


More information about the Libc-alpha mailing list