public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v2 0/9] ld: Implement DT_RELR for x86
@ 2022-01-08 18:38 H.J. Lu
  2022-01-08 18:38 ` [PATCH v2 1/9] elf: Add .relr.dyn to special_sections_r H.J. Lu
                   ` (10 more replies)
  0 siblings, 11 replies; 20+ messages in thread
From: H.J. Lu @ 2022-01-08 18:38 UTC (permalink / raw)
  To: binutils; +Cc: Nick Clifton, Alan Modra, libc-alpha

Hi Nick,

I'd like to enable DT_RELR for x86 in binutils 2.38.


H.J.
---
Changes in v2:

1. Drop the _bfd_elf_link_iterate_on_relocs patch, which has been checked
into master branch.
2. Also pack R_*_RELATIVE relocations against dynamic symbols.
3. Skip relocation against IFUNC symbol earlier.
4. Don't require the --relax option enabled.
5. Add more DT_RELR tests:
   a. Add a test with relative relocation in section with 1-byte
      alignment.
   b. Add a test with -z pack-relative-relocs --no-relax.
   c. Add tests for packing R_*_RELATIVE relocations against dynamic
      symbols.

DT_RELR encodes consecutive R_*_RELATIVE relocations in GOT (the global
offset table) and data sections in a compact format:

https://groups.google.com/g/generic-abi/c/bX460iggiKg

On some targets, R_*_RELATIVE relocations are counted and the GOT offsets
are allocated when setting the dynamic section sizes after seeing all
relocations.  R_*_RELATIVE relocations are generated while relocating
sections after section layout has been finalized.

For x86 targets, the old check_relocs is renamed to scan_relocs and a
new check_relocs is added to chek input sections and create dynamic
relocation sections so that they will be mapped to output sections.
scan_relocs is now called from elf_backend_always_size_sections.

On some targets, the DT_RELR section size can be computed only after all
symbols addresses can be determined:

1. Update ldelf_map_segments to pass need_layout to
_bfd_elf_map_sections_to_segments which will size DT_RELR section and
set need_layout to true if the DT_RELR section size is changed.
2.  Set the preliminary DT_RELR section size before mapping sections to
segments and set the final DT_RELR section size after regular symbol
processing is done.

On x86, DT_RELR is implemented with linker relaxation:

1. During linker relaxation, we scan input relocations with the same
logic in relocate_section to determine if a relative relocation should
be generated and save the relative relocation candidate information for
sizing the DT_RELR section later after all symbols addresses can be
determined.  For these relative relocations which can't be placed in
the DT_RELR section, they will be placed in the rela.dyn/rel.dyn
section.
2. When DT_RELR is enabled, _bfd_elf_map_sections_to_segments calls a
backend function to size the DT_RELR section which will compute the
DT_RELR section size and tell ldelf_map_segments to layout sections
again when the DT_RELR section size has been increased.
3. After regular symbol processing is finished, bfd_elf_final_link calls
a backend function to finish the DT_RELR section.

When DT_RELR is enabled, to avoid random run-time crash with older glibc
binaries without DT_RELR support, add a GLIBC_ABI_DT_RELR symbol version,
which is provided by glibc with DT_RELR support, dependency on the shared
C library if it provides a GLIBC_2.XX symbol version.

It can build DT_RELR enabled glibc successfully on x86-64, x32 and
i686.

H.J. Lu (9):
  elf: Add .relr.dyn to special_sections_r
  elf: Extract _bfd_elf_process_reverse_copy
  elf: Pass need_layout to _bfd_elf_map_sections_to_segments
  ld: Initial DT_RELR support
  elf: Add size_relative_relocs and finish_relative_relocs
  elf: Support DT_RELR in linker tests
  x86: Add DT_RELR support
  ld: Add simple DT_RELR tests
  ld: Add glibc dependency for DT_RELR

 bfd/elf-bfd.h                                 |  15 +-
 bfd/elf.c                                     |  22 +-
 bfd/elf32-i386.c                              |  77 +-
 bfd/elf64-x86-64.c                            |  92 +-
 bfd/elflink.c                                 | 168 ++-
 bfd/elfxx-target.h                            |   8 +
 bfd/elfxx-x86.c                               | 954 ++++++++++++++++++
 bfd/elfxx-x86.h                               | 147 ++-
 binutils/testsuite/lib/binutils-common.exp    |   1 +
 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                                    |  13 +
 ld/ldelf.c                                    |   9 +
 ld/ldelfgen.c                                 |   3 +-
 ld/ldlang.c                                   |   3 +-
 ld/scripttempl/elf.sc                         |   4 +
 ld/testsuite/config/default.exp               |  16 +
 ld/testsuite/ld-elf/dt-relr-1.s               |  13 +
 ld/testsuite/ld-elf/dt-relr-1a.d              |  10 +
 ld/testsuite/ld-elf/dt-relr-1b.d              |   9 +
 ld/testsuite/ld-elf/dt-relr-1c.d              |   9 +
 ld/testsuite/ld-elf/dt-relr-2.s               |  20 +
 ld/testsuite/ld-elf/dt-relr-2a.d              |  10 +
 ld/testsuite/ld-elf/dt-relr-2b.d              |  17 +
 ld/testsuite/ld-elf/dt-relr-2c.d              |  17 +
 ld/testsuite/ld-elf/dt-relr-2d.d              |  17 +
 ld/testsuite/ld-elf/dt-relr-2e.d              |   9 +
 ld/testsuite/ld-elf/dt-relr-2f.d              |   8 +
 ld/testsuite/ld-elf/dt-relr-2g.d              |   9 +
 ld/testsuite/ld-elf/dt-relr-2h.d              |   9 +
 ld/testsuite/ld-elf/dt-relr-3.s               |  12 +
 ld/testsuite/ld-elf/dt-relr-3a.d              |   9 +
 ld/testsuite/ld-elf/dt-relr-3b.d              |   9 +
 ld/testsuite/ld-elf/dt-relr-glibc-1.c         |  11 +
 ld/testsuite/ld-elf/dt-relr-glibc-1a.rd       |   4 +
 ld/testsuite/ld-elf/dt-relr-glibc-1b.rd       |   7 +
 ld/testsuite/ld-elf/dt-relr.exp               |  44 +
 ld/testsuite/ld-elf/shared.exp                |   3 +-
 ld/testsuite/ld-i386/dt-relr-1.d              |  14 +
 ld/testsuite/ld-i386/dt-relr-1.s              |   3 +
 ld/testsuite/ld-i386/export-class.exp         |   2 +-
 ld/testsuite/ld-i386/i386.exp                 |  21 +-
 ld/testsuite/ld-i386/ibt-plt-2a.d             |   2 +-
 ld/testsuite/ld-i386/ibt-plt-3a.d             |   2 +-
 ld/testsuite/ld-i386/ibt-plt-3c.d             |   2 +-
 ld/testsuite/ld-i386/pr26869.d                |   2 +-
 ld/testsuite/ld-i386/report-reloc-1.d         |   2 +-
 ld/testsuite/ld-ifunc/ifunc-2-i386-now.d      |   2 +-
 .../ld-ifunc/ifunc-2-local-i386-now.d         |   2 +-
 .../ld-ifunc/ifunc-2-local-x86-64-now.d       |   2 +-
 ld/testsuite/ld-ifunc/ifunc-2-x86-64-now.d    |   2 +-
 ld/testsuite/ld-ifunc/pr17154-x86-64-now.d    |   2 +-
 ld/testsuite/ld-ifunc/pr17154-x86-64.d        |   2 +-
 ld/testsuite/ld-x86-64/bnd-branch-1-now.d     |   2 +-
 ld/testsuite/ld-x86-64/bnd-ifunc-1-now.d      |   2 +-
 ld/testsuite/ld-x86-64/bnd-ifunc-2-now.d      |   2 +-
 ld/testsuite/ld-x86-64/bnd-ifunc-2.d          |   2 +-
 ld/testsuite/ld-x86-64/bnd-plt-1-now.d        |   2 +-
 ld/testsuite/ld-x86-64/bnd-plt-1.d            |   2 +-
 ld/testsuite/ld-x86-64/dt-relr-1-x32.d        |  15 +
 ld/testsuite/ld-x86-64/dt-relr-1.d            |  14 +
 ld/testsuite/ld-x86-64/dt-relr-1.s            |   3 +
 ld/testsuite/ld-x86-64/export-class.exp       |   3 +-
 ld/testsuite/ld-x86-64/ibt-plt-2a-x32.d       |   2 +-
 ld/testsuite/ld-x86-64/ibt-plt-2a.d           |   2 +-
 ld/testsuite/ld-x86-64/ibt-plt-3a-x32.d       |   2 +-
 ld/testsuite/ld-x86-64/ibt-plt-3a.d           |   2 +-
 ld/testsuite/ld-x86-64/ilp32-4.d              |   2 +-
 ld/testsuite/ld-x86-64/load1c.d               |   2 +-
 ld/testsuite/ld-x86-64/load1d.d               |   2 +-
 ld/testsuite/ld-x86-64/pr13082-2b.d           |   2 +-
 ld/testsuite/ld-x86-64/pr14207.d              |   2 +-
 ld/testsuite/ld-x86-64/pr18176.d              |   2 +-
 ld/testsuite/ld-x86-64/pr19162.d              |   2 +-
 ld/testsuite/ld-x86-64/pr19636-2d.d           |   2 +-
 ld/testsuite/ld-x86-64/pr19636-2l.d           |   2 +-
 ld/testsuite/ld-x86-64/pr20253-1d.d           |   2 +-
 ld/testsuite/ld-x86-64/pr20253-1f.d           |   2 +-
 ld/testsuite/ld-x86-64/pr20253-1j.d           |   2 +-
 ld/testsuite/ld-x86-64/pr20253-1l.d           |   2 +-
 ld/testsuite/ld-x86-64/report-reloc-1-x32.d   |   2 +-
 ld/testsuite/ld-x86-64/report-reloc-1.d       |   2 +-
 ld/testsuite/ld-x86-64/x86-64.exp             |  67 +-
 88 files changed, 1883 insertions(+), 155 deletions(-)
 create mode 100644 ld/emulparams/dt-relr.sh
 create mode 100644 ld/testsuite/ld-elf/dt-relr-1.s
 create mode 100644 ld/testsuite/ld-elf/dt-relr-1a.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-1b.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-1c.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2.s
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2a.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2b.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2c.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2d.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2e.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2f.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2g.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2h.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-3.s
 create mode 100644 ld/testsuite/ld-elf/dt-relr-3a.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-3b.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-glibc-1.c
 create mode 100644 ld/testsuite/ld-elf/dt-relr-glibc-1a.rd
 create mode 100644 ld/testsuite/ld-elf/dt-relr-glibc-1b.rd
 create mode 100644 ld/testsuite/ld-elf/dt-relr.exp
 create mode 100644 ld/testsuite/ld-i386/dt-relr-1.d
 create mode 100644 ld/testsuite/ld-i386/dt-relr-1.s
 create mode 100644 ld/testsuite/ld-x86-64/dt-relr-1-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/dt-relr-1.d
 create mode 100644 ld/testsuite/ld-x86-64/dt-relr-1.s

-- 
2.33.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 1/9] elf: Add .relr.dyn to special_sections_r
  2022-01-08 18:38 [PATCH v2 0/9] ld: Implement DT_RELR for x86 H.J. Lu
@ 2022-01-08 18:38 ` H.J. Lu
  2022-01-08 18:38 ` [PATCH v2 2/9] elf: Extract _bfd_elf_process_reverse_copy H.J. Lu
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: H.J. Lu @ 2022-01-08 18:38 UTC (permalink / raw)
  To: binutils; +Cc: Nick Clifton, Alan Modra, libc-alpha

	* elf.c (special_sections_r): Add .relr.dyn.
---
 bfd/elf.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/bfd/elf.c b/bfd/elf.c
