[prev in list] [next in list] [prev in thread] [next in thread] 

List:       binutils
Subject:    [PATCH v2] ld: Check ELF relocs before allocation
From:       "H.J. Lu via Binutils" <binutils () sourceware ! org>
Date:       2021-12-29 22:14:31
Message-ID: 20211229221431.530456-1-hjl.tools () gmail ! com
[Download RAW message or body]

DT_RELR encodes consecutive R_*_RELATIVE relocations in GOT (the global
offset table) 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.

To prepare for DT_RELR implementation on these targets, we need to delay
checking ELF relocations before allocation so that when relocations are
checked, all input sections have been mapped to output sections, dynamic
symbols are known and R_*_RELATIVE relocations can be counted.  This is
only enabled for x86 targets.

If relocation check is delayed, when the first time lang_check_relocs is
called, a new ELF backend function, make_reloc_section, is called to
to create dynamic relocation sections so that they will be mapped to
output sections.  ldelf_before_allocation calls lang_check_relocs again
to check relocations.

DT_RELR encoding may be generated in the relax pass when R_*_RELATIVE
relocations and their GOT offsets are known.  A later fix up is needed if
the final GOT vma is different from when DT_RELR encoding was generated.

Since relocations are checked after __start, __stop, .startof. and
.sizeof. symbols have been finalized on x86, __[start|stop]_SECNAME for
--gc-sections -z start-stop-gc are now zero when all SECNAME sections
been garbage collected.  This is no need for elf_x86_start_stop_gc_p.

bfd/

	* elf-bfd.h (elf_backend_data): Add make_reloc_section.
	* elf32-i386.c (elf_i386_convert_load_reloc): Don't call
	elf_x86_start_stop_gc_p.
	(elf_i386_check_relocs): Don't call
	_bfd_elf_make_dynamic_reloc_section.
	(elf_i386_make_reloc_section): New.
	(elf_backend_make_reloc_section): Likewise.
	* elf64-x86-64.c (elf_x86_64_convert_load_reloc): Likewise.
	(elf_x86_64_check_relocs): Don't call
	_bfd_elf_make_dynamic_reloc_section.
	(elf_x86_64_make_reloc_section): New.
	(elf_backend_make_reloc_section): Likewise.
	* elflink.c (_bfd_elf_link_check_relocs_or_make_reloc_sections):
	New.  Renamed and modified from _bfd_elf_link_check_relocs.
	(_bfd_elf_link_check_relocs): New.
	* elfxx-target.h (elf_backend_make_reloc_section): New.
	(elfNN_bed): Add elf_backend_make_reloc_section.
	* elfxx-x86.h (bfd_elf64_bfd_link_make_reloc_sections): Likewise.
	(bfd_elf32_bfd_link_make_reloc_sections): Likewise.
	(elf_x86_start_stop_gc_p): Removed.

include/

	* bfdlink.h (bfd_link_check_relocs_phase): New enum.
	(bfd_link_info): Rename check_relocs_after_open_input to
	check_relocs_choice.  Add check_relocs_phase.

ld/

	* ldelf.c (ldelf_before_allocation): Call lang_check_relocs if
	relocation check should be done before allocation.
	* ldlang.c (lang_check_relocs): Remove static.  Don't check
	link_info.check_relocs_after_open_input.
	(lang_process): Set link_info.check_relocs_phase to
	check_relocs_after_open_input before calling lang_check_relocs.
	Set link_info.check_relocs_phase to
	check_relocs_before_allocation before calling
	ldemul_before_allocation.
	* ldlang.h (lang_check_relocs): New.
	* ldmain.c (main): Initialize link_info.check_relocs_phase
	to check_relocs_before_open_input.
	* emulparams/elf32_x86_64.sh (CHECK_RELOCS_CHOICE): New.
	* emulparams/elf_i386.sh (CHECK_RELOCS_CHOICE): Likewise.
	* emulparams/elf_i386_be.sh (CHECK_RELOCS_CHOICE): Likewise.
	* emulparams/elf_i386_ldso.sh (CHECK_RELOCS_CHOICE): Likewise.
	* emulparams/elf_i386_vxworks.sh (CHECK_RELOCS_CHOICE): Likewise.
	* emulparams/elf_x86_64.sh (CHECK_RELOCS_CHOICE): Likewise.
	* emultempl/aarch64elf.em (gld${EMULATION_NAME}_before_parse):
	Set link_info.check_relocs_choice instead of
	link_info.check_relocs_after_open_input.
	* emultempl/armelf.em (gld${EMULATION_NAME}_before_parse):
	Likewise.
	* emultempl/mmix-elfnmmo.em (gld${EMULATION_NAME}_before_parse):
	Likewise.
	* emultempl/scoreelf.em (gld${EMULATION_NAME}_before_parse):
	Likewise.
	* emultempl/elf.em (CHECK_RELOCS_CHOICE): New.
	(gld${EMULATION_NAME}_before_parse): Set
	link_info.check_relocs_choice instead of
	link_info.check_relocs_after_open_input.
	* testsuite/ld-i386/pr27491-1a.d: Updated.
	* testsuite/ld-x86-64/pr27491-1a.d: Likewise.
