diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 896aa08fd76..81f8fd47db7 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2632,6 +2632,10 @@ extern int bfd_elf_add_dt_needed_tag
   (bfd *, struct bfd_link_info *);
 extern bool _bfd_elf_link_check_relocs
   (bfd *, struct bfd_link_info *);
+extern bool _bfd_elf_link_iterate_on_relocs
+ (bfd *, struct bfd_link_info *,
+  bool (*) (bfd *, struct bfd_link_info *, asection *,
+	    const Elf_Internal_Rela *));
 
 extern bool bfd_elf_link_record_dynamic_symbol
   (struct bfd_link_info *, struct elf_link_hash_entry *);
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 97962072ff0..d1f61be5044 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -522,7 +522,7 @@ elf_i386_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
    Functions named elf_i386_* are called by external routines, other
    functions are only called locally.  elf_i386_* functions appear
    in this file more or less in the order in which they are called
-   from external routines.  eg. elf_i386_check_relocs is called
+   from external routines.  eg. elf_i386_scan_relocs is called
    early in the link process, elf_i386_finish_dynamic_sections is
    one of the last functions.  */
 
@@ -1106,7 +1106,7 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd,
 	    }
 
 	  /* We checked the transition before when we were called from
-	     elf_i386_check_relocs.  We only want to check the new
+	     elf_i386_scan_relocs.  We only want to check the new
 	     transition which hasn't been checked before.  */
 	  check = new_to_type != to_type && from_type == to_type;
 	  to_type = new_to_type;
@@ -1387,11 +1387,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)
 	    {
@@ -1452,21 +1447,20 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
 }
 
 /* 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,
-		       struct bfd_link_info *info,
-		       asection *sec,
-		       const Elf_Internal_Rela *relocs)
+elf_i386_scan_relocs (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;
   bfd_byte *contents;
   bool converted;
 
@@ -1496,8 +1490,6 @@ elf_i386_check_relocs (bfd *abfd,
 
   converted = false;
 
-  sreloc = NULL;
-
   rel_end = relocs + sec->reloc_count;
   for (rel = relocs; rel < rel_end; rel++)
     {
@@ -1818,18 +1810,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)
@@ -1924,6 +1904,24 @@ elf_i386_check_relocs (bfd *abfd,
   return false;
 }
 
+static bool
+elf_i386_always_size_sections (bfd *output_bfd,
+			       struct bfd_link_info *info)
+{
+  bfd *abfd;
+
+  /* Scan relocations after rel_from_abs has been set on __ehdr_start.  */
+  for (abfd = info->input_bfds;
+       abfd != (bfd *) NULL;
+       abfd = abfd->link.next)
+    if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+	&& !_bfd_elf_link_iterate_on_relocs (abfd, info,
+					     elf_i386_scan_relocs))
+      return false;
+
+  return _bfd_x86_elf_always_size_sections (output_bfd, info);
+}
+
 /* Set the correct type for an x86 ELF section.  We do this by the
    section name, which is a hack, but ought to work.  */
 
@@ -2000,7 +1998,7 @@ elf_i386_relocate_section (bfd *output_bfd,
   bool is_vxworks_tls;
   unsigned plt_entry_size;
 
-  /* Skip if check_relocs failed.  */
+  /* Skip if check_relocs or scan_relocs failed.  */
   if (input_section->check_relocs_failed)
     return false;
 
@@ -4390,7 +4388,7 @@ elf_i386_link_setup_gnu_properties (struct bfd_link_info *info)
 #define bfd_elf32_get_synthetic_symtab	      elf_i386_get_synthetic_symtab
 
 #define elf_backend_relocs_compatible	      _bfd_elf_relocs_compatible
-#define elf_backend_check_relocs	      elf_i386_check_relocs
+#define elf_backend_always_size_sections      elf_i386_always_size_sections
 #define elf_backend_create_dynamic_sections   _bfd_elf_create_dynamic_sections
 #define elf_backend_fake_sections	      elf_i386_fake_sections
 #define elf_backend_finish_dynamic_sections   elf_i386_finish_dynamic_sections
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 22aa3ee3b68..ad885f89e11 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -1309,7 +1309,7 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
 	    }
 
 	  /* We checked the transition before when we were called from
-	     elf_x86_64_check_relocs.  We only want to check the new
+	     elf_x86_64_scan_relocs.  We only want to check the new
 	     transition which hasn't been checked before.  */
 	  check = new_to_type != to_type && from_type == to_type;
 	  to_type = new_to_type;
@@ -1628,11 +1628,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;
@@ -1823,20 +1818,19 @@ 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,
-			 asection *sec,
-			 const Elf_Internal_Rela *relocs)
+elf_x86_64_scan_relocs (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;
   bfd_byte *contents;
   bool converted;
 
@@ -1866,8 +1860,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++)
     {
@@ -2263,19 +2255,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)
@@ -2371,6 +2350,24 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
   return false;
 }
 
+static bool
+elf_x86_64_always_size_sections (bfd *output_bfd,
+				 struct bfd_link_info *info)
+{
+  bfd *abfd;
+
+  /* Scan relocations after rel_from_abs has been set on __ehdr_start.  */
+  for (abfd = info->input_bfds;
+       abfd != (bfd *) NULL;
+       abfd = abfd->link.next)
+    if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+	&& !_bfd_elf_link_iterate_on_relocs (abfd, info,
+					     elf_x86_64_scan_relocs))
+      return false;
+
+  return _bfd_x86_elf_always_size_sections (output_bfd, info);
+}
+
 /* Return the relocation value for @tpoff relocation
    if STT_TLS virtual address is ADDRESS.  */
 
@@ -2413,7 +2410,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
   unsigned int plt_entry_size;
   bool status;
 
