Message ID | 20220107190631.309790-6-hjl.tools@gmail.com |
---|---|
State | Superseded |
Headers | show |
Series | ld: Implement DT_RELR for x86 | expand |
Context | Check | Description |
---|---|---|
dj/TryBot-apply_patch | fail | Patch failed to apply to master at the time it was sent |
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.
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