---
 bfd/elf-bfd.h                       |   6 ++
 bfd/elf32-i386.c                    | 117 +++++++++++++++++++++-----
 bfd/elf64-x86-64.c                  | 126 +++++++++++++++++++++++-----
 bfd/elflink.c                       |  58 ++++++++++++-
 bfd/elfxx-target.h                  |   4 +
 bfd/elfxx-x86.h                     |  33 --------
 include/bfdlink.h                   |  19 ++++-
 ld/emulparams/elf32_x86_64.sh       |   1 +
 ld/emulparams/elf_i386.sh           |   1 +
 ld/emulparams/elf_i386_be.sh        |   1 +
 ld/emulparams/elf_i386_ldso.sh      |   1 +
 ld/emulparams/elf_i386_vxworks.sh   |   1 +
 ld/emulparams/elf_x86_64.sh         |   1 +
 ld/emultempl/aarch64elf.em          |   2 +-
 ld/emultempl/armelf.em              |   2 +-
 ld/emultempl/elf.em                 |   6 +-
 ld/emultempl/mmix-elfnmmo.em        |   2 +-
 ld/emultempl/scoreelf.em            |   2 +-
 ld/ldelf.c                          |   4 +
 ld/ldlang.c                         |  34 ++++----
 ld/ldlang.h                         |   3 +
 ld/ldmain.c                         |   1 +
 ld/testsuite/ld-i386/pr27491-1a.d   |   4 +-
 ld/testsuite/ld-x86-64/pr27491-1a.d |   4 +-
 24 files changed, 322 insertions(+), 111 deletions(-)

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index be2eb38ea6a..1f2c4b3c39c 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1100,6 +1100,12 @@ struct elf_backend_data
     (bfd *abfd, struct bfd_link_info *info, asection *o,
      const Elf_Internal_Rela *relocs);
 
