[05/10] ld: Initial DT_RELR support
Checks
Commit Message
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
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
>
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
> >
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.
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.
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.
@@ -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. */
@@ -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. */
@@ -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;
@@ -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
new file mode 100644
@@ -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"
@@ -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"
@@ -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
@@ -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"
@@ -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
@@ -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.
@@ -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"),
@@ -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;
@@ -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