From a94d834c9d0108f0bb50ddc311554d1bed320f54 Mon Sep 17 00:00:00 2001
From: Nick Clifton <nickc@redhat.com>
Date: Tue, 2 Aug 2016 11:56:55 +0100
Subject: [PATCH] Fix SH GOT allocation in the presence of linker garbage collection.

	PR ld/17739
ld	* emulparams/shelf.sh (CHECK_RELOCS_AFTER_OPEN_INPUT): Define with
	valye 'yes'.
	* emulparams/shelf32.sh: Likewise.
	* emulparams/shelf32.sh: Likewise.
	* emulparams/shelf_nto.sh: Likewise.
	* emulparams/shelf_nto.sh: Likewise.
	* emulparams/shelf_vxworks.sh: Likewise.
	* emulparams/shelf_vxworks.sh: Likewise.
	* emulparams/shlelf32_linux.sh: Likewise.
	* emulparams/shlelf32_linux.sh: Likewise.
	* emulparams/shlelf_linux.sh: Likewise.
	* emulparams/shlelf_linux.sh: Likewise.
	* emulparams/shlelf_nto.sh: Likewise.
	* emulparams/shlelf_nto.sh: Likewise.

bfd	* elf32-sh.c (sh_elf_gc_sweep_hook): Delete.
	(elf_backend_sweep_hook): Delete.
---
 bfd/elf32-sh.c                  |  215 ---------------------------------------
 ld/emulparams/shelf.sh          |    3 +
 ld/emulparams/shelf32.sh        |    3 +
 ld/emulparams/shelf_nto.sh      |    3 +
 ld/emulparams/shelf_vxworks.sh  |    4 +
 ld/emulparams/shlelf32_linux.sh |    4 +-
 ld/emulparams/shlelf_linux.sh   |    3 +
 ld/emulparams/shlelf_nto.sh     |    3 +
 10 files changed, 46 insertions(+), 216 deletions(-)

diff --git a/bfd/elf32-sh.c b/bfd/elf32-sh.c
index 52a5fd1..84c5b1e 100644
--- a/bfd/elf32-sh.c
+++ b/bfd/elf32-sh.c
@@ -5682,220 +5682,6 @@ sh_elf_gc_mark_hook (asection *sec,
   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
 }
 