index 1003bd2cdbe..ef0d18105ba 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -2714,6 +2714,7 @@ static const struct bfd_elf_special_section special_sections_r[] =
 {
   { STRING_COMMA_LEN (".rodata"), -2, SHT_PROGBITS, SHF_ALLOC },
   { STRING_COMMA_LEN (".rodata1"), 0, SHT_PROGBITS, SHF_ALLOC },
+  { STRING_COMMA_LEN (".relr.dyn"), 0, SHT_RELR, SHF_ALLOC },
   { STRING_COMMA_LEN (".rela"),	  -1, SHT_RELA,	    0 },
   { STRING_COMMA_LEN (".rel"),	  -1, SHT_REL,	    0 },
   { NULL,		    0,	   0, 0,	    0 }
-- 
2.33.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 2/9] elf: Extract _bfd_elf_process_reverse_copy
  2022-01-08 18:38 [PATCH v2 0/9] ld: Implement DT_RELR for x86 H.J. Lu
  2022-01-08 18:38 ` [PATCH v2 1/9] elf: Add .relr.dyn to special_sections_r H.J. Lu
@ 2022-01-08 18:38 ` H.J. Lu
  2022-01-08 18:38 ` [PATCH v2 3/9] elf: Pass need_layout to _bfd_elf_map_sections_to_segments H.J. Lu
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: H.J. Lu @ 2022-01-08 18:38 UTC (permalink / raw)
  To: binutils; +Cc: Nick Clifton, Alan Modra, libc-alpha

Extract _bfd_elf_process_reverse_copy from elf_link_input_bfd so that
it can be called in check_relocs to set SEC_ELF_REVERSE_COPY before
elf_link_input_bfd is called.

	* elf-bfd.h (_bfd_elf_process_reverse_copy): New prototype.
	* elflink.c (_bfd_elf_process_reverse_copy): New.  Extracted
	from elf_link_input_bfd.
	(elf_link_input_bfd): Call _bfd_elf_process_reverse_copy.
---
 bfd/elf-bfd.h |  2 ++
 bfd/elflink.c | 60 ++++++++++++++++++++++++++++++++-------------------
 2 files changed, 40 insertions(+), 22 deletions(-)

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 81f8fd47db7..2441b3c0cd7 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2331,6 +2331,8 @@ extern const struct bfd_elf_special_section *_bfd_elf_get_special_section
   (const char *, const struct bfd_elf_special_section *, unsigned int);
 extern const struct bfd_elf_special_section *_bfd_elf_get_sec_type_attr
   (bfd *, asection *);
+extern bool _bfd_elf_process_reverse_copy (asection *, unsigned int,
+					   unsigned int);
 
 extern bool _bfd_elf_link_hide_sym_by_version
   (struct bfd_link_info *, struct elf_link_hash_entry *);
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 059461b5725..29ef9ddf8b9 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -10851,6 +10851,41 @@ _bfd_elf_check_kept_section (asection *sec, struct bfd_link_info *info)
   return kept;
 }
 
+/* Set SEC_ELF_REVERSE_COPY on section S when we need to reverse-copy
+   input .ctors/.dtors sections if they are placed in .init_array or
+   .finit_array for output.  ADDRESS_SIZE is address in bytes.
+   INT_RELS_PER_EXT_REL is the number of internal relocations to
+   allocate per external relocation entry.  */
+
+bool
+_bfd_elf_process_reverse_copy (asection *s, unsigned int address_size,
+			       unsigned int int_rels_per_ext_rel)
+{
+  if (s->size <= address_size
+      || (s->flags & SEC_ELF_REVERSE_COPY) != 0)
+    return true;
+
+  if (((startswith (s->name, ".ctors")
+	&& strcmp (s->output_section->name, ".init_array") == 0)
+       || (startswith (s->name, ".dtors")
+	   && strcmp (s->output_section->name, ".fini_array") == 0))
+      && (s->name[6] == 0 || s->name[6] == '.'))
+    {
+      if (s->size * int_rels_per_ext_rel
+	  != s->reloc_count * address_size)
+	{
+	  _bfd_error_handler
+	    /* xgettext:c-format */
+	    (_("error: %pB: size of section %pA is not multiple of "
+	       "address size"), s->owner, s);
+	  bfd_set_error (bfd_error_bad_value);
+	  return false;
+	}
+      s->flags |= SEC_ELF_REVERSE_COPY;
+    }
+  return true;
+}
+
 /* Link an input file into the linker output file.  This function
    handles all the sections and relocations of the input file at once.
    This is so that we only have to read the local symbols once, and
@@ -11249,28 +11284,9 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 
 	  /* We need to reverse-copy input .ctors/.dtors sections if
 	     they are placed in .init_array/.finit_array for output.  */
-	  if (o->size > address_size
-	      && ((startswith (o->name, ".ctors")
-		   && strcmp (o->output_section->name,
-			      ".init_array") == 0)
-		  || (startswith (o->name, ".dtors")
-		      && strcmp (o->output_section->name,
-				 ".fini_array") == 0))
-	      && (o->name[6] == 0 || o->name[6] == '.'))
-	    {
-	      if (o->size * bed->s->int_rels_per_ext_rel
-		  != o->reloc_count * address_size)
-		{
-		  _bfd_error_handler
-		    /* xgettext:c-format */
-		    (_("error: %pB: size of section %pA is not "
-		       "multiple of address size"),
-		     input_bfd, o);
-		  bfd_set_error (bfd_error_bad_value);
-		  return false;
-		}
-	      o->flags |= SEC_ELF_REVERSE_COPY;
-	    }
+	  if (!_bfd_elf_process_reverse_copy (o, address_size,
+					      bed->s->int_rels_per_ext_rel))
+	    return false;
 
 	  action_discarded = -1;
 	  if (!elf_section_ignore_discarded_relocs (o))
-- 
2.33.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 3/9] elf: Pass need_layout to _bfd_elf_map_sections_to_segments
  2022-01-08 18:38 [PATCH v2 0/9] ld: Implement DT_RELR for x86 H.J. Lu
  2022-01-08 18:38 ` [PATCH v2 1/9] elf: Add .relr.dyn to special_sections_r H.J. Lu
  2022-01-08 18:38 ` [PATCH v2 2/9] elf: Extract _bfd_elf_process_reverse_copy H.J. Lu
@ 2022-01-08 18:38 ` H.J. Lu
  2022-01-08 18:38 ` [PATCH v2 4/9] ld: Initial DT_RELR support H.J. Lu
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: H.J. Lu @ 2022-01-08 18:38 UTC (permalink / raw)
  To: binutils; +Cc: Nick Clifton, Alan Modra, libc-alpha

On some targets, the DT_RELR section size can be computed only after all
symbols addresses can be determined.  Update ldelf_map_segments to pass
need_layout to _bfd_elf_map_sections_to_segments which will size DT_RELR
section and set need_layout to true if the DT_RELR section size is changed.

bfd/

	* elf-bfd.h (_bfd_elf_map_sections_to_segments): Add a bool
	pointer argument.
	* elf.c (_bfd_elf_map_sections_to_segments): Add a bool pointer
	argument to indicate if section layout needs update.
	(assign_file_positions_for_load_sections): Pass NULL to
	_bfd_elf_map_sections_to_segments.
	* elflink.c (_bfd_elf_strip_zero_sized_dynamic_sections): Pass
	NULL to _bfd_elf_map_sections_to_segments.

ld/

	* ldelfgen.c (ldelf_map_segments): Pass &need_layout to
	_bfd_elf_map_sections_to_segments.
---
 bfd/elf-bfd.h | 2 +-
 bfd/elf.c     | 9 ++++++---
 bfd/elflink.c | 3 ++-
 ld/ldelfgen.c | 3 ++-
 4 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 2441b3c0cd7..c4d2ef00d6b 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2718,7 +2718,7 @@ extern struct elf_segment_map * _bfd_elf_make_dynamic_segment
   (bfd *, asection *);
 
 extern bool _bfd_elf_map_sections_to_segments
-  (bfd *, struct bfd_link_info *);
+  (bfd *, struct bfd_link_info *, bool *);
 
 extern bool _bfd_elf_is_function_type (unsigned int);
 
diff --git a/bfd/elf.c b/bfd/elf.c
index ef0d18105ba..8b866b63e18 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -4609,10 +4609,13 @@ elf_modify_segment_map (bfd *abfd,
 #define IS_TBSS(s) \
   ((s->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) == SEC_THREAD_LOCAL)
 
-/* Set up a mapping from BFD sections to program segments.  */
+/* Set up a mapping from BFD sections to program segments.  Update
+   NEED_LAYOUT if the section layout is changed.  */
 
 bool
-_bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
+_bfd_elf_map_sections_to_segments (bfd *abfd,
+				   struct bfd_link_info *info,
+				   bool *need_layout ATTRIBUTE_UNUSED)
 {
   unsigned int count;
   struct elf_segment_map *m;
@@ -5416,7 +5419,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
   unsigned int opb = bfd_octets_per_byte (abfd, NULL);
 
   if (link_info == NULL
-      && !_bfd_elf_map_sections_to_segments (abfd, link_info))
+      && !_bfd_elf_map_sections_to_segments (abfd, link_info, NULL))
     return false;
 
   alloc = 0;
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 29ef9ddf8b9..bea413ec24e 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -3676,7 +3676,8 @@ _bfd_elf_strip_zero_sized_dynamic_sections (struct bfd_link_info *info)
     {
       /* Regenerate program headers.  */
       elf_seg_map (info->output_bfd) = NULL;
-      return _bfd_elf_map_sections_to_segments (info->output_bfd, info);
+      return _bfd_elf_map_sections_to_segments (info->output_bfd, info,
+						NULL);
     }
 
   return true;
diff --git a/ld/ldelfgen.c b/ld/ldelfgen.c
index 5c033bbfbe0..58b37c65bc9 100644
--- a/ld/ldelfgen.c
+++ b/ld/ldelfgen.c
@@ -304,7 +304,8 @@ ldelf_map_segments (bool need_layout)
 	  if (lang_phdr_list == NULL)
 	    elf_seg_map (link_info.output_bfd) = NULL;
 	  if (!_bfd_elf_map_sections_to_segments (link_info.output_bfd,
-						  &link_info))
+						  &link_info,
+						  &need_layout))
 	    einfo (_("%F%P: map sections to segments failed: %E\n"));
 
 	  if (phdr_size != elf_program_header_size (link_info.output_bfd))
-- 
2.33.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 4/9] ld: Initial DT_RELR support
  2022-01-08 18:38 [PATCH v2 0/9] ld: Implement DT_RELR for x86 H.J. Lu
                   ` (2 preceding siblings ...)
  2022-01-08 18:38 ` [PATCH v2 3/9] elf: Pass need_layout to _bfd_elf_map_sections_to_segments H.J. Lu
@ 2022-01-08 18:38 ` H.J. Lu
  2022-01-08 18:38 ` [PATCH v2 5/9] elf: Add size_relative_relocs and finish_relative_relocs H.J. Lu
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: H.J. Lu @ 2022-01-08 18:38 UTC (permalink / raw)
  To: binutils; +Cc: Nick Clifton, Alan Modra, libc-alpha

Add a -z pack-relative-relocs option to enable DT_RELR and create a
relr.dyn section for DT_RELR.  DT_RELR is implemented with the linker
relaxation infrastructure, but it doesn't require the --relax option
enabled.  -z pack-relative-relocs implies -z combreloc.  -z nocombreloc
implies -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.
	* ldlang.c (lang_relax_sections): Also enable relaxation if
	DT_RELR is enabled.
	* 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                    | 11 +++++++++++
 ld/ldelf.c                    |  9 +++++++++
 ld/ldlang.c                   |  3 ++-
 ld/scripttempl/elf.sc         |  4 ++++
 13 files changed, 73 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..36113723c9b 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}.  @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
diff --git a/ld/ldelf.c b/ld/ldelf.c
index d15f027e91a..7a1a553cae7 100644
--- a/ld/ldelf.c
+++ b/ld/ldelf.c
@@ -71,6 +71,15 @@ 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;
+
+  /* Add 3 spare tags for DT_RELR, DT_RELRSZ and DT_RELRENT.  */
+  if (link_info.enable_dt_relr)
+    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/ldlang.c b/ld/ldlang.c
index 9dbc8752f87..84536a5b24d 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -7699,7 +7699,8 @@ lang_find_relro_sections (void)
 void
 lang_relax_sections (bool need_layout)
 {
-  if (RELAXATION_ENABLED)
+  /* NB: Also enable relaxation to layout sections for DT_RELR.  */
+  if (RELAXATION_ENABLED || link_info.enable_dt_relr)
     {
       /* We may need more than one relaxation pass.  */
       int i = link_info.relax_pass;
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


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 5/9] elf: Add size_relative_relocs and finish_relative_relocs
  2022-01-08 18:38 [PATCH v2 0/9] ld: Implement DT_RELR for x86 H.J. Lu
                   ` (3 preceding siblings ...)
  2022-01-08 18:38 ` [PATCH v2 4/9] ld: Initial DT_RELR support H.J. Lu
@ 2022-01-08 18:38 ` H.J. Lu
  2022-01-08 18:38 ` [PATCH v2 6/9] elf: Support DT_RELR in linker tests H.J. Lu
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: H.J. Lu @ 2022-01-08 18:38 UTC (permalink / raw)
  To: binutils; +Cc: Nick Clifton, Alan Modra, libc-alpha

On some targets, the DT_RELR section size can be computed only after all
symbols addresses can be determined.  Set the preliminary DT_RELR section
size before mapping sections to segments and set the final DT_RELR section
size after regular symbol processing is done.

	* elf-bfd.h (elf_backend_data): Add size_relative_relocs and
	finish_relative_relocs.
	* elf.c (_bfd_elf_map_sections_to_segments): Call
	size_relative_relocs if DT_RELR is enabled.
	* elflink.c (bfd_elf_final_link): Call finish_relative_relocs
	after regular symbol processing is finished if DT_RELR is enabled.
	* elfxx-target.h (elf_backend_size_relative_relocs): New.
	(elf_backend_finish_relative_relocs): Likewise.
	(elfNN_bed): Add elf_backend_size_relative_relocs and
	elf_backend_finish_relative_relocs.
---
 bfd/elf-bfd.h      | 10 ++++++++++
 bfd/elf.c          | 14 ++++++++++++--
 bfd/elflink.c      |  8 ++++++++
 bfd/elfxx-target.h |  8 ++++++++
 4 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 4e73d79ee77..c006008ab7e 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1105,6 +1105,16 @@ struct elf_backend_data
     (bfd *abfd, struct bfd_link_info *info, asection *o,
      const Elf_Internal_Rela *relocs);
 
+  /* The SIZE_RELATIVE_RELOCS function is called to size relative
+     relocations when mappig sections to segments.  */
+  bool (*size_relative_relocs)
+    (struct bfd_link_info *info, bool *need_layout);
+
+  /* The FINISH_RELATIVE_RELOCS function is called to finish relative
+     relocations in bfd_elf_final_link.  */
+  bool (*finish_relative_relocs)
+    (struct bfd_link_info *info);
+
   /* The CHECK_DIRECTIVES function is called once per input file by
      the add_symbols phase of the ELF backend linker.  The function
      must inspect the bfd and create any additional symbols according
diff --git a/bfd/elf.c b/bfd/elf.c
index 8b866b63e18..14c2c7ba734 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -4615,7 +4615,7 @@ elf_modify_segment_map (bfd *abfd,
 bool
 _bfd_elf_map_sections_to_segments (bfd *abfd,
 				   struct bfd_link_info *info,
-				   bool *need_layout ATTRIBUTE_UNUSED)
+				   bool *need_layout)
 {
   unsigned int count;
   struct elf_segment_map *m;
@@ -4626,7 +4626,17 @@ _bfd_elf_map_sections_to_segments (bfd *abfd,
   no_user_phdrs = elf_seg_map (abfd) == NULL;
 
   if (info != NULL)
-    info->user_phdrs = !no_user_phdrs;
+    {
+      info->user_phdrs = !no_user_phdrs;
+
+      /* Size the relative relocations if DT_RELR is enabled.  */
+      if (info->enable_dt_relr
+	  && need_layout != NULL
+	  && bed->size_relative_relocs
+	  && !bed->size_relative_relocs (info, need_layout))
+	info->callbacks->einfo
+	  (_("%F%P: failed to size relative relocations\n"));
+    }
 
   if (no_user_phdrs && bfd_count_sections (abfd) != 0)
     {
diff --git a/bfd/elflink.c b/bfd/elflink.c
index d51b00b6c10..31b13f5df7a 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -12625,6 +12625,14 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   if (!_bfd_elf_fixup_eh_frame_hdr (info))
     return false;
 
+  /* Finish relative relocations here after regular symbol processing
+     is finished if DT_RELR is enabled.  */
+  if (info->enable_dt_relr
+      && bed->finish_relative_relocs
+      && !bed->finish_relative_relocs (info))
+    info->callbacks->einfo
+      (_("%F%P: %pB: failed to finish relative relocations\n"), abfd);
+
   /* Since ELF permits relocations to be against local symbols, we
      must have the local symbols available when we do the relocations.
      Since we would rather only read the local symbols once, and we
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 360b056ff58..e31985ef777 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -478,6 +478,12 @@
 #ifndef elf_backend_check_relocs
 #define elf_backend_check_relocs	0
 #endif
+#ifndef elf_backend_size_relative_relocs
+#define elf_backend_size_relative_relocs 0
+#endif
+#ifndef elf_backend_finish_relative_relocs
+#define elf_backend_finish_relative_relocs 0
+#endif
 #ifndef elf_backend_check_directives
 #define elf_backend_check_directives	0
 #endif
@@ -842,6 +848,8 @@ static const struct elf_backend_data elfNN_bed =
   elf_backend_omit_section_dynsym,
   elf_backend_relocs_compatible,
   elf_backend_check_relocs,
+  elf_backend_size_relative_relocs,
+  elf_backend_finish_relative_relocs,
   elf_backend_check_directives,
   elf_backend_notice_as_needed,
   elf_backend_adjust_dynamic_symbol,
-- 
2.33.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 6/9] elf: Support DT_RELR in linker tests
  2022-01-08 18:38 [PATCH v2 0/9] ld: Implement DT_RELR for x86 H.J. Lu
                   ` (4 preceding siblings ...)
  2022-01-08 18:38 ` [PATCH v2 5/9] elf: Add size_relative_relocs and finish_relative_relocs H.J. Lu
@ 2022-01-08 18:38 ` H.J. Lu
  2022-01-08 18:38 ` [PATCH v2 7/9] x86: Add DT_RELR support H.J. Lu
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: H.J. Lu @ 2022-01-08 18:38 UTC (permalink / raw)
  To: binutils; +Cc: Nick Clifton, Alan Modra, libc-alpha

Allow eabling and disabling DT_RELR in linker tests.  Disable DT_RELR in
linker tests which don't expect DT_RELR in linker outputs.

binutils/

	* testsuite/lib/binutils-common.exp (run_dump_test): Make
	DT_RELR_LDFLAGS and NO_DT_RELR_LDFLAGS global.

ld/

	* testsuite/config/default.exp (DT_RELR_LDFLAGS): New.
	(DT_RELR_CC_LDFLAGS): Likewise.
	(NO_DT_RELR_LDFLAGS): Likewise.
	(NO_DT_RELR_CC_LDFLAGS): Likewise.
	* testsuite/ld-elf/shared.exp: Pass $NO_DT_RELR_LDFLAGS to
	linker for some tests.
	* testsuite/ld-i386/export-class.exp: Likewise.
	* testsuite/ld-i386/i386.exp: Likewise.
	* testsuite/ld-i386/ibt-plt-2a.d: Pass $NO_DT_RELR_LDFLAGS to
	linker.
	* testsuite/ld-i386/ibt-plt-3a.d: Likewise.
	* testsuite/ld-i386/ibt-plt-3c.d: Likewise.
	* testsuite/ld-i386/pr26869.d: Likewise.
	* testsuite/ld-i386/report-reloc-1.d: Likewise.
	* testsuite/ld-ifunc/ifunc-2-i386-now.d: Likewise.
	* testsuite/ld-ifunc/ifunc-2-local-i386-now.d: Likewise.
	* testsuite/ld-ifunc/ifunc-2-local-x86-64-now.d: Likewise.
	* testsuite/ld-ifunc/ifunc-2-x86-64-now.d: Likewise.
	* testsuite/ld-ifunc/pr17154-x86-64.d: Likewise.
	* testsuite/ld-x86-64/bnd-branch-1-now.d: Likewise.
	* testsuite/ld-x86-64/bnd-ifunc-1-now.d: Likewise.
	* testsuite/ld-x86-64/bnd-ifunc-2-now.d: Likewise.
	* testsuite/ld-x86-64/bnd-ifunc-2.d: Likewise.
	* testsuite/ld-x86-64/bnd-plt-1-now.d: Likewise.
	* testsuite/ld-x86-64/bnd-plt-1.d: Likewise.
	* testsuite/ld-x86-64/ibt-plt-2a-x32.d: Likewise.
	* testsuite/ld-x86-64/ibt-plt-2a.d: Likewise.
	* testsuite/ld-x86-64/ibt-plt-3a-x32.d: Likewise.
	* testsuite/ld-x86-64/ibt-plt-3a.d: Likewise.
	* testsuite/ld-x86-64/ilp32-4.d: Likewise.
	* testsuite/ld-x86-64/load1c.d: Likewise.
	* testsuite/ld-x86-64/load1d.d: Likewise.
	* testsuite/ld-x86-64/pr13082-2b.d: Likewise.
	* testsuite/ld-x86-64/pr14207.d: Likewise.
	* testsuite/ld-x86-64/pr18176.d: Likewise.
	* testsuite/ld-x86-64/pr19162.d: Likewise.
	* testsuite/ld-x86-64/pr19636-2d.d: Likewise.
	* testsuite/ld-x86-64/pr19636-2l.d: Likewise.
	* testsuite/ld-x86-64/pr20253-1d.d: Likewise.
	* testsuite/ld-x86-64/pr20253-1f.d: Likewise.
	* testsuite/ld-x86-64/pr20253-1j.d: Likewise.
	* testsuite/ld-x86-64/pr20253-1l.d: Likewise.
	* testsuite/ld-x86-64/report-reloc-1-x32.d: Likewise.
	* testsuite/ld-x86-64/report-reloc-1.d: Likewise.
	* testsuite/ld-x86-64/export-class.exp (x86_64_export_class_test):
	Pass $NO_DT_RELR_LDFLAGS to linker.
	* testsuite/ld-x86-64/x86-64.exp: Pass $NO_DT_RELR_LDFLAGS to
	linker for some tests.
---
 binutils/testsuite/lib/binutils-common.exp    |  1 +
 ld/testsuite/config/default.exp               | 16 +++++
 ld/testsuite/ld-elf/shared.exp                |  3 +-
 ld/testsuite/ld-i386/export-class.exp         |  2 +-
 ld/testsuite/ld-i386/i386.exp                 | 20 ++++--
 ld/testsuite/ld-i386/ibt-plt-2a.d             |  2 +-
 ld/testsuite/ld-i386/ibt-plt-3a.d             |  2 +-
 ld/testsuite/ld-i386/ibt-plt-3c.d             |  2 +-
 ld/testsuite/ld-i386/pr26869.d                |  2 +-
 ld/testsuite/ld-i386/report-reloc-1.d         |  2 +-
 ld/testsuite/ld-ifunc/ifunc-2-i386-now.d      |  2 +-
 .../ld-ifunc/ifunc-2-local-i386-now.d         |  2 +-
 .../ld-ifunc/ifunc-2-local-x86-64-now.d       |  2 +-
 ld/testsuite/ld-ifunc/ifunc-2-x86-64-now.d    |  2 +-
 ld/testsuite/ld-ifunc/pr17154-x86-64-now.d    |  2 +-
 ld/testsuite/ld-ifunc/pr17154-x86-64.d        |  2 +-
 ld/testsuite/ld-x86-64/bnd-branch-1-now.d     |  2 +-
 ld/testsuite/ld-x86-64/bnd-ifunc-1-now.d      |  2 +-
 ld/testsuite/ld-x86-64/bnd-ifunc-2-now.d      |  2 +-
 ld/testsuite/ld-x86-64/bnd-ifunc-2.d          |  2 +-
 ld/testsuite/ld-x86-64/bnd-plt-1-now.d        |  2 +-
 ld/testsuite/ld-x86-64/bnd-plt-1.d            |  2 +-
 ld/testsuite/ld-x86-64/export-class.exp       |  3 +-
 ld/testsuite/ld-x86-64/ibt-plt-2a-x32.d       |  2 +-
 ld/testsuite/ld-x86-64/ibt-plt-2a.d           |  2 +-
 ld/testsuite/ld-x86-64/ibt-plt-3a-x32.d       |  2 +-
 ld/testsuite/ld-x86-64/ibt-plt-3a.d           |  2 +-
 ld/testsuite/ld-x86-64/ilp32-4.d              |  2 +-
 ld/testsuite/ld-x86-64/load1c.d               |  2 +-
 ld/testsuite/ld-x86-64/load1d.d               |  2 +-
 ld/testsuite/ld-x86-64/pr13082-2b.d           |  2 +-
 ld/testsuite/ld-x86-64/pr14207.d              |  2 +-
 ld/testsuite/ld-x86-64/pr18176.d              |  2 +-
 ld/testsuite/ld-x86-64/pr19162.d              |  2 +-
 ld/testsuite/ld-x86-64/pr19636-2d.d           |  2 +-
 ld/testsuite/ld-x86-64/pr19636-2l.d           |  2 +-
 ld/testsuite/ld-x86-64/pr20253-1d.d           |  2 +-
 ld/testsuite/ld-x86-64/pr20253-1f.d           |  2 +-
 ld/testsuite/ld-x86-64/pr20253-1j.d           |  2 +-
 ld/testsuite/ld-x86-64/pr20253-1l.d           |  2 +-
 ld/testsuite/ld-x86-64/report-reloc-1-x32.d   |  2 +-
 ld/testsuite/ld-x86-64/report-reloc-1.d       |  2 +-
 ld/testsuite/ld-x86-64/x86-64.exp             | 65 ++++++++++++-------
 43 files changed, 115 insertions(+), 67 deletions(-)

diff --git a/binutils/testsuite/lib/binutils-common.exp b/binutils/testsuite/lib/binutils-common.exp
index 0e0ba8e5aee..88fdc1a71c7 100644
--- a/binutils/testsuite/lib/binutils-common.exp
+++ b/binutils/testsuite/lib/binutils-common.exp
@@ -855,6 +855,7 @@ proc run_dump_test { name {extra_options {}} } {
     global ELFEDIT ELFEDITFLAGS LD LDFLAGS NM NMFLAGS OBJCOPY OBJCOPYFLAGS
     global OBJDUMP OBJDUMPFLAGS READELF READELFFLAGS STRIP STRIPFLAGS
     global copyfile env runtests srcdir subdir verbose
+    global DT_RELR_LDFLAGS NO_DT_RELR_LDFLAGS
 
     if [string match "*/*" $name] {
 	set file $name
diff --git a/ld/testsuite/config/default.exp b/ld/testsuite/config/default.exp
index c988d5d2924..52e75048ede 100644
--- a/ld/testsuite/config/default.exp
+++ b/ld/testsuite/config/default.exp
@@ -313,6 +313,22 @@ if ![info exists LDFLAGS] then {
     set LDFLAGS {}
 }
 
+if { ![info exists DT_RELR_LDFLAGS] } then {
+    set DT_RELR_LDFLAGS "-z pack-relative-relocs"
+}
+
+if { ![info exists DT_RELR_CC_LDFLAGS] } then {
+    set DT_RELR_CC_LDFLAGS "-Wl,-z,pack-relative-relocs"
+}
+
+if { ![info exists NO_DT_RELR_LDFLAGS] } then {
+    set NO_DT_RELR_LDFLAGS "-z nopack-relative-relocs"
+}
+
+if { ![info exists NO_DT_RELR_CC_LDFLAGS] } then {
+    set NO_DT_RELR_CC_LDFLAGS "-Wl,-z,nopack-relative-relocs"
+}
+
 # Set LD_CLASS to "64bit" for a 64-bit *host* linker.
 if { ![info exists LD_CLASS] } then {
     set REAL_LD [findfile $base_dir/.libs/ld-new .libs/ld-new $LD [transform ld]]
diff --git a/ld/testsuite/ld-elf/shared.exp b/ld/testsuite/ld-elf/shared.exp
index cb3b8c15cfc..1381544e6f8 100644
--- a/ld/testsuite/ld-elf/shared.exp
+++ b/ld/testsuite/ld-elf/shared.exp
@@ -452,7 +452,8 @@ setup_xfail mips*-*-* bfin-*-*
 clear_xfail bfin-*-linux*
 run_ld_link_tests [list \
     [list "-Bsymbolic-functions" \
-	"-shared -Bsymbolic-functions" "" "$AFLAGS_PIC" \
+	"-shared -Bsymbolic-functions $NO_DT_RELR_LDFLAGS" \
+	"" "$AFLAGS_PIC" \
 	{symbolic-func.s} {{readelf {-r --wide} symbolic-func.r}} \
 	"symbolic-func.so"] \
 ]
diff --git a/ld/testsuite/ld-i386/export-class.exp b/ld/testsuite/ld-i386/export-class.exp
index 47b2c0f0056..04bc6a0d836 100644
--- a/ld/testsuite/ld-i386/export-class.exp
+++ b/ld/testsuite/ld-i386/export-class.exp
@@ -74,7 +74,7 @@ run_ld_link_tests [list \
 run_ld_link_tests [list \
     [list \
 	"$testname (final shared object)" \
-	"-shared -Tdata=0x12340000 tmpdir/i386-export-class-ref-r.o tmpdir/i386-export-class-lib.so" "" \
+	"-shared $NO_DT_RELR_LDFLAGS -Tdata=0x12340000 tmpdir/i386-export-class-ref-r.o tmpdir/i386-export-class-lib.so" "" \
 	"" \
 	{ ../ld-elf/export-class-dep.s ../ld-elf/export-class-def.s } \
 	{ \
diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp
index 3ed6e42e78f..c2d8d8268c3 100644
--- a/ld/testsuite/ld-i386/i386.exp
+++ b/ld/testsuite/ld-i386/i386.exp
@@ -177,12 +177,6 @@ set i386tests {
      {{readelf -Ssrl tlsbindesc.rd} {objdump -drj.text tlsbindesc.dd}
       {objdump -sj.got tlsbindesc.sd} {objdump -sj.tdata tlsbindesc.td}}
       "tlsbindesc"}
-    {"TLS -fno-pic -shared"
-     "-shared -melf_i386 --no-ld-generated-unwind-info -z notext \
-      -z noseparate-code --hash-style=sysv" ""
-     "--32" {tlsnopic1.s tlsnopic2.s}
-     {{readelf -Ssrl tlsnopic.rd} {objdump -drj.text tlsnopic.dd}
-      {objdump -sj.got tlsnopic.sd}} "libtlsnopic.so"}
     {"TLS with global dynamic and descriptors"
      "-shared -melf_i386 --no-ld-generated-unwind-info \
       -z noseparate-code --hash-style=sysv" ""
@@ -293,6 +287,20 @@ iamcu_tests
 
 run_ld_link_tests $i386tests
 
+run_ld_link_tests [list \
+    [list \
+	"TLS -fno-pic -shared" \
+	"-shared -melf_i386 --no-ld-generated-unwind-info -z notext \
+	 -z noseparate-code --hash-style=sysv $NO_DT_RELR_LDFLAGS" \
+	"" "--32" \
+	{tlsnopic1.s tlsnopic2.s} \
+	{{readelf -Ssrl tlsnopic.rd} \
+	 {objdump -drj.text tlsnopic.dd} \
+	 {objdump -sj.got tlsnopic.sd}} \
+	"libtlsnopic.so" \
+    ] \
+]
+
 run_dump_test "abs"
 run_dump_test "pcrel8"
 run_dump_test "pcrel16"
diff --git a/ld/testsuite/ld-i386/ibt-plt-2a.d b/ld/testsuite/ld-i386/ibt-plt-2a.d
index 42aa2ce7410..98b6fb9a5aa 100644
--- a/ld/testsuite/ld-i386/ibt-plt-2a.d
+++ b/ld/testsuite/ld-i386/ibt-plt-2a.d
@@ -1,6 +1,6 @@
 #source: ibt-plt-2.s
 #as: --32
-#ld: -shared -m elf_i386 -z ibtplt --hash-style=sysv -z noseparate-code
+#ld: -shared -m elf_i386 -z ibtplt --hash-style=sysv -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-i386/ibt-plt-3a.d b/ld/testsuite/ld-i386/ibt-plt-3a.d
index b357a74a33b..91f2023db35 100644
--- a/ld/testsuite/ld-i386/ibt-plt-3a.d
+++ b/ld/testsuite/ld-i386/ibt-plt-3a.d
@@ -1,6 +1,6 @@
 #source: ibt-plt-3.s
 #as: --32
-#ld: -shared -m elf_i386 -z ibtplt --hash-style=sysv -z noseparate-code
+#ld: -shared -m elf_i386 -z ibtplt --hash-style=sysv -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-i386/ibt-plt-3c.d b/ld/testsuite/ld-i386/ibt-plt-3c.d
index b357a74a33b..91f2023db35 100644
--- a/ld/testsuite/ld-i386/ibt-plt-3c.d
+++ b/ld/testsuite/ld-i386/ibt-plt-3c.d
@@ -1,6 +1,6 @@
 #source: ibt-plt-3.s
 #as: --32
-#ld: -shared -m elf_i386 -z ibtplt --hash-style=sysv -z noseparate-code
+#ld: -shared -m elf_i386 -z ibtplt --hash-style=sysv -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-i386/pr26869.d b/ld/testsuite/ld-i386/pr26869.d
index bfd00a70e9b..c8b1acc51ae 100644
--- a/ld/testsuite/ld-i386/pr26869.d
+++ b/ld/testsuite/ld-i386/pr26869.d
@@ -1,5 +1,5 @@
 #as: --32
-#ld: -shared -melf_i386
+#ld: -shared -melf_i386 $NO_DT_RELR_LDFLAGS
 #readelf: -r -s --wide
 
 Relocation section '.rel.dyn' at offset 0x[a-f0-9]+ contains 1 entry:
diff --git a/ld/testsuite/ld-i386/report-reloc-1.d b/ld/testsuite/ld-i386/report-reloc-1.d
index 51fbbd8d105..162161592a1 100644
--- a/ld/testsuite/ld-i386/report-reloc-1.d
+++ b/ld/testsuite/ld-i386/report-reloc-1.d
@@ -1,6 +1,6 @@
 #source: report-reloc-1.s
 #as: --32
-#ld: -pie -melf_i386 -z report-relative-reloc
+#ld: -pie -melf_i386 -z report-relative-reloc $NO_DT_RELR_LDFLAGS
 #warning_output: report-reloc-1.l
 #readelf: -r --wide
 
diff --git a/ld/testsuite/ld-ifunc/ifunc-2-i386-now.d b/ld/testsuite/ld-ifunc/ifunc-2-i386-now.d
index 0d3f7b80d06..aae24b2809d 100644
--- a/ld/testsuite/ld-ifunc/ifunc-2-i386-now.d
+++ b/ld/testsuite/ld-ifunc/ifunc-2-i386-now.d
@@ -1,5 +1,5 @@
 #source: ifunc-2-i386.s
-#ld: -z now -m elf_i386 -shared --hash-style=sysv -z noseparate-code
+#ld: -z now -m elf_i386 -shared --hash-style=sysv -z noseparate-code $NO_DT_RELR_LDFLAGS
 #as: --32
 #objdump: -dw
 #target: x86_64-*-* i?86-*-*
diff --git a/ld/testsuite/ld-ifunc/ifunc-2-local-i386-now.d b/ld/testsuite/ld-ifunc/ifunc-2-local-i386-now.d
index 48d2084d38f..86083c12a08 100644
--- a/ld/testsuite/ld-ifunc/ifunc-2-local-i386-now.d
+++ b/ld/testsuite/ld-ifunc/ifunc-2-local-i386-now.d
@@ -1,5 +1,5 @@
 #source: ifunc-2-local-i386.s
-#ld: -z now -m elf_i386 -shared --hash-style=sysv -z noseparate-code
+#ld: -z now -m elf_i386 -shared --hash-style=sysv -z noseparate-code $NO_DT_RELR_LDFLAGS
 #as: --32
 #objdump: -dw
 #target: x86_64-*-* i?86-*-*
diff --git a/ld/testsuite/ld-ifunc/ifunc-2-local-x86-64-now.d b/ld/testsuite/ld-ifunc/ifunc-2-local-x86-64-now.d
index 14866a8f6cc..be3da08e12b 100644
--- a/ld/testsuite/ld-ifunc/ifunc-2-local-x86-64-now.d
+++ b/ld/testsuite/ld-ifunc/ifunc-2-local-x86-64-now.d
@@ -1,6 +1,6 @@
 #source: ifunc-2-local-x86-64.s
 #as: --64
-#ld: -z now -shared -melf_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -z now -shared -melf_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 #target: x86_64-*-*
 
diff --git a/ld/testsuite/ld-ifunc/ifunc-2-x86-64-now.d b/ld/testsuite/ld-ifunc/ifunc-2-x86-64-now.d
index 1cd60941ac0..b504f9adedd 100644
--- a/ld/testsuite/ld-ifunc/ifunc-2-x86-64-now.d
+++ b/ld/testsuite/ld-ifunc/ifunc-2-x86-64-now.d
@@ -1,6 +1,6 @@
 #source: ifunc-2-x86-64.s
 #as: --64
-#ld: -z now -shared -melf_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -z now -shared -melf_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 #target: x86_64-*-*
 
diff --git a/ld/testsuite/ld-ifunc/pr17154-x86-64-now.d b/ld/testsuite/ld-ifunc/pr17154-x86-64-now.d
index 4cc1dc206d5..f6920272b63 100644
--- a/ld/testsuite/ld-ifunc/pr17154-x86-64-now.d
+++ b/ld/testsuite/ld-ifunc/pr17154-x86-64-now.d
@@ -1,6 +1,6 @@
 #source: pr17154-x86.s
 #as: --64
-#ld: -z now -shared -melf_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -z now -shared -melf_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 #target: x86_64-*-*
 
diff --git a/ld/testsuite/ld-ifunc/pr17154-x86-64.d b/ld/testsuite/ld-ifunc/pr17154-x86-64.d
index 9fb23d410e3..90918426ee5 100644
--- a/ld/testsuite/ld-ifunc/pr17154-x86-64.d
+++ b/ld/testsuite/ld-ifunc/pr17154-x86-64.d
@@ -1,6 +1,6 @@
 #source: pr17154-x86.s
 #as: --64
-#ld: -shared -melf_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -shared -melf_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 #target: x86_64-*-*
 
diff --git a/ld/testsuite/ld-x86-64/bnd-branch-1-now.d b/ld/testsuite/ld-x86-64/bnd-branch-1-now.d
index b7bc4e526cc..b1bcea3cf4c 100644
--- a/ld/testsuite/ld-x86-64/bnd-branch-1-now.d
+++ b/ld/testsuite/ld-x86-64/bnd-branch-1-now.d
@@ -1,6 +1,6 @@
 #source: bnd-branch-1.s -mx86-used-note=no
 #as: --64
-#ld: -z now -shared -melf_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -z now -shared -melf_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-x86-64/bnd-ifunc-1-now.d b/ld/testsuite/ld-x86-64/bnd-ifunc-1-now.d
index 15ecfe1cc50..86ba30a46d5 100644
--- a/ld/testsuite/ld-x86-64/bnd-ifunc-1-now.d
+++ b/ld/testsuite/ld-x86-64/bnd-ifunc-1-now.d
@@ -1,6 +1,6 @@
 #source: bnd-ifunc-1.s
 #as: --64 -madd-bnd-prefix -mx86-used-note=no
-#ld: -z now -shared -melf_x86_64 -z bndplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -z now -shared -melf_x86_64 -z bndplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-x86-64/bnd-ifunc-2-now.d b/ld/testsuite/ld-x86-64/bnd-ifunc-2-now.d
index 211d72d2335..fa7ec07aaf0 100644
--- a/ld/testsuite/ld-x86-64/bnd-ifunc-2-now.d
+++ b/ld/testsuite/ld-x86-64/bnd-ifunc-2-now.d
@@ -1,6 +1,6 @@
 #source: bnd-ifunc-2.s
 #as: --64 -madd-bnd-prefix -mx86-used-note=no
-#ld: -z now -shared -melf_x86_64 -z bndplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -z now -shared -melf_x86_64 -z bndplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-x86-64/bnd-ifunc-2.d b/ld/testsuite/ld-x86-64/bnd-ifunc-2.d
index f80ba15aa35..36534b14feb 100644
--- a/ld/testsuite/ld-x86-64/bnd-ifunc-2.d
+++ b/ld/testsuite/ld-x86-64/bnd-ifunc-2.d
@@ -1,5 +1,5 @@
 #as: --64 -madd-bnd-prefix -mx86-used-note=no
-#ld: -shared -melf_x86_64 -z bndplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -shared -melf_x86_64 -z bndplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 #...
diff --git a/ld/testsuite/ld-x86-64/bnd-plt-1-now.d b/ld/testsuite/ld-x86-64/bnd-plt-1-now.d
index 24e28210a0a..47289a04f43 100644
--- a/ld/testsuite/ld-x86-64/bnd-plt-1-now.d
+++ b/ld/testsuite/ld-x86-64/bnd-plt-1-now.d
@@ -1,6 +1,6 @@
 #source: bnd-branch-1.s
 #as: --64 -mx86-used-note=no
-#ld: -z now -shared -melf_x86_64 -z bndplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -z now -shared -melf_x86_64 -z bndplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-x86-64/bnd-plt-1.d b/ld/testsuite/ld-x86-64/bnd-plt-1.d
index 0df32555c18..f047da897ce 100644
--- a/ld/testsuite/ld-x86-64/bnd-plt-1.d
+++ b/ld/testsuite/ld-x86-64/bnd-plt-1.d
@@ -1,6 +1,6 @@
 #source: bnd-branch-1.s
 #as: --64 -mx86-used-note=no
-#ld: -shared -melf_x86_64 -z bndplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -shared -melf_x86_64 -z bndplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-x86-64/export-class.exp b/ld/testsuite/ld-x86-64/export-class.exp
index 26896d1ca87..14c2d240fac 100644
--- a/ld/testsuite/ld-x86-64/export-class.exp
+++ b/ld/testsuite/ld-x86-64/export-class.exp
@@ -31,6 +31,7 @@ if { ![istarget x86_64*-*-linux*] } {
 }
 
 proc x86_64_export_class_test { abi flag emul } {
+    global NO_DT_RELR_LDFLAGS
 
     set testname "x86-64 $abi symbol export class test"
 
@@ -75,7 +76,7 @@ proc x86_64_export_class_test { abi flag emul } {
     run_ld_link_tests [list \
 	[list \
 	    "$testname (final shared object)" \
-	    "$LDFLAGS -shared -Tdata=0x12340000 tmpdir/x86-64-$abi-export-class-ref-r.o tmpdir/x86-64-$abi-export-class-lib.so" "" \
+	    "$LDFLAGS $NO_DT_RELR_LDFLAGS -shared -Tdata=0x12340000 tmpdir/x86-64-$abi-export-class-ref-r.o tmpdir/x86-64-$abi-export-class-lib.so" "" \
 	    "$AFLAGS" \
 	    { ../ld-elf/export-class-dep.s ../ld-elf/export-class-def.s } \
 	    [list \
diff --git a/ld/testsuite/ld-x86-64/ibt-plt-2a-x32.d b/ld/testsuite/ld-x86-64/ibt-plt-2a-x32.d
index a19cece98e8..23e31e62f55 100644
--- a/ld/testsuite/ld-x86-64/ibt-plt-2a-x32.d
+++ b/ld/testsuite/ld-x86-64/ibt-plt-2a-x32.d
@@ -1,6 +1,6 @@
 #source: ibt-plt-2.s
 #as: --x32
-#ld: -shared -m elf32_x86_64 -z ibtplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -shared -m elf32_x86_64 -z ibtplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-x86-64/ibt-plt-2a.d b/ld/testsuite/ld-x86-64/ibt-plt-2a.d
index 92785929092..adbbf62e84d 100644
--- a/ld/testsuite/ld-x86-64/ibt-plt-2a.d
+++ b/ld/testsuite/ld-x86-64/ibt-plt-2a.d
@@ -1,6 +1,6 @@
 #source: ibt-plt-2.s
 #as: --64 -defsym __64_bit__=1
-#ld: -shared -m elf_x86_64 -z ibtplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -shared -m elf_x86_64 -z ibtplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-x86-64/ibt-plt-3a-x32.d b/ld/testsuite/ld-x86-64/ibt-plt-3a-x32.d
index d6f8bb3afbe..f52b1cc796f 100644
--- a/ld/testsuite/ld-x86-64/ibt-plt-3a-x32.d
+++ b/ld/testsuite/ld-x86-64/ibt-plt-3a-x32.d
@@ -1,6 +1,6 @@
 #source: ibt-plt-3.s
 #as: --x32
-#ld: -shared -m elf32_x86_64 -z ibtplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -shared -m elf32_x86_64 -z ibtplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-x86-64/ibt-plt-3a.d b/ld/testsuite/ld-x86-64/ibt-plt-3a.d
index 9c15ed4f928..8bd8851ea73 100644
--- a/ld/testsuite/ld-x86-64/ibt-plt-3a.d
+++ b/ld/testsuite/ld-x86-64/ibt-plt-3a.d
@@ -1,6 +1,6 @@
 #source: ibt-plt-3.s
 #as: --64 -defsym __64_bit__=1
-#ld: -shared -m elf_x86_64 -z ibtplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -shared -m elf_x86_64 -z ibtplt --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-x86-64/ilp32-4.d b/ld/testsuite/ld-x86-64/ilp32-4.d
index 34be012056e..ad5c9cdf858 100644
--- a/ld/testsuite/ld-x86-64/ilp32-4.d
+++ b/ld/testsuite/ld-x86-64/ilp32-4.d
@@ -1,5 +1,5 @@
 #as: --x32
-#ld: -m elf32_x86_64 -shared --no-ld-generated-unwind-info --hash-style=sysv
+#ld: -m elf32_x86_64 -shared --no-ld-generated-unwind-info --hash-style=sysv $NO_DT_RELR_LDFLAGS
 #readelf: -d -S --wide
 #target: x86_64-*-linux*
 
diff --git a/ld/testsuite/ld-x86-64/load1c.d b/ld/testsuite/ld-x86-64/load1c.d
index db9c69fadbf..7404c7093b4 100644
--- a/ld/testsuite/ld-x86-64/load1c.d
+++ b/ld/testsuite/ld-x86-64/load1c.d
@@ -1,6 +1,6 @@
 #source: load1.s
 #as: --64
-#ld: -shared -melf_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -shared -melf_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-x86-64/load1d.d b/ld/testsuite/ld-x86-64/load1d.d
index 7ccae532f27..1b474a375c7 100644
--- a/ld/testsuite/ld-x86-64/load1d.d
+++ b/ld/testsuite/ld-x86-64/load1d.d
@@ -1,6 +1,6 @@
 #source: load1.s
 #as: --x32
-#ld: -shared -melf32_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -shared -melf32_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-x86-64/pr13082-2b.d b/ld/testsuite/ld-x86-64/pr13082-2b.d
index c218eafe34c..71c44fc0ee5 100644
--- a/ld/testsuite/ld-x86-64/pr13082-2b.d
+++ b/ld/testsuite/ld-x86-64/pr13082-2b.d
@@ -1,7 +1,7 @@
 #source: pr13082-2.s
 #name: PR ld/13082-2 (b)
 #as: --x32
-#ld: -pie -melf32_x86_64
+#ld: -pie -melf32_x86_64 $NO_DT_RELR_LDFLAGS
 #readelf: -r --wide
 
 Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 1 entry:
diff --git a/ld/testsuite/ld-x86-64/pr14207.d b/ld/testsuite/ld-x86-64/pr14207.d
index f330600b916..e3af36146c6 100644
--- a/ld/testsuite/ld-x86-64/pr14207.d
+++ b/ld/testsuite/ld-x86-64/pr14207.d
@@ -1,6 +1,6 @@
 #name: PR ld/14207
 #as: --64
-#ld: -melf_x86_64 -shared -z relro -z now --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -melf_x86_64 -shared -z relro -z now --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #readelf: -l --wide
 #target: x86_64-*-linux*
 
diff --git a/ld/testsuite/ld-x86-64/pr18176.d b/ld/testsuite/ld-x86-64/pr18176.d
index 4e3ad9ff08d..a99ff15ac6b 100644
--- a/ld/testsuite/ld-x86-64/pr18176.d
+++ b/ld/testsuite/ld-x86-64/pr18176.d
@@ -1,6 +1,6 @@
 #name: PR ld/18176
 #as: --64
-#ld: -melf_x86_64 -shared -z relro -T pr18176.t -z max-page-size=0x200000 -z common-page-size=0x1000
+#ld: -melf_x86_64 -shared -z relro -T pr18176.t -z max-page-size=0x200000 -z common-page-size=0x1000 $NO_DT_RELR_LDFLAGS
 #readelf: -l --wide
 #target: x86_64-*-linux*
 
diff --git a/ld/testsuite/ld-x86-64/pr19162.d b/ld/testsuite/ld-x86-64/pr19162.d
index 2d51dabe729..f458853d8e5 100644
--- a/ld/testsuite/ld-x86-64/pr19162.d
+++ b/ld/testsuite/ld-x86-64/pr19162.d
@@ -1,7 +1,7 @@
 #source: pr19162a.s
 #source: pr19162b.s
 #as: --64
-#ld: -melf_x86_64 -shared -z noseparate-code -z max-page-size=0x200000 -z common-page-size=0x1000 --hash-style=sysv
+#ld: -melf_x86_64 -shared -z noseparate-code -z max-page-size=0x200000 -z common-page-size=0x1000 --hash-style=sysv $NO_DT_RELR_LDFLAGS
 #readelf: -l --wide
 #target: x86_64-*-linux*
 
diff --git a/ld/testsuite/ld-x86-64/pr19636-2d.d b/ld/testsuite/ld-x86-64/pr19636-2d.d
index 3bd33a9a915..092992be9d4 100644
--- a/ld/testsuite/ld-x86-64/pr19636-2d.d
+++ b/ld/testsuite/ld-x86-64/pr19636-2d.d
@@ -1,6 +1,6 @@
 #source: pr19636-2.s
 #as: --64 -mrelax-relocations=no
-#ld: -pie -m elf_x86_64 --no-dynamic-linker --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -pie -m elf_x86_64 --no-dynamic-linker --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-x86-64/pr19636-2l.d b/ld/testsuite/ld-x86-64/pr19636-2l.d
index 1b894b3e97c..8c23c0b7411 100644
--- a/ld/testsuite/ld-x86-64/pr19636-2l.d
+++ b/ld/testsuite/ld-x86-64/pr19636-2l.d
@@ -1,6 +1,6 @@
 #source: pr19636-2.s
 #as: --64 -mrelax-relocations=no
-#ld: -pie -m elf_x86_64 --no-dynamic-linker --hash-style=sysv -z dynamic-undefined-weak -z max-page-size=0x200000 -z noseparate-code
+#ld: -pie -m elf_x86_64 --no-dynamic-linker --hash-style=sysv -z dynamic-undefined-weak -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 #warning: -z dynamic-undefined-weak ignored
 
diff --git a/ld/testsuite/ld-x86-64/pr20253-1d.d b/ld/testsuite/ld-x86-64/pr20253-1d.d
index f9f03ba8403..057577bdc57 100644
--- a/ld/testsuite/ld-x86-64/pr20253-1d.d
+++ b/ld/testsuite/ld-x86-64/pr20253-1d.d
@@ -1,6 +1,6 @@
 #source: pr20253-1.s
 #as: --64
-#ld: -pie -melf_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -pie -melf_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-x86-64/pr20253-1f.d b/ld/testsuite/ld-x86-64/pr20253-1f.d
index 6666bcaf147..479db8202e8 100644
--- a/ld/testsuite/ld-x86-64/pr20253-1f.d
+++ b/ld/testsuite/ld-x86-64/pr20253-1f.d
@@ -1,6 +1,6 @@
 #source: pr20253-1.s
 #as: --64
-#ld: -shared -melf_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -shared -melf_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-x86-64/pr20253-1j.d b/ld/testsuite/ld-x86-64/pr20253-1j.d
index 88c9715ad75..20176a2d357 100644
--- a/ld/testsuite/ld-x86-64/pr20253-1j.d
+++ b/ld/testsuite/ld-x86-64/pr20253-1j.d
@@ -1,6 +1,6 @@
 #source: pr20253-1.s
 #as: --x32
-#ld: -pie -melf32_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -pie -melf32_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-x86-64/pr20253-1l.d b/ld/testsuite/ld-x86-64/pr20253-1l.d
index 7428a721b16..4b179077dec 100644
--- a/ld/testsuite/ld-x86-64/pr20253-1l.d
+++ b/ld/testsuite/ld-x86-64/pr20253-1l.d
@@ -1,6 +1,6 @@
 #source: pr20253-1.s
 #as: --x32
-#ld: -shared -melf32_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code
+#ld: -shared -melf32_x86_64 --hash-style=sysv -z max-page-size=0x200000 -z noseparate-code $NO_DT_RELR_LDFLAGS
 #objdump: -dw
 
 .*: +file format .*
diff --git a/ld/testsuite/ld-x86-64/report-reloc-1-x32.d b/ld/testsuite/ld-x86-64/report-reloc-1-x32.d
index c66f956c473..63fe7b1bb8a 100644
--- a/ld/testsuite/ld-x86-64/report-reloc-1-x32.d
+++ b/ld/testsuite/ld-x86-64/report-reloc-1-x32.d
@@ -1,6 +1,6 @@
 #source: report-reloc-1.s
 #as: --x32
-#ld: -pie -melf32_x86_64 -z report-relative-reloc
+#ld: -pie -melf32_x86_64 -z report-relative-reloc $NO_DT_RELR_LDFLAGS
 #warning_output: report-reloc-1.l
 #readelf: -r --wide
 
diff --git a/ld/testsuite/ld-x86-64/report-reloc-1.d b/ld/testsuite/ld-x86-64/report-reloc-1.d
index 1b5f91fdd3f..69f164c9434 100644
--- a/ld/testsuite/ld-x86-64/report-reloc-1.d
+++ b/ld/testsuite/ld-x86-64/report-reloc-1.d
@@ -1,6 +1,6 @@
 #source: report-reloc-1.s
 #as: --64
-#ld: -pie -melf_x86_64 -z report-relative-reloc
+#ld: -pie -melf_x86_64 -z report-relative-reloc $NO_DT_RELR_LDFLAGS
 #warning_output: report-reloc-1.l
 #readelf: -r --wide
 
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index c100879397e..b4048128057 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -45,28 +45,6 @@ set x86_64tests {
     {"basic PLT generation"
      "-melf_x86_64 tmpdir/libpltlib.so" "" "--64" {plt.s}
      {{objdump -drj.plt plt.pd}} "plt"}
-    {"TLS -fpic -shared transitions"
-     "-shared -melf_x86_64 --no-ld-generated-unwind-info \
-      -z noseparate-code -z max-page-size=0x200000 --hash-style=sysv" ""
-     "--64" {tlspic1.s tlspic2.s}
-     {{readelf -WSsrl tlspic.rd} {objdump -drj.text\ -Mintel64 tlspic.dd}
-      {objdump -sj.got tlspic.sd} {objdump -sj.tdata tlspic.td}}
-      "libtlspic.so"}
-    {"TLS -fpic -shared transitions with r15 as GOT base"
-     "-shared -melf_x86_64 --no-ld-generated-unwind-info \
-      -z noseparate-code -z max-page-size=0x200000 --hash-style=sysv" ""
-     "--64 -mrelax-relocations=yes"
-     {tlspic3.s tlspic2.s}
-     {{readelf -WSsrl tlspic2.rd} {objdump -drj.text\ -Mintel64 tlspic2.dd}
-      {objdump -sj.got tlspic2.sd} {objdump -sj.tdata tlspic2.td}}
-      "libtlspic2.so"}
-    {"TLS descriptor -fpic -shared transitions"
-     "-shared -melf_x86_64 --no-ld-generated-unwind-info \
-      -z noseparate-code -z max-page-size=0x200000 --hash-style=sysv" ""
-     "--64" {tlsdesc.s tlspic2.s}
-     {{readelf -WSsrld tlsdesc.rd} {objdump -drj.text tlsdesc.dd}
-      {objdump "-s -j.got -j.got.plt" tlsdesc.sd} {objdump -sj.tdata tlsdesc.td}
-      {objdump -drj.plt tlsdesc.pd}} "libtlsdesc.so"}
     {"Helper shared library" "-shared -melf_x86_64" ""
      "--64" {tlslib.s} {} "libtlslib.so"}
     {"TLS -fpic and -fno-pic exec transitions"
@@ -240,6 +218,49 @@ set x86_64tests {
 
 run_ld_link_tests $x86_64tests
 
+run_ld_link_tests [list \
+    [list \
+	"TLS -fpic -shared transitions" \
+	"-shared -melf_x86_64 --no-ld-generated-unwind-info \
+	 -z noseparate-code -z max-page-size=0x200000 --hash-style=sysv \
+	 $NO_DT_RELR_LDFLAGS" \
+	"" "--64" \
+	{tlspic1.s tlspic2.s} \
+	{{readelf -WSsrl tlspic.rd} \
+	 {objdump {-drj.text -Mintel64} tlspic.dd} \
+	 {objdump -sj.got tlspic.sd} \
+	 {objdump -sj.tdata tlspic.td}} \
+	"libtlspic.so" \
+    ] \
+    [list \
+	"TLS -fpic -shared transitions with r15 as GOT base" \
+	"-shared -melf_x86_64 --no-ld-generated-unwind-info \
+	 -z noseparate-code -z max-page-size=0x200000 --hash-style=sysv \
+	 $NO_DT_RELR_LDFLAGS" \
+	 "" "--64 -mrelax-relocations=yes" \
+	{tlspic3.s tlspic2.s} \
+	{{readelf -WSsrl tlspic2.rd} \
+	 {objdump {-drj.text -Mintel64} tlspic2.dd} \
+	 {objdump -sj.got tlspic2.sd} \
+	 {objdump -sj.tdata tlspic2.td}} \
+	"libtlspic2.so" \
+    ] \
+    [list \
+	"TLS descriptor -fpic -shared transitions" \
+	"-shared -melf_x86_64 --no-ld-generated-unwind-info \
+	 -z noseparate-code -z max-page-size=0x200000 --hash-style=sysv \
+	 $NO_DT_RELR_LDFLAGS" \
+	"" "--64" \
+	{tlsdesc.s tlspic2.s} \
+	{{readelf -WSsrld tlsdesc.rd} \
+	 {objdump -drj.text tlsdesc.dd} \
+	 {objdump {-s -j.got -j.got.plt} tlsdesc.sd} \
+	 {objdump -sj.tdata tlsdesc.td} \
+	 {objdump -drj.plt tlsdesc.pd}} \
+	 "libtlsdesc.so" \
+    ] \
+]
+
 set test_name "Mixed x86_64 and i386 input test 1"
 set test mixed1
 if { ![ld_link $ld tmpdir/$test "-m$emul tmpdir/${test}a.o tmpdir/${test}b.o"] } {
-- 
2.33.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 7/9] x86: Add DT_RELR support
  2022-01-08 18:38 [PATCH v2 0/9] ld: Implement DT_RELR for x86 H.J. Lu
                   ` (5 preceding siblings ...)
  2022-01-08 18:38 ` [PATCH v2 6/9] elf: Support DT_RELR in linker tests H.J. Lu
@ 2022-01-08 18:38 ` H.J. Lu
  2022-01-08 18:38 ` [PATCH v2 8/9] ld: Add simple DT_RELR tests H.J. Lu
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: H.J. Lu @ 2022-01-08 18:38 UTC (permalink / raw)
  To: binutils; +Cc: Nick Clifton, Alan Modra, libc-alpha

DT_RELR is implemented with linker relaxation:

1. During linker relaxation, we scan input relocations with the same
logic in relocate_section to determine if a relative relocation should
be generated and save the relative relocation candidate information for
sizing the DT_RELR section later after all symbols addresses can be
determined.  For these relative relocations which can't be placed in
the DT_RELR section, they will be placed in the rela.dyn/rel.dyn
section.
2. When DT_RELR is enabled, _bfd_elf_map_sections_to_segments calls a
backend function to size the DT_RELR section which will compute the
DT_RELR section size and tell ldelf_map_segments to layout sections
again when the DT_RELR section size has been increased.
3. After regular symbol processing is finished, bfd_elf_final_link calls
a backend function to finish the DT_RELR section.

	* elf32-i386.c (elf_i386_scan_relocs): Set SEC_ELF_REVERSE_COPY
	on input section for DT_RELR.
	(elf_i386_relocate_section): Don't generate relative relocation
	when DT_RELR is enabled.
	(elf_i386_finish_dynamic_symbol): Likewise.
	* elf64-x86-64.c (elf_x86_64_scan_relocs): Set
	SEC_ELF_REVERSE_COPY on input section for DT_RELR.
	(elf_x86_64_relocate_section): Don't generate relative relocation
	when DT_RELR is enabled.
	(elf_x86_64_finish_dynamic_symbol): Likewise.
	* elfxx-x86.c (_bfd_x86_elf_link_hash_table_create): Initialize
	relative_r_type, relative_r_name, elf_append_reloc,
	elf_write_addend and elf_write_addend_in_got.
	(elf_x86_relative_reloc_record_add): New function.
	(_bfd_x86_elf_link_relax_section): Likewise.
	(elf64_dt_relr_bitmap_add): Likewise.
	(elf32_dt_relr_bitmap_add): Likewise.
	(_bfd_elf32_write_addend): Likewise.
	(_bfd_elf64_write_addend): Likewise.
	(elf_x86_size_or_finish_relative_reloc): Likewise.
	(elf_x86_compute_dl_relr_bitmap): Likewise.
	(elf_x86_write_dl_relr_bitmap): Likewise.
	(elf_x86_relative_reloc_compare ): Likewise.
	(_bfd_elf_x86_size_relative_relocs): Likewise.
	(_bfd_elf_x86_finish_relative_relocs): Likewise.
	(_bfd_x86_elf_size_dynamic_sections): Skip the .relr.dyn section.
	(_bfd_x86_elf_finish_dynamic_sections): Convert 3 spare dynamic
	tags to DT_RELR, DT_RELRSZ and for compact relative relocation.
	* elfxx-x86.h (X86_64_GOT_TYPE_P): New.
	(I386_GOT_TYPE_P): Likewise.
	(X86_GOT_TYPE_P): Likewise.
	(X86_64_RELATIVE_RELOC_TYPE_P): Likewise.
	(I386_RELATIVE_RELOC_TYPE_P): Likewise.
	(X86_RELATIVE_RELOC_TYPE_P): Likewise.
	(X86_LOCAL_GOT_RELATIVE_RELOC_P): Likewise.
	(I386_PCREL_TYPE_P): Likewise.
	(X86_64_PCREL_TYPE_P): Likewise.
	(X86_64_NEED_DYNAMIC_RELOC_TYPE_P): Rewrite.
	(I386_NEED_DYNAMIC_RELOC_TYPE_P): Likewise.
	(GENERATE_DYNAMIC_RELOCATION_P): Also check rel_from_abs.
	(elf_x86_link_hash_entry): Add got_relative_reloc_done.
	(elf_x86_relative_reloc_record): New.
	(elf_x86_relative_reloc_data): Likewise.
	(elf_dt_relr_bitmap): Likewise.
	(elf_x86_link_hash_table): Add dt_relr_bitmap, relative_reloc,
	unaligned_relative_reloc, relative_r_type, relative_r_name,
	elf_append_reloc, elf_write_addend, elf_write_addend_in_got and
	relative_reloc_done.
	(elf_x86_relative_reloc_done): New.
	(relative_reloc_packed): Likewise.
	(_bfd_x86_elf_link_relax_section): Likewise.
	(_bfd_elf_x86_size_relative_relocs): Likewise.
	(_bfd_elf_x86_finish_relative_relocs): Likewise.
	(_bfd_elf32_write_addend): Likewise.
	(_bfd_elf64_write_addend): Likewise.
	(bfd_elf32_bfd_relax_section): Likewise.
	(bfd_elf64_bfd_relax_section): Likewise.
	(elf_backend_size_relative_relocs): Likewise.
	(elf_backend_finish_relative_relocs): Likewise.
	(elf_x86_allocate_local_got_info): Also allocate
	relative_reloc_done.
---
 bfd/elf32-i386.c   |  77 ++--
 bfd/elf64-x86-64.c |  92 +++--
 bfd/elfxx-x86.c    | 954 +++++++++++++++++++++++++++++++++++++++++++++
 bfd/elfxx-x86.h    | 147 ++++++-
 4 files changed, 1213 insertions(+), 57 deletions(-)

diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index d1f61be5044..1916ef723d0 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -1456,6 +1456,7 @@ elf_i386_scan_relocs (bfd *abfd,
 		      asection *sec,
 		      const Elf_Internal_Rela *relocs)
 {
+  const struct elf_backend_data *bed;
   struct elf_x86_link_hash_table *htab;
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
@@ -1485,6 +1486,14 @@ elf_i386_scan_relocs (bfd *abfd,
       return false;
     }
 
+  bed = get_elf_backend_data (abfd);
+
+  /* Set SEC_ELF_REVERSE_COPY here so that the correct section offset
+     will be used for DT_RELR.  */
+  if (!_bfd_elf_process_reverse_copy (sec, 4,
+				      bed->s->int_rels_per_ext_rel))
+    return false;
+
   symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
 
@@ -2473,8 +2482,10 @@ elf_i386_relocate_section (bfd *output_bfd,
 		      bfd_put_32 (output_bfd, relocation,
 				  htab->elf.sgot->contents + off);
 		      h->got.offset |= 1;
-
-		      if (GENERATE_RELATIVE_RELOC_P (info, h))
+		      /* NB: Don't generate relative relocation here if
+			 it has been generated by DT_RELR.  */
+		      if (!info->enable_dt_relr
+			  && GENERATE_RELATIVE_RELOC_P (info, h))
 			{
 			  /* PR ld/21402: If this symbol isn't dynamic
 			     in PIC, generate R_386_RELATIVE here.  */
@@ -2504,7 +2515,9 @@ elf_i386_relocate_section (bfd *output_bfd,
 			      htab->elf.sgot->contents + off);
 		  local_got_offsets[r_symndx] |= 1;
 
-		  if (bfd_link_pic (info))
+		  /* NB: Don't generate relative relocation here if it
+		     has been generated by DT_RELR.  */
+		  if (!info->enable_dt_relr && bfd_link_pic (info))
 		    relative_reloc = true;
 		}
 	    }
@@ -2707,6 +2720,7 @@ elf_i386_relocate_section (bfd *output_bfd,
 	    {
 	      Elf_Internal_Rela outrel;
 	      bool skip, relocate;
+	      bool generate_dynamic_reloc = true;
 	      asection *sreloc;
 
 	      /* When generating a shared object, these relocations
@@ -2734,23 +2748,33 @@ elf_i386_relocate_section (bfd *output_bfd,
 		{
 		  /* This symbol is local, or marked to become local.  */
 		  relocate = true;
-		  outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
+		  /* NB: Don't generate relative relocation here if it
+		     has been generated by DT_RELR.  */
+		  if (info->enable_dt_relr)
+		    generate_dynamic_reloc = false;
+		  else
+		    {
+		      outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
 
-		  if (htab->params->report_relative_reloc)
-		    _bfd_x86_elf_link_report_relative_reloc
-		      (info, input_section, h, sym, "R_386_RELATIVE",
-		       &outrel);
+		      if (htab->params->report_relative_reloc)
+			_bfd_x86_elf_link_report_relative_reloc
+			  (info, input_section, h, sym, "R_386_RELATIVE",
+			   &outrel);
+		    }
 		}
 
-	      sreloc = elf_section_data (input_section)->sreloc;
-
-	      if (sreloc == NULL || sreloc->contents == NULL)
+	      if (generate_dynamic_reloc)
 		{
-		  r = bfd_reloc_notsupported;
-		  goto check_relocation_error;
-		}
+		  sreloc = elf_section_data (input_section)->sreloc;
 
-	      elf_append_rel (output_bfd, sreloc, &outrel);
+		  if (sreloc == NULL || sreloc->contents == NULL)
+		    {
+		      r = bfd_reloc_notsupported;
+		      goto check_relocation_error;
+		    }
+
+		  elf_append_rel (output_bfd, sreloc, &outrel);
+		}
 
 	      /* If this reloc is against an external symbol, we do
 		 not want to fiddle with the addend.  Otherwise, we
@@ -3776,6 +3800,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
       Elf_Internal_Rela rel;
       asection *relgot = htab->elf.srelgot;
       const char *relative_reloc_name = NULL;
+      bool generate_dynamic_reloc = true;
 
       /* This symbol has an entry in the global offset table.  Set it
 	 up.  */
@@ -3858,8 +3883,13 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
 	       && SYMBOL_REFERENCES_LOCAL_P (info, h))
 	{
 	  BFD_ASSERT((h->got.offset & 1) != 0);
-	  rel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
-	  relative_reloc_name = "R_386_RELATIVE";
+	  if (info->enable_dt_relr)
+	    generate_dynamic_reloc = false;
+	  else
+	    {
+	      rel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
+	      relative_reloc_name = "R_386_RELATIVE";
+	    }
 	}
       else
 	{
@@ -3870,12 +3900,15 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
 	  rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT);
 	}
 
-      if (relative_reloc_name != NULL
-	  && htab->params->report_relative_reloc)
-	_bfd_x86_elf_link_report_relative_reloc
-	  (info, relgot, h, sym, relative_reloc_name, &rel);
+      if (generate_dynamic_reloc)
+	{
+	  if (relative_reloc_name != NULL
+	      && htab->params->report_relative_reloc)
+	    _bfd_x86_elf_link_report_relative_reloc
+	      (info, relgot, h, sym, relative_reloc_name, &rel);
 
-      elf_append_rel (output_bfd, relgot, &rel);
+	  elf_append_rel (output_bfd, relgot, &rel);
+	}
     }
 
   if (h->needs_copy)
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index ad885f89e11..09ec0e0053e 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -1826,6 +1826,7 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
 			asection *sec,
 			const Elf_Internal_Rela *relocs)
 {
+  const struct elf_backend_data *bed;
   struct elf_x86_link_hash_table *htab;
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
@@ -1855,6 +1856,14 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
       return false;
     }
 
+  bed = get_elf_backend_data (abfd);
+
+  /* Set SEC_ELF_REVERSE_COPY here so that the correct section offset
+     will be used for DT_RELR.  */
+  if (!_bfd_elf_process_reverse_copy (sec, ABI_64_P (abfd) ? 8 : 4,
+				      bed->s->int_rels_per_ext_rel))
+    return false;
+
   symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
 
@@ -2867,7 +2876,10 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 			 as -1 | 1 still is -1.  */
 		      h->got.offset |= 1;
 
-		      if (GENERATE_RELATIVE_RELOC_P (info, h))
+		      /* NB: Don't generate relative relocation here if
+			 it has been generated by DT_RELR.  */
+		      if (!info->enable_dt_relr
+			  && GENERATE_RELATIVE_RELOC_P (info, h))
 			{
 			  /* If this symbol isn't dynamic in PIC,
 			     generate R_X86_64_RELATIVE here.  */
@@ -2899,8 +2911,11 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 
 		  /* NB: GOTPCREL relocations against local absolute
 		     symbol store relocation value in the GOT slot
-		     without relative relocation.  */
-		  if (bfd_link_pic (info)
+		     without relative relocation.  Don't generate
+		     relative relocation here if it has been generated
+		     by DT_RELR.  */
+		  if (!info->enable_dt_relr
+		      && bfd_link_pic (info)
 		      && !(sym->st_shndx == SHN_ABS
 			   && (r_type == R_X86_64_GOTPCREL
 			       || r_type == R_X86_64_GOTPCRELX
@@ -3215,6 +3230,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 	    {
 	      Elf_Internal_Rela outrel;
 	      bool skip, relocate;
+	      bool generate_dynamic_reloc = true;
 	      asection *sreloc;
 	      const char *relative_reloc_name = NULL;
 
@@ -3253,9 +3269,17 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 			  && htab->params->no_reloc_overflow_check))
 		    {
 		      relocate = true;
-		      outrel.r_info = htab->r_info (0, R_X86_64_RELATIVE);
-		      outrel.r_addend = relocation + rel->r_addend;
-		      relative_reloc_name = "R_X86_64_RELATIVE";
+		      /* NB: Don't generate relative relocation here if
+			 it has been generated by DT_RELR.  */
+		      if (info->enable_dt_relr)
+			generate_dynamic_reloc = false;
+		      else
+			{
+			  outrel.r_info =
+			    htab->r_info (0, R_X86_64_RELATIVE);
+			  outrel.r_addend = relocation + rel->r_addend;
+			  relative_reloc_name = "R_X86_64_RELATIVE";
+			}
 		    }
 		  else if (r_type == R_X86_64_64
 			   && !ABI_64_P (output_bfd))
@@ -3323,21 +3347,24 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 		    }
 		}
 
-	      sreloc = elf_section_data (input_section)->sreloc;
-
-	      if (sreloc == NULL || sreloc->contents == NULL)
+	      if (generate_dynamic_reloc)
 		{
-		  r = bfd_reloc_notsupported;
-		  goto check_relocation_error;
-		}
+		  sreloc = elf_section_data (input_section)->sreloc;
 
-	      if (relative_reloc_name
-		  && htab->params->report_relative_reloc)
-		_bfd_x86_elf_link_report_relative_reloc
-		  (info, input_section, h, sym, relative_reloc_name,
-		   &outrel);
+		  if (sreloc == NULL || sreloc->contents == NULL)
+		    {
+		      r = bfd_reloc_notsupported;
+		      goto check_relocation_error;
+		    }
 
-	      elf_append_rela (output_bfd, sreloc, &outrel);
+		  if (relative_reloc_name
+		      && htab->params->report_relative_reloc)
+		    _bfd_x86_elf_link_report_relative_reloc
+		      (info, input_section, h, sym,
+		       relative_reloc_name, &outrel);
+
+		  elf_append_rela (output_bfd, sreloc, &outrel);
+		}
 
 	      /* If this reloc is against an external symbol, we do
 		 not want to fiddle with the addend.  Otherwise, we
@@ -4424,6 +4451,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
       Elf_Internal_Rela rela;
       asection *relgot = htab->elf.srelgot;
       const char *relative_reloc_name = NULL;
+      bool generate_dynamic_reloc = true;
 
       /* This symbol has an entry in the global offset table.  Set it
 	 up.  */
@@ -4506,11 +4534,16 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
 	  if (!SYMBOL_DEFINED_NON_SHARED_P (h))
 	    return false;
 	  BFD_ASSERT((h->got.offset & 1) != 0);
-	  rela.r_info = htab->r_info (0, R_X86_64_RELATIVE);
-	  rela.r_addend = (h->root.u.def.value
-			   + h->root.u.def.section->output_section->vma
-			   + h->root.u.def.section->output_offset);
-	  relative_reloc_name = "R_X86_64_RELATIVE";
+	  if (info->enable_dt_relr)
+	    generate_dynamic_reloc = false;
+	  else
+	    {
+	      rela.r_info = htab->r_info (0, R_X86_64_RELATIVE);
+	      rela.r_addend = (h->root.u.def.value
+			       + h->root.u.def.section->output_section->vma
+			       + h->root.u.def.section->output_offset);
+	      relative_reloc_name = "R_X86_64_RELATIVE";
+	    }
 	}
       else
 	{
@@ -4522,12 +4555,15 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
 	  rela.r_addend = 0;
 	}
 
-      if (relative_reloc_name != NULL
-	  && htab->params->report_relative_reloc)
-	_bfd_x86_elf_link_report_relative_reloc
-	  (info, relgot, h, sym, relative_reloc_name, &rela);
+      if (generate_dynamic_reloc)
+	{
+	  if (relative_reloc_name != NULL
+	      && htab->params->report_relative_reloc)
+	    _bfd_x86_elf_link_report_relative_reloc
+	      (info, relgot, h, sym, relative_reloc_name, &rela);
 
-      elf_append_rela (output_bfd, relgot, &rela);
+	  elf_append_rela (output_bfd, relgot, &rela);
+	}
     }
 
   if (h->needs_copy)
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index 25f7717ea88..119929bb093 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -726,6 +726,10 @@ _bfd_x86_elf_link_hash_table_create (bfd *abfd)
       ret->got_entry_size = 8;
       ret->pcrel_plt = true;
       ret->tls_get_addr = "__tls_get_addr";
+      ret->relative_r_type = R_X86_64_RELATIVE;
+      ret->relative_r_name = "R_X86_64_RELATIVE";
+      ret->elf_append_reloc = elf_append_rela;
+      ret->elf_write_addend_in_got = _bfd_elf64_write_addend;
     }
   if (ABI_64_P (abfd))
     {
@@ -733,6 +737,7 @@ _bfd_x86_elf_link_hash_table_create (bfd *abfd)
       ret->pointer_r_type = R_X86_64_64;
       ret->dynamic_interpreter = ELF64_DYNAMIC_INTERPRETER;
       ret->dynamic_interpreter_size = sizeof ELF64_DYNAMIC_INTERPRETER;
+      ret->elf_write_addend = _bfd_elf64_write_addend;
     }
   else
     {
@@ -743,6 +748,7 @@ _bfd_x86_elf_link_hash_table_create (bfd *abfd)
 	  ret->dynamic_interpreter = ELFX32_DYNAMIC_INTERPRETER;
 	  ret->dynamic_interpreter_size
 	    = sizeof ELFX32_DYNAMIC_INTERPRETER;
+	  ret->elf_write_addend = _bfd_elf32_write_addend;
 	}
       else
 	{
@@ -751,6 +757,11 @@ _bfd_x86_elf_link_hash_table_create (bfd *abfd)
 	  ret->got_entry_size = 4;
 	  ret->pcrel_plt = false;
 	  ret->pointer_r_type = R_386_32;
+	  ret->relative_r_type = R_386_RELATIVE;
+	  ret->relative_r_name = "R_386_RELATIVE";
+	  ret->elf_append_reloc = elf_append_rel;
+	  ret->elf_write_addend = _bfd_elf32_write_addend;
+	  ret->elf_write_addend_in_got = _bfd_elf32_write_addend;
 	  ret->dynamic_interpreter = ELF32_DYNAMIC_INTERPRETER;
 	  ret->dynamic_interpreter_size
 	    = sizeof ELF32_DYNAMIC_INTERPRETER;
@@ -977,6 +988,919 @@ _bfd_x86_elf_check_relocs (bfd *abfd,
   return true;
 }
 
+/* Add an entry to the relative reloc record.  */
+
+static bool
+elf_x86_relative_reloc_record_add
+  (struct bfd_link_info *info,
+   struct elf_x86_relative_reloc_data *relative_reloc,
+   Elf_Internal_Rela *rel, asection *sec,
+   asection *sym_sec, struct elf_link_hash_entry *h,
+   Elf_Internal_Sym *sym, bfd_vma offset)
+{
+  bfd_size_type newidx;
+
+  if (relative_reloc->data == NULL)
+    {
+      relative_reloc->data = bfd_malloc
+	(sizeof (struct elf_x86_relative_reloc_record));
+      relative_reloc->count = 0;
+      relative_reloc->size = 1;
+    }
+
+  newidx = relative_reloc->count++;
+
+  if (relative_reloc->count > relative_reloc->size)
+    {
+      relative_reloc->size <<= 1;
+      relative_reloc->data = bfd_realloc
+	(relative_reloc->data,
+	 (relative_reloc->size
+	  * sizeof (struct elf_x86_relative_reloc_record)));
+    }
+
+  if (relative_reloc->data == NULL)
+    {
+      info->callbacks->einfo
+	/* xgettext:c-format */
+	(_("%F%P: %pB: failed to allocate relative reloc record\n"),
+	 info->output_bfd);
+      return false;
+    }
+
+  relative_reloc->data[newidx].rel = *rel;
+  relative_reloc->data[newidx].sec = sec;
+  if (h != NULL)
+    {
+      /* Set SYM to NULL to indicate a global symbol.  */
+      relative_reloc->data[newidx].sym = NULL;
+      relative_reloc->data[newidx].u.h = h;
+    }
+  else
+    {
+      relative_reloc->data[newidx].sym = sym;
+      relative_reloc->data[newidx].u.sym_sec = sym_sec;
+    }
+  relative_reloc->data[newidx].offset = offset;
+  relative_reloc->data[newidx].address = 0;
+  return true;
+}
+
+/* After input sections have been mapped to output sections and
+   addresses of output sections are set initiallly, scan input
+   relocations with the same logic in relocate_section to determine
+   if a relative relocation should be generated.  Save the relative
+   relocation candidate information for sizing the DT_RELR section
+   later after all symbols addresses can be determined.  */
+
+bool
+_bfd_x86_elf_link_relax_section (bfd *abfd ATTRIBUTE_UNUSED,
+				 asection *input_section,
+				 struct bfd_link_info *info,
+				 bool *again)
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Rela *internal_relocs;
+  Elf_Internal_Rela *irel, *irelend;
+  Elf_Internal_Sym *isymbuf = NULL;
+  struct elf_link_hash_entry **sym_hashes;
+  const struct elf_backend_data *bed;
+  struct elf_x86_link_hash_table *htab;
+  bfd_vma *local_got_offsets;
+  bool is_x86_64;
+  bool unaligned_section;
+
+  if (bfd_link_relocatable (info))
+    return true;
+
+  /* Assume we're not going to change any sizes, and we'll only need
+     one pass.  */
+  *again = false;
+
+  bed = get_elf_backend_data (abfd);
+  htab = elf_x86_hash_table (info, bed->target_id);
+  if (htab == NULL)
+    return true;
+
+  /* Nothing to do if there are no relocations or relative relocations
+     have been packed.  */
+  if (input_section == htab->elf.srelrdyn
+      || input_section->relative_reloc_packed
+      || ((input_section->flags & (SEC_RELOC | SEC_ALLOC))
+	  != (SEC_RELOC | SEC_ALLOC))
+      || (input_section->flags & SEC_DEBUGGING) != 0
+      || input_section->reloc_count == 0)
+    return true;
+
+  /* Skip if the section isn't aligned.  */
+  unaligned_section = input_section->alignment_power == 0;
+
+  is_x86_64 = bed->target_id == X86_64_ELF_DATA;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+  local_got_offsets = elf_local_got_offsets (abfd);
+
+  /* Load the relocations for this section.  */
+  internal_relocs =
+    _bfd_elf_link_read_relocs (abfd, input_section, NULL,
+			       (Elf_Internal_Rela *) NULL,
+			       info->keep_memory);
+  if (internal_relocs == NULL)
+    return false;
+
+  irelend = internal_relocs + input_section->reloc_count;
+  for (irel = internal_relocs; irel < irelend; irel++)
+    {
+      unsigned int r_type;
+      unsigned int r_symndx;
+      Elf_Internal_Sym *isym;
+      struct elf_link_hash_entry *h;
+      struct elf_x86_link_hash_entry *eh;
+      bfd_vma offset;
+      bool resolved_to_zero;
+      bool need_copy_reloc_in_pie;
+      bool pc32_reloc;
+      asection *sec;
+      /* Offset must be a multiple of 2.  */
+      bool unaligned_offset = (irel->r_offset & 1) != 0;
+      /* True if there is a relative relocation against a dynamic
+	 symbol.  */
+      bool dynamic_relative_reloc_p;
+
+      /* Get the value of the symbol referred to by the reloc.  */
+      r_symndx = htab->r_sym (irel->r_info);
+
+      r_type = ELF32_R_TYPE (irel->r_info);
+      /* Clear the R_X86_64_converted_reloc_bit bit.  */
+      r_type &= ~R_X86_64_converted_reloc_bit;
+
+      sec = NULL;
+      h = NULL;
+      dynamic_relative_reloc_p = false;
+
+      if (r_symndx < symtab_hdr->sh_info)
+	{
+	  /* Read this BFD's local symbols.  */
+	  if (isymbuf == NULL)
+	    {
+	      isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+	      if (isymbuf == NULL)
+		isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+						symtab_hdr->sh_info, 0,
+						NULL, NULL, NULL);
+	      if (isymbuf == NULL)
+		goto error_return;
+	    }
+
+	  isym = isymbuf + r_symndx;
+	  switch (isym->st_shndx)
+	    {
+	    case SHN_ABS:
+	      sec = bfd_abs_section_ptr;
+	      break;
+	    case SHN_COMMON:
+	      sec = bfd_com_section_ptr;
+	      break;
+	    case SHN_X86_64_LCOMMON:
+	      if (!is_x86_64)
+		abort ();
+	      sec = &_bfd_elf_large_com_section;
+	      break;
+	    default:
+	      sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+	      break;
+	    }
+
+	  /* Skip relocation against local STT_GNU_IFUNC symbol.  */
+	  if (ELF32_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
+	    continue;
+
+	  eh = (struct elf_x86_link_hash_entry *) h;
+	  resolved_to_zero = false;
+	}
+      else
+	{
+	  /* Get H and SEC for GENERATE_DYNAMIC_RELOCATION_P below.  */
+	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+	  while (h->root.type == bfd_link_hash_indirect
+		 || h->root.type == bfd_link_hash_warning)
+	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+	  if (h->root.type == bfd_link_hash_defined
+	      || h->root.type == bfd_link_hash_defweak)
+	    sec = h->root.u.def.section;
+
+	  /* Skip relocation against STT_GNU_IFUNC symbol.  */
+	  if (h->type == STT_GNU_IFUNC)
+	    continue;
+
+	  eh = (struct elf_x86_link_hash_entry *) h;
+	  resolved_to_zero = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh);
+
+	  /* NB: See how elf_backend_finish_dynamic_symbol is called
+	     from elf_link_output_extsym.  */
+	  if ((h->dynindx != -1 || h->forced_local)
+	      && ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+		   || h->root.type != bfd_link_hash_undefweak)
+		  || !h->forced_local)
+	      && h->got.offset != (bfd_vma) -1
+	      && ! GOT_TLS_GD_ANY_P (elf_x86_hash_entry (h)->tls_type)
+	      && elf_x86_hash_entry (h)->tls_type != GOT_TLS_IE
+	      && !resolved_to_zero
+	      && SYMBOL_REFERENCES_LOCAL_P (info, h)
+	      && SYMBOL_DEFINED_NON_SHARED_P (h))
+	    dynamic_relative_reloc_p = true;
+
+	  isym = NULL;
+	}
+
+      if (X86_GOT_TYPE_P (is_x86_64, r_type))
+	{
+	  /* Pack GOT relative relocations.  There should be only a
+	     single R_*_RELATIVE relocation in GOT.  */
+	  if (eh != NULL)
+	    {
+	      if (eh->got_relative_reloc_done)
+		continue;
+
+	      if (!(dynamic_relative_reloc_p
+		    || (RESOLVED_LOCALLY_P (info, h, htab)
+			&& GENERATE_RELATIVE_RELOC_P (info, h))))
+		continue;
+
+	      if (!dynamic_relative_reloc_p)
+		eh->no_finish_dynamic_symbol = 1;
+	      eh->got_relative_reloc_done = 1;
+	      offset = h->got.offset;
+	    }
+	  else
+	    {
+	      if (elf_x86_relative_reloc_done (abfd)[r_symndx])
+		continue;
+
+	      if (!X86_LOCAL_GOT_RELATIVE_RELOC_P (is_x86_64, info,
+						   isym))
+		continue;
+
+	      elf_x86_relative_reloc_done (abfd)[r_symndx] = 1;
+	      offset = local_got_offsets[r_symndx];
+	    }
+
+	  if (!elf_x86_relative_reloc_record_add (info,
+						  &htab->relative_reloc,
+						  irel, htab->elf.sgot,
+						  sec, h, isym, offset))
+	    goto error_return;
+
+	  continue;
+	}
+
+      if (is_x86_64
+	  && irel->r_addend == 0
+	  && !ABI_64_P (info->output_bfd))
+	{
+	  /* For x32, if addend is zero, treat R_X86_64_64 like
+	     R_X86_64_32 and R_X86_64_SIZE64 like R_X86_64_SIZE32.  */
+	  if (r_type == R_X86_64_64)
+	    r_type = R_X86_64_32;
+	  else if (r_type == R_X86_64_SIZE64)
+	    r_type = R_X86_64_SIZE32;
+	}
+
+      if (!X86_RELATIVE_RELOC_TYPE_P (is_x86_64, r_type))
+	continue;
+
+      /* Pack non-GOT relative relocations.  */
+      if (is_x86_64)
+	{
+	  need_copy_reloc_in_pie =
+	    (bfd_link_pie (info)
+	     && h != NULL
+	     && (h->needs_copy
+		 || eh->needs_copy
+		 || (h->root.type == bfd_link_hash_undefined))
+	     && (X86_PCREL_TYPE_P (true, r_type)
+		 || X86_SIZE_TYPE_P (true, r_type)));
+	  pc32_reloc = false;
+	}
+      else
+	{
+	  need_copy_reloc_in_pie = false;
+	  pc32_reloc = r_type == R_386_PC32;
+	}
+
+      if (GENERATE_DYNAMIC_RELOCATION_P (is_x86_64, info, eh, r_type,
+					 sec, need_copy_reloc_in_pie,
+					 resolved_to_zero, pc32_reloc))
+	{
+	  /* When generating a shared object, these relocations
+	     are copied into the output file to be resolved at run
+	     time.	*/
+	  offset = _bfd_elf_section_offset (info->output_bfd, info,
+					    input_section,
+					    irel->r_offset);
+	  if (offset == (bfd_vma) -1
+	      || offset == (bfd_vma) -2
+	      || COPY_INPUT_RELOC_P (is_x86_64, info, h, r_type))
+	    continue;
+
+	  /* This symbol is local, or marked to become local.  When
+	     relocation overflow check is disabled, we convert
+	     R_X86_64_32 to dynamic R_X86_64_RELATIVE.  */
+	  if (is_x86_64
+	      && !(r_type == htab->pointer_r_type
+		   || (r_type == R_X86_64_32
+		       && htab->params->no_reloc_overflow_check)))
+	    continue;
+
+	  if (!elf_x86_relative_reloc_record_add
+	        (info,
+		 ((unaligned_section || unaligned_offset)
+		  ? &htab->unaligned_relative_reloc
+		  : &htab->relative_reloc),
+		 irel, input_section, sec, h, isym, offset))
+	    goto error_return;
+	}
+    }
+
+  input_section->relative_reloc_packed = 1;
+
+  return true;
+
+error_return:
+  if ((unsigned char *) isymbuf != symtab_hdr->contents)
+    free (isymbuf);
+  if (elf_section_data (input_section)->relocs != internal_relocs)
+    free (internal_relocs);
+  return false;
+}
+
+/* Add an entry to the 64-bit DT_RELR bitmap.  */
+
+static void
+elf64_dt_relr_bitmap_add
+  (struct bfd_link_info *info, struct elf_dt_relr_bitmap *bitmap,
+   uint64_t entry)
+{
+  bfd_size_type newidx;
+
+  if (bitmap->u.elf64 == NULL)
+    {
+      bitmap->u.elf64 = bfd_malloc (sizeof (uint64_t));
+      bitmap->count = 0;
+      bitmap->size = 1;
+    }
+
+  newidx = bitmap->count++;
+
+  if (bitmap->count > bitmap->size)
+    {
+      bitmap->size <<= 1;
+      bitmap->u.elf64 = bfd_realloc (bitmap->u.elf64,
+				     (bitmap->size * sizeof (uint64_t)));
+    }
+
+  if (bitmap->u.elf64 == NULL)
+    {
+      info->callbacks->einfo
+	/* xgettext:c-format */
+	(_("%F%P: %pB: failed to allocate 64-bit DT_RELR bitmap\n"),
+	 info->output_bfd);
+    }
+
+  bitmap->u.elf64[newidx] = entry;
+}
+
+/* Add an entry to the 32-bit DT_RELR bitmap.  */
+
+static void
+elf32_dt_relr_bitmap_add
+  (struct bfd_link_info *info, struct elf_dt_relr_bitmap *bitmap,
+   uint32_t entry)
+{
+  bfd_size_type newidx;
+
+  if (bitmap->u.elf32 == NULL)
+    {
+      bitmap->u.elf32 = bfd_malloc (sizeof (uint32_t));
+      bitmap->count = 0;
+      bitmap->size = 1;
+    }
+
+  newidx = bitmap->count++;
+
+  if (bitmap->count > bitmap->size)
+    {
+      bitmap->size <<= 1;
+      bitmap->u.elf32 = bfd_realloc (bitmap->u.elf32,
+				     (bitmap->size * sizeof (uint32_t)));
+    }
+
+  if (bitmap->u.elf32 == NULL)
+    {
+      info->callbacks->einfo
+	/* xgettext:c-format */
+	(_("%F%P: %pB: failed to allocate 32-bit DT_RELR bitmap\n"),
+	 info->output_bfd);
+    }
+
+  bitmap->u.elf32[newidx] = entry;
+}
+
+void
+_bfd_elf32_write_addend (bfd *abfd, uint64_t value, void *addr)
+{
+  bfd_put_32 (abfd, value, addr);
+}
+
+void
+_bfd_elf64_write_addend (bfd *abfd, uint64_t value, void *addr)
+{
+  bfd_put_64 (abfd, value, addr);
+}
+
+/* Size or finish relative relocations to determine the run-time
+   addresses for DT_RELR bitmap computation later.  OUTREL is set
+   to NULL in the sizing phase and non-NULL in the finising phase
+   where the regular relative relocations will be written out.  */
+
+static void
+elf_x86_size_or_finish_relative_reloc
+  (bool is_x86_64, struct bfd_link_info *info,
+   struct elf_x86_link_hash_table *htab, bool unaligned,
+   Elf_Internal_Rela *outrel)
+{
+  unsigned int align_mask;
+  bfd_size_type i, count;
+  asection *sec, *srel;
+  struct elf_link_hash_entry *h;
+  bfd_vma offset;
+  Elf_Internal_Sym *sym;
+  asection *sym_sec;
+  asection *sgot = htab->elf.sgot;
+  asection *srelgot = htab->elf.srelgot;
+  struct elf_x86_relative_reloc_data *relative_reloc;
+
+  if (unaligned)
+    {
+      align_mask = 0;
+      relative_reloc = &htab->unaligned_relative_reloc;
+    }
+  else
+    {
+      align_mask = 1;
+      relative_reloc = &htab->relative_reloc;
+    }
+
+  count = relative_reloc->count;
+  for (i = 0; i < count; i++)
+    {
+      sec = relative_reloc->data[i].sec;
+      sym = relative_reloc->data[i].sym;
+
+      /* If SYM is NULL, it must be a global symbol.  */
+      if (sym == NULL)
+	h = relative_reloc->data[i].u.h;
+      else
+	h = NULL;
+
+      if (is_x86_64)
+	{
+	  bfd_vma relocation;
+	  /* This function may be called more than once and REL may be
+	     updated by _bfd_elf_rela_local_sym below.  */
+	  Elf_Internal_Rela rel = relative_reloc->data[i].rel;
+
+	  if (h != NULL)
+	    {
+	      if (h->root.type == bfd_link_hash_defined
+		  || h->root.type == bfd_link_hash_defweak)
+		{
+		  sym_sec = h->root.u.def.section;
+		  relocation = (h->root.u.def.value
+				+ sym_sec->output_section->vma
+				+ sym_sec->output_offset);
+		}
+	      else
+		{
+		  /* Allow undefined symbol only at the sizing phase.  */
+		  if (outrel == NULL)
+		    relocation = 0;
+		  else
+		    abort ();
+		}
+	    }
+	  else
+	    {
+	      sym_sec = relative_reloc->data[i].u.sym_sec;
+	      relocation = _bfd_elf_rela_local_sym
+		(info->output_bfd, sym, &sym_sec, &rel);
+	    }
+
+	  if (outrel != NULL)
+	    {
+	      outrel->r_addend = relocation;
+	      if (sec == sgot)
+		{
+		  if (h != NULL && h->needs_plt)
+		    abort ();
+		}
+	      else
+		outrel->r_addend += rel.r_addend;
+
+	      /* Write the implicit addend if ALIGN_MASK isn't 0.  */
+	      if (align_mask)
+		{
+		  if (sec == sgot)
+		    {
+		      if (relative_reloc->data[i].offset >= sec->size)
+			abort ();
+		      htab->elf_write_addend_in_got
+			(info->output_bfd, outrel->r_addend,
+			 sec->contents + relative_reloc->data[i].offset);
+		    }
+		  else
+		    {
+		      if (rel.r_offset >= sec->size)
+			abort ();
+		      htab->elf_write_addend
+			(info->output_bfd, outrel->r_addend,
+			 (elf_section_data (sec)->this_hdr.contents
+			  + rel.r_offset));
+		    }
+		}
+	    }
+	}
+
+      if (sec == sgot)
+	srel = srelgot;
+      else
+	srel = elf_section_data (sec)->sreloc;
+      offset = (sec->output_section->vma + sec->output_offset
+		+ relative_reloc->data[i].offset);
+      relative_reloc->data[i].address = offset;
+      if (outrel != NULL)
+	{
+	  outrel->r_offset = offset;
+
+	  if ((outrel->r_offset & align_mask) != 0)
+	    abort ();
+
+	  if (htab->params->report_relative_reloc)
+	    _bfd_x86_elf_link_report_relative_reloc
+	      (info, sec, h, sym, htab->relative_r_name, outrel);
+
+	  /* Generate regular relative relocation if ALIGN_MASK is 0.  */
+	  if (align_mask == 0)
+	    htab->elf_append_reloc (info->output_bfd, srel, outrel);
+	}
+    }
+}
+
+/* Compute the DT_RELR section size.  Set NEED_PLAYOUT to true if
+   the DT_RELR section size has been increased.  */
+
+static void
+elf_x86_compute_dl_relr_bitmap
+  (struct bfd_link_info *info, struct elf_x86_link_hash_table *htab,
+   bool *need_layout)
+{
+  bfd_vma base;
+  bfd_size_type i, count, new_count;
+  struct elf_x86_relative_reloc_data *relative_reloc =
+    &htab->relative_reloc;
+  /* Save the old DT_RELR bitmap count.  Don't shrink the DT_RELR bitmap
+     if the new DT_RELR bitmap count is smaller than the old one.  Pad
+     with trailing 1s which won't be decoded to more relocations.  */
+  bfd_size_type dt_relr_bitmap_count = htab->dt_relr_bitmap.count;
+
+  /* Clear the DT_RELR bitmap count.  */
+  htab->dt_relr_bitmap.count = 0;
+
+  count = relative_reloc->count;
+
+  if (ABI_64_P (info->output_bfd))
+    {
+      /* Compute the 64-bit DT_RELR bitmap.  */
+      i = 0;
+      while (i < count)
+	{
+	  if ((relative_reloc->data[i].address % 1) != 0)
+	    abort ();
+
+	  elf64_dt_relr_bitmap_add (info, &htab->dt_relr_bitmap,
+				    relative_reloc->data[i].address);
+
+	  base = relative_reloc->data[i].address + 8;
+	  i++;
+
+	  while (i < count)
+	    {
+	      uint64_t bitmap = 0;
+	      for (; i < count; i++)
+		{
+		  bfd_vma delta = (relative_reloc->data[i].address
+				   - base);
+		  /* Stop if it is too far from base.  */
+		  if (delta >= 63 * 8)
+		    break;
+		  /* Stop if it isn't a multiple of 8.  */
+		  if ((delta % 8) != 0)
+		    break;
+		  bitmap |= 1ULL << (delta / 8);
+		}
+
+	      if (bitmap == 0)
+		break;
+
+	      elf64_dt_relr_bitmap_add (info, &htab->dt_relr_bitmap,
+					(bitmap << 1) | 1);
+
+	      base += 63 * 8;
+	    }
+	}
+
+      new_count = htab->dt_relr_bitmap.count;
+      if (dt_relr_bitmap_count > new_count)
+	{
+	  /* Don't shrink the DT_RELR section size to avoid section
+	     layout oscillation.  Instead, pad the DT_RELR bitmap with
+	     1s which do not decode to more relocations.  */
+
+	  htab->dt_relr_bitmap.count = dt_relr_bitmap_count;
+	  count = dt_relr_bitmap_count - new_count;
+	  for (i = 0; i < count; i++)
+	    htab->dt_relr_bitmap.u.elf64[new_count + i] = 1;
+	}
+    }
+  else
+    {
+      /* Compute the 32-bit DT_RELR bitmap.  */
+      i = 0;
+      while (i < count)
+	{
+	  if ((relative_reloc->data[i].address % 1) != 0)
+	    abort ();
+
+	  elf32_dt_relr_bitmap_add (info, &htab->dt_relr_bitmap,
+				    relative_reloc->data[i].address);
+
+	  base = relative_reloc->data[i].address + 4;
+	  i++;
+
+	  while (i < count)
+	    {
+	      uint32_t bitmap = 0;
+	      for (; i < count; i++)
+		{
+		  bfd_vma delta = (relative_reloc->data[i].address
+				   - base);
+		  /* Stop if it is too far from base.  */
+		  if (delta >= 31 * 4)
+		    break;
+		  /* Stop if it isn't a multiple of 4.  */
+		  if ((delta % 4) != 0)
+		    break;
+		  bitmap |= 1ULL << (delta / 4);
+		}
+
+	      if (bitmap == 0)
+		break;
+
+	      elf32_dt_relr_bitmap_add (info, &htab->dt_relr_bitmap,
+					(bitmap << 1) | 1);
+
+	      base += 31 * 4;
+	    }
+	}
+
+      new_count = htab->dt_relr_bitmap.count;
+      if (dt_relr_bitmap_count > new_count)
+	{
+	  /* Don't shrink the DT_RELR section size to avoid section
+	     layout oscillation.  Instead, pad the DT_RELR bitmap with
+	     1s which do not decode to more relocations.  */
+
+	  htab->dt_relr_bitmap.count = dt_relr_bitmap_count;
+	  count = dt_relr_bitmap_count - new_count;
+	  for (i = 0; i < count; i++)
+	    htab->dt_relr_bitmap.u.elf32[new_count + i] = 1;
+	}
+    }
+
+  if (htab->dt_relr_bitmap.count != dt_relr_bitmap_count)
+    {
+      if (need_layout)
+	{
+	  /* The .relr.dyn section size is changed.  Update the section
+	     size and tell linker to layout sections again.  */
+	  htab->elf.srelrdyn->size =
+	    (htab->dt_relr_bitmap.count
+	     * (ABI_64_P (info->output_bfd) ? 8 : 4));
+
+	  *need_layout = true;
+	}
+      else
+	info->callbacks->einfo
+	  /* xgettext:c-format */
+	  (_("%F%P: %pB: size of compact relative reloc section is "
+	     "changed: new (%lu) != old (%lu)\n"),
+	   info->output_bfd, htab->dt_relr_bitmap.count,
+	   dt_relr_bitmap_count);
+    }
+}
+
+/* Write out the DT_RELR section.  */
+
+static void
+elf_x86_write_dl_relr_bitmap (struct bfd_link_info *info,
+			      struct elf_x86_link_hash_table *htab)
+{
+  asection *sec = htab->elf.srelrdyn;
+  bfd_size_type size = sec->size;
+  bfd_size_type i;
+  unsigned char *contents;
+
+  contents = (unsigned char *) bfd_alloc (sec->owner, size);
+  if (contents == NULL)
+    info->callbacks->einfo
+      /* xgettext:c-format */
+      (_("%F%P: %pB: failed to allocate compact relative reloc section\n"),
+       info->output_bfd);
+
+  /* Cache the section contents for elf_link_input_bfd.  */
+  sec->contents = contents;
+
+  if (ABI_64_P (info->output_bfd))
+    for (i = 0; i < htab->dt_relr_bitmap.count; i++, contents += 8)
+      bfd_put_64 (info->output_bfd, htab->dt_relr_bitmap.u.elf64[i],
+		  contents);
+  else
+    for (i = 0; i < htab->dt_relr_bitmap.count; i++, contents += 4)
+      bfd_put_32 (info->output_bfd, htab->dt_relr_bitmap.u.elf32[i],
+		  contents);
+}
+
+/* Sort relative relocations by address.  */
+
+static int
+elf_x86_relative_reloc_compare (const void *pa, const void *pb)
+{
+  struct elf_x86_relative_reloc_record *a =
+    (struct elf_x86_relative_reloc_record *) pa;
+  struct elf_x86_relative_reloc_record *b =
+    (struct elf_x86_relative_reloc_record *) pb;
+  if (a->address < b->address)
+    return -1;
+  if (a->address > b->address)
+    return 1;
+  return 0;
+}
+
+bool
+_bfd_elf_x86_size_relative_relocs (struct bfd_link_info *info,
+				   bool *need_layout)
+{
+  struct elf_x86_link_hash_table *htab;
+  const struct elf_backend_data *bed;
+  bool is_x86_64;
+  bfd_size_type i, count, unaligned_count;
+  asection *sec, *srel;
+
+  /* Do nothing for ld -r.  */
+  if (bfd_link_relocatable (info))
+    return true;
+
+  bed = get_elf_backend_data (info->output_bfd);
+  htab = elf_x86_hash_table (info, bed->target_id);
+  if (htab == NULL)
+    return false;
+
+  count = htab->relative_reloc.count;
+  unaligned_count = htab->unaligned_relative_reloc.count;
+  if (count == 0)
+    {
+      if (htab->generate_relative_reloc_pass == 0
+	  && htab->elf.srelrdyn != NULL)
+	{
+	  /* Remove the empty .relr.dyn sections now.  */
+	  if (!bfd_is_abs_section (htab->elf.srelrdyn->output_section))
+	    {
+	      bfd_section_list_remove
+		(info->output_bfd, htab->elf.srelrdyn->output_section);
+	      info->output_bfd->section_count--;
+	    }
+	  bfd_section_list_remove (htab->elf.srelrdyn->owner,
+				   htab->elf.srelrdyn);
+	  htab->elf.srelrdyn->owner->section_count--;
+	}
+      if (unaligned_count == 0)
+	{
+	  htab->generate_relative_reloc_pass++;
+	  return true;
+	}
+    }
+
+  is_x86_64 = bed->target_id == X86_64_ELF_DATA;
+
+  /* Size relative relocations.  */
+  if (htab->generate_relative_reloc_pass)
+    {
+      /* Reset the regular relative relocation count.  */
+      for (i = 0; i < unaligned_count; i++)
+	{
+	  sec = htab->unaligned_relative_reloc.data[i].sec;
+	  srel = elf_section_data (sec)->sreloc;
+	  srel->reloc_count = 0;
+	}
+    }
+  else
+    {
+      /* Remove the reserved space for compact relative relocations.  */
+      if (count)
+	{
+	  asection *sgot = htab->elf.sgot;
+	  asection *srelgot = htab->elf.srelgot;
+
+	  for (i = 0; i < count; i++)
+	    {
+	      sec = htab->relative_reloc.data[i].sec;
+	      if (sec == sgot)
+		srel = srelgot;
+	      else
+		srel = elf_section_data (sec)->sreloc;
+	      srel->size -= htab->sizeof_reloc;
+	    }
+	}
+    }
+
+  /* Size unaligned relative relocations.  */
+  if (unaligned_count)
+    elf_x86_size_or_finish_relative_reloc (is_x86_64, info, htab,
+					   true, NULL);
+
+  if (count)
+    {
+      elf_x86_size_or_finish_relative_reloc (is_x86_64, info, htab,
+					     false, NULL);
+
+      /* Sort relative relocations by addresses.  We only need to
+	 sort them in the first pass since the relative positions
+	 won't change.  */
+      if (htab->generate_relative_reloc_pass == 0)
+	qsort (htab->relative_reloc.data, count,
+	       sizeof (struct elf_x86_relative_reloc_record),
+	       elf_x86_relative_reloc_compare);
+
+      elf_x86_compute_dl_relr_bitmap (info, htab, need_layout);
+    }
+
+  htab->generate_relative_reloc_pass++;
+
+  return true;
+}
+
+bool
+_bfd_elf_x86_finish_relative_relocs (struct bfd_link_info *info)
+{
+  struct elf_x86_link_hash_table *htab;
+  const struct elf_backend_data *bed;
+  Elf_Internal_Rela outrel;
+  bool is_x86_64;
+  bfd_size_type count;
+
+  /* Do nothing for ld -r.  */
+  if (bfd_link_relocatable (info))
+    return true;
+
+  bed = get_elf_backend_data (info->output_bfd);
+  htab = elf_x86_hash_table (info, bed->target_id);
+  if (htab == NULL)
+    return false;
+
+  is_x86_64 = bed->target_id == X86_64_ELF_DATA;
+
+  outrel.r_info = htab->r_info (0, htab->relative_r_type);
+
+  if (htab->unaligned_relative_reloc.count)
+    elf_x86_size_or_finish_relative_reloc (is_x86_64, info, htab,
+					   true, &outrel);
+
+  count = htab->relative_reloc.count;
+  if (count)
+    {
+      elf_x86_size_or_finish_relative_reloc (is_x86_64, info, htab,
+					     false, &outrel);
+
+      elf_x86_compute_dl_relr_bitmap (info, htab, NULL);
+
+      elf_x86_write_dl_relr_bitmap (info, htab);
+    }
+
+  return true;
+}
+
 bool
 _bfd_elf_x86_valid_reloc_p (asection *input_section,
 			    struct bfd_link_info *info,
@@ -1332,6 +2256,11 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd,
       if ((s->flags & SEC_LINKER_CREATED) == 0)
 	continue;
 
+      /* The .relr.dyn section for compact relative relocation will
+	 be filled later.  */
+      if (s == htab->elf.srelrdyn)
+	continue;
+
       if (s == htab->elf.splt
 	  || s == htab->elf.sgot)
 	{
@@ -1459,6 +2388,7 @@ _bfd_x86_elf_finish_dynamic_sections (bfd *output_bfd,
   asection *sdyn;
   bfd_byte *dyncon, *dynconend;
   bfd_size_type sizeof_dyn;
+  bfd_size_type dt_relr_bitmap_count;
 
   bed = get_elf_backend_data (output_bfd);
   htab = elf_x86_hash_table (info, bed->target_id);
@@ -1517,6 +2447,8 @@ _bfd_x86_elf_finish_dynamic_sections (bfd *output_bfd,
   if (sdyn == NULL || htab->elf.sgot == NULL)
     abort ();
 
+  dt_relr_bitmap_count = htab->dt_relr_bitmap.count;
+
   sizeof_dyn = bed->s->sizeof_dyn;
   dyncon = sdyn->contents;
   dynconend = sdyn->contents + sdyn->size;
@@ -1535,6 +2467,28 @@ _bfd_x86_elf_finish_dynamic_sections (bfd *output_bfd,
 	    break;
 	  continue;
 
+	case DT_NULL:
+	  if (dt_relr_bitmap_count != 0)
+	    {
+	      /* Convert 3 spare dynamic tags to DT_RELR, DT_RELRSZ and
+		 DT_RELRENT for compact relative relocation.  */
+	      s = htab->elf.srelrdyn;
+	      dyn.d_tag = DT_RELR;
+	      dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
+	      (*bed->s->swap_dyn_out) (output_bfd, &dyn, dyncon);
+	      dyncon += sizeof_dyn;
+	      dyn.d_tag = DT_RELRSZ;
+	      dyn.d_un.d_val = s->size;
+	      (*bed->s->swap_dyn_out) (output_bfd, &dyn, dyncon);
+	      dyncon += sizeof_dyn;
+	      dyn.d_tag = DT_RELRENT;
+	      dyn.d_un.d_val = ABI_64_P (output_bfd) ? 8 : 4;
+	      elf_section_data (s->output_section)->this_hdr.sh_entsize
+		= dyn.d_un.d_val;
+	      dt_relr_bitmap_count = 0;
+	    }
+	  break;
+
 	case DT_PLTGOT:
 	  s = htab->elf.sgotplt;
 	  dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index 1bb80280918..4b5784ca08a 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -47,18 +47,35 @@
 #define X86_SIZE_TYPE_P(IS_X86_64, TYPE) \
   ((IS_X86_64) ? X86_64_SIZE_TYPE_P(TYPE) : I386_SIZE_TYPE_P (TYPE))
 
-#define X86_64_NEED_DYNAMIC_RELOC_TYPE_P(TYPE) \
-  (X86_64_SIZE_TYPE_P (TYPE) \
-   || X86_64_PCREL_TYPE_P (TYPE) \
+#define X86_64_GOT_TYPE_P(TYPE) \
+  ((TYPE) == R_X86_64_GOTPCREL \
+   || (TYPE) == R_X86_64_GOTPCRELX \
+   || (TYPE) == R_X86_64_REX_GOTPCRELX)
+#define I386_GOT_TYPE_P(TYPE) \
+  ((TYPE) == R_386_GOT32 || (TYPE) == R_386_GOT32X)
+#define X86_GOT_TYPE_P(IS_X86_64, TYPE) \
+  ((IS_X86_64) ? X86_64_GOT_TYPE_P (TYPE) : I386_GOT_TYPE_P (TYPE))
+
+#define X86_64_RELATIVE_RELOC_TYPE_P(TYPE) \
+  (X86_64_PCREL_TYPE_P (TYPE) \
    || (TYPE) == R_X86_64_8 \
    || (TYPE) == R_X86_64_16 \
    || (TYPE) == R_X86_64_32 \
    || (TYPE) == R_X86_64_32S \
    || (TYPE) == R_X86_64_64)
+#define I386_RELATIVE_RELOC_TYPE_P(TYPE) \
+  ((TYPE) == R_386_32 || (TYPE) == R_386_PC32)
+#define X86_RELATIVE_RELOC_TYPE_P(IS_X86_64, TYPE) \
+  ((IS_X86_64) \
+   ? X86_64_RELATIVE_RELOC_TYPE_P (TYPE) \
+   : I386_RELATIVE_RELOC_TYPE_P(TYPE))
+
+#define X86_64_NEED_DYNAMIC_RELOC_TYPE_P(TYPE) \
+  (X86_64_SIZE_TYPE_P (TYPE) \
+   || X86_64_RELATIVE_RELOC_TYPE_P (TYPE))
 #define I386_NEED_DYNAMIC_RELOC_TYPE_P(TYPE) \
   (I386_SIZE_TYPE_P (TYPE) \
-   || I386_PCREL_TYPE_P (TYPE) \
-   || (TYPE) == R_386_32 \
+   || I386_RELATIVE_RELOC_TYPE_P (TYPE) \
    || (TYPE) == R_386_TLS_LE \
    || (TYPE) == R_386_TLS_LE_32)
 #define X86_NEED_DYNAMIC_RELOC_TYPE_P(IS_X86_64, TYPE) \
@@ -66,11 +83,23 @@
    ? X86_64_NEED_DYNAMIC_RELOC_TYPE_P (TYPE) \
    : I386_NEED_DYNAMIC_RELOC_TYPE_P (TYPE))
 
+#define X86_LOCAL_GOT_RELATIVE_RELOC_P(IS_X86_64, INFO, SYM) \
+  (bfd_link_pic (INFO) \
+   && (!(IS_X86_64) || ((SYM) != NULL && (SYM)->st_shndx != SHN_ABS)))
+
 #define PLT_CIE_LENGTH		20
 #define PLT_FDE_LENGTH		36
 #define PLT_FDE_START_OFFSET	4 + PLT_CIE_LENGTH + 8
 #define PLT_FDE_LEN_OFFSET	4 + PLT_CIE_LENGTH + 12
 
+#define I386_PCREL_TYPE_P(TYPE) ((TYPE) == R_386_PC32)
+#define X86_64_PCREL_TYPE_P(TYPE) \
+  ((TYPE) == R_X86_64_PC8 \
+   || (TYPE) == R_X86_64_PC16 \
+   || (TYPE) == R_X86_64_PC32 \
+   || (TYPE) == R_X86_64_PC32_BND \
+   || (TYPE) == R_X86_64_PC64)
+
 #define ABI_64_P(abfd) \
   (get_elf_backend_data (abfd)->s->elfclass == ELFCLASS64)
 
@@ -160,12 +189,18 @@
    relocations against resolved undefined weak symbols in PIE, except
    when PC32_RELOC is TRUE.  Undefined weak symbol is bound locally
    when PIC is false.  Don't generate dynamic relocations against
-   non-preemptible absolute symbol.  */
+   non-preemptible absolute symbol.  NB: rel_from_abs is set on symbols
+   defined by linker scripts from "dot" (also SEGMENT_START or ORIGIN)
+   outside of an output section statement, which will be converted from
+   absolute to section-relative in set_sym_sections called from
+   ldexp_finalize_syms after ldemul_finish.   */
 #define GENERATE_DYNAMIC_RELOCATION_P(IS_X86_64, INFO, EH, R_TYPE, \
 				      SEC, NEED_COPY_RELOC_IN_PIE, \
 				      RESOLVED_TO_ZERO, PC32_RELOC) \
   ((bfd_link_pic (INFO) \
     && !(bfd_is_abs_section (SEC) \
+	 && ((EH) == NULL \
+	     || (EH)->elf.root.rel_from_abs == 0) \
 	 && ((EH) == NULL \
 	     || SYMBOL_REFERENCES_LOCAL (INFO, &(EH)->elf))) \
     && !(NEED_COPY_RELOC_IN_PIE) \
@@ -302,6 +337,10 @@ struct elf_x86_link_hash_entry
   /* Don't call finish_dynamic_symbol on this symbol.  */
   unsigned int no_finish_dynamic_symbol : 1;
 
+  /* R_*_RELATIVE relocation in GOT for this symbol has been
+     processed.  */
+  unsigned int got_relative_reloc_done : 1;
+
   /* TRUE if symbol is __tls_get_addr.  */
   unsigned int tls_get_addr : 1;
 
@@ -481,6 +520,52 @@ struct elf_x86_plt_layout
 #define elf_x86_hash_entry(ent) \
   ((struct elf_x86_link_hash_entry *)(ent))
 
+/* Information of an input relocation used to compute its contribution
+   to the DT_RELR section size.  */
+
+struct elf_x86_relative_reloc_record
+{
+  /* The original relocation info.  */
+  Elf_Internal_Rela rel;
+  /* The input or the GOT section where the relocation is applied.  */
+  asection *sec;
+  /* Local symbol info.  NULL for global symbol.  */
+  Elf_Internal_Sym *sym;
+  union
+    {
+      /* Section where the local symbol is defined.  */
+      asection *sym_sec;
+      /* Global symbol hash.  */
+      struct elf_link_hash_entry *h;
+    } u;
+  /* The offset into the output section where the relative relocation
+     will be applied at run-time.  */
+  bfd_vma offset;
+  /* The run-time address.  */
+  bfd_vma address;
+};
+
+struct elf_x86_relative_reloc_data
+{
+  bfd_size_type count;
+  bfd_size_type size;
+  struct elf_x86_relative_reloc_record *data;
+};
+
+/* DT_RELR bitmap.  */
+struct elf_dt_relr_bitmap
+{
+  bfd_size_type count;
+  bfd_size_type size;
+  union
+    {
+      /* 32-bit bitmap.  */
+      uint32_t *elf32;
+      /* 64-bit bitmap.  */
+      uint64_t *elf64;
+    } u;
+};
+
 /* x86 ELF linker hash table.  */
 
 struct elf_x86_link_hash_table
@@ -533,6 +618,18 @@ struct elf_x86_link_hash_table
      is only used for i386.  */
   bfd_vma next_tls_desc_index;
 
+  /* DT_RELR bitmap.  */
+  struct elf_dt_relr_bitmap dt_relr_bitmap;
+
+  /* Relative relocation data.  */
+  struct elf_x86_relative_reloc_data relative_reloc;
+
+  /* Unaligned relative relocation data.  */
+  struct elf_x86_relative_reloc_data unaligned_relative_reloc;
+
+  /* Number of relative reloc generation pass.  */
+  unsigned int generate_relative_reloc_pass;
+
    /* Value used to fill the unused bytes of the first PLT entry.  This
       is only used for i386.  */
   bfd_byte plt0_pad_byte;
@@ -554,9 +651,14 @@ struct elf_x86_link_hash_table
   unsigned int sizeof_reloc;
   unsigned int got_entry_size;
   unsigned int pointer_r_type;
+  unsigned int relative_r_type;
   int dynamic_interpreter_size;
   const char *dynamic_interpreter;
   const char *tls_get_addr;
+  const char *relative_r_name;
+  void (*elf_append_reloc) (bfd *, asection *, Elf_Internal_Rela *);
+  void (*elf_write_addend) (bfd *, uint64_t, void *);
+  void (*elf_write_addend_in_got) (bfd *, uint64_t, void *);
 
   /* Options passed from the linker.  */
   struct elf_linker_x86_params *params;
@@ -591,6 +693,10 @@ struct elf_x86_obj_tdata
 
   /* GOTPLT entries for TLS descriptors.  */
   bfd_vma *local_tlsdesc_gotent;
+
+  /* R_*_RELATIVE relocation in GOT for this local symbol has been
+     processed.  */
+  char *relative_reloc_done;
 };
 
 enum elf_x86_plt_type
@@ -626,6 +732,9 @@ struct elf_x86_plt
 #define elf_x86_local_tlsdesc_gotent(abfd) \
   (elf_x86_tdata (abfd)->local_tlsdesc_gotent)
 
+#define elf_x86_relative_reloc_done(abfd) \
+  (elf_x86_tdata (abfd)->relative_reloc_done)
+
 #define elf_x86_compute_jump_table_size(htab) \
   ((htab)->elf.srelplt->reloc_count * (htab)->got_entry_size)
 
@@ -637,6 +746,7 @@ struct elf_x86_plt
 /* Rename some of the generic section flags to better document how they
    are used here.  */
 #define check_relocs_failed	sec_flg0
+#define relative_reloc_packed	sec_flg1
 
 extern bool _bfd_x86_elf_mkobject
   (bfd *);
@@ -676,6 +786,18 @@ extern bool _bfd_x86_elf_check_relocs
   (bfd *, struct bfd_link_info *, asection *,
    const Elf_Internal_Rela *);
 
+extern bool _bfd_x86_elf_link_relax_section
+  (bfd *, asection *, struct bfd_link_info *, bool *);
+
+extern bool _bfd_elf_x86_size_relative_relocs
+  (struct bfd_link_info *, bool *);
+
+extern bool _bfd_elf_x86_finish_relative_relocs
+  (struct bfd_link_info *);
+
+extern void _bfd_elf32_write_addend (bfd *, uint64_t, void *);
+extern void _bfd_elf64_write_addend (bfd *, uint64_t, void *);
+
 extern bool _bfd_elf_x86_valid_reloc_p
   (asection *, struct bfd_link_info *, struct elf_x86_link_hash_table *,
    const Elf_Internal_Rela *, struct elf_link_hash_entry *,
@@ -752,6 +874,10 @@ extern void _bfd_x86_elf_link_report_relative_reloc
   _bfd_x86_elf_link_check_relocs
 #define bfd_elf32_bfd_link_check_relocs \
   _bfd_x86_elf_link_check_relocs
+#define bfd_elf32_bfd_relax_section \
+  _bfd_x86_elf_link_relax_section
+#define bfd_elf64_bfd_relax_section \
+  _bfd_x86_elf_link_relax_section
 
 #define elf_backend_check_relocs \
   _bfd_x86_elf_check_relocs
@@ -777,6 +903,10 @@ extern void _bfd_x86_elf_link_report_relative_reloc
   _bfd_x86_elf_merge_gnu_properties
 #define elf_backend_fixup_gnu_properties \
   _bfd_x86_elf_link_fixup_gnu_properties
+#define elf_backend_size_relative_relocs \
+  _bfd_elf_x86_size_relative_relocs
+#define elf_backend_finish_relative_relocs \
+  _bfd_elf_x86_finish_relative_relocs
 
 #define ELF_P_ALIGN ELF_MINPAGESIZE
 
@@ -789,7 +919,8 @@ elf_x86_allocate_local_got_info (bfd *abfd, bfd_size_type count)
   if (local_got_refcounts == NULL)
     {
       bfd_size_type size = count * (sizeof (bfd_signed_vma)
-				    + sizeof (bfd_vma) + sizeof(char));
+				    + sizeof (bfd_vma)
+				    + 2 * sizeof(char));
       local_got_refcounts = (bfd_signed_vma *) bfd_zalloc (abfd, size);
       if (local_got_refcounts == NULL)
 	return false;
@@ -798,6 +929,8 @@ elf_x86_allocate_local_got_info (bfd *abfd, bfd_size_type count)
 	(bfd_vma *) (local_got_refcounts + count);
       elf_x86_local_got_tls_type (abfd) =
 	(char *) (local_got_refcounts + 2 * count);
+      elf_x86_relative_reloc_done (abfd) =
+	((char *) (local_got_refcounts + 2 * count)) + count;
     }
   return true;
 }
-- 
2.33.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 8/9] ld: Add simple DT_RELR tests
  2022-01-08 18:38 [PATCH v2 0/9] ld: Implement DT_RELR for x86 H.J. Lu
                   ` (6 preceding siblings ...)
  2022-01-08 18:38 ` [PATCH v2 7/9] x86: Add DT_RELR support H.J. Lu
@ 2022-01-08 18:38 ` H.J. Lu
  2022-01-08 18:38 ` [PATCH v2 9/9] ld: Add glibc dependency for DT_RELR H.J. Lu
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: H.J. Lu @ 2022-01-08 18:38 UTC (permalink / raw)
  To: binutils; +Cc: Nick Clifton, Alan Modra, libc-alpha

	* testsuite/ld-elf/dt-relr-1.s: New file.
	* testsuite/ld-elf/dt-relr-1a.d: Likewise.
	* testsuite/ld-elf/dt-relr-1b.d: Likewise.
	* testsuite/ld-elf/dt-relr-1c.d: Likewise.
	* testsuite/ld-elf/dt-relr-2.s: Likewise.
	* testsuite/ld-elf/dt-relr-2a.d: Likewise.
	* testsuite/ld-elf/dt-relr-2b.d: Likewise.
	* testsuite/ld-elf/dt-relr-2c.d: Likewise.
	* testsuite/ld-elf/dt-relr-2d.d: Likewise.
	* testsuite/ld-elf/dt-relr-2e.d: Likewise.
	* testsuite/ld-elf/dt-relr-2f.d: Likewise.
	* testsuite/ld-elf/dt-relr-2g.d: Likewise.
	* testsuite/ld-elf/dt-relr-2h.d: Likewise.
	* testsuite/ld-elf/dt-relr-3.s: Likewise.
	* testsuite/ld-elf/dt-relr-3a.d: Likewise.
	* testsuite/ld-elf/dt-relr-3b.d: Likewise.
	* testsuite/ld-i386/dt-relr-1.d: Likewise.
	* testsuite/ld-i386/dt-relr-1.s: Likewise.
	* testsuite/ld-x86-64/dt-relr-1-x32.d: Likewise.
	* testsuite/ld-x86-64/dt-relr-1.d: Likewise.
	* testsuite/ld-x86-64/dt-relr-1.s: Likewise.
	* testsuite/ld-i386/i386.exp: Run dt-relr-1.
	* testsuite/ld-x86-64/x86-64.exp: Run dt-relr-1 and
	dt-relr-1-x32.
---
 ld/testsuite/ld-elf/dt-relr-1.s        | 13 +++++++++++++
 ld/testsuite/ld-elf/dt-relr-1a.d       | 10 ++++++++++
 ld/testsuite/ld-elf/dt-relr-1b.d       |  9 +++++++++
 ld/testsuite/ld-elf/dt-relr-1c.d       |  9 +++++++++
 ld/testsuite/ld-elf/dt-relr-2.s        | 20 ++++++++++++++++++++
 ld/testsuite/ld-elf/dt-relr-2a.d       | 10 ++++++++++
 ld/testsuite/ld-elf/dt-relr-2b.d       | 17 +++++++++++++++++
 ld/testsuite/ld-elf/dt-relr-2c.d       | 17 +++++++++++++++++
 ld/testsuite/ld-elf/dt-relr-2d.d       | 17 +++++++++++++++++
 ld/testsuite/ld-elf/dt-relr-2e.d       |  9 +++++++++
 ld/testsuite/ld-elf/dt-relr-2f.d       |  8 ++++++++
 ld/testsuite/ld-elf/dt-relr-2g.d       |  9 +++++++++
 ld/testsuite/ld-elf/dt-relr-2h.d       |  9 +++++++++
 ld/testsuite/ld-elf/dt-relr-3.s        | 12 ++++++++++++
 ld/testsuite/ld-elf/dt-relr-3a.d       |  9 +++++++++
 ld/testsuite/ld-elf/dt-relr-3b.d       |  9 +++++++++
 ld/testsuite/ld-i386/dt-relr-1.d       | 14 ++++++++++++++
 ld/testsuite/ld-i386/dt-relr-1.s       |  3 +++
 ld/testsuite/ld-i386/i386.exp          |  1 +
 ld/testsuite/ld-x86-64/dt-relr-1-x32.d | 15 +++++++++++++++
 ld/testsuite/ld-x86-64/dt-relr-1.d     | 14 ++++++++++++++
 ld/testsuite/ld-x86-64/dt-relr-1.s     |  3 +++
 ld/testsuite/ld-x86-64/x86-64.exp      |  2 ++
 23 files changed, 239 insertions(+)
 create mode 100644 ld/testsuite/ld-elf/dt-relr-1.s
 create mode 100644 ld/testsuite/ld-elf/dt-relr-1a.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-1b.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-1c.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2.s
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2a.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2b.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2c.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2d.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2e.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2f.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2g.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2h.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-3.s
 create mode 100644 ld/testsuite/ld-elf/dt-relr-3a.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-3b.d
 create mode 100644 ld/testsuite/ld-i386/dt-relr-1.d
 create mode 100644 ld/testsuite/ld-i386/dt-relr-1.s
 create mode 100644 ld/testsuite/ld-x86-64/dt-relr-1-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/dt-relr-1.d
 create mode 100644 ld/testsuite/ld-x86-64/dt-relr-1.s

diff --git a/ld/testsuite/ld-elf/dt-relr-1.s b/ld/testsuite/ld-elf/dt-relr-1.s
new file mode 100644
index 00000000000..1eb34588160
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-1.s
@@ -0,0 +1,13 @@
+	.text
+	.p2align 3
+	.globl _start
+_start:
+	.byte 0
+
+	.data
+	.p2align 3
+	.globl data
+data:
+	.byte 0
+	// Offset is not a multiple of 2.  Don't use DT_RELR.
+	.dc.a __ehdr_start + 10
diff --git a/ld/testsuite/ld-elf/dt-relr-1a.d b/ld/testsuite/ld-elf/dt-relr-1a.d
new file mode 100644
index 00000000000..55c93cefb59
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-1a.d
@@ -0,0 +1,10 @@
+#source: dt-relr-1.s
+#ld: -e _start $DT_RELR_LDFLAGS
+#readelf: -rW -d
+#target: x86_64-*-linux* i?86-*-linux-gnu i?86-*-gnu*
+
+#...
+There is no dynamic section in this file.
+#...
+There are no relocations in this file.
+#pass
diff --git a/ld/testsuite/ld-elf/dt-relr-1b.d b/ld/testsuite/ld-elf/dt-relr-1b.d
new file mode 100644
index 00000000000..2b78f75d378
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-1b.d
@@ -0,0 +1,9 @@
+#source: dt-relr-1.s
+#ld: -e _start -pie $DT_RELR_LDFLAGS
+#readelf: -rW -d
+#target: x86_64-*-linux* i?86-*-linux-gnu i?86-*-gnu*
+
+#failif
+#...
+Relocation section '\.relr\.dyn' at offset .*
+#pass
diff --git a/ld/testsuite/ld-elf/dt-relr-1c.d b/ld/testsuite/ld-elf/dt-relr-1c.d
new file mode 100644
index 00000000000..14f6cda6832
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-1c.d
@@ -0,0 +1,9 @@
+#source: dt-relr-1.s
+#ld: -shared $DT_RELR_LDFLAGS
+#readelf: -rW -d
+#target: x86_64-*-linux* i?86-*-linux-gnu i?86-*-gnu*
+
+#failif
+#...
+Relocation section '\.relr\.dyn' at offset .*
+#pass
diff --git a/ld/testsuite/ld-elf/dt-relr-2.s b/ld/testsuite/ld-elf/dt-relr-2.s
new file mode 100644
index 00000000000..bd1f3dfa16f
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-2.s
@@ -0,0 +1,20 @@
+	.text
+	.p2align 3
+	.globl _start
+_start:
+	.byte 0
+
+	.data
+	.p2align 3
+	.globl data
+data:
+
+	.dc.a .data
+	.dc.a 0
+	.dc.a data + 2
+	.dc.a __ehdr_start + 4
+	.dc.a __ehdr_start + 9
+
+	.byte 0
+	// Offset is not a multiple of 2.  Don't use DT_RELR.
+	.dc.a __ehdr_start + 10
diff --git a/ld/testsuite/ld-elf/dt-relr-2a.d b/ld/testsuite/ld-elf/dt-relr-2a.d
new file mode 100644
index 00000000000..31ef9e8e80e
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-2a.d
@@ -0,0 +1,10 @@
+#source: dt-relr-2.s
+#ld: -e _start $DT_RELR_LDFLAGS
+#readelf: -rW -d
+#target: x86_64-*-linux* i?86-*-linux-gnu i?86-*-gnu*
+
+#...
+There is no dynamic section in this file.
+#...
+There are no relocations in this file.
+#pass
diff --git a/ld/testsuite/ld-elf/dt-relr-2b.d b/ld/testsuite/ld-elf/dt-relr-2b.d
new file mode 100644
index 00000000000..7c401732a56
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-2b.d
@@ -0,0 +1,17 @@
+#source: dt-relr-2.s
+#ld: -e _start -pie $DT_RELR_LDFLAGS
+#readelf: -rW -d
+#target: x86_64-*-linux* i?86-*-linux-gnu i?86-*-gnu*
+
+#...
+ 0x[0-9a-f]+ \(RELR\)    +0x[0-9a-f]+
+ 0x[0-9a-f]+ \(RELRSZ\)  +(8|16) \(bytes\)
+ 0x[0-9a-f]+ \(RELRENT\) +(4|8) \(bytes\)
+#...
+Relocation section '\.rel(a|)\.dyn' at offset 0x[0-9a-f]+ contains 1 entry:
+#...
+[0-9a-f]+ +[0-9a-f]+ +R_.*_RELATIVE .*
+#...
+Relocation section '\.relr\.dyn' at offset 0x[0-9a-f]+ contains 2 entries:
+  4 offsets
+#pass
diff --git a/ld/testsuite/ld-elf/dt-relr-2c.d b/ld/testsuite/ld-elf/dt-relr-2c.d
new file mode 100644
index 00000000000..63877b2f90f
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-2c.d
@@ -0,0 +1,17 @@
+#source: dt-relr-2.s
+#ld: -shared $DT_RELR_LDFLAGS
+#readelf: -rW -d
+#target: x86_64-*-linux* i?86-*-linux-gnu i?86-*-gnu*
+
+#...
+ 0x[0-9a-f]+ \(RELR\)    +0x[0-9a-f]+
+ 0x[0-9a-f]+ \(RELRSZ\)  +(8|16) \(bytes\)
+ 0x[0-9a-f]+ \(RELRENT\) +(4|8) \(bytes\)
+#...
+Relocation section '\.rel(a|)\.dyn' at offset 0x[0-9a-f]+ contains 2 entries:
+#...
+[0-9a-f]+ +[0-9a-f]+ +R_.*_RELATIVE .*
+#...
+Relocation section '\.relr\.dyn' at offset 0x[0-9a-f]+ contains 2 entries:
+  3 offsets
+#pass
diff --git a/ld/testsuite/ld-elf/dt-relr-2d.d b/ld/testsuite/ld-elf/dt-relr-2d.d
new file mode 100644
index 00000000000..e11528f395c
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-2d.d
@@ -0,0 +1,17 @@
+#source: dt-relr-2.s
+#ld: -e _start -pie $DT_RELR_LDFLAGS --no-relax
+#readelf: -rW -d
+#target: x86_64-*-linux* i?86-*-linux-gnu i?86-*-gnu*
+
+#...
+ 0x[0-9a-f]+ \(RELR\)    +0x[0-9a-f]+
+ 0x[0-9a-f]+ \(RELRSZ\)  +(8|16) \(bytes\)
+ 0x[0-9a-f]+ \(RELRENT\) +(4|8) \(bytes\)
+#...
+Relocation section '\.rel(a|)\.dyn' at offset 0x[0-9a-f]+ contains 1 entry:
+#...
+[0-9a-f]+ +[0-9a-f]+ +R_.*_RELATIVE .*
+#...
+Relocation section '\.relr\.dyn' at offset 0x[0-9a-f]+ contains 2 entries:
+  4 offsets
+#pass
diff --git a/ld/testsuite/ld-elf/dt-relr-2e.d b/ld/testsuite/ld-elf/dt-relr-2e.d
new file mode 100644
index 00000000000..79ea62b096a
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-2e.d
@@ -0,0 +1,9 @@
+#source: dt-relr-2.s
+#ld: -e _start -pie $DT_RELR_LDFLAGS -z nocombreloc
+#readelf: -rW -d
+#target: x86_64-*-linux* i?86-*-linux-gnu i?86-*-gnu*
+
+#failif
+#...
+Relocation section '\.relr\.dyn' at offset .*
+#pass
diff --git a/ld/testsuite/ld-elf/dt-relr-2f.d b/ld/testsuite/ld-elf/dt-relr-2f.d
new file mode 100644
index 00000000000..4ad592f71fb
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-2f.d
@@ -0,0 +1,8 @@
+#source: dt-relr-2.s
+#ld: -r $DT_RELR_LDFLAGS
+#readelf: -rW
+#target: x86_64-*-linux* i?86-*-linux-gnu i?86-*-gnu*
+
+#...
+Relocation section '\.rel(a|)\.data' at offset 0x[0-9a-f]+ contains 5 entries:
+#pass
diff --git a/ld/testsuite/ld-elf/dt-relr-2g.d b/ld/testsuite/ld-elf/dt-relr-2g.d
new file mode 100644
index 00000000000..78e370068af
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-2g.d
@@ -0,0 +1,9 @@
+#source: dt-relr-2.s
+#ld: -e _start -pie $NO_DT_RELR_LDFLAGS
+#readelf: -rW -d
+#target: x86_64-*-linux* i?86-*-linux-gnu i?86-*-gnu*
+
+#failif
+#...
+Relocation section '\.relr\.dyn' at offset .*
+#pass
diff --git a/ld/testsuite/ld-elf/dt-relr-2h.d b/ld/testsuite/ld-elf/dt-relr-2h.d
new file mode 100644
index 00000000000..312373fb179
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-2h.d
@@ -0,0 +1,9 @@
+#source: dt-relr-2.s
+#ld: -e _start -shared $NO_DT_RELR_LDFLAGS
+#readelf: -rW -d
+#target: x86_64-*-linux* i?86-*-linux-gnu i?86-*-gnu*
+
+#failif
+#...
+Relocation section '\.relr\.dyn' at offset .*
+#pass
diff --git a/ld/testsuite/ld-elf/dt-relr-3.s b/ld/testsuite/ld-elf/dt-relr-3.s
new file mode 100644
index 00000000000..d020132466f
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-3.s
@@ -0,0 +1,12 @@
+	.text
+	.p2align 3
+	.globl _start
+_start:
+	.byte 0
+
+	// Section alignment is not a multiple of 2.  Don't use DT_RELR.
+	.data
+	.p2align 0
+	.globl data
+data:
+	.dc.a data
diff --git a/ld/testsuite/ld-elf/dt-relr-3a.d b/ld/testsuite/ld-elf/dt-relr-3a.d
new file mode 100644
index 00000000000..5a8a014803d
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-3a.d
@@ -0,0 +1,9 @@
+#source: dt-relr-3.s
+#ld: -e _start -pie $DT_RELR_LDFLAGS
+#readelf: -rW -d
+#target: x86_64-*-linux* i?86-*-linux-gnu i?86-*-gnu*
+
+#failif
+#...
+Relocation section '\.relr\.dyn' at offset .*
+#pass
diff --git a/ld/testsuite/ld-elf/dt-relr-3b.d b/ld/testsuite/ld-elf/dt-relr-3b.d
new file mode 100644
index 00000000000..6c38e6968dc
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-3b.d
@@ -0,0 +1,9 @@
+#source: dt-relr-3.s
+#ld: -shared $DT_RELR_LDFLAGS
+#readelf: -rW -d
+#target: x86_64-*-linux* i?86-*-linux-gnu i?86-*-gnu*
+
+#failif
+#...
+Relocation section '\.relr\.dyn' at offset .*
+#pass
diff --git a/ld/testsuite/ld-i386/dt-relr-1.d b/ld/testsuite/ld-i386/dt-relr-1.d
new file mode 100644
index 00000000000..98b74e9b305
--- /dev/null
+++ b/ld/testsuite/ld-i386/dt-relr-1.d
@@ -0,0 +1,14 @@
+#as: --32
+#ld: -shared -melf_i386 $DT_RELR_LDFLAGS
+#readelf: -r -s --wide
+
+Relocation section '.relr.dyn' at offset 0x[a-f0-9]+ contains 1 entry:
+ +1 offset
+[a-f0-9]+
+
+#...
+Symbol table '.symtab' contains [0-9]+ entries:
+   Num:    Value  Size Type    Bind   Vis      Ndx Name
+#...
+ +[a-f0-9]+: 00000000     0 NOTYPE  LOCAL  DEFAULT    1 __ehdr_start
+#pass
diff --git a/ld/testsuite/ld-i386/dt-relr-1.s b/ld/testsuite/ld-i386/dt-relr-1.s
new file mode 100644
index 00000000000..e492b98e869
--- /dev/null
+++ b/ld/testsuite/ld-i386/dt-relr-1.s
@@ -0,0 +1,3 @@
+	.text
+foo:
+	pushl	__ehdr_start@GOT(%ebx)
diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp
index c2d8d8268c3..bbfbf23f63d 100644
--- a/ld/testsuite/ld-i386/i386.exp
+++ b/ld/testsuite/ld-i386/i386.exp
@@ -507,6 +507,7 @@ run_dump_test "pr27491-1c"
 run_dump_test "pr27491-2"
 run_dump_test "pr27491-3"
 run_dump_test "pr27491-4"
+run_dump_test "dt-relr-1"
 
 if { !([istarget "i?86-*-linux*"]
        || [istarget "i?86-*-gnu*"]
diff --git a/ld/testsuite/ld-x86-64/dt-relr-1-x32.d b/ld/testsuite/ld-x86-64/dt-relr-1-x32.d
new file mode 100644
index 00000000000..b16f1d75d24
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/dt-relr-1-x32.d
@@ -0,0 +1,15 @@
+#source: dt-relr-1.s
+#as: --x32
+#ld: -shared -melf32_x86_64 $DT_RELR_LDFLAGS
+#readelf: -r -s --wide
+
+Relocation section '.relr.dyn' at offset 0x[a-f0-9]+ contains 1 entry:
+ +1 offset
+[a-f0-9]+
+
+#...
+Symbol table '.symtab' contains [0-9]+ entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+#...
+ +[0-9]+: +[a-f0-9]+ +0 +NOTYPE +LOCAL +DEFAULT +[0-9]+ +__ehdr_start
+#pass
diff --git a/ld/testsuite/ld-x86-64/dt-relr-1.d b/ld/testsuite/ld-x86-64/dt-relr-1.d
new file mode 100644
index 00000000000..6d30c6a0a94
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/dt-relr-1.d
@@ -0,0 +1,14 @@
+#as: --64
+#ld: -shared -melf_x86_64 $DT_RELR_LDFLAGS
+#readelf: -r -s --wide
+
+Relocation section '.relr.dyn' at offset 0x[a-f0-9]+ contains 1 entry:
+ +1 offset
+[a-f0-9]+
+
+#...
+Symbol table '.symtab' contains [0-9]+ entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+#...
+ +[0-9]+: +[a-f0-9]+ +0 +NOTYPE +LOCAL +DEFAULT +[0-9]+ +__ehdr_start
+#pass
diff --git a/ld/testsuite/ld-x86-64/dt-relr-1.s b/ld/testsuite/ld-x86-64/dt-relr-1.s
new file mode 100644
index 00000000000..234ec0bf142
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/dt-relr-1.s
@@ -0,0 +1,3 @@
+	.text
+foo:
+	add	__ehdr_start@GOTPCREL(%rip), %rax
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index b4048128057..6a908452af0 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -507,6 +507,8 @@ run_dump_test "pr27491-1c"
 run_dump_test "pr27491-2"
 run_dump_test "pr27491-3"
 run_dump_test "pr27491-4"
+run_dump_test "dt-relr-1"
+run_dump_test "dt-relr-1-x32"
 
 if ![istarget "x86_64-*-linux*"] {
     return
-- 
2.33.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 9/9] ld: Add glibc dependency for DT_RELR
  2022-01-08 18:38 [PATCH v2 0/9] ld: Implement DT_RELR for x86 H.J. Lu
                   ` (7 preceding siblings ...)
  2022-01-08 18:38 ` [PATCH v2 8/9] ld: Add simple DT_RELR tests H.J. Lu
@ 2022-01-08 18:38 ` H.J. Lu
  2022-01-10 15:31   ` Florian Weimer
  2022-01-08 21:53 ` [PATCH v2 0/9] ld: Implement DT_RELR for x86 Fangrui Song
  2022-01-11 10:13 ` Nick Clifton
  10 siblings, 1 reply; 20+ messages in thread
From: H.J. Lu @ 2022-01-08 18:38 UTC (permalink / raw)
  To: binutils; +Cc: Nick Clifton, Alan Modra, libc-alpha

When DT_RELR is enabled, to avoid random run-time crash with older glibc
binaries without DT_RELR support, add a GLIBC_ABI_DT_RELR symbol version,
which is provided by glibc with DT_RELR support, dependency on the shared
C library if it provides a GLIBC_2.XX symbol version.

bfd/

	* elflink.c (elf_link_add_dt_relr_dependency): New function.
	(bfd_elf_size_dynamic_sections): Call
	elf_link_add_dt_relr_dependency if DT_RELR is enabled.

ld/

	* ld.texi: Mention GLIBC_ABI_DT_RELR in -z pack-relative-relocs
	entry.
	* testsuite/ld-elf/dt-relr-glibc-1.c: New file.
	* testsuite/ld-elf/dt-relr-glibc-1a.rd: Likewise.
	* testsuite/ld-elf/dt-relr-glibc-1b.rd: Likewise.
	* testsuite/ld-elf/dt-relr.exp: Likewise.
---
 bfd/elflink.c                           | 86 +++++++++++++++++++++++++
 ld/ld.texi                              |  6 +-
 ld/testsuite/ld-elf/dt-relr-glibc-1.c   | 11 ++++
 ld/testsuite/ld-elf/dt-relr-glibc-1a.rd |  4 ++
 ld/testsuite/ld-elf/dt-relr-glibc-1b.rd |  7 ++
 ld/testsuite/ld-elf/dt-relr.exp         | 44 +++++++++++++
 6 files changed, 156 insertions(+), 2 deletions(-)
 create mode 100644 ld/testsuite/ld-elf/dt-relr-glibc-1.c
 create mode 100644 ld/testsuite/ld-elf/dt-relr-glibc-1a.rd
 create mode 100644 ld/testsuite/ld-elf/dt-relr-glibc-1b.rd
 create mode 100644 ld/testsuite/ld-elf/dt-relr.exp

diff --git a/bfd/elflink.c b/bfd/elflink.c
index 31b13f5df7a..05ac1cb7a63 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -2213,6 +2213,85 @@ _bfd_elf_export_symbol (struct elf_link_hash_entry *h, void *data)
   return true;
 }
 \f
+/* Return true if GLIBC_ABI_DT_RELR is added to the list of version
+   dependencies successfully.  GLIBC_ABI_DT_RELR will be put into the
+   .gnu.version_r section.  */
+
+static bool
+elf_link_add_dt_relr_dependency (struct elf_find_verdep_info *rinfo)
+{
+  bfd *glibc_bfd = NULL;
+  Elf_Internal_Verneed *t;
+  Elf_Internal_Vernaux *a;
+  size_t amt;
+  const char *relr = "GLIBC_ABI_DT_RELR";
+
+  /* See if we already know about GLIBC_PRIVATE_DT_RELR.  */
+  for (t = elf_tdata (rinfo->info->output_bfd)->verref;
+       t != NULL;
+       t = t->vn_nextref)
+    {
+      const char *soname = bfd_elf_get_dt_soname (t->vn_bfd);
+      /* Skip the shared library if it isn't libc.so.  */
+      if (!soname || !startswith (soname, "libc.so."))
+	continue;
+
+      for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+	{
+	  /* Return if GLIBC_PRIVATE_DT_RELR dependency has been
+	     added.  */
+	  if (a->vna_nodename == relr
+	      || strcmp (a->vna_nodename, relr) == 0)
+	    return true;
+
+	  /* Check if libc.so provides GLIBC_2.XX version.  */
+	  if (!glibc_bfd && startswith (a->vna_nodename, "GLIBC_2."))
+	    glibc_bfd = t->vn_bfd;
+	}
+
+      break;
+    }
+
+  /* Skip if it isn't linked against glibc.  */
+  if (glibc_bfd == NULL)
+    return true;
+
+  /* This is a new version.  Add it to tree we are building.  */
+  if (t == NULL)
+    {
+      amt = sizeof *t;
+      t = (Elf_Internal_Verneed *) bfd_zalloc (rinfo->info->output_bfd,
+					       amt);
+      if (t == NULL)
+	{
+	  rinfo->failed = true;
+	  return false;
+	}
+
+      t->vn_bfd = glibc_bfd;
+      t->vn_nextref = elf_tdata (rinfo->info->output_bfd)->verref;
+      elf_tdata (rinfo->info->output_bfd)->verref = t;
+    }
+
+  amt = sizeof *a;
+  a = (Elf_Internal_Vernaux *) bfd_zalloc (rinfo->info->output_bfd, amt);
+  if (a == NULL)
+    {
+      rinfo->failed = true;
+      return false;
+    }
+
+  a->vna_nodename = relr;
+  a->vna_flags = 0;
+  a->vna_nextptr = t->vn_auxptr;
+  a->vna_other = rinfo->vers + 1;
+  ++rinfo->vers;
+
+  t->vn_auxptr = a;
+
+  return true;
+}
+
 /* Look through the symbols which are defined in other shared
    libraries and referenced here.  Update the list of version
    dependencies.  This will be put into the .gnu.version_r section.
@@ -6940,6 +7019,13 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
       if (sinfo.failed)
 	return false;
 
+      if (info->enable_dt_relr)
+	{
+	  elf_link_add_dt_relr_dependency (&sinfo);
+	  if (sinfo.failed)
+	    return false;
+	}
+
       if (elf_tdata (output_bfd)->verref == NULL)
 	s->flags |= SEC_EXCLUDE;
       else
diff --git a/ld/ld.texi b/ld/ld.texi
index 36113723c9b..bf26f8cd3bf 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1438,8 +1438,10 @@ 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}.  @option{nopack-relative-relocs}
-is the default, which disables compact relative relocation.  Supported
-for i386 and x86-64.
+is the default, which disables compact relative relocation.  When linked
+against the GNU C Library, a GLIBC_ABI_DT_RELR symbol version dependency
+on the shared C Library is added to the output.  Supported for i386 and
+x86-64.
 
 @item relro
 @itemx norelro
diff --git a/ld/testsuite/ld-elf/dt-relr-glibc-1.c b/ld/testsuite/ld-elf/dt-relr-glibc-1.c
new file mode 100644
index 00000000000..beacffe29e7
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-glibc-1.c
@@ -0,0 +1,11 @@
+#define REL(n) \
+  static int data##n; \
+  void *p##n = &data##n;
+
+REL(1)
+REL(2)
+REL(3)
+REL(4)
+REL(5)
+REL(6)
+REL(7)
diff --git a/ld/testsuite/ld-elf/dt-relr-glibc-1a.rd b/ld/testsuite/ld-elf/dt-relr-glibc-1a.rd
new file mode 100644
index 00000000000..51bda5d70a1
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-glibc-1a.rd
@@ -0,0 +1,4 @@
+#failif
+#...
+  0x[a-f0-9]+:   Name: GLIBC_ABI_DT_RELR  Flags: none  Version: [0-9]+
+#...
diff --git a/ld/testsuite/ld-elf/dt-relr-glibc-1b.rd b/ld/testsuite/ld-elf/dt-relr-glibc-1b.rd
new file mode 100644
index 00000000000..6556a6d939e
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr-glibc-1b.rd
@@ -0,0 +1,7 @@
+#...
+Version needs section '.gnu.version_r' contains 1 entry:
+ Addr: 0x[0-9a-f]+ +Offset: 0x[0-9a-f]+ +Link: +[0-9]+ +\(.dynstr\)
+ +0+: Version: 1 +File: libc\.so\.6(|\.1) +Cnt: +[0-9]+
+#...
+  0x[a-f0-9]+:   Name: GLIBC_ABI_DT_RELR  Flags: none  Version: [0-9]+
+#pass
diff --git a/ld/testsuite/ld-elf/dt-relr.exp b/ld/testsuite/ld-elf/dt-relr.exp
new file mode 100644
index 00000000000..51d21e400ab
--- /dev/null
+++ b/ld/testsuite/ld-elf/dt-relr.exp
@@ -0,0 +1,44 @@
+# Expect script for DT_RELR.
+#   Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+# Linux tests.
+if { ![istarget "*-*-linux*"] } {
+    return
+}
+
+run_cc_link_tests [list \
+    [list \
+	"Build dt-relr-glibc-1a.so" \
+	"-shared $NO_DT_RELR_CC_LDFLAGS" \
+	"-fPIC" \
+	{ dt-relr-glibc-1.c } \
+	{{readelf {--version-info} dt-relr-glibc-1a.rd}} \
+	"glibc-relr-1a.so" \
+    ] \
+    [list \
+	"Build dt-relr-glibc-1b.so" \
+	"-shared $DT_RELR_CC_LDFLAGS" \
+	"-fPIC" \
+	{ dt-relr-glibc-1.c } \
+	{{readelf {-W --version-info} dt-relr-glibc-1b.rd}} \
+	"dt-relr-glibc-1b.so" \
+    ] \
+]
-- 
2.33.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 0/9] ld: Implement DT_RELR for x86
  2022-01-08 18:38 [PATCH v2 0/9] ld: Implement DT_RELR for x86 H.J. Lu
                   ` (8 preceding siblings ...)
  2022-01-08 18:38 ` [PATCH v2 9/9] ld: Add glibc dependency for DT_RELR H.J. Lu
@ 2022-01-08 21:53 ` Fangrui Song
  2022-01-09  8:13   ` Alexander Monakov
  2022-01-11 10:13 ` Nick Clifton
  10 siblings, 1 reply; 20+ messages in thread