+  /* The MAKE_RELOC_SECTION function is called to make the dynamic reloc
+     section associated with the input section.  */
+  bool (*make_reloc_section)
+    (bfd *abfd, struct bfd_link_info *info, asection *o,
+     const Elf_Internal_Rela *relocs);
+
   /* 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/elf32-i386.c b/bfd/elf32-i386.c
index d4f8ec3b21d..3f3f1786d8d 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -1393,11 +1393,6 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr \
*symtab_hdr,  || h->root.type == bfd_link_hash_defweak)
 	      && local_ref))
 	{
-	  /* Skip __start_SECNAME/__stop_SECNAME when --gc-sections
-	     -z start-stop-gc are used.  */
-	  if (elf_x86_start_stop_gc_p (link_info, h))
-	    return true;
-
 	convert_load:
 	  if (opcode == 0x8b)
 	    {
@@ -1462,8 +1457,8 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr \
*symtab_hdr,  #define check_relocs_failed	sec_flg0
 
 /* Look through the relocs for a section during the first phase, and
-   calculate needed space in the global offset table, procedure linkage
-   table, and dynamic reloc sections.  */
+   calculate needed space in the global offset table, and procedure
+   linkage table.  */
 
 static bool
 elf_i386_check_relocs (bfd *abfd,
@@ -1476,7 +1471,6 @@ elf_i386_check_relocs (bfd *abfd,
   struct elf_link_hash_entry **sym_hashes;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
-  asection *sreloc;
   bfd_byte *contents;
   bool converted;
 
@@ -1506,8 +1500,6 @@ elf_i386_check_relocs (bfd *abfd,
 
   converted = false;
 
-  sreloc = NULL;
-
   rel_end = relocs + sec->reloc_count;
   for (rel = relocs; rel < rel_end; rel++)
     {
@@ -1841,18 +1833,6 @@ elf_i386_check_relocs (bfd *abfd,
 	      struct elf_dyn_relocs *p;
 	      struct elf_dyn_relocs **head;
 
-	      /* We must copy these reloc types into the output file.
-		 Create a reloc section in dynobj and make room for
-		 this reloc.  */
-	      if (sreloc == NULL)
-		{
-		  sreloc = _bfd_elf_make_dynamic_reloc_section
-		    (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ false);
-
-		  if (sreloc == NULL)
-		    goto error_return;
-		}
-
 	      /* If this is a global symbol, we count the number of
 		 relocations we need for this symbol.  */
 	      if (h != NULL)
@@ -1947,6 +1927,97 @@ elf_i386_check_relocs (bfd *abfd,
   return false;
 }
 
+/* Look through the relocs for a section during the first phase and
+   make the dynamic reloc section.  */
+
+static bool
+elf_i386_make_reloc_section (bfd *abfd,
+			     struct bfd_link_info *info,
+			     asection *sec,
+			     const Elf_Internal_Rela *relocs)
+{
+  struct elf_x86_link_hash_table *htab;
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  const Elf_Internal_Rela *rel;
+  const Elf_Internal_Rela *rel_end;
+  asection *sreloc;
+
+  if (bfd_link_relocatable (info))
+    return true;
+
+  htab = elf_x86_hash_table (info, I386_ELF_DATA);
+  if (htab == NULL)
+    {
+      sec->check_relocs_failed = 1;
+      return false;
+    }
+
+  BFD_ASSERT (is_x86_elf (abfd, htab));
+
+  symtab_hdr = &elf_symtab_hdr (abfd);
+  sym_hashes = elf_sym_hashes (abfd);
+
+  rel_end = relocs + sec->reloc_count;
+  for (rel = relocs; rel < rel_end; rel++)
+    {
+      unsigned int r_type;
+      unsigned int r_symndx;
+      struct elf_link_hash_entry *h;
+
+      r_symndx = htab->r_sym (rel->r_info);
+      r_type = ELF32_R_TYPE (rel->r_info);
+
+      if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
+	{
+	  /* xgettext:c-format */
+	  _bfd_error_handler (_("%pB: bad symbol index: %d"),
+			      abfd, r_symndx);
+	  goto error_return;
+	}
+
+      if (r_symndx < symtab_hdr->sh_info)
+	h = NULL;
+      else
+	{
+	  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;
+	}
+
+      switch (r_type)
+	{
+	default:
+	  break;
+	case R_386_SIZE32:
+	case R_386_TLS_LE_32:
+	case R_386_TLS_LE:
+	case R_386_32:
+	case R_386_PC32:
+	  if (NEED_DYNAMIC_RELOCATION_P (info, true, h, sec, r_type,
+					 htab->pointer_r_type))
+	    {
+	      /* We may copy these reloc types into the output file.
+		 Create a reloc section in dynobj and make room for
+		 this reloc.  */
+	      sreloc = _bfd_elf_make_dynamic_reloc_section
+		(sec, htab->elf.dynobj, 2, abfd, /*rela?*/ false);
+
+	      if (sreloc != NULL)
+		return true;
+
+  error_return:
+	      sec->check_relocs_failed = 1;
+	      return false;
+	    }
+	  break;
+	}
+    }
+
+  return true;
+}
+
 /* Set the correct type for an x86 ELF section.  We do this by the
    section name, which is a hack, but ought to work.  */
 
@@ -4424,6 +4495,8 @@ elf_i386_link_setup_gnu_properties (struct bfd_link_info *info)
 #define elf_backend_relocate_section	      elf_i386_relocate_section
 #define elf_backend_setup_gnu_properties      elf_i386_link_setup_gnu_properties
 #define elf_backend_hide_symbol		      _bfd_x86_elf_hide_symbol
+#define elf_backend_make_reloc_section \
+  elf_i386_make_reloc_section
 
 #define elf_backend_linux_prpsinfo32_ugid16	true
 
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index bb6df798d7b..67b773e90fa 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -1643,11 +1643,6 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
 			   || h->root.type == bfd_link_hash_defweak)
 			  && h->root.u.def.section == bfd_und_section_ptr))))
 	    {
-	      /* Skip __start_SECNAME/__stop_SECNAME when --gc-sections
-	         -z start-stop-gc are used.  */
-	      if (elf_x86_start_stop_gc_p (link_info, h))
-		return true;
-
 	      /* Skip since R_X86_64_32/R_X86_64_32S may overflow.  */
 	      if (no_overflow)
 		return true;
@@ -1838,8 +1833,8 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
 }
 
 /* Look through the relocs for a section during the first phase, and
-   calculate needed space in the global offset table, procedure
-   linkage table, and dynamic reloc sections.  */
+   calculate needed space in the global offset table, and procedure
+   linkage table.  */
 
 static bool
 elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
@@ -1851,7 +1846,6 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
   struct elf_link_hash_entry **sym_hashes;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
-  asection *sreloc;
   bfd_byte *contents;
   bool converted;
 
@@ -1881,8 +1875,6 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
   converted = false;
 
-  sreloc = NULL;
-
   rel_end = relocs + sec->reloc_count;
   for (rel = relocs; rel < rel_end; rel++)
     {
@@ -2290,19 +2282,6 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info \
*info,  struct elf_dyn_relocs *p;
 	      struct elf_dyn_relocs **head;
 
-	      /* We must copy these reloc types into the output file.
-		 Create a reloc section in dynobj and make room for
-		 this reloc.  */
-	      if (sreloc == NULL)
-		{
-		  sreloc = _bfd_elf_make_dynamic_reloc_section
-		    (sec, htab->elf.dynobj, ABI_64_P (abfd) ? 3 : 2,
-		     abfd, /*rela?*/ true);
-
-		  if (sreloc == NULL)
-		    goto error_return;
-		}
-
 	      /* If this is a global symbol, we count the number of
 		 relocations we need for this symbol.  */
 	      if (h != NULL)
@@ -2398,6 +2377,105 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info \
*info,  return false;
 }
 
+/* Look through the relocs for a section during the first phase and
+   make the dynamic reloc section.  */
+
+static bool
+elf_x86_64_make_reloc_section (bfd *abfd,
+			       struct bfd_link_info *info,
+			       asection *sec,
+			       const Elf_Internal_Rela *relocs)
+{
+  struct elf_x86_link_hash_table *htab;
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  const Elf_Internal_Rela *rel;
+  const Elf_Internal_Rela *rel_end;
+  asection *sreloc;
+
+  if (bfd_link_relocatable (info))
+    return true;
+
+  htab = elf_x86_hash_table (info, X86_64_ELF_DATA);
+  if (htab == NULL)
+    {
+      sec->check_relocs_failed = 1;
+      return false;
+    }
+
+  BFD_ASSERT (is_x86_elf (abfd, htab));
+
+  symtab_hdr = &elf_symtab_hdr (abfd);
+  sym_hashes = elf_sym_hashes (abfd);
+
+  rel_end = relocs + sec->reloc_count;
+  for (rel = relocs; rel < rel_end; rel++)
+    {
+      unsigned int r_type;
+      unsigned int r_symndx;
+      struct elf_link_hash_entry *h;
+
+      r_symndx = htab->r_sym (rel->r_info);
+      r_type = ELF32_R_TYPE (rel->r_info);
+
+      if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
+	{
+	  /* xgettext:c-format */
+	  _bfd_error_handler (_("%pB: bad symbol index: %d"),
+			      abfd, r_symndx);
+	  goto error_return;
+	}
+
+      if (r_symndx < symtab_hdr->sh_info)
+	h = NULL;
+      else
+	{
+	  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;
+	}
+
+      switch (r_type)
+	{
+	default:
+	  break;
+	case R_X86_64_SIZE32:
+	case R_X86_64_SIZE64:
+	case R_X86_64_32:
+	case R_X86_64_8:
+	case R_X86_64_16:
+	case R_X86_64_32S:
+	case R_X86_64_PC8:
+	case R_X86_64_PC16:
+	case R_X86_64_PC32:
+	case R_X86_64_PC32_BND:
+	case R_X86_64_PC64:
+	case R_X86_64_64:
+	  if (NEED_DYNAMIC_RELOCATION_P (info, true, h, sec, r_type,
+					 htab->pointer_r_type))
+	    {
+	      /* We may copy these reloc types into the output file.
+		 Create a reloc section in dynobj and make room for
+		 this reloc.  */
+	      sreloc = _bfd_elf_make_dynamic_reloc_section
+		(sec, htab->elf.dynobj, ABI_64_P (abfd) ? 3 : 2,
+		 abfd, /*rela?*/ true);
+
+	      if (sreloc != NULL)
+		return true;
+
+  error_return:
+	      sec->check_relocs_failed = 1;
+	      return false;
+	    }
+	  break;
+	}
+    }
+
+  return true;
+}
+
 /* Return the relocation value for @tpoff relocation
    if STT_TLS virtual address is ADDRESS.  */
 
@@ -5306,6 +5384,8 @@ elf_x86_64_special_sections[]=
   elf_x86_64_link_setup_gnu_properties
 #define elf_backend_hide_symbol \
   _bfd_x86_elf_hide_symbol
+#define elf_backend_make_reloc_section \
+  elf_x86_64_make_reloc_section
 
 #undef	elf64_bed
 #define elf64_bed elf64_x86_64_bed
diff --git a/bfd/elflink.c b/bfd/elflink.c
index dc38548b23b..433170eac93 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -4008,10 +4008,14 @@ _bfd_elf_notice_as_needed (bfd *ibfd,
   return (*info->callbacks->notice) (info, NULL, NULL, ibfd, NULL, act, 0);
 }
 
-/* Check relocations an ELF object file.  */
+/* Implementation of checking relocations or make reloc sections in an
+   ELF object file.  */
 
-bool
-_bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
+static bool
+elf_link_check_relocs_or_make_reloc_sections
+  (bfd *abfd, struct bfd_link_info *info,
+   bool (*action) (bfd *, struct bfd_link_info *, asection *,
+		   const Elf_Internal_Rela *))
 {
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   struct elf_link_hash_table *htab = elf_hash_table (info);
@@ -4070,7 +4074,7 @@ _bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info \
*info)  if (internal_relocs == NULL)
 	    return false;
 
-	  ok = (*bed->check_relocs) (abfd, info, o, internal_relocs);
+	  ok = action (abfd, info, o, internal_relocs);
 
 	  if (elf_section_data (o)->relocs != internal_relocs)
 	    free (internal_relocs);
@@ -4083,6 +4087,52 @@ _bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info \
*info)  return true;
 }
 