-  /* Skip if check_relocs failed.  */
+  /* Skip if check_relocs or scan_relocs failed.  */
   if (input_section->check_relocs_failed)
     return false;
 
@@ -5238,7 +5235,7 @@ elf_x86_64_special_sections[]=
   elf_x86_64_reloc_name_lookup
 
 #define elf_backend_relocs_compatible	    elf_x86_64_relocs_compatible
-#define elf_backend_check_relocs	    elf_x86_64_check_relocs
+#define elf_backend_always_size_sections    elf_x86_64_always_size_sections
 #define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections
 #define elf_backend_finish_dynamic_sections elf_x86_64_finish_dynamic_sections
 #define elf_backend_finish_dynamic_symbol   elf_x86_64_finish_dynamic_symbol
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 08c161713cc..059461b5725 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -4008,10 +4008,13 @@ _bfd_elf_notice_as_needed (bfd *ibfd,
   return (*info->callbacks->notice) (info, NULL, NULL, ibfd, NULL, act, 0);
 }
 
-/* Check relocations an ELF object file.  */
+/* Call ACTION on each relocation in an ELF object file.  */
 
 bool
-_bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
+_bfd_elf_link_iterate_on_relocs
+  (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);
@@ -4035,7 +4038,6 @@ _bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
      different format.  It probably can't be done.  */
   if ((abfd->flags & DYNAMIC) == 0
       && is_elf_hash_table (&htab->root)
-      && bed->check_relocs != NULL
       && elf_object_id (abfd) == elf_hash_table_id (htab)
       && (*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
     {
@@ -4070,7 +4072,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 +4085,19 @@ _bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
   return true;
 }
 
+/* Check relocations in an ELF object file.  This is called after
+   all input files have been opened.  */
+
+bool
+_bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
+{
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  if (bed->check_relocs != NULL)
+    return _bfd_elf_link_iterate_on_relocs (abfd, info,
+					    bed->check_relocs);
+  return true;
+}
+
 /* Add symbols from an ELF object file to the linker hash table.  */
 
 static bool
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index ca4b90e22cc..25f7717ea88 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -892,6 +892,91 @@ _bfd_x86_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info)
   return _bfd_elf_link_check_relocs (abfd, info);
 }
 
+/* Look through the relocs for a section before allocation to make the
+   dynamic reloc section.  */
+
+bool
+_bfd_x86_elf_check_relocs (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;
+  const struct elf_backend_data *bed;
+  bool is_x86_64;
+
+  if (bfd_link_relocatable (info))
+    return true;
+
+  bed = get_elf_backend_data (abfd);
+  htab = elf_x86_hash_table (info, bed->target_id);
+  if (htab == NULL)
+    {
+      sec->check_relocs_failed = 1;
+      return false;
+    }
+
+  is_x86_64 = bed->target_id == X86_64_ELF_DATA;
+
+  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;
+	}
+
+      if (X86_NEED_DYNAMIC_RELOC_TYPE_P (is_x86_64, r_type)
+	  && NEED_DYNAMIC_RELOCATION_P (is_x86_64, 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, sec->use_rela_p);
+
+	  if (sreloc != NULL)
+	    return true;
+
+  error_return:
+	  sec->check_relocs_failed = 1;
+	  return false;
+	}
+    }
+
+  return true;
+}
+
 bool
 _bfd_elf_x86_valid_reloc_p (asection *input_section,
 			    struct bfd_link_info *info,
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index 16565a5638b..1bb80280918 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -47,6 +47,25 @@
 #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) \
+   || (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_NEED_DYNAMIC_RELOC_TYPE_P(TYPE) \
+  (I386_SIZE_TYPE_P (TYPE) \
+   || I386_PCREL_TYPE_P (TYPE) \
+   || (TYPE) == R_386_32 \
+   || (TYPE) == R_386_TLS_LE \
+   || (TYPE) == R_386_TLS_LE_32)
+#define X86_NEED_DYNAMIC_RELOC_TYPE_P(IS_X86_64, TYPE) \
+  ((IS_X86_64) \
+   ? X86_64_NEED_DYNAMIC_RELOC_TYPE_P (TYPE) \
+   : I386_NEED_DYNAMIC_RELOC_TYPE_P (TYPE))
+
 #define PLT_CIE_LENGTH		20
 #define PLT_FDE_LENGTH		36
 #define PLT_FDE_START_OFFSET	4 + PLT_CIE_LENGTH + 8
@@ -653,6 +672,10 @@ extern int _bfd_x86_elf_compare_relocs
 extern bool _bfd_x86_elf_link_check_relocs
   (bfd *, struct bfd_link_info *);
 
+extern bool _bfd_x86_elf_check_relocs
+  (bfd *, struct bfd_link_info *, asection *,
+   const Elf_Internal_Rela *);
+
 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 *,
@@ -730,10 +753,10 @@ extern void _bfd_x86_elf_link_report_relative_reloc
 #define bfd_elf32_bfd_link_check_relocs \
   _bfd_x86_elf_link_check_relocs
 
+#define elf_backend_check_relocs \
+  _bfd_x86_elf_check_relocs
 #define elf_backend_size_dynamic_sections \
   _bfd_x86_elf_size_dynamic_sections
-#define elf_backend_always_size_sections \
-  _bfd_x86_elf_always_size_sections
 #define elf_backend_merge_symbol_attribute \
   _bfd_x86_elf_merge_symbol_attribute
 #define elf_backend_copy_indirect_symbol \
@@ -757,39 +780,6 @@ extern void _bfd_x86_elf_link_report_relative_reloc
 
 #define ELF_P_ALIGN ELF_MINPAGESIZE
 
-/* 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;
-}
-
 /* Allocate x86 GOT info for local symbols.  */
 
 static inline bool
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