From: Fangrui Song @ 2022-01-08 21:53 UTC (permalink / raw)
  To: H.J. Lu; +Cc: binutils, libc-alpha

On 2022-01-08, H.J. Lu via Binutils wrote:
>Hi Nick,
>
>I'd like to enable DT_RELR for x86 in binutils 2.38.
>
>
>H.J.
>---
>Changes in v2:
>
>1. Drop the _bfd_elf_link_iterate_on_relocs patch, which has been checked
>into master branch.
>2. Also pack R_*_RELATIVE relocations against dynamic symbols.
>3. Skip relocation against IFUNC symbol earlier.
>4. Don't require the --relax option enabled.
>5. Add more DT_RELR tests:
>   a. Add a test with relative relocation in section with 1-byte
>      alignment.
>   b. Add a test with -z pack-relative-relocs --no-relax.
>   c. Add tests for packing R_*_RELATIVE relocations against dynamic
>      symbols.
>
>DT_RELR encodes consecutive R_*_RELATIVE relocations in GOT (the global
>offset table) and data sections in a compact format:
>
>https://groups.google.com/g/generic-abi/c/bX460iggiKg
>
>On some targets, R_*_RELATIVE relocations are counted and the GOT offsets
>are allocated when setting the dynamic section sizes after seeing all
>relocations.  R_*_RELATIVE relocations are generated while relocating
>sections after section layout has been finalized.
>
>For x86 targets, the old check_relocs is renamed to scan_relocs and a
>new check_relocs is added to chek input sections and create dynamic
>relocation sections so that they will be mapped to output sections.
>scan_relocs is now called from elf_backend_always_size_sections.
>
>On some targets, the DT_RELR section size can be computed only after all
>symbols addresses can be determined:
>
>1. Update ldelf_map_segments to pass need_layout to
>_bfd_elf_map_sections_to_segments which will size DT_RELR section and
>set need_layout to true if the DT_RELR section size is changed.
>2.  Set the preliminary DT_RELR section size before mapping sections to
>segments and set the final DT_RELR section size after regular symbol
>processing is done.
>
>On x86, DT_RELR is implemented with linker relaxation:
>
>1. During linker relaxation, we scan input relocations with the same
>logic in relocate_section to determine if a relative relocation should
>be generated and save the relative relocation candidate information for
>sizing the DT_RELR section later after all symbols addresses can be
>determined.  For these relative relocations which can't be placed in
>the DT_RELR section, they will be placed in the rela.dyn/rel.dyn
>section.
>2. When DT_RELR is enabled, _bfd_elf_map_sections_to_segments calls a
>backend function to size the DT_RELR section which will compute the
>DT_RELR section size and tell ldelf_map_segments to layout sections
>again when the DT_RELR section size has been increased.
>3. After regular symbol processing is finished, bfd_elf_final_link calls
>a backend function to finish the DT_RELR section.
>
>When DT_RELR is enabled, to avoid random run-time crash with older glibc
>binaries without DT_RELR support, add a GLIBC_ABI_DT_RELR symbol version,
>which is provided by glibc with DT_RELR support, dependency on the shared
>C library if it provides a GLIBC_2.XX symbol version.
>
>It can build DT_RELR enabled glibc successfully on x86-64, x32 and
>i686.
>
>H.J. Lu (9):
>  elf: Add .relr.dyn to special_sections_r
>  elf: Extract _bfd_elf_process_reverse_copy
>  elf: Pass need_layout to _bfd_elf_map_sections_to_segments
>  ld: Initial DT_RELR support
>  elf: Add size_relative_relocs and finish_relative_relocs
>  elf: Support DT_RELR in linker tests
>  x86: Add DT_RELR support
>  ld: Add simple DT_RELR tests
>  ld: Add glibc dependency for DT_RELR