+/* Check relocations or make reloc sections in an ELF object file,
+   depending on the current check relocs phase and the target choice.  */
+
+bool
+_bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
+{
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  switch (info->check_relocs_choice)
+    {
+    case check_relocs_before_open_input:
+      abort ();
+      break;
+    case check_relocs_after_open_input:
+      switch (info->check_relocs_phase)
+	{
+	case check_relocs_before_open_input:
+	  abort ();
+	  break;
+	case check_relocs_after_open_input:
+	  return elf_link_check_relocs_or_make_reloc_sections
+	    (abfd, info, bed->check_relocs);
+	  break;
+	case check_relocs_before_allocation:
+	  break;
+	}
+      break;
+    case check_relocs_before_allocation:
+      switch (info->check_relocs_phase)
+	{
+	case check_relocs_before_open_input:
+	  abort ();
+	  break;
+	case check_relocs_after_open_input:
+	  return elf_link_check_relocs_or_make_reloc_sections
+	    (abfd, info, bed->make_reloc_section);
+	  break;
+	case check_relocs_before_allocation:
+	  return elf_link_check_relocs_or_make_reloc_sections
+	    (abfd, info, bed->check_relocs);
+	  break;
+	}
+      break;
+    }
+  return true;
+}
+
 /* Add symbols from an ELF object file to the linker hash table.  */
 
 static bool
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 4c6b1f20340..9ed3d548668 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -474,6 +474,9 @@
 #ifndef elf_backend_check_relocs
 #define elf_backend_check_relocs	0
 #endif