-/* Update the got entry reference counts for the section being removed.  */
-
-static bfd_boolean
-sh_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
-		      asection *sec, const Elf_Internal_Rela *relocs)
-{
-  Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes;
-  bfd_signed_vma *local_got_refcounts;
-  union gotref *local_funcdesc;
-  const Elf_Internal_Rela *rel, *relend;
-
-  if (bfd_link_relocatable (info))
-    return TRUE;
-
-  elf_section_data (sec)->local_dynrel = NULL;
-
-  symtab_hdr = &elf_symtab_hdr (abfd);
-  sym_hashes = elf_sym_hashes (abfd);
-  local_got_refcounts = elf_local_got_refcounts (abfd);
-  local_funcdesc = sh_elf_local_funcdesc (abfd);
-
-  relend = relocs + sec->reloc_count;
-  for (rel = relocs; rel < relend; rel++)
-    {
-      unsigned long r_symndx;
-      unsigned int r_type;
-      struct elf_link_hash_entry *h = NULL;
-#ifdef INCLUDE_SHMEDIA
-      int seen_stt_datalabel = 0;
-#endif
-
-      r_symndx = ELF32_R_SYM (rel->r_info);
-      if (r_symndx >= symtab_hdr->sh_info)
-	{
-	  struct elf_sh_link_hash_entry *eh;
-	  struct elf_sh_dyn_relocs **pp;
-	  struct elf_sh_dyn_relocs *p;
-
-	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-	  while (h->root.type == bfd_link_hash_indirect
-		 || h->root.type == bfd_link_hash_warning)
-	    {
-#ifdef INCLUDE_SHMEDIA
-	      seen_stt_datalabel |= h->type == STT_DATALABEL;
-#endif
-	      h = (struct elf_link_hash_entry *) h->root.u.i.link;
-	    }
-	  eh = (struct elf_sh_link_hash_entry *) h;
-	  for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
-	    if (p->sec == sec)
-	      {
-		/* Everything must go for SEC.  */
-		*pp = p->next;
-		break;
-	      }
-	}
-
-      r_type = ELF32_R_TYPE (rel->r_info);
-      switch (sh_elf_optimized_tls_reloc (info, r_type, h != NULL))
-	{
-	case R_SH_TLS_LD_32:
-	  if (sh_elf_hash_table (info)->tls_ldm_got.refcount > 0)
-	    sh_elf_hash_table (info)->tls_ldm_got.refcount -= 1;
-	  break;
-
-	case R_SH_GOT32:
-	case R_SH_GOT20:
-	case R_SH_GOTOFF:
-	case R_SH_GOTOFF20:
-	case R_SH_GOTPC:
-#ifdef INCLUDE_SHMEDIA
-	case R_SH_GOT_LOW16:
-	case R_SH_GOT_MEDLOW16:
-	case R_SH_GOT_MEDHI16:
-	case R_SH_GOT_HI16:
-	case R_SH_GOT10BY4:
-	case R_SH_GOT10BY8:
-	case R_SH_GOTOFF_LOW16:
-	case R_SH_GOTOFF_MEDLOW16:
-	case R_SH_GOTOFF_MEDHI16:
-	case R_SH_GOTOFF_HI16:
-	case R_SH_GOTPC_LOW16:
-	case R_SH_GOTPC_MEDLOW16:
-	case R_SH_GOTPC_MEDHI16:
-	case R_SH_GOTPC_HI16:
-#endif
-	case R_SH_TLS_GD_32:
-	case R_SH_TLS_IE_32:
-	case R_SH_GOTFUNCDESC:
-	case R_SH_GOTFUNCDESC20:
-	  if (h != NULL)
-	    {
-#ifdef INCLUDE_SHMEDIA
-	      if (seen_stt_datalabel)
-		{
-		  struct elf_sh_link_hash_entry *eh;
-		  eh = (struct elf_sh_link_hash_entry *) h;
-		  if (eh->datalabel_got.refcount > 0)
-		    eh->datalabel_got.refcount -= 1;
-		}
-	      else
-#endif
-		if (h->got.refcount > 0)
-		  h->got.refcount -= 1;
-	    }
-	  else if (local_got_refcounts != NULL)
-	    {
-#ifdef INCLUDE_SHMEDIA
-	      if (rel->r_addend & 1)
-		{
-		  if (local_got_refcounts[symtab_hdr->sh_info + r_symndx] > 0)
-		    local_got_refcounts[symtab_hdr->sh_info + r_symndx] -= 1;
-		}
-	      else
-#endif
-		if (local_got_refcounts[r_symndx] > 0)
-		  local_got_refcounts[r_symndx] -= 1;
-	    }
-	  break;
-
-	case R_SH_FUNCDESC:
-	  if (h != NULL)
-	    sh_elf_hash_entry (h)->abs_funcdesc_refcount -= 1;
-	  else if (sh_elf_hash_table (info)->fdpic_p && !bfd_link_pic (info))
-	    sh_elf_hash_table (info)->srofixup->size -= 4;
-
-	  /* Fall through.  */
-
-	case R_SH_GOTOFFFUNCDESC:
-	case R_SH_GOTOFFFUNCDESC20:
-	  if (h != NULL)
-	    sh_elf_hash_entry (h)->funcdesc.refcount -= 1;
-	  else
-	    local_funcdesc[r_symndx].refcount -= 1;
-	  break;
-
-	case R_SH_DIR32:
-	  if (sh_elf_hash_table (info)->fdpic_p && !bfd_link_pic (info)
-	      && (sec->flags & SEC_ALLOC) != 0)
-	    sh_elf_hash_table (info)->srofixup->size -= 4;
-	  /* Fall thru */
-
-	case R_SH_REL32:
-	  if (bfd_link_pic (info))
-	    break;
-	  /* Fall thru */
-
-	case R_SH_PLT32:
-#ifdef INCLUDE_SHMEDIA
-	case R_SH_PLT_LOW16:
-	case R_SH_PLT_MEDLOW16:
-	case R_SH_PLT_MEDHI16:
-	case R_SH_PLT_HI16:
-#endif
-	  if (h != NULL)
-	    {
-	      if (h->plt.refcount > 0)
-		h->plt.refcount -= 1;
-	    }
-	  break;
-
-	case R_SH_GOTPLT32:
-#ifdef INCLUDE_SHMEDIA
-	case R_SH_GOTPLT_LOW16:
-	case R_SH_GOTPLT_MEDLOW16:
-	case R_SH_GOTPLT_MEDHI16:
-	case R_SH_GOTPLT_HI16:
-	case R_SH_GOTPLT10BY4:
-	case R_SH_GOTPLT10BY8:
-#endif
-	  if (h != NULL)
-	    {
-	      struct elf_sh_link_hash_entry *eh;
-	      eh = (struct elf_sh_link_hash_entry *) h;
-	      if (eh->gotplt_refcount > 0)
-		{
-		  eh->gotplt_refcount -= 1;
-		  if (h->plt.refcount > 0)
-		    h->plt.refcount -= 1;
-		}
-#ifdef INCLUDE_SHMEDIA
-	      else if (seen_stt_datalabel)
-		{
-		  if (eh->datalabel_got.refcount > 0)
-		    eh->datalabel_got.refcount -= 1;
-		}
-#endif
-	      else if (h->got.refcount > 0)
-		h->got.refcount -= 1;
-	    }
-	  else if (local_got_refcounts != NULL)
-	    {
-#ifdef INCLUDE_SHMEDIA
-	      if (rel->r_addend & 1)
-		{
-		  if (local_got_refcounts[symtab_hdr->sh_info + r_symndx] > 0)
-		    local_got_refcounts[symtab_hdr->sh_info + r_symndx] -= 1;
-		}
-	      else
-#endif
-		if (local_got_refcounts[r_symndx] > 0)
-		  local_got_refcounts[r_symndx] -= 1;
-	    }
-	  break;
-
-	default:
-	  break;
-	}
-    }
-
-  return TRUE;
-}
-
 /* Copy the extra info we tack onto an elf_link_hash_entry.  */
 
 static void