Thank you so much for the heroic work.
I cannot think of other items.

When linking clang, there is no longer RELA R_X86_64_RELATIVE. Nice!
clang -fsanitize=memory built ld passed.
gcc -fsanitize=address built ld passed (ld has pre-existing leaks. This
patch series does not add more leaks.)

Reviewed-by: Fangrui Song <i@maskray.me>
(perhaps binutils doesn't use this...)

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 0/9] ld: Implement DT_RELR for x86
  2022-01-08 21:53 ` [PATCH v2 0/9] ld: Implement DT_RELR for x86 Fangrui Song
@ 2022-01-09  8:13   ` Alexander Monakov
  2022-01-13  2:54     ` Fangrui Song
  0 siblings, 1 reply; 20+ messages in thread
From: Alexander Monakov @ 2022-01-09  8:13 UTC (permalink / raw)
  To: Fangrui Song; +Cc: H.J. Lu, libc-alpha, binutils

On Sat, 8 Jan 2022, Fangrui Song wrote:

> Thank you so much for the heroic work.
> I cannot think of other items.

I am bummed that Rich Felker's solution for compatibility (sane diagnostic
for loading a new PIE/DSO with old ld.so) was not accepted:
https://sourceware.org/pipermail/libc-alpha/2021-November/133313.html

(add just one new relocation to indicate presence of SHT_RELR)

It would have been a nice solution that works the same across all OS'es,
without requiring changes in ld.so. Was there something wrong with it?

Alexander

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 9/9] ld: Add glibc dependency for DT_RELR
  2022-01-08 18:38 ` [PATCH v2 9/9] ld: Add glibc dependency for DT_RELR H.J. Lu