+#ifndef elf_backend_make_reloc_section
+#define elf_backend_make_reloc_section	0
+#endif
 #ifndef elf_backend_check_directives
 #define elf_backend_check_directives	0
 #endif
@@ -837,6 +840,7 @@ static const struct elf_backend_data elfNN_bed =
   elf_backend_omit_section_dynsym,
   elf_backend_relocs_compatible,
   elf_backend_check_relocs,
+  elf_backend_make_reloc_section,
   elf_backend_check_directives,
   elf_backend_notice_as_needed,
   elf_backend_adjust_dynamic_symbol,
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index aab641ab751..8251f641a77 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -731,36 +731,3 @@ 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
-
-/* Return true if H is a __start_SECNAME/__stop_SECNAME symbol for the
-   SECNAME section which has been garbage collected by --gc-sections
-   -z start-stop-gc.  */
-
-static inline bool
-elf_x86_start_stop_gc_p (struct bfd_link_info *link_info,
-			 struct elf_link_hash_entry *h)
-{
-  if (h->start_stop
-      && link_info->gc_sections
-      && link_info->start_stop_gc)
-    {
-      asection *s = h->root.u.def.section;
-
-      do
-	{
-	  /* Return false if any SECNAME section is kept.  */
-	  if (s->gc_mark)
-	    return false;
-	  s = bfd_get_next_section_by_name (s->owner, s);
-	}
-      while (s != NULL);
-
-      /* Return true only if all SECNAME sections have been garbage
-	 collected.  */
-      return true;
-    }
-
-  /* Return false if H isn't a __start_SECNAME/__stop_SECNAME symbol or
-     --gc-sections or -z start-stop-gc isn't used.  */
-  return false;
-}
diff --git a/include/bfdlink.h b/include/bfdlink.h
index 566529ee644..3040c23689d 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -284,6 +284,17 @@ enum textrel_check_method
 #define bfd_link_textrel_check(info) \
   (info->textrel_check != textrel_check_none)
 
+/* When to check relocations.  */
+enum bfd_link_check_relocs_phase
+{
+  /* Check relocations before all input files have been opened.  */
+  check_relocs_before_open_input = 0,
+  /* Check relocations after all input files have been opened.  */
+  check_relocs_after_open_input,
+  /* Check relocations before allocation.  */
+  check_relocs_before_allocation
+};
+
 typedef enum {with_flags, without_flags} flag_type;
 
 /* A section flag list.  */
@@ -501,9 +512,11 @@ struct bfd_link_info
   /* TRUE if program headers ought to be loaded.  */
   unsigned int load_phdrs: 1;
 
-  /* TRUE if we should check relocations after all input files have
-     been opened.  */
-  unsigned int check_relocs_after_open_input: 1;
+  /* When to check relocations.  */
+  ENUM_BITFIELD (bfd_link_check_relocs_phase) check_relocs_choice: 2;
+
+  /* The current phase to check relocations.  */
+  ENUM_BITFIELD (bfd_link_check_relocs_phase) check_relocs_phase: 2;
 
   /* TRUE if generation of .interp/PT_INTERP should be suppressed.  */
   unsigned int nointerp: 1;