@@ -7455,7 +7241,6 @@ sh_elf_encode_eh_address (bfd *abfd,
 					sh_elf_merge_private_data
 
 #define elf_backend_gc_mark_hook	sh_elf_gc_mark_hook
-#define elf_backend_gc_sweep_hook	sh_elf_gc_sweep_hook
 #define elf_backend_check_relocs	sh_elf_check_relocs
 #define elf_backend_copy_indirect_symbol \
 					sh_elf_copy_indirect_symbol
diff --git a/ld/emulparams/shelf.sh b/ld/emulparams/shelf.sh
index 83680a6..d3f4752 100644
--- a/ld/emulparams/shelf.sh
+++ b/ld/emulparams/shelf.sh
@@ -11,6 +11,9 @@ MACHINE=
 TEMPLATE_NAME=elf32
 GENERATE_SHLIB_SCRIPT=yes
 EMBEDDED=yes
+# PR 17739.  Delay checking relocs until after all files have
+# been opened and linker garbage collection has taken place.
+CHECK_RELOCS_AFTER_OPEN_INPUT=yes
 
 # These are for compatibility with the COFF toolchain.
 ENTRY=start
diff --git a/ld/emulparams/shelf32.sh b/ld/emulparams/shelf32.sh
index 966bd30..bf362c5 100644
--- a/ld/emulparams/shelf32.sh
+++ b/ld/emulparams/shelf32.sh
@@ -11,6 +11,9 @@ ALIGNMENT=8
 TEMPLATE_NAME=elf32
 GENERATE_SHLIB_SCRIPT=yes
 EMBEDDED=yes
+# PR 17739.  Delay checking relocs until after all files have
+# been opened and linker garbage collection has taken place.
+CHECK_RELOCS_AFTER_OPEN_INPUT=yes
 
 DATA_START_SYMBOLS='PROVIDE (___data = .);'
 
diff --git a/ld/emulparams/shelf_nto.sh b/ld/emulparams/shelf_nto.sh
index c4d71aa..46efd87 100644
--- a/ld/emulparams/shelf_nto.sh
+++ b/ld/emulparams/shelf_nto.sh
@@ -9,3 +9,6 @@ TEMPLATE_NAME=elf32
 GENERATE_SHLIB_SCRIPT=yes
 TEXT_START_SYMBOLS='_btext = .;'
 ENTRY=_start
+# PR 17739.  Delay checking relocs until after all files have
+# been opened and linker garbage collection has taken place.
+CHECK_RELOCS_AFTER_OPEN_INPUT=yes
diff --git a/ld/emulparams/shelf_vxworks.sh b/ld/emulparams/shelf_vxworks.sh
index 77619cb..759ffac 100644
--- a/ld/emulparams/shelf_vxworks.sh
+++ b/ld/emulparams/shelf_vxworks.sh
@@ -14,6 +14,10 @@ TEMPLATE_NAME=elf32
 GENERATE_SHLIB_SCRIPT=yes
 ENTRY=__start
 SYMPREFIX=_
+# PR 17739.  Delay checking relocs until after all files have
+# been opened and linker garbage collection has taken place.
+CHECK_RELOCS_AFTER_OPEN_INPUT=yes
+
 GOT=".got          ${RELOCATING-0} : {
   PROVIDE(__GLOBAL_OFFSET_TABLE_ = .);
   *(.got.plt) *(.got) }"