@ 2022-01-10 15:31   ` Florian Weimer
  2022-01-10 15:40     ` H.J. Lu
  0 siblings, 1 reply; 20+ messages in thread
From: Florian Weimer @ 2022-01-10 15:31 UTC (permalink / raw)
  To: H.J. Lu via Binutils; +Cc: H.J. Lu, libc-alpha

* H. J. Lu via Binutils:

> +  const char *relr = "GLIBC_ABI_DT_RELR";

This needs to be in the implementation namespace, otherwise the user can
provide their own symbol, effectively breaking the lockout.

Thanks,
Florian


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 9/9] ld: Add glibc dependency for DT_RELR
  2022-01-10 15:31   ` Florian Weimer
@ 2022-01-10 15:40     ` H.J. Lu
  2022-01-10 15:42       ` Florian Weimer
  0 siblings, 1 reply; 20+ messages in thread
From: H.J. Lu @ 2022-01-10 15:40 UTC (permalink / raw)
  To: Florian Weimer; +Cc: H.J. Lu via Binutils, GNU C Library

On Mon, Jan 10, 2022 at 7:31 AM Florian Weimer <fweimer@redhat.com> wrote:
>
> * H. J. Lu via Binutils:
>
> > +  const char *relr = "GLIBC_ABI_DT_RELR";
>
> This needs to be in the implementation namespace, otherwise the user can
> provide their own symbol, effectively breaking the lockout.
>

Isn't "GLIBC_XXX" in the implementation namespace? If not,
can you recommend a name?

Thanks.

-- 
H.J.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 9/9] ld: Add glibc dependency for DT_RELR
  2022-01-10 15:40     ` H.J. Lu