diff --git a/ld/emulparams/elf32_x86_64.sh b/ld/emulparams/elf32_x86_64.sh
index ac0a7aa6dcf..26b615df944 100644
--- a/ld/emulparams/elf32_x86_64.sh
+++ b/ld/emulparams/elf32_x86_64.sh
@@ -10,6 +10,7 @@ source_sh ${srcdir}/emulparams/static.sh
 SCRIPT_NAME=elf
 ELFSIZE=32
 OUTPUT_FORMAT="elf32-x86-64"
+CHECK_RELOCS_CHOICE=check_relocs_before_allocation
 NO_REL_RELOCS=yes
 TEXT_START_ADDR=0x400000
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
diff --git a/ld/emulparams/elf_i386.sh b/ld/emulparams/elf_i386.sh
index 98532e5edbc..994ecb0994d 100644
--- a/ld/emulparams/elf_i386.sh
+++ b/ld/emulparams/elf_i386.sh
@@ -8,6 +8,7 @@ source_sh ${srcdir}/emulparams/x86-64-level.sh
 source_sh ${srcdir}/emulparams/static.sh
 SCRIPT_NAME=elf
 OUTPUT_FORMAT="elf32-i386"
+CHECK_RELOCS_CHOICE=check_relocs_before_allocation
 NO_RELA_RELOCS=yes
 TEXT_START_ADDR=0x08048000
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
diff --git a/ld/emulparams/elf_i386_be.sh b/ld/emulparams/elf_i386_be.sh
index dbe68e99e63..65a931a36f3 100644
--- a/ld/emulparams/elf_i386_be.sh
+++ b/ld/emulparams/elf_i386_be.sh
@@ -4,6 +4,7 @@ source_sh ${srcdir}/emulparams/call_nop.sh
 SCRIPT_NAME=elf
 OUTPUT_FORMAT="elf32-i386"
 EXTRA_EM_FILE="elf-x86"
+CHECK_RELOCS_CHOICE=check_relocs_before_allocation
 NO_RELA_RELOCS=yes
 TEXT_START_ADDR=0x80000000
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
diff --git a/ld/emulparams/elf_i386_ldso.sh b/ld/emulparams/elf_i386_ldso.sh
index 081de5f8e71..0c57f1712c5 100644
--- a/ld/emulparams/elf_i386_ldso.sh
+++ b/ld/emulparams/elf_i386_ldso.sh
@@ -5,6 +5,7 @@ source_sh ${srcdir}/emulparams/call_nop.sh
 SCRIPT_NAME=elf
 OUTPUT_FORMAT="elf32-i386"
 EXTRA_EM_FILE="elf-x86"
+CHECK_RELOCS_CHOICE=check_relocs_before_allocation
 NO_RELA_RELOCS=yes
 TEXT_START_ADDR=0x08048000
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
diff --git a/ld/emulparams/elf_i386_vxworks.sh b/ld/emulparams/elf_i386_vxworks.sh
index 40c809263d1..38198b3d9bd 100644
--- a/ld/emulparams/elf_i386_vxworks.sh
+++ b/ld/emulparams/elf_i386_vxworks.sh
@@ -1,5 +1,6 @@
 SCRIPT_NAME=elf
 OUTPUT_FORMAT="elf32-i386-vxworks"
+CHECK_RELOCS_CHOICE=check_relocs_before_allocation
 NO_RELA_RELOCS=yes
 TEXT_START_ADDR=0x08048000
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
diff --git a/ld/emulparams/elf_x86_64.sh b/ld/emulparams/elf_x86_64.sh
index 48d0974711b..72439fecfc4 100644
--- a/ld/emulparams/elf_x86_64.sh
+++ b/ld/emulparams/elf_x86_64.sh
@@ -11,6 +11,7 @@ source_sh ${srcdir}/emulparams/static.sh
 SCRIPT_NAME=elf
 ELFSIZE=64
 OUTPUT_FORMAT="elf64-x86-64"
+CHECK_RELOCS_CHOICE=check_relocs_before_allocation
 NO_REL_RELOCS=yes
 TEXT_START_ADDR=0x400000
 MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
diff --git a/ld/emultempl/aarch64elf.em b/ld/emultempl/aarch64elf.em
index 4e1d8f8a240..35ab829b8da 100644
--- a/ld/emultempl/aarch64elf.em
+++ b/ld/emultempl/aarch64elf.em
@@ -46,7 +46,7 @@ gld${EMULATION_NAME}_before_parse (void)
   input_flags.dynamic = ${DYNAMIC_LINK-true};
   config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo true ; else \