diff --git a/ld/emulparams/shlelf32_linux.sh b/ld/emulparams/shlelf32_linux.sh
index 81aea39..0327e57 100644
--- a/ld/emulparams/shlelf32_linux.sh
+++ b/ld/emulparams/shlelf32_linux.sh
@@ -13,7 +13,9 @@ ALIGNMENT=8
 TEMPLATE_NAME=elf32
 GENERATE_SHLIB_SCRIPT=yes
 GENERATE_PIE_SCRIPT=yes
-
+# PR 17739.  Delay checking relocs until after all files have
+# been opened and linker garbage collection has taken place.
+CHECK_RELOCS_AFTER_OPEN_INPUT=yes
 
 DATA_START_SYMBOLS='PROVIDE (___data = .);'
 
diff --git a/ld/emulparams/shlelf_linux.sh b/ld/emulparams/shlelf_linux.sh
index c14aae2..4e2a581 100644
--- a/ld/emulparams/shlelf_linux.sh
+++ b/ld/emulparams/shlelf_linux.sh
@@ -12,6 +12,9 @@ MACHINE=
 TEMPLATE_NAME=elf32
 GENERATE_SHLIB_SCRIPT=yes
 GENERATE_PIE_SCRIPT=yes
+# PR 17739.  Delay checking relocs until after all files have
+# been opened and linker garbage collection has taken place.
+CHECK_RELOCS_AFTER_OPEN_INPUT=yes
 
 DATA_START_SYMBOLS='PROVIDE (__data_start = .);';
 
diff --git a/ld/emulparams/shlelf_nto.sh b/ld/emulparams/shlelf_nto.sh
index 16f6508..f8ffc13 100644
--- a/ld/emulparams/shlelf_nto.sh
+++ b/ld/emulparams/shlelf_nto.sh
@@ -9,3 +9,6 @@ TEMPLATE_NAME=elf32
 GENERATE_SHLIB_SCRIPT=yes
 TEXT_START_SYMBOLS='_btext = .;'
 ENTRY=_start
+# PR 17739.  Delay checking relocs until after all files have
+# been opened and linker garbage collection has taken place.
+CHECK_RELOCS_AFTER_OPEN_INPUT=yes
-- 
1.7.1