@ 2022-01-10 15:42       ` Florian Weimer
  0 siblings, 0 replies; 20+ messages in thread
From: Florian Weimer @ 2022-01-10 15:42 UTC (permalink / raw)
  To: H.J. Lu; +Cc: H.J. Lu via Binutils, GNU C Library

* H. J. Lu:

> On Mon, Jan 10, 2022 at 7:31 AM Florian Weimer <fweimer@redhat.com> wrote:
>>
>> * H. J. Lu via Binutils:
>>
>> > +  const char *relr = "GLIBC_ABI_DT_RELR";
>>
>> This needs to be in the implementation namespace, otherwise the user can
>> provide their own symbol, effectively breaking the lockout.
>>
>
> Isn't "GLIBC_XXX" in the implementation namespace? If not,
> can you recommend a name?

Hmm.  I thought it was a symbol dependency, but it's actually a symbol
*version* dependency.  As a symbol version dependency, it should be
okay.

Thanks,
Florian


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 0/9] ld: Implement DT_RELR for x86
  2022-01-08 18:38 [PATCH v2 0/9] ld: Implement DT_RELR for x86 H.J. Lu
                   ` (9 preceding siblings ...)
  2022-01-08 21:53 ` [PATCH v2 0/9] ld: Implement DT_RELR for x86 Fangrui Song
@ 2022-01-11 10:13 ` Nick Clifton
  2022-01-11 14:08   ` H.J. Lu
  10 siblings, 1 reply; 20+ messages in thread
From: Nick Clifton @ 2022-01-11 10:13 UTC (permalink / raw)
  To: H.J. Lu, binutils; +Cc: Alan Modra, libc-alpha

Hi H.J.

   The patch set looks good to me, but there is one problem.  With the
   set applied there is a new linker testsuite regression for non x86
   ELF based targets (eg: s390-linux, xtensa-elf, aarch64-linux-gnu to
   mention just a few):

     Executing on host: sh -c {./ld-new -o tmpdir/symbolic-func.so
      -z norelro -L/ld/testsuite/ld-elf -shared -Bsymbolic-functions
      -z nopack-relative-relocs tmpdir/symbolic-func.o  2>&1}
       /dev/null ld.tmp (timeout = 300)
     spawn [open ...]

     ./ld-new: warning: -z nopack-relative-relocs ignored
     ./ld-new: warning: -z nopack-relative-relocs ignored
     FAIL: -Bsymbolic-functions

   Please could you investigate and fix this issue ?

Cheers
   Nick


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 0/9] ld: Implement DT_RELR for x86
  2022-01-11 10:13 ` Nick Clifton
@ 2022-01-11 14:08   ` H.J. Lu
  2022-01-12 12:33     ` Nick Clifton
  0 siblings, 1 reply; 20+ messages in thread
From: H.J. Lu @ 2022-01-11 14:08 UTC (permalink / raw)
  To: Nick Clifton; +Cc: Binutils, Alan Modra, GNU C Library

On Tue, Jan 11, 2022 at 2:13 AM Nick Clifton <nickc@redhat.com> wrote:
>
> Hi H.J.
>
>    The patch set looks good to me, but there is one problem.  With the
>    set applied there is a new linker testsuite regression for non x86
>    ELF based targets (eg: s390-linux, xtensa-elf, aarch64-linux-gnu to
>    mention just a few):
>
>      Executing on host: sh -c {./ld-new -o tmpdir/symbolic-func.so
>       -z norelro -L/ld/testsuite/ld-elf -shared -Bsymbolic-functions
>       -z nopack-relative-relocs tmpdir/symbolic-func.o  2>&1}
>        /dev/null ld.tmp (timeout = 300)
>      spawn [open ...]
>
>      ./ld-new: warning: -z nopack-relative-relocs ignored
>      ./ld-new: warning: -z nopack-relative-relocs ignored
>      FAIL: -Bsymbolic-functions
>
>    Please could you investigate and fix this issue ?
>