echo false ; fi`;  config.separate_code = `if test "x${SEPARATE_CODE}" = xyes ; then \
                echo true ; else echo false ; fi`;
-  link_info.check_relocs_after_open_input = true;
+  link_info.check_relocs_choice = $CHECK_RELOCS_CHOICE;
 EOF
 if test -n "$COMMONPAGESIZE"; then
 fragment <<EOF
diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em
index 7aec17e5ede..a23220af527 100644
--- a/ld/emultempl/armelf.em
+++ b/ld/emultempl/armelf.em
@@ -59,7 +59,7 @@ gld${EMULATION_NAME}_before_parse (void)
   input_flags.dynamic = ${DYNAMIC_LINK-true};
   config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo true ; else \
echo false ; fi`;  config.separate_code = `if test "x${SEPARATE_CODE}" = xyes ; then \
                echo true ; else echo false ; fi`;
-  link_info.check_relocs_after_open_input = true;
+  link_info.check_relocs_choice = $CHECK_RELOCS_CHOICE;
 EOF
 if test -n "$COMMONPAGESIZE"; then
 fragment <<EOF
diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
index bfaf8130a3e..1403fd1e3fa 100644
--- a/ld/emultempl/elf.em
+++ b/ld/emultempl/elf.em
@@ -58,6 +58,10 @@ static void gld${EMULATION_NAME}_before_allocation (void);
 static void gld${EMULATION_NAME}_after_allocation (void);
 EOF
 
+if test -z "$CHECK_RELOCS_CHOICE"; then
+  CHECK_RELOCS_CHOICE=check_relocs_after_open_input
+fi
+
 # Import any needed special functions and/or overrides.
 #
 source_em ${srcdir}/emultempl/elf-generic.em
@@ -81,7 +85,7 @@ gld${EMULATION_NAME}_before_parse (void)
   input_flags.dynamic = ${DYNAMIC_LINK-true};
   config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo true ; else \
echo false ; fi`;  config.separate_code = `if test "x${SEPARATE_CODE}" = xyes ; then \
                echo true ; else echo false ; fi`;
-  link_info.check_relocs_after_open_input = true;
+  link_info.check_relocs_choice = $CHECK_RELOCS_CHOICE;
 EOF
 if test -n "$COMMONPAGESIZE"; then
 fragment <<EOF
diff --git a/ld/emultempl/mmix-elfnmmo.em b/ld/emultempl/mmix-elfnmmo.em
index a88fc5a6596..4d94790fe95 100644
--- a/ld/emultempl/mmix-elfnmmo.em
+++ b/ld/emultempl/mmix-elfnmmo.em
@@ -30,7 +30,7 @@ static void gld${EMULATION_NAME}_before_parse (void);
 static void
 mmix_before_parse (void)
 {
-  link_info.check_relocs_after_open_input = true;
+  link_info.check_relocs_choice = check_relocs_after_open_input;
   gld${EMULATION_NAME}_before_parse ();
 }
 
diff --git a/ld/emultempl/scoreelf.em b/ld/emultempl/scoreelf.em
index 9aea76a8f51..725976c5d03 100644
--- a/ld/emultempl/scoreelf.em
+++ b/ld/emultempl/scoreelf.em
@@ -39,7 +39,7 @@ gld${EMULATION_NAME}_before_parse (void)
   input_flags.dynamic = ${DYNAMIC_LINK-true};
   config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo true ; else \
echo false ; fi`;  config.separate_code = `if test "x${SEPARATE_CODE}" = xyes ; then \
                echo true ; else echo false ; fi`;
-  link_info.check_relocs_after_open_input = true;
+  link_info.check_relocs_choice = $CHECK_RELOCS_CHOICE;
 EOF
 if test -n "$COMMONPAGESIZE"; then
 fragment <<EOF
diff --git a/ld/ldelf.c b/ld/ldelf.c
index 529992b02ae..045f584339e 100644
--- a/ld/ldelf.c
+++ b/ld/ldelf.c
@@ -1617,6 +1617,10 @@ ldelf_before_allocation (char *audit, char *depaudit,
       lang_for_each_statement (ldelf_find_statement_assignment);
     }
 
+  /* Check relocations after __ehdr_start has been finalized.  */
+  if (link_info.check_relocs_choice == check_relocs_before_allocation)
+    lang_check_relocs ();
+
   /* Let the ELF backend work out the sizes of any sections required
      by dynamic linking.  */
   rpath = command_line.rpath;
diff --git a/ld/ldlang.c b/ld/ldlang.c
index a0ff1229344..d71e30c42aa 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -7914,24 +7914,21 @@ lang_add_gc_name (const char *name)
 
 /* Check relocations.  */
 
-static void
+void
 lang_check_relocs (void)
 {
-  if (link_info.check_relocs_after_open_input)
-    {
-      bfd *abfd;
+  bfd *abfd;
 
-      for (abfd = link_info.input_bfds;
-	   abfd != (bfd *) NULL; abfd = abfd->link.next)
-	if (!bfd_link_check_relocs (abfd, &link_info))
-	  {
-	    /* No object output, fail return.  */
-	    config.make_executable = false;
-	    /* Note: we do not abort the loop, but rather
-	       continue the scan in case there are other
-	       bad relocations to report.  */
-	  }
-    }
+  for (abfd = link_info.input_bfds;
+       abfd != (bfd *) NULL; abfd = abfd->link.next)
+    if (!bfd_link_check_relocs (abfd, &link_info))
+      {
+	/* No object output, fail return.  */
+	config.make_executable = false;
+	/* Note: we do not abort the loop, but rather
+	   continue the scan in case there are other
+	   bad relocations to report.  */
+      }
 }
 
 /* Look through all output sections looking for places where we can
@@ -8165,8 +8162,10 @@ lang_process (void)
 
   lang_mark_undefineds ();
 
-  /* Check relocations.  */
-  lang_check_relocs ();
+  /* Check relocations after all input files have been opened.  */
+  link_info.check_relocs_phase = check_relocs_after_open_input;
+  if (link_info.check_relocs_choice != check_relocs_before_open_input)
+    lang_check_relocs ();
 
   ldemul_after_check_relocs ();
 
@@ -8233,6 +8232,7 @@ lang_process (void)
 
   /* Do anything special before sizing sections.  This is where ELF
      and other back-ends size dynamic sections.  */
+  link_info.check_relocs_phase = check_relocs_before_allocation;
   ldemul_before_allocation ();
 
   /* We must record the program headers before we try to fix the
diff --git a/ld/ldlang.h b/ld/ldlang.h
index f68ae27b409..7189c726564 100644
--- a/ld/ldlang.h
+++ b/ld/ldlang.h
@@ -717,6 +717,9 @@ lang_print_memory_usage (void);
 extern void
 lang_add_gc_name (const char *);
 
+extern void
+lang_check_relocs (void);
+
 extern bool
 print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr);
 
diff --git a/ld/ldmain.c b/ld/ldmain.c
index 02029237e1a..aefef9029dc 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -359,6 +359,7 @@ main (int argc, char **argv)
 #endif
   link_info.start_stop_gc = false;
   link_info.start_stop_visibility = STV_PROTECTED;
+  link_info.check_relocs_phase = check_relocs_before_open_input;
 
   ldfile_add_arch ("");
   emulation = get_emulation (argc, argv);
diff --git a/ld/testsuite/ld-i386/pr27491-1a.d b/ld/testsuite/ld-i386/pr27491-1a.d
index 006c17695c1..39b25f6507f 100644
--- a/ld/testsuite/ld-i386/pr27491-1a.d
+++ b/ld/testsuite/ld-i386/pr27491-1a.d
@@ -9,6 +9,6 @@
 Disassembly of section .text:
 
 [a-f0-9]+ <foo>:
- +[a-f0-9]+:	8b 83 ([0-9a-f]{2} ){4}[ \t]+mov +-0x[a-f0-9]+\(%ebx\),%eax
- +[a-f0-9]+:	8b 83 ([0-9a-f]{2} ){4}[ \t]+mov +-0x[a-f0-9]+\(%ebx\),%eax
+ +[a-f0-9]+:	c7 c0 00 00 00 00    	mov    \$0x0,%eax
+ +[a-f0-9]+:	c7 c0 00 00 00 00    	mov    \$0x0,%eax
 #pass
diff --git a/ld/testsuite/ld-x86-64/pr27491-1a.d \
b/ld/testsuite/ld-x86-64/pr27491-1a.d index ade5c6fa4f9..215124c6401 100644
--- a/ld/testsuite/ld-x86-64/pr27491-1a.d
+++ b/ld/testsuite/ld-x86-64/pr27491-1a.d
@@ -9,6 +9,6 @@
 Disassembly of section .text:
 
 [a-f0-9]+ <foo>:
- +[a-f0-9]+:	48 8b 05 ([0-9a-f]{2} ){4}[ \t]+mov +0x[a-f0-9]+\(%rip\),%rax[ \t]+# \
                [a-f0-9]+ <_DYNAMIC\+0x[a-f0-9]+>
- +[a-f0-9]+:	48 8b 05 ([0-9a-f]{2} ){4}[ \t]+mov +0x[a-f0-9]+\(%rip\),%rax[ \t]+# \
[a-f0-9]+ <_DYNAMIC\+0x[a-f0-9]+> + +[a-f0-9]+:	48 c7 c0 00 00 00 00 	mov    \
\$0x0,%rax + +[a-f0-9]+:	48 c7 c0 00 00 00 00 	mov    \$0x0,%rax
 #pass
-- 
2.33.1


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic