This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA:] Use refcount in SH ELF backend


This patch makes 32-bit SH ELF backend to use refcount. It's
basically copy&paste from the i386 code. There are no new
regressions for cross sh4-unknown-linux-gnu and sh64-any-elf.
I've tested it also in building glibc and gcc in native
sh4-unknown-linux-gnu environment and found no problems.
This patch affects SHMEDIA code for which I can't do enough
tests, so should be checked by SH5 experts.

	kaz
--

2002-06-29  Kaz Kojima  <kkojima@rr.iij4u.or.jp>

	* elf32-sh.c (sh_elf_copy_indirect_symbol): New.
	(create_got_section, allocate_dynrelocs, readonly_dynrelocs):
	Likewise.
	(struct elf_sh_pcrel_relocs_copied): Removed.
	(struct elf_sh_dyn_relocs): New.
	(struct elf_sh_link_hash_entry): Replace pcrel_relocs_copied
	field with dyn_relocs.
	(struct elf_sh_link_hash_table): Add short-cuts to get dynamic
	sections and sym_sec.
	(sh_elf_link_hash_newfunc): Clear dyn_relocs.
	(sh_elf_link_hash_table_create): Clear shorts-cuts and sym_sec.
	(sh_elf_create_dynamic_sections): Use create_got_section instead
	of _bfd_elf_create_got_section.
	(sh_elf_check_relocs): Likewise.
	(sh_elf_create_dynamic_sections): Use short-cuts to the dynamic
	sections.
	(sh_elf_adjust_dynamic_symbol, sh_elf_size_dynamic_sections,
	sh_elf_relocate_section, sh_elf_check_relocs,
	sh_elf_finish_dynamic_symbol, sh_elf_finish_dynamic_sections):
	Likewise.
	(sh_elf_adjust_dynamic_symbol): Handle nocopyreloc. Keep the
	dynamic relocations and avoiding the copy relocation when we
	didn't find any dynamic relocations in the section which has
	contents or is read-only.
	(WILL_CALL_FINISH_DYNAMIC_SYMBOL): New.
	(sh_elf_size_dynamic_sections): Don't reset the size of
	.rela.got section even if dynamic_sections_created flag is off.
	Don't use sh_elf_discard_copies. Scan all input bfd and use
	allocate_dynrelocs. Call readonly_dynrelocs to determine
	whether we need DT_TEXTREL.
	(sh_elf_adjust_dynamic_symbol): Use plt.refcount to determine
	whether the symbol was never referred to.
	(sh_elf_relocate_section): Use WILL_CALL_FINISH_DYNAMIC_SYMBOL.
	(sh_elf_gc_sweep_hook): Fill with the real sweep function.
	(sh_elf_check_relocs): Call create_got_section if the short-cut
	to .got is null. Increment reference counters only instead of
	allocating space on dynamic sections here. Don't conditionalize
	uninitialized got.offset value when marking the symbol as a
	global offset table entry. Keep relocations for symbols satisfied
	by a dynamic library to avoid copy relocations for the symbol.
	Set dynobj field of an elf hash table if needed.
	(sh_elf_finish_dynamic_sections): Handle null section pointer
	correctly.
	(elf_backend_copy_indirect_symbol): Defined.
	(elf_backend_can_refcount): Defined.

Index: elf32-sh.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-sh.c,v
retrieving revision 1.50
diff -u -3 -p -r1.50 elf32-sh.c
--- elf32-sh.c	25 Jun 2002 06:21:52 -0000	1.50
+++ elf32-sh.c	29 Jun 2002 05:26:45 -0000
@@ -56,6 +56,8 @@ static boolean sh_elf_relocate_section
 static bfd_byte *sh_elf_get_relocated_section_contents
   PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *,
 	   bfd_byte *, boolean, asymbol **));
+static void sh_elf_copy_indirect_symbol
+  PARAMS ((struct elf_link_hash_entry *, struct elf_link_hash_entry *));
 static boolean sh_elf_check_relocs
   PARAMS ((bfd *, struct bfd_link_info *, asection *,
 	   const Elf_Internal_Rela *));
@@ -75,6 +77,8 @@ static boolean sh_elf_finish_dynamic_sec
 static bfd_reloc_status_type sh_elf_reloc_loop
   PARAMS ((int, bfd *, asection *, bfd_byte *, bfd_vma, asection *,
 	   bfd_vma, bfd_vma));
+static boolean create_got_section
+  PARAMS((bfd *, struct bfd_link_info *));
 static boolean sh_elf_create_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
 static asection * sh_elf_gc_mark_hook
@@ -83,6 +87,10 @@ static asection * sh_elf_gc_mark_hook
 static boolean sh_elf_gc_sweep_hook
   PARAMS ((bfd *, struct bfd_link_info *, asection *,
 	   const Elf_Internal_Rela *));
+static boolean allocate_dynrelocs
+  PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean readonly_dynrelocs
+  PARAMS ((struct elf_link_hash_entry *, PTR));
 static enum elf_reloc_type_class sh_elf_reloc_type_class
   PARAMS ((const Elf_Internal_Rela *));
 #ifdef INCLUDE_SHMEDIA
@@ -3432,22 +3440,23 @@ static const bfd_byte *elf_sh_pic_plt_en
 #endif
 
 /* The sh linker needs to keep track of the number of relocs that it
-   decides to copy in check_relocs for each symbol.  This is so that
-   it can discard PC relative relocs if it doesn't need them when
-   linking with -Bsymbolic.  We store the information in a field
-   extending the regular ELF linker hash table.  */
-
-/* This structure keeps track of the number of PC relative relocs we
-   have copied for a given symbol.  */
-
-struct elf_sh_pcrel_relocs_copied
-{
-  /* Next section.  */
-  struct elf_sh_pcrel_relocs_copied *next;
-  /* A section in dynobj.  */
-  asection *section;
-  /* Number of relocs copied in this section.  */
+   decides to copy as dynamic relocs in check_relocs for each symbol.
+   This is so that it can later discard them if they are found to be
+   unnecessary.  We store the information in a field extending the
+   regular ELF linker hash table.  */
+
+struct elf_sh_dyn_relocs
+{
+  struct elf_sh_dyn_relocs *next;
+
+  /* The input section of the reloc.  */
+  asection *sec;
+
+  /* Total number of relocs copied for the input section.  */
   bfd_size_type count;
+
+  /* Number of pc-relative relocs copied for the input section.  */
+  bfd_size_type pc_count;
 };
 
 /* sh ELF linker hash entry.  */
@@ -3460,8 +3469,8 @@ struct elf_sh_link_hash_entry
   bfd_vma datalabel_got_offset;
 #endif
 
-  /* Number of PC relative relocs copied for this symbol.  */
-  struct elf_sh_pcrel_relocs_copied *pcrel_relocs_copied;
+  /* Track dynamic relocs copied for this symbol.  */
+  struct elf_sh_dyn_relocs *dyn_relocs;
 };
 
 /* sh ELF linker hash table.  */
@@ -3469,12 +3478,19 @@ struct elf_sh_link_hash_entry
 struct elf_sh_link_hash_table
 {
   struct elf_link_hash_table root;
-};
 
-/* Declare this now that the above structures are defined.  */
+  /* Short-cuts to get to dynamic linker sections.  */
+  asection *sgot;
+  asection *sgotplt;
+  asection *srelgot;
+  asection *splt;
+  asection *srelplt;
+  asection *sdynbss;
+  asection *srelbss;
 
-static boolean sh_elf_discard_copies
-  PARAMS ((struct elf_sh_link_hash_entry *, PTR));
+  /* Small local sym to section mapping cache.  */
+  struct sym_sec_cache sym_sec;
+};
 
 /* Traverse an sh ELF linker hash table.  */
 
@@ -3515,7 +3531,10 @@ sh_elf_link_hash_newfunc (entry, table, 
 				     table, string));
   if (ret != (struct elf_sh_link_hash_entry *) NULL)
     {
-      ret->pcrel_relocs_copied = NULL;
+      struct elf_sh_link_hash_entry *eh;
+
+      eh = (struct elf_sh_link_hash_entry *) ret;
+      eh->dyn_relocs = NULL;
 #ifdef INCLUDE_SHMEDIA
       ret->datalabel_got_offset = (bfd_vma) -1;
 #endif
@@ -3544,9 +3563,51 @@ sh_elf_link_hash_table_create (abfd)
       return NULL;
     }
 
+  ret->sgot = NULL;
+  ret->sgotplt = NULL;
+  ret->srelgot = NULL;
+  ret->splt = NULL;
+  ret->srelplt = NULL;
+  ret->sdynbss = NULL;
+  ret->srelbss = NULL;
+  ret->sym_sec.abfd = NULL;
+
   return &ret->root.root;
 }
 
+/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up
+   shortcuts to them in our hash table.  */
+
+static boolean
+create_got_section (dynobj, info)
+     bfd *dynobj;
+     struct bfd_link_info *info;
+{
+  struct elf_sh_link_hash_table *htab;
+
+  if (! _bfd_elf_create_got_section (dynobj, info))
+    return false;
+
+  htab = sh_elf_hash_table (info);
+  htab->sgot = bfd_get_section_by_name (dynobj, ".got");
+  htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
+  if (! htab->sgot || ! htab->sgotplt)
+    abort ();
+
+  htab->srelgot = bfd_make_section (dynobj, ".rela.got");
+  if (htab->srelgot == NULL
+      || ! bfd_set_section_flags (dynobj, htab->srelgot,
+				  (SEC_ALLOC
+				   | SEC_LOAD
+				   | SEC_HAS_CONTENTS
+				   | SEC_IN_MEMORY
+				   | SEC_LINKER_CREATED
+				   | SEC_READONLY))
+      || ! bfd_set_section_alignment (dynobj, htab->srelgot, 2))
+    return false;
+  return true;
+}
+
 /* Create dynamic sections when linking against a dynamic object.  */
 
 static boolean