Fixed in the v3 patch:

https://sourceware.org/pipermail/binutils/2022-January/119292.html

by

Changes in v3:

1. Set DT_RELR_LDFLAGS, DT_RELR_CC_LDFLAGS, NO_DT_RELR_LDFLAGS and
NO_DT_RELR_CC_LDFLAGS to empty for non-Linux/x86 targets.
2. Run x86 DT_RELR tests only for Linux/x86 targets.

Thanks.

-- 
H.J.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 0/9] ld: Implement DT_RELR for x86
  2022-01-11 14:08   ` H.J. Lu
@ 2022-01-12 12:33     ` Nick Clifton
  0 siblings, 0 replies; 20+ messages in thread
From: Nick Clifton @ 2022-01-12 12:33 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Binutils, Alan Modra, GNU C Library

Hi H.J.

> Fixed in the v3 patch:
> 
> https://sourceware.org/pipermail/binutils/2022-January/119292.html
> 
> by
> 
> Changes in v3:
> 
> 1. Set DT_RELR_LDFLAGS, DT_RELR_CC_LDFLAGS, NO_DT_RELR_LDFLAGS and
> NO_DT_RELR_CC_LDFLAGS to empty for non-Linux/x86 targets.
> 2. Run x86 DT_RELR tests only for Linux/x86 targets.

Patch series approved  - please apply.

Cheers
   Nick



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 0/9] ld: Implement DT_RELR for x86
  2022-01-09  8:13   ` Alexander Monakov
@ 2022-01-13  2:54     ` Fangrui Song
  2022-01-13  3:00       ` H.J. Lu
  0 siblings, 1 reply; 20+ messages in thread
From: Fangrui Song @ 2022-01-13  2:54 UTC (permalink / raw)
  To: Alexander Monakov; +Cc: H.J. Lu, libc-alpha, binutils

On 2022-01-09, Alexander Monakov wrote:
>On Sat, 8 Jan 2022, Fangrui Song wrote:
>
>> Thank you so much for the heroic work.
>> I cannot think of other items.
>
>I am bummed that Rich Felker's solution for compatibility (sane diagnostic
>for loading a new PIE/DSO with old ld.so) was not accepted:
>https://sourceware.org/pipermail/libc-alpha/2021-November/133313.html
>
>(add just one new relocation to indicate presence of SHT_RELR)
>
>It would have been a nice solution that works the same across all OS'es,
>without requiring changes in ld.so. Was there something wrong with it?
>
>Alexander

Hi Alexander, I think the .gnu.version_r approach is better.
For FreeBSD/musl/etc, there is no version node called GLIBC_2*,
ld.bfd -z pack-relative-relocs will not add anything.

For a relocation approach, every psABI needs to define which relocation
type is used as the available indicator (something like
R_*_GNU_VTENTRY). It's too much work for something only glibc needs.



Now that the ld patch series has landed on
https://sourceware.org/git/?p=binutils-gdb.git, what's the next step for the
glibc patch? The current diff I have is
https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/maskray/relr
I think making ld.so/libc.so themselves compatible with DT_RELR can
be separate changes (I personally do not know enough ld.so to contribute
it...)

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 0/9] ld: Implement DT_RELR for x86
  2022-01-13  2:54     ` Fangrui Song
@ 2022-01-13  3:00       ` H.J. Lu
  0 siblings, 0 replies; 20+ messages in thread
From: H.J. Lu @ 2022-01-13  3:00 UTC (permalink / raw)
  To: Fangrui Song; +Cc: Alexander Monakov, GNU C Library, Binutils

On Wed, Jan 12, 2022 at 6:54 PM Fangrui Song <i@maskray.me> wrote:
>
> On 2022-01-09, Alexander Monakov wrote:
> >On Sat, 8 Jan 2022, Fangrui Song wrote:
> >
> >> Thank you so much for the heroic work.
> >> I cannot think of other items.
> >
> >I am bummed that Rich Felker's solution for compatibility (sane diagnostic
> >for loading a new PIE/DSO with old ld.so) was not accepted:
> >https://sourceware.org/pipermail/libc-alpha/2021-November/133313.html
> >
> >(add just one new relocation to indicate presence of SHT_RELR)
> >
> >It would have been a nice solution that works the same across all OS'es,
> >without requiring changes in ld.so. Was there something wrong with it?
> >
> >Alexander
>
> Hi Alexander, I think the .gnu.version_r approach is better.
> For FreeBSD/musl/etc, there is no version node called GLIBC_2*,
> ld.bfd -z pack-relative-relocs will not add anything.
>
> For a relocation approach, every psABI needs to define which relocation
> type is used as the available indicator (something like
> R_*_GNU_VTENTRY). It's too much work for something only glibc needs.
>
>
>
> Now that the ld patch series has landed on
> https://sourceware.org/git/?p=binutils-gdb.git, what's the next step for the
> glibc patch? The current diff I have is
> https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/maskray/relr
> I think making ld.so/libc.so themselves compatible with DT_RELR can
> be separate changes (I personally do not know enough ld.so to contribute
> it...)

It is too late for glibc 2.35.  It should go in after 2.35 is branched.
My DT_RELR branch is based on your patch:

https://gitlab.com/x86-glibc/glibc/-/commits/users/hjl/relr/master

My branch requires -z pack-relative-relocs to enable DT_RELR
and supports zero DT_RELA/DT_REL values generated by ld.

-- 
H.J.

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2022-01-13  3:01 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-08 18:38 [PATCH v2 0/9] ld: Implement DT_RELR for x86 H.J. Lu
2022-01-08 18:38 ` [PATCH v2 1/9] elf: Add .relr.dyn to special_sections_r H.J. Lu
2022-01-08 18:38 ` [PATCH v2 2/9] elf: Extract _bfd_elf_process_reverse_copy H.J. Lu
2022-01-08 18:38 ` [PATCH v2 3/9] elf: Pass need_layout to _bfd_elf_map_sections_to_segments H.J. Lu
2022-01-08 18:38 ` [PATCH v2 4/9] ld: Initial DT_RELR support H.J. Lu
2022-01-08 18:38 ` [PATCH v2 5/9] elf: Add size_relative_relocs and finish_relative_relocs H.J. Lu
2022-01-08 18:38 ` [PATCH v2 6/9] elf: Support DT_RELR in linker tests H.J. Lu
2022-01-08 18:38 ` [PATCH v2 7/9] x86: Add DT_RELR support H.J. Lu
2022-01-08 18:38 ` [PATCH v2 8/9] ld: Add simple DT_RELR tests H.J. Lu
2022-01-08 18:38 ` [PATCH v2 9/9] ld: Add glibc dependency for DT_RELR H.J. Lu
2022-01-10 15:31   ` Florian Weimer
2022-01-10 15:40     ` H.J. Lu
2022-01-10 15:42       ` Florian Weimer
2022-01-08 21:53 ` [PATCH v2 0/9] ld: Implement DT_RELR for x86 Fangrui Song
2022-01-09  8:13   ` Alexander Monakov
2022-01-13  2:54     ` Fangrui Song
2022-01-13  3:00       ` H.J. Lu
2022-01-11 10:13 ` Nick Clifton
2022-01-11 14:08   ` H.J. Lu
2022-01-12 12:33     ` Nick Clifton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).