@@ -3554,6 +3615,7 @@ sh_elf_create_dynamic_sections (abfd, in
      bfd *abfd;
      struct bfd_link_info *info;
 {
+  struct elf_sh_link_hash_table *htab;
   flagword flags, pltflags;
   register asection *s;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
@@ -3574,6 +3636,8 @@ sh_elf_create_dynamic_sections (abfd, in
       return false;
     }
 
+  htab = sh_elf_hash_table (info);
+
   /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
      .rel[a].bss sections.  */
 
@@ -3588,6 +3652,7 @@ sh_elf_create_dynamic_sections (abfd, in
     pltflags |= SEC_READONLY;
 
   s = bfd_make_section (abfd, ".plt");
+  htab->splt = s;
   if (s == NULL
       || ! bfd_set_section_flags (abfd, s, pltflags)
       || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
@@ -3614,12 +3679,13 @@ sh_elf_create_dynamic_sections (abfd, in
 
   s = bfd_make_section (abfd,
 			bed->default_use_rela_p ? ".rela.plt" : ".rel.plt");
+  htab->srelplt = s;
   if (s == NULL
       || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
       || ! bfd_set_section_alignment (abfd, s, ptralign))
     return false;
 
-  if (! _bfd_elf_create_got_section (abfd, info))
+  if (! create_got_section (abfd, info))
     return false;
 
   {
@@ -3655,6 +3721,7 @@ sh_elf_create_dynamic_sections (abfd, in
 	 initialize them at run time.  The linker script puts the .dynbss
 	 section into the .bss section of the final image.  */
       s = bfd_make_section (abfd, ".dynbss");
+      htab->sdynbss = s;
       if (s == NULL
 	  || ! bfd_set_section_flags (abfd, s, SEC_ALLOC))
 	return false;
@@ -3675,6 +3742,7 @@ sh_elf_create_dynamic_sections (abfd, in
 	  s = bfd_make_section (abfd,
 				(bed->default_use_rela_p
 				 ? ".rela.bss" : ".rel.bss"));
+	  htab->srelbss = s;
 	  if (s == NULL
 	      || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
 	      || ! bfd_set_section_alignment (abfd, s, ptralign))
@@ -3696,6 +3764,9 @@ sh_elf_adjust_dynamic_symbol (info, h)
      struct bfd_link_info *info;
      struct elf_link_hash_entry *h;
 {
+  struct elf_sh_link_hash_table *htab;
+  struct elf_sh_link_hash_entry *eh;
+  struct elf_sh_dyn_relocs *p;
   bfd *dynobj;
   asection *s;
   unsigned int power_of_two;
@@ -3719,66 +3790,26 @@ sh_elf_adjust_dynamic_symbol (info, h)
   if (h->type == STT_FUNC
       || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
     {
-      if (! info->shared
-	  && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
-	  && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0)
+      if (h->plt.refcount <= 0
+	  || (! info->shared
+	      && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
+	      && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0
+	      && h->root.type != bfd_link_hash_undefweak
+	      && h->root.type != bfd_link_hash_undefined))
 	{
 	  /* This case can occur if we saw a PLT reloc in an input
 	     file, but the symbol was never referred to by a dynamic
 	     object.  In such a case, we don't actually need to build
 	     a procedure linkage table, and we can just do a REL32
 	     reloc instead.  */
-	  BFD_ASSERT ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0);
-	  return true;
-	}
-
-      /* Make sure this symbol is output as a dynamic symbol.  */
-      if (h->dynindx == -1)
-	{
-	  if (! bfd_elf32_link_record_dynamic_symbol (info, h))
-	    return false;
-	}
-
-      s = bfd_get_section_by_name (dynobj, ".plt");
-      BFD_ASSERT (s != NULL);
-
-      /* If this is the first .plt entry, make room for the special
-	 first entry.  */
-      if (s->_raw_size == 0)
-	s->_raw_size += PLT_ENTRY_SIZE;
-
-      /* If this symbol is not defined in a regular file, and we are
-	 not generating a shared library, then set the symbol to this
-	 location in the .plt.  This is required to make function
-	 pointers compare as equal between the normal executable and
-	 the shared library.  */
-      if (! info->shared
-	  && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
-	{
-	  h->root.u.def.section = s;
-	  h->root.u.def.value = s->_raw_size;
+	  h->plt.offset = (bfd_vma) -1;
+	  h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
 	}
 
-      h->plt.offset = s->_raw_size;
-
-      /* Make room for this entry.  */
-      s->_raw_size += elf_sh_sizeof_plt (info);
-
-      /* We also need to make an entry in the .got.plt section, which
-	 will be placed in the .got section by the linker script.  */
-
-      s = bfd_get_section_by_name (dynobj, ".got.plt");
-      BFD_ASSERT (s != NULL);
-      s->_raw_size += 4;
-
-      /* We also need to make an entry in the .rela.plt section.  */
-
-      s = bfd_get_section_by_name (dynobj, ".rela.plt");
-      BFD_ASSERT (s != NULL);
-      s->_raw_size += sizeof (Elf32_External_Rela);
-
       return true;
     }
+  else
+    h->plt.offset = (bfd_vma) -1;
 
   /* If this is a weak symbol, and there is a real definition, the
      processor independent code will have arranged for us to see the
@@ -3807,6 +3838,30 @@ sh_elf_adjust_dynamic_symbol (info, h)
   if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0)
     return true;
 
+  /* If -z nocopyreloc was given, we won't generate them either.  */
+  if (info->nocopyreloc)
+    {
+      h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF;
+      return true;
+    }
+
+  eh = (struct elf_sh_link_hash_entry *) h;
+  for (p = eh->dyn_relocs; p != NULL; p = p->next)
+    {
+      s = p->sec->output_section;
+      if (s != NULL && (s->flags & (SEC_READONLY | SEC_HAS_CONTENTS)) != 0)
+	break;
+    }
+
+  /* If we didn't find any dynamic relocs in sections which needs the
+     copy reloc, then we'll be keeping the dynamic relocs and avoiding
+     the copy reloc.  */ 
+  if (p == NULL)
+    {
+      h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF;
+      return true;
+    }
+
   /* We must allocate the symbol in our .dynbss section, which will
      become part of the .bss section of the executable.  There will be
      an entry for this symbol in the .dynsym section.  The dynamic
@@ -3817,7 +3872,8 @@ sh_elf_adjust_dynamic_symbol (info, h)
      both the dynamic object and the regular object will refer to the
      same memory location for the variable.  */
 
-  s = bfd_get_section_by_name (dynobj, ".dynbss");
+  htab = sh_elf_hash_table (info);
+  s = htab->sdynbss;
   BFD_ASSERT (s != NULL);
 
   /* We must generate a R_SH_COPY reloc to tell the dynamic linker to
@@ -3828,7 +3884,7 @@ sh_elf_adjust_dynamic_symbol (info, h)
     {
       asection *srel;
 
-      srel = bfd_get_section_by_name (dynobj, ".rela.bss");
+      srel = htab->srelbss;
       BFD_ASSERT (srel != NULL);
       srel->_raw_size += sizeof (Elf32_External_Rela);
       h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY;
@@ -3859,6 +3915,236 @@ sh_elf_adjust_dynamic_symbol (info, h)
   return true;
 }
 
+/* This is the condition under which sh_elf_finish_dynamic_symbol
+   will be called from elflink.h.  If elflink.h doesn't call our
+   finish_dynamic_symbol routine, we'll need to do something about
+   initializing any .plt and .got entries in sh_elf_relocate_section.  */
+#define WILL_CALL_FINISH_DYNAMIC_SYMBOL(DYN, INFO, H) \
+  ((DYN)								\
+   && ((INFO)->shared							\
+       || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)	\
+   && ((H)->dynindx != -1						\
+       || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0))
+
+/* Allocate space in .plt, .got and associated reloc sections for
+   dynamic relocs.  */
+
+static boolean
+allocate_dynrelocs (h, inf)
+     struct elf_link_hash_entry *h;
+     PTR inf;
+{
+  struct bfd_link_info *info;
+  struct elf_sh_link_hash_table *htab;
+  struct elf_sh_link_hash_entry *eh;
+  struct elf_sh_dyn_relocs *p;
+
+  if (h->root.type == bfd_link_hash_indirect)
+    return true;
+
+  if (h->root.type == bfd_link_hash_warning)
+    /* When warning symbols are created, they **replace** the "real"
+       entry in the hash table, thus we never get to see the real
+       symbol in a hash traversal.  So look at it now.  */
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+  info = (struct bfd_link_info *) inf;
+  htab = sh_elf_hash_table (info);
+
+  if (htab->root.dynamic_sections_created
+      && h->plt.refcount > 0)
+    {
+      /* Make sure this symbol is output as a dynamic symbol.
+	 Undefined weak syms won't yet be marked as dynamic.  */
+      if (h->dynindx == -1
+	  && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+	{
+	  if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+	    return false;
+	}
+
+      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info, h))
+	{
+	  asection *s = htab->splt;
+
+	  /* If this is the first .plt entry, make room for the special
+	     first entry.  */
+	  if (s->_raw_size == 0)
+	    s->_raw_size += PLT_ENTRY_SIZE;
+
+	  h->plt.offset = s->_raw_size;
+
+	  /* If this symbol is not defined in a regular file, and we are
+	     not generating a shared library, then set the symbol to this
+	     location in the .plt.  This is required to make function
+	     pointers compare as equal between the normal executable and
+	     the shared library.  */
+	  if (! info->shared
+	      && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+	    {
+	      h->root.u.def.section = s;
+	      h->root.u.def.value = h->plt.offset;
+	    }
+
+	  /* Make room for this entry.  */
+	  s->_raw_size += PLT_ENTRY_SIZE;
+
+	  /* We also need to make an entry in the .got.plt section, which
+	     will be placed in the .got section by the linker script.  */
+	  htab->sgotplt->_raw_size += 4;
+
+	  /* We also need to make an entry in the .rel.plt section.  */
+	  htab->srelplt->_raw_size += sizeof (Elf32_External_Rela);
+	}
+      else
+	{
+	  h->plt.offset = (bfd_vma) -1;
+	  h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+	}
+    }
+  else
+    {
+      h->plt.offset = (bfd_vma) -1;
+      h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+    }
+
+  if (h->got.refcount > 0)
+    {
+      asection *s;
+      boolean dyn;
+
+      /* Make sure this symbol is output as a dynamic symbol.
+	 Undefined weak syms won't yet be marked as dynamic.  */
+      if (h->dynindx == -1
+	  && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+	{
+	  if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+	    return false;
+	}
+
+      s = htab->sgot;
+#ifdef INCLUDE_SHMEDIA
+      if (h->type == STT_DATALABEL)
+	{
+	  struct elf_sh_link_hash_entry *hsh;
+
+	  h = (struct elf_link_hash_entry *) h->root.u.i.link;
+	  hsh = (struct elf_sh_link_hash_entry *)h;
+	  hsh->datalabel_got_offset = s->_raw_size;
+	}
+      else
+	h->got.offset = s->_raw_size;
+#else
+      h->got.offset = s->_raw_size;
+#endif
+      s->_raw_size += 4;
+      dyn = htab->root.dynamic_sections_created;
+      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h))
+	htab->srelgot->_raw_size += sizeof (Elf32_External_Rela);
+    }
+  else
+    h->got.offset = (bfd_vma) -1;
+
+  eh = (struct elf_sh_link_hash_entry *) h;
+  if (eh->dyn_relocs == NULL)
+    return true;
+
+  /* In the shared -Bsymbolic case, discard space allocated for
+     dynamic pc-relative relocs against symbols which turn out to be
+     defined in regular objects.  For the normal shared case, discard
+     space for pc-relative relocs that have become local due to symbol
+     visibility changes.  */
+
+  if (info->shared)
+    {
+      if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0
+	  && ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0
+	      || info->symbolic))
+	{
+	  struct elf_sh_dyn_relocs **pp;
+
+	  for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+	    {
+	      p->count -= p->pc_count;
+	      p->pc_count = 0;
+	      if (p->count == 0)
+		*pp = p->next;
+	      else
+		pp = &p->next;
+	    }
+	}
+    }
+  else
+    {
+      /* For the non-shared case, discard space for relocs against
+	 symbols which turn out to need copy relocs or are not
+	 dynamic.  */
+
+      if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0
+	  && (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+	       && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+	      || (htab->root.dynamic_sections_created
+		  && (h->root.type == bfd_link_hash_undefweak
+		      || h->root.type == bfd_link_hash_undefined))))
+	{
+	  /* Make sure this symbol is output as a dynamic symbol.
+	     Undefined weak syms won't yet be marked as dynamic.  */
+	  if (h->dynindx == -1
+	      && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+	    {
+	      if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+		return false;
+	    }
+
+	  /* If that succeeded, we know we'll be keeping all the
+	     relocs.  */
+	  if (h->dynindx != -1)
+	    goto keep;
+	}
+
+      eh->dyn_relocs = NULL;
+
+    keep: ;
+    }
+
+  /* Finally, allocate space.  */
+  for (p = eh->dyn_relocs; p != NULL; p = p->next)
+    {
+      asection *sreloc = elf_section_data (p->sec)->sreloc;
+      sreloc->_raw_size += p->count * sizeof (Elf32_External_Rela);
+    }
+
+  return true;
+}
+
+/* Find any dynamic relocs that apply to read-only sections.  */
+
+static boolean
+readonly_dynrelocs (h, inf)
+     struct elf_link_hash_entry *h;
+     PTR inf;
+{
+  struct elf_sh_link_hash_entry *eh;
+  struct elf_sh_dyn_relocs *p;
+
+  eh = (struct elf_sh_link_hash_entry *) h;
+  for (p = eh->dyn_relocs; p != NULL; p = p->next)
+    {
+      asection *s = p->sec->output_section;
+
+      if (s != NULL && (s->flags & SEC_READONLY) != 0)
+	{
+	  struct bfd_link_info *info = (struct bfd_link_info *) inf;
+
+	  info->flags |= DF_TEXTREL;
+
+	  /* Not an error, just cut short the traversal.  */
+	  return false;
+	}
+    }
+  return true;
+}
+
 /* Set the sizes of the dynamic sections.  */
 
 static boolean
@@ -3866,11 +4152,13 @@ sh_elf_size_dynamic_sections (output_bfd
      bfd *output_bfd ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
 {
+  struct elf_sh_link_hash_table *htab;
   bfd *dynobj;
   asection *s;
-  boolean plt;
   boolean relocs;
+  bfd *ibfd;
 
+  htab = sh_elf_hash_table (info);
   dynobj = elf_hash_table (info)->dynobj;
   BFD_ASSERT (dynobj != NULL);
 
@@ -3885,102 +4173,131 @@ sh_elf_size_dynamic_sections (output_bfd
 	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
 	}
     }
-  else
-    {
-      /* We may have created entries in the .rela.got section.
-	 However, if we are not creating the dynamic sections, we will
-	 not actually use these entries.  Reset the size of .rela.got,
-	 which will cause it to get stripped from the output file
-	 below.  */
-      s = bfd_get_section_by_name (dynobj, ".rela.got");
-      if (s != NULL)
-	s->_raw_size = 0;
-    }
-
-  /* If this is a -Bsymbolic shared link, then we need to discard all
-     PC relative relocs against symbols defined in a regular object.
-     We allocated space for them in the check_relocs routine, but we
-     will not fill them in in the relocate_section routine.  */
-  if (info->shared && info->symbolic)
-    sh_elf_link_hash_traverse (sh_elf_hash_table (info),
-			       sh_elf_discard_copies,
-			       (PTR) NULL);
-
-  /* The check_relocs and adjust_dynamic_symbol entry points have
-     determined the sizes of the various dynamic sections.  Allocate
-     memory for them.  */
-  plt = false;
-  relocs = false;
-  for (s = dynobj->sections; s != NULL; s = s->next)
-    {
-      const char *name;
-      boolean strip;
 
-      if ((s->flags & SEC_LINKER_CREATED) == 0)
-	continue;
-
-      /* It's OK to base decisions on the section name, because none
-	 of the dynobj section names depend upon the input files.  */
-      name = bfd_get_section_name (dynobj, s);
+  /* Set up .got offsets for local syms, and space for local dynamic
+     relocs.  */
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    {
+      bfd_signed_vma *local_got;
+      bfd_signed_vma *end_local_got;
+      bfd_size_type locsymcount;
+      Elf_Internal_Shdr *symtab_hdr;
+      asection *srel;
 
-      strip = false;
+      if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+	continue;
 
-      if (strcmp (name, ".plt") == 0)
+      for (s = ibfd->sections; s != NULL; s = s->next)
 	{
-	  if (s->_raw_size == 0)
-	    {
-	      /* Strip this section if we don't need it; see the
-		 comment below.  */
-	      strip = true;
-	    }
-	  else
+	  struct elf_sh_dyn_relocs *p;
+
+	  for (p = *((struct elf_sh_dyn_relocs **)
+		     &elf_section_data (s)->local_dynrel);
+	       p != NULL;
+	       p = p->next)
 	    {
-	      /* Remember whether there is a PLT.  */
-	      plt = true;
+	      if (! bfd_is_abs_section (p->sec)
+		  && bfd_is_abs_section (p->sec->output_section))
+		{
+		  /* Input section has been discarded, either because
+		     it is a copy of a linkonce section or due to
+		     linker script /DISCARD/, so we'll be discarding
+		     the relocs too.  */
+		}
+	      else if (p->count != 0)
+		{
+		  srel = elf_section_data (p->sec)->sreloc;
+		  srel->_raw_size += p->count * sizeof (Elf32_External_Rela);
+		  if ((p->sec->output_section->flags & SEC_READONLY) != 0)
+		    info->flags |= DF_TEXTREL;
+		}
 	    }
 	}
-      else if (strncmp (name, ".rela", 5) == 0)
+
+      local_got = elf_local_got_refcounts (ibfd);
+      if (!local_got)
+	continue;
+
+      symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
+      locsymcount = symtab_hdr->sh_info;
+#ifdef INCLUDE_SHMEDIA
+      /* Count datalabel local GOT.  */
+      locsymcount *= 2;
+#endif
+      end_local_got = local_got + locsymcount;
+      s = htab->sgot;
+      srel = htab->srelgot;
+      for (; local_got < end_local_got; ++local_got)
 	{
-	  if (s->_raw_size == 0)
+	  if (*local_got > 0)
 	    {
-	      /* If we don't need this section, strip it from the
-		 output file.  This is mostly to handle .rela.bss and
-		 .rela.plt.  We must create both sections in
-		 create_dynamic_sections, because they must be created
-		 before the linker maps input sections to output
-		 sections.  The linker does that before
-		 adjust_dynamic_symbol is called, and it is that
-		 function which decides whether anything needs to go
-		 into these sections.  */
-	      strip = true;
+	      *local_got = s->_raw_size;
+	      s->_raw_size += 4;
+	      if (info->shared)
+		srel->_raw_size += sizeof (Elf32_External_Rela);
 	    }
 	  else
-	    {
-	      /* Remember whether there are any reloc sections other
-		 than .rela.plt.  */
-	      if (strcmp (name, ".rela.plt") != 0)
-		relocs = true;
+	    *local_got = (bfd_vma) -1;
+	}
+    }
 
-	      /* We use the reloc_count field as a counter if we need
-		 to copy relocs into the output file.  */
-	      s->reloc_count = 0;
-	    }
+  /* Allocate global sym .plt and .got entries, and space for global
+     sym dynamic relocs.  */
+  elf_link_hash_traverse (&htab->root, allocate_dynrelocs, (PTR) info);
+
+  /* We now have determined the sizes of the various dynamic sections.
+     Allocate memory for them.  */
+  relocs = false;
+  for (s = dynobj->sections; s != NULL; s = s->next)
+    {
+      if ((s->flags & SEC_LINKER_CREATED) == 0)
+	continue;
+
+      if (s == htab->splt
+	  || s == htab->sgot
+	  || s == htab->sgotplt)
+	{
+	  /* Strip this section if we don't need it; see the
+	     comment below.  */
 	}
-      else if (strncmp (name, ".got", 4) != 0)
+      else if (strncmp (bfd_get_section_name (dynobj, s), ".rela", 5) == 0)
+	{
+	  if (s->_raw_size != 0 && s != htab->srelplt)
+	    relocs = true;
+
+	  /* We use the reloc_count field as a counter if we need
+	     to copy relocs into the output file.  */
+	  s->reloc_count = 0;
+	}
+      else
 	{
 	  /* It's not one of our sections, so don't allocate space.  */
 	  continue;
 	}
 
-      if (strip)
+      if (s->_raw_size == 0)
 	{
+	  /* If we don't need this section, strip it from the
+	     output file.  This is mostly to handle .rel.bss and
+	     .rela.plt.  We must create both sections in
+	     create_dynamic_sections, because they must be created
+	     before the linker maps input sections to output
+	     sections.  The linker does that before
+	     adjust_dynamic_symbol is called, and it is that
+	     function which decides whether anything needs to go
+	     into these sections.  */
+
 	  _bfd_strip_section_from_output (info, s);
 	  continue;
 	}
 
-      /* Allocate memory for the section contents.  */
-      s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size);
-      if (s->contents == NULL && s->_raw_size != 0)
+      /* Allocate memory for the section contents.  We use bfd_zalloc
+	 here in case unused entries are not reclaimed before the
+	 section's contents are written out.  This should not happen,
+	 but this way if it does, we get a R_SH_NONE reloc instead
+	 of garbage.  */
+      s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size);
+      if (s->contents == NULL)
 	return false;
     }
 
@@ -3996,64 +4313,44 @@ sh_elf_size_dynamic_sections (output_bfd
 
       if (! info->shared)
 	{
-	  if (!add_dynamic_entry (DT_DEBUG, 0))
+	  if (! add_dynamic_entry (DT_DEBUG, 0))
 	    return false;
 	}
 
-      if (plt)
+      if (htab->splt->_raw_size != 0)
 	{
-	  if (!add_dynamic_entry (DT_PLTGOT, 0)
-	      || !add_dynamic_entry (DT_PLTRELSZ, 0)
-	      || !add_dynamic_entry (DT_PLTREL, DT_RELA)
-	      || !add_dynamic_entry (DT_JMPREL, 0))
+	  if (! add_dynamic_entry (DT_PLTGOT, 0)
+	      || ! add_dynamic_entry (DT_PLTRELSZ, 0)
+	      || ! add_dynamic_entry (DT_PLTREL, DT_RELA)
+	      || ! add_dynamic_entry (DT_JMPREL, 0))
 	    return false;
 	}
 
       if (relocs)
 	{
-	  if (!add_dynamic_entry (DT_RELA, 0)
-	      || !add_dynamic_entry (DT_RELASZ, 0)
-	      || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela)))
+	  if (! add_dynamic_entry (DT_RELA, 0)
+	      || ! add_dynamic_entry (DT_RELASZ, 0)
+	      || ! add_dynamic_entry (DT_RELAENT,
+				      sizeof (Elf32_External_Rela)))
 	    return false;
-	}
 
-      if ((info->flags & DF_TEXTREL) != 0)
-	{
-	  if (!add_dynamic_entry (DT_TEXTREL, 0))
-	    return false;
+	  /* If any dynamic relocs apply to a read-only section,
+	     then we need a DT_TEXTREL entry.  */
+	  if ((info->flags & DF_TEXTREL) == 0)
+	    elf_link_hash_traverse (&htab->root, readonly_dynrelocs,
+				    (PTR) info);
+
+	  if ((info->flags & DF_TEXTREL) != 0)
+	    {
+	      if (! add_dynamic_entry (DT_TEXTREL, 0))
+		return false;
+	    }
 	}
     }
 #undef add_dynamic_entry
 
   return true;
 }
-
-/* This function is called via sh_elf_link_hash_traverse if we are
-   creating a shared object with -Bsymbolic.  It discards the space
-   allocated to copy PC relative relocs against symbols which are
-   defined in regular objects.  We allocated space for them in the
-   check_relocs routine, but we won't fill them in in the
-   relocate_section routine.  */
-
-static boolean
-sh_elf_discard_copies (h, ignore)
-     struct elf_sh_link_hash_entry *h;
-     PTR ignore ATTRIBUTE_UNUSED;
-{
-  struct elf_sh_pcrel_relocs_copied *s;
-
-  if (h->root.root.type == bfd_link_hash_warning)
-    h = (struct elf_sh_link_hash_entry *) h->root.root.u.i.link;
-
-  /* We only discard relocs for symbols defined in a regular object.  */
-  if ((h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
-    return true;
-
-  for (s = h->pcrel_relocs_copied; s != NULL; s = s->next)
-    s->section->_raw_size -= s->count * sizeof (Elf32_External_Rela);
-
-  return true;
-}
 
 /* Relocate an SH ELF section.  */
 
@@ -4069,6 +4366,7 @@ sh_elf_relocate_section (output_bfd, inf
      Elf_Internal_Sym *local_syms;
      asection **local_sections;
 {
+  struct elf_sh_link_hash_table *htab;
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
   Elf_Internal_Rela *rel, *relend;
@@ -4079,14 +4377,15 @@ sh_elf_relocate_section (output_bfd, inf
   asection *splt;
   asection *sreloc;
 
+  htab = sh_elf_hash_table (info);
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (input_bfd);
   dynobj = elf_hash_table (info)->dynobj;
   local_got_offsets = elf_local_got_offsets (input_bfd);
 
-  sgot = NULL;
-  sgotplt = NULL;
-  splt = NULL;
+  sgot = htab->sgot;
+  sgotplt = htab->sgotplt;
+  splt = htab->splt;
   sreloc = NULL;
 
   rel = relocs;
@@ -4246,6 +4545,9 @@ sh_elf_relocate_section (output_bfd, inf
 	  if (h->root.type == bfd_link_hash_defined
 	      || h->root.type == bfd_link_hash_defweak)
 	    {
+	      boolean dyn;
+
+	      dyn = elf_hash_table (info)->dynamic_sections_created;
 	      sec = h->root.u.def.section;
 	      /* In these cases, we don't need the relocation value.
 		 We check specially because in some obscure cases
@@ -4266,7 +4568,7 @@ sh_elf_relocate_section (output_bfd, inf
 		       || r_type == R_SH_GOT_MEDLOW16
 		       || r_type == R_SH_GOT_MEDHI16
 		       || r_type == R_SH_GOT_HI16)
-		      && elf_hash_table (info)->dynamic_sections_created
+		      && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h)
 		      && (! info->shared
 			  || (! info->symbolic && h->dynindx != -1)
 			  || (h->elf_link_hash_flags
@@ -4281,15 +4583,17 @@ sh_elf_relocate_section (output_bfd, inf
 			  || (h->elf_link_hash_flags
 			      & ELF_LINK_HASH_DEF_REGULAR) == 0)
 		      && ((r_type == R_SH_DIR32
-			   && !(ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
-				|| ELF_ST_VISIBILITY (h->other) == STV_HIDDEN))
+			   && (h->elf_link_hash_flags
+			       & ELF_LINK_FORCED_LOCAL) == 0)
 			  || r_type == R_SH_REL32)
 		      && ((input_section->flags & SEC_ALLOC) != 0
 			  /* DWARF will emit R_SH_DIR32 relocations in its
 			     sections against symbols defined externally
 			     in shared libraries.  We can't do anything
 			     with them here.  */
-			  || (input_section->flags & SEC_DEBUGGING) != 0)))
+			  || ((input_section->flags & SEC_DEBUGGING) != 0
+			      && (h->elf_link_hash_flags
+				  & ELF_LINK_HASH_DEF_DYNAMIC) != 0))))
 		relocation = 0;
 	      else if (sec->output_section == NULL)
 		{
@@ -4312,14 +4616,17 @@ sh_elf_relocate_section (output_bfd, inf
 	  else if (h->root.type == bfd_link_hash_undefweak)
 	    relocation = 0;
 	  else if (info->shared
-	       && (!info->symbolic || info->allow_shlib_undefined)
-	       && !info->no_undefined)
+		   && (! info->symbolic || info->allow_shlib_undefined)
+		   && ! info->no_undefined
+		   && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
 	    relocation = 0;
 	  else
 	    {
 	      if (! ((*info->callbacks->undefined_symbol)
 		     (info, h->root.root.string, input_bfd,
-		      input_section, rel->r_offset, true)))
+		      input_section, rel->r_offset,
+		      (!info->shared || info->no_undefined
+		       || ELF_ST_VISIBILITY (h->other)))))
 		return false;
 	      relocation = 0;
 	    }
@@ -4500,8 +4807,7 @@ sh_elf_relocate_section (output_bfd, inf
 	     procedure linkage table.  */
 
 	  if (h == NULL
-	      || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
-	      || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
+	      || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)
 	      || ! info->shared
 	      || info->symbolic
 	      || h->dynindx == -1
@@ -4511,12 +4817,8 @@ sh_elf_relocate_section (output_bfd, inf
 
 	  /* Relocation is to the entry for this symbol in the global
 	     offset table extension for the procedure linkage table.  */
-	  if (sgotplt == NULL)
-	    {
-	      sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
-	      BFD_ASSERT (sgotplt != NULL);
-	    }
 
+	  BFD_ASSERT (sgotplt != NULL);
 	  relocation = (sgotplt->output_offset
 			+ ((h->plt.offset / elf_sh_sizeof_plt (info)
 			    - 1 + 3) * 4));
@@ -4539,15 +4841,13 @@ sh_elf_relocate_section (output_bfd, inf
 #endif
 	  /* Relocation is to the entry for this symbol in the global
 	     offset table.  */
-	  if (sgot == NULL)
-	    {
-	      sgot = bfd_get_section_by_name (dynobj, ".got");
-	      BFD_ASSERT (sgot != NULL);
-	    }
+
+	  BFD_ASSERT (sgot != NULL);
 
 	  if (h != NULL)
 	    {
 	      bfd_vma off;
+	      boolean dyn;
 
 	      off = h->got.offset;
 #ifdef INCLUDE_SHMEDIA
@@ -4561,11 +4861,11 @@ sh_elf_relocate_section (output_bfd, inf
 #endif
 	      BFD_ASSERT (off != (bfd_vma) -1);
 
-	      if (! elf_hash_table (info)->dynamic_sections_created
+	      dyn = htab->root.dynamic_sections_created;
+	      if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h)
 		  || (info->shared
 		      && (info->symbolic || h->dynindx == -1
-			  || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
-			  || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
+			  || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL))
 		      && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
 		{
 		  /* This is actually a static link, or it is a
@@ -4684,11 +4984,7 @@ sh_elf_relocate_section (output_bfd, inf
 	  /* Relocation is relative to the start of the global offset
 	     table.  */
 
-	  if (sgot == NULL)
-	    {
-	      sgot = bfd_get_section_by_name (dynobj, ".got");
-	      BFD_ASSERT (sgot != NULL);
-	    }
+	  BFD_ASSERT (sgot != NULL);
 
 	  /* Note that sgot->output_offset is not involved in this
 	     calculation.  We always want the start of .got.  If we
@@ -4714,12 +5010,7 @@ sh_elf_relocate_section (output_bfd, inf
 #endif
 	  /* Use global offset table as symbol value.  */
 
-	  if (sgot == NULL)
-	    {
-	      sgot = bfd_get_section_by_name (dynobj, ".got");
-	      BFD_ASSERT (sgot != NULL);
-	    }
-
+	  BFD_ASSERT (sgot != NULL);
 	  relocation = sgot->output_section->vma;
 
 #ifdef GOT_BIAS
@@ -4745,8 +5036,7 @@ sh_elf_relocate_section (output_bfd, inf
 	  if (h == NULL)
 	    goto final_link_relocate;
 
-	  if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
-	      || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
+	  if (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)
 	    goto final_link_relocate;
 
 	  if (h->plt.offset == (bfd_vma) -1)
@@ -4757,12 +5047,7 @@ sh_elf_relocate_section (output_bfd, inf
 	      goto final_link_relocate;
 	    }
 
-	  if (splt == NULL)
-	    {
-	      splt = bfd_get_section_by_name (dynobj, ".plt");
-	      BFD_ASSERT (splt != NULL);
-	    }
-
+	  BFD_ASSERT (splt != NULL);
 	  relocation = (splt->output_section->vma
 			+ splt->output_offset
 			+ h->plt.offset);
@@ -5020,18 +5305,185 @@ sh_elf_gc_mark_hook (abfd, info, rel, h,
 
 static boolean
 sh_elf_gc_sweep_hook (abfd, info, sec, relocs)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
-     asection *sec ATTRIBUTE_UNUSED;
-     const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection *sec;
+     const Elf_Internal_Rela *relocs;
 {
-  /* We use got and plt entries for sh, but it would seem that the
-     existing SH code does no sort of reference counting or whatnot on
-     its GOT and PLT entries, so it is not possible to garbage collect
-     them at this time.  */
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  bfd_signed_vma *local_got_refcounts;
+  const Elf_Internal_Rela *rel, *relend;
+  unsigned long r_symndx;
+  struct elf_link_hash_entry *h;
+
+  elf_section_data (sec)->local_dynrel = NULL;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+  local_got_refcounts = elf_local_got_refcounts (abfd);
+
+  relend = relocs + sec->reloc_count;
+  for (rel = relocs; rel < relend; rel++)
+    switch (ELF32_R_TYPE (rel->r_info))
+      {
+      case R_SH_GOT32:
+      case R_SH_GOTOFF:
+      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
+	r_symndx = ELF32_R_SYM (rel->r_info);
+	if (r_symndx >= symtab_hdr->sh_info)
+	  {
+	    h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+	    if (h->got.refcount > 0)
+	      h->got.refcount -= 1;
+	  }
+	else if (local_got_refcounts != NULL)
+	  {
+	    if (local_got_refcounts[r_symndx] > 0)
+	      local_got_refcounts[r_symndx] -= 1;
+	  }
+	break;
+
+      case R_SH_DIR32:
+      case R_SH_REL32:
+	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];
+
+	    if (!info->shared && h->plt.refcount > 0)
+	      h->plt.refcount -= 1;
+
+	    eh = (struct elf_sh_link_hash_entry *) h;
+
+	    for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
+	      if (p->sec == sec)
+		{
+		  if (ELF32_R_TYPE (rel->r_info) == R_SH_REL32)
+		    p->pc_count -= 1;
+		  p->count -= 1;
+		  if (p->count == 0)
+		    *pp = p->next;
+		  break;
+		}
+	  }
+	break;
+
+      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
+	r_symndx = ELF32_R_SYM (rel->r_info);
+	if (r_symndx >= symtab_hdr->sh_info)
+	  {
+	    h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+	    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
+	r_symndx = ELF32_R_SYM (rel->r_info);
+	if (r_symndx >= symtab_hdr->sh_info)
+	  {
+	    h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+	    if (h->got.refcount > 0)
+	      h->got.refcount -= 1;
+	    if (h->plt.refcount > 0)
+	      h->plt.refcount -= 1;
+	  }
+	else if (local_got_refcounts != NULL)
+	  {
+	    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
+sh_elf_copy_indirect_symbol (dir, ind)
+     struct elf_link_hash_entry *dir, *ind;
+{
+  struct elf_sh_link_hash_entry *edir, *eind;
+
+  edir = (struct elf_sh_link_hash_entry *) dir;
+  eind = (struct elf_sh_link_hash_entry *) ind;
+
+  if (eind->dyn_relocs != NULL)
+    {
+      if (edir->dyn_relocs != NULL)
+	{
+	  struct elf_sh_dyn_relocs **pp;
+	  struct elf_sh_dyn_relocs *p;
+
+	  BFD_ASSERT (ind->root.type != bfd_link_hash_indirect);
+
+	  /* Add reloc counts against the weak sym to the strong sym
+	     list.  Merge any entries against the same section.  */
+	  for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
+	    {
+	      struct elf_sh_dyn_relocs *q;
+
+	      for (q = edir->dyn_relocs; q != NULL; q = q->next)
+		if (q->sec == p->sec)
+		  {
+		    q->pc_count += p->pc_count;
+		    q->count += p->count;
+		    *pp = p->next;
+		    break;
+		  }
+	      if (q == NULL)
+		pp = &p->next;
+	    }
+	  *pp = edir->dyn_relocs;
+	}
+
+      edir->dyn_relocs = eind->dyn_relocs;
+      eind->dyn_relocs = NULL;
+    }
+
+  _bfd_elf_link_hash_copy_indirect (dir, ind);
+}
+
 /* Look through the relocs for a section during the first phase.
    Since we don't do .gots or .plts, we just need to consider the
    virtual table relocs for gc.  */
@@ -5045,6 +5497,7 @@ sh_elf_check_relocs (abfd, info, sec, re
 {
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+  struct elf_sh_link_hash_table *htab;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
   bfd *dynobj;
@@ -5066,7 +5519,8 @@ sh_elf_check_relocs (abfd, info, sec, re
   if (!elf_bad_symtab (abfd))
     sym_hashes_end -= symtab_hdr->sh_info;
 
-  dynobj = elf_hash_table (info)->dynobj;
+  htab = sh_elf_hash_table (info);
+  dynobj =  elf_hash_table (info)->dynobj;
   local_got_offsets = elf_local_got_offsets (abfd);
 
   rel_end = relocs + sec->reloc_count;
@@ -5082,7 +5536,7 @@ sh_elf_check_relocs (abfd, info, sec, re
 	h = sym_hashes[r_symndx - symtab_hdr->sh_info];
 
       /* Some relocs require a global offset table.  */
-      if (dynobj == NULL)
+      if (htab->sgot == NULL)
 	{
 	  switch (ELF32_R_TYPE (rel->r_info))
 	    {
@@ -5112,8 +5566,9 @@ sh_elf_check_relocs (abfd, info, sec, re
 	    case R_SH_GOTPC_MEDHI16:
 	    case R_SH_GOTPC_HI16:
 #endif
-	      elf_hash_table (info)->dynobj = dynobj = abfd;
-	      if (! _bfd_elf_create_got_section (dynobj, info))
+	      if (dynobj == NULL)
+		elf_hash_table (info)->dynobj = dynobj = abfd;
+	      if (! create_got_section (dynobj, info))
 		return false;
 	      break;
 
@@ -5148,133 +5603,34 @@ sh_elf_check_relocs (abfd, info, sec, re
 	case R_SH_GOT10BY4:
 	case R_SH_GOT10BY8:
 #endif
-	  /* This symbol requires a global offset table entry.  */
-
-	  if (sgot == NULL)
-	    {
-	      sgot = bfd_get_section_by_name (dynobj, ".got");
-	      BFD_ASSERT (sgot != NULL);
-	    }
-
-	  if (srelgot == NULL
-	      && (h != NULL || info->shared))
-	    {
-	      srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
-	      if (srelgot == NULL)
-		{
-		  srelgot = bfd_make_section (dynobj, ".rela.got");
-		  if (srelgot == NULL
-		      || ! bfd_set_section_flags (dynobj, srelgot,
-						  (SEC_ALLOC
-						   | SEC_LOAD
-						   | SEC_HAS_CONTENTS
-						   | SEC_IN_MEMORY
-						   | SEC_LINKER_CREATED
-						   | SEC_READONLY))
-		      || ! bfd_set_section_alignment (dynobj, srelgot, 2))
-		    return false;
-		}
-	    }
-
 	  if (h != NULL)
-	    {
-#ifdef INCLUDE_SHMEDIA
-	      if (h->type == STT_DATALABEL)
-		{
-		  struct elf_sh_link_hash_entry *hsh;
-
-		  h = (struct elf_link_hash_entry *) h->root.u.i.link;
-		  hsh = (struct elf_sh_link_hash_entry *)h;
-		  if (hsh->datalabel_got_offset != (bfd_vma) -1)
-		    break;
-
-		  hsh->datalabel_got_offset = sgot->_raw_size;
-		}
-	      else
-		{
-#endif
-	      if (h->got.offset != (bfd_vma) -1)
-		{
-		  /* We have already allocated space in the .got.  */
-		  break;
-		}
-	      h->got.offset = sgot->_raw_size;
-#ifdef INCLUDE_SHMEDIA
-		}
-#endif
-
-	      /* Make sure this symbol is output as a dynamic symbol.  */
-	      if (h->dynindx == -1)
-		{
-		  if (! bfd_elf32_link_record_dynamic_symbol (info, h))
-		    return false;
-		}
-
-	      srelgot->_raw_size += sizeof (Elf32_External_Rela);
-	    }
+	    h->got.refcount += 1;
 	  else
 	    {
+	      bfd_signed_vma *local_got_refcounts;
+
 	      /* This is a global offset table entry for a local
-	         symbol.  */
-	      if (local_got_offsets == NULL)
+		 symbol.  */
+	      local_got_refcounts = elf_local_got_refcounts (abfd);
+	      if (local_got_refcounts == NULL)
 		{
 		  bfd_size_type size;
-		  register unsigned int i;
 
 		  size = symtab_hdr->sh_info;
-		  size *= sizeof (bfd_vma);
+		  size *= sizeof (bfd_signed_vma);
 #ifdef INCLUDE_SHMEDIA
 		  /* Reserve space for both the datalabel and
 		     codelabel local GOT offsets.  */
 		  size *= 2;
 #endif
-		  local_got_offsets = (bfd_vma *) bfd_alloc (abfd, size);
-		  if (local_got_offsets == NULL)
+		  local_got_refcounts = ((bfd_signed_vma *)
+					 bfd_zalloc (abfd, size));
+		  if (local_got_refcounts == NULL)
 		    return false;
-		  elf_local_got_offsets (abfd) = local_got_offsets;
-		  for (i = 0; i < symtab_hdr->sh_info; i++)
-		    local_got_offsets[i] = (bfd_vma) -1;
-#ifdef INCLUDE_SHMEDIA
-		  for (; i < 2 * symtab_hdr->sh_info; i++)
-		    local_got_offsets[i] = (bfd_vma) -1;
-#endif
-		}
-#ifdef INCLUDE_SHMEDIA
-	      if ((rel->r_addend & 1) != 0)
-		{
-		  if (local_got_offsets[symtab_hdr->sh_info
-					+ r_symndx] != (bfd_vma) -1)
-		    {
-		      /* We have already allocated space in the .got.  */
-		      break;
-		    }
-		  local_got_offsets[symtab_hdr->sh_info
-				    + r_symndx] = sgot->_raw_size;
-		}
-	      else
-		{
-#endif
-	      if (local_got_offsets[r_symndx] != (bfd_vma) -1)
-		{
-		  /* We have already allocated space in the .got.  */
-		  break;
-		}
-	      local_got_offsets[r_symndx] = sgot->_raw_size;
-#ifdef INCLUDE_SHMEDIA
-		}
-#endif
-
-	      if (info->shared)
-		{
-		  /* If we are generating a shared object, we need to
-		     output a R_SH_RELATIVE reloc so that the dynamic
-		     linker can adjust this GOT entry.  */
-		  srelgot->_raw_size += sizeof (Elf32_External_Rela);
+		  elf_local_got_refcounts (abfd) = local_got_refcounts;
 		}
+	      local_got_refcounts[r_symndx] += 1;
 	    }
-
-	  sgot->_raw_size += 4;
-
 	  break;
 
 	case R_SH_GOTPLT32:
@@ -5290,22 +5646,14 @@ sh_elf_check_relocs (abfd, info, sec, re
 	     creating a procedure linkage table entry.  */
 
 	  if (h == NULL
-	      || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
-	      || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
+	      || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)
 	      || ! info->shared
 	      || info->symbolic
-	      || h->dynindx == -1
-	      || h->got.offset != (bfd_vma) -1)
+	      || h->dynindx == -1)
 	    goto force_got;
 
-	  /* Make sure this symbol is output as a dynamic symbol.  */
-	  if (h->dynindx == -1)
-	    {
-	      if (! bfd_elf32_link_record_dynamic_symbol (info, h))
-		return false;
-	    }
-
 	  h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+	  h->plt.refcount += 1;
 
 	  break;
 
@@ -5328,18 +5676,20 @@ sh_elf_check_relocs (abfd, info, sec, re
 	  if (h == NULL)
 	    continue;
 
-	  if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
-	      || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
+	  if (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)
 	    break;
 
 	  h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
-
+	  h->plt.refcount += 1;
 	  break;
 
 	case R_SH_DIR32:
 	case R_SH_REL32:
-	  if (h != NULL)
-	    h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF;
+	  if (h != NULL && ! info->shared)
+	    {
+	      h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF;
+	      h->plt.refcount += 1;
+	    }
 
 	  /* If we are creating a shared library, and this is a reloc
 	     against a global symbol, or a non PC relative reloc
@@ -5352,15 +5702,35 @@ sh_elf_check_relocs (abfd, info, sec, re
 	     possible that DEF_REGULAR is not set now but will be set
 	     later (it is never cleared).  We account for that
 	     possibility below by storing information in the
-	     pcrel_relocs_copied field of the hash table entry.  */
-	  if (info->shared
-	      && (sec->flags & SEC_ALLOC) != 0
-	      && (ELF32_R_TYPE (rel->r_info) != R_SH_REL32
-		  || (h != NULL
-		      && (! info->symbolic
-			  || (h->elf_link_hash_flags
-			      & ELF_LINK_HASH_DEF_REGULAR) == 0))))
+	     dyn_relocs field of the hash table entry. A similar
+	     situation occurs when creating shared libraries and symbol
+	     visibility changes render the symbol local.
+
+	     If on the other hand, we are creating an executable, we
+	     may need to keep relocations for symbols satisfied by a
+	     dynamic library if we manage to avoid copy relocs for the
+	     symbol.  */
+	  if ((info->shared
+	       && (sec->flags & SEC_ALLOC) != 0
+	       && (ELF32_R_TYPE (rel->r_info) != R_SH_REL32
+		   || (h != NULL
+		       && (! info->symbolic
+			   || h->root.type == bfd_link_hash_defweak
+			   || (h->elf_link_hash_flags
+			       & ELF_LINK_HASH_DEF_REGULAR) == 0))))
+	      || (! info->shared
+		  && (sec->flags & SEC_ALLOC) != 0
+		  && h != NULL
+		  && (h->root.type == bfd_link_hash_defweak
+		      || (h->elf_link_hash_flags
+			  & ELF_LINK_HASH_DEF_REGULAR) == 0)))
 	    {
+	      struct elf_sh_dyn_relocs *p;
+	      struct elf_sh_dyn_relocs **head;
+
+	      if (dynobj == NULL)
+		elf_hash_table (info)->dynobj = dynobj = abfd;
+
 	      /* When creating a shared object, we must copy these
 		 reloc types into the output file.  We create a reloc
 		 section in dynobj and make room for this reloc.  */
@@ -5396,44 +5766,44 @@ sh_elf_check_relocs (abfd, info, sec, re
 		    }
 		  if (sec->flags & SEC_READONLY)
 		    info->flags |= DF_TEXTREL;
+		  elf_section_data (sec)->sreloc = sreloc;
 		}
 
-	      sreloc->_raw_size += sizeof (Elf32_External_Rela);
-
-	      /* If we are linking with -Bsymbolic, and this is a
-		 global symbol, we count the number of PC relative
-		 relocations we have entered for this symbol, so that
-		 we can discard them again if the symbol is later
-		 defined by a regular object.  Note that this function
-		 is only called if we are using an elf_sh linker
-		 hash table, which means that h is really a pointer to
-		 an elf_sh_link_hash_entry.  */
-	      if (h != NULL && info->symbolic
-		  && ELF32_R_TYPE (rel->r_info) == R_SH_REL32)
+	      /* If this is a global symbol, we count the number of
+		 relocations we need for this symbol.  */
+	      if (h != NULL)
+		head = &((struct elf_sh_link_hash_entry *) h)->dyn_relocs;
+	      else
 		{
-		  struct elf_sh_link_hash_entry *eh;
-		  struct elf_sh_pcrel_relocs_copied *p;
+		  asection *s;
 
-		  eh = (struct elf_sh_link_hash_entry *) h;
+		  /* Track dynamic relocs needed for local syms too.  */
+		  s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
+						 sec, r_symndx);
+		  if (s == NULL)
+		    return false;
 
-		  for (p = eh->pcrel_relocs_copied; p != NULL; p = p->next)
-		    if (p->section == sreloc)
-		      break;
+		  head = ((struct elf_sh_dyn_relocs **)
+			  &elf_section_data (s)->local_dynrel);
+		}
 
+	      p = *head;
+	      if (p == NULL || p->sec != sec)
+		{
+		  bfd_size_type amt = sizeof (*p);
+		  p = ((struct elf_sh_dyn_relocs *) bfd_alloc (dynobj, amt));
 		  if (p == NULL)
-		    {
-		      p = ((struct elf_sh_pcrel_relocs_copied *)
-			   bfd_alloc (dynobj, (bfd_size_type) sizeof *p));
-		      if (p == NULL)
-			return false;
-		      p->next = eh->pcrel_relocs_copied;
-		      eh->pcrel_relocs_copied = p;
-		      p->section = sreloc;
-		      p->count = 0;
-		    }
-
-		  ++p->count;
+		    return false;
+		  p->next = *head;
+		  *head = p;
+		  p->sec = sec;
+		  p->count = 0;
+		  p->pc_count = 0;
 		}
+
+	      p->count += 1;
+	      if (ELF32_R_TYPE (rel->r_info) == R_SH_REL32)
+		p->pc_count += 1;
 	    }
 
 	  break;
@@ -5567,8 +5937,10 @@ sh_elf_finish_dynamic_symbol (output_bfd
      struct elf_link_hash_entry *h;
      Elf_Internal_Sym *sym;
 {
+  struct elf_sh_link_hash_table *htab;
   bfd *dynobj;
 
+  htab = sh_elf_hash_table (info);
   dynobj = elf_hash_table (info)->dynobj;
 
   if (h->plt.offset != (bfd_vma) -1)
@@ -5586,9 +5958,9 @@ sh_elf_finish_dynamic_symbol (output_bfd
 
       BFD_ASSERT (h->dynindx != -1);
 
-      splt = bfd_get_section_by_name (dynobj, ".plt");
-      sgot = bfd_get_section_by_name (dynobj, ".got.plt");
-      srel = bfd_get_section_by_name (dynobj, ".rela.plt");
+      splt = htab->splt;
+      sgot = htab->sgotplt;
+      srel = htab->srelplt;
       BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL);
 
       /* Get the index in the procedure linkage table which
@@ -5716,21 +6088,23 @@ sh_elf_finish_dynamic_symbol (output_bfd
       /* This symbol has an entry in the global offset table.  Set it
 	 up.  */
 
-      sgot = bfd_get_section_by_name (dynobj, ".got");
-      srel = bfd_get_section_by_name (dynobj, ".rela.got");
+      sgot = htab->sgot;
+      srel = htab->srelgot;
       BFD_ASSERT (sgot != NULL && srel != NULL);
 
       rel.r_offset = (sgot->output_section->vma
 		      + sgot->output_offset
 		      + (h->got.offset &~ (bfd_vma) 1));
 
-      /* If this is a -Bsymbolic link, and the symbol is defined
-	 locally, we just want to emit a RELATIVE reloc.  Likewise if
-	 the symbol was forced to be local because of a version file.
+      /* If this is a static link, or it is a -Bsymbolic link and the
+	 symbol is defined locally or was forced to be local because
+	 of a version file, we just want to emit a RELATIVE reloc.
 	 The entry in the global offset table will already have been
 	 initialized in the relocate_section function.  */
       if (info->shared
-	  && (info->symbolic || h->dynindx == -1)
+	  && (info->symbolic
+	      || h->dynindx == -1
+	      || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL))
 	  && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
 	{
 	  rel.r_info = ELF32_R_INFO (0, R_SH_RELATIVE);
@@ -5792,14 +6166,15 @@ sh_elf_finish_dynamic_sections (output_b
      bfd *output_bfd;
      struct bfd_link_info *info;
 {
+  struct elf_sh_link_hash_table *htab;
   bfd *dynobj;
   asection *sgot;
   asection *sdyn;
 
+  htab = sh_elf_hash_table (info);
   dynobj = elf_hash_table (info)->dynobj;
 
-  sgot = bfd_get_section_by_name (dynobj, ".got.plt");
-  BFD_ASSERT (sgot != NULL);
+  sgot = htab->sgotplt;
   sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
 
   if (elf_hash_table (info)->dynamic_sections_created)
@@ -5807,14 +6182,13 @@ sh_elf_finish_dynamic_sections (output_b
       asection *splt;
       Elf32_External_Dyn *dyncon, *dynconend;
 
-      BFD_ASSERT (sdyn != NULL);
+      BFD_ASSERT (sgot != NULL && sdyn != NULL);
 
       dyncon = (Elf32_External_Dyn *) sdyn->contents;
       dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
       for (; dyncon < dynconend; dyncon++)
 	{
 	  Elf_Internal_Dyn dyn;
-	  const char *name;
 	  asection *s;
 
 	  bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
@@ -5825,20 +6199,19 @@ sh_elf_finish_dynamic_sections (output_b
 	      break;
 
 	    case DT_PLTGOT:
-	      name = ".got";
+	      s = htab->sgot->output_section;
 	      goto get_vma;
 
 	    case DT_JMPREL:
-	      name = ".rela.plt";
+	      s = htab->srelplt->output_section;
 	    get_vma:
-	      s = bfd_get_section_by_name (output_bfd, name);
 	      BFD_ASSERT (s != NULL);
 	      dyn.d_un.d_ptr = s->vma;
 	      bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
 	      break;
 
 	    case DT_PLTRELSZ:
-	      s = bfd_get_section_by_name (output_bfd, ".rela.plt");
+	      s = htab->srelplt->output_section;
 	      BFD_ASSERT (s != NULL);
 	      if (s->_cooked_size != 0)
 		dyn.d_un.d_val = s->_cooked_size;
@@ -5857,9 +6230,9 @@ sh_elf_finish_dynamic_sections (output_b
 		 the linker script arranges for .rela.plt to follow all
 		 other relocation sections, we don't have to worry
 		 about changing the DT_RELA entry.  */
-	      s = bfd_get_section_by_name (output_bfd, ".rela.plt");
-	      if (s != NULL)
+	      if (htab->srelplt != NULL)
 		{
+		  s = htab->srelplt->output_section;
 		  if (s->_cooked_size != 0)
 		    dyn.d_un.d_val -= s->_cooked_size;
 		  else
@@ -5871,7 +6244,7 @@ sh_elf_finish_dynamic_sections (output_b
 	}
 
       /* Fill in the first entry in the procedure linkage table.  */
-      splt = bfd_get_section_by_name (dynobj, ".plt");
+      splt = htab->splt;
       if (splt && splt->_raw_size > 0)
 	{
 	  if (info->shared)
@@ -5917,7 +6290,7 @@ sh_elf_finish_dynamic_sections (output_b
     }
 
   /* Fill in the first three entries in the global offset table.  */
-  if (sgot->_raw_size > 0)
+  if (sgot && sgot->_raw_size > 0)
     {
       if (sdyn == NULL)
 	bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents);
@@ -5927,9 +6300,9 @@ sh_elf_finish_dynamic_sections (output_b
 		    sgot->contents);
       bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4);
       bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8);
-    }
 
-  elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+      elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+    }
 
   return true;
 }
@@ -5980,8 +6353,8 @@ sh_elf_reloc_type_class (rela)
 #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_can_gc_sections	1
+#define elf_backend_copy_indirect_symbol \
+					sh_elf_copy_indirect_symbol
 #define elf_backend_create_dynamic_sections \
 					sh_elf_create_dynamic_sections
 #define bfd_elf32_bfd_link_hash_table_create \
@@ -5996,6 +6369,8 @@ sh_elf_reloc_type_class (rela)
 					sh_elf_finish_dynamic_sections
 #define elf_backend_reloc_type_class	sh_elf_reloc_type_class
 
+#define elf_backend_can_gc_sections	1
+#define elf_backend_can_refcount	1
 #define elf_backend_want_got_plt	1
 #define elf_backend_plt_readonly	1
 #define elf_backend_want_plt_sym	0


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]