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]

PowerPC64 linker fixes.


PowerPC64-ELF uses a similar scheme to PowerPC64-XCOFF in that
functions have both a function code symbol and a function descriptor
symbol.  A call to foo in a relocatable object file looks like:

	.text
x:
	bl	.foo
	nop

The function definition in another object file might be:

	.section .opd
foo:	.quad	.foo
	.quad	.TOC.@tocbase
	.quad	0

	.text
.foo:	blr

When the linker resolves the call during a static link, the branch
unsurprisingly just goes to .foo and the .opd information is unused.
If the function definition is in a shared library, things are a little
different:  The call goes via a plt call stub, the opd information gets
copied to the plt, and the linker patches the nop.

x:
	bl	.foo_stub
	ld	2,40(1)


.foo_stub:
	addis	12,2,Lfoo@toc@ha	# in practice, the call stub
	addi	12,12,Lfoo@toc@l	# is slightly optimised, but
	std	2,40(1)			# this is the general idea
	ld	11,0(12)
	ld	2,8(12)
	mtctr	11
	ld	11,16(12)
	bctr

	.section .plt
Lfoo:	reloc (R_PPC64_JMP_SLOT, foo)

The "reloc ()" notation is supposed to indicate that the linker emits
an R_PPC64_JMP_SLOT reloc against foo.  The dynamic linker does the opd
copying.

What are the difficulties here?  Well, firstly, the relocations
examined by the linker in check_relocs are against the function code
sym .foo, while the dynamic relocation in the plt is emitted against
the function descriptor symbol, foo.  Somewhere along the line, we need
to carefully copy dynamic link information from one symbol to the other.
Secondly, the generic part of the elf linker will make .foo a dynamic
symbol as is normal for most other backends.  We need foo dynamic
instead, at least for an application final link.  However, when
creating a shared library containing foo, we need to have both symbols
dynamic so that references to .foo are satisfied during the early
stages of linking.  Otherwise the linker might decide to pull in a
definition from some other object, eg. a static library.  Thirdly, we'd
like to use .foo as the stub symbol to avoid creating another symbol.
We need to make sure that when .foo labels a stub in a shared library,
it isn't exported.

bfd/ChangeLog
	* elf64-ppc.c (struct ppc_link_hash_entry): Add is_func and
	is_func_descriptor fields.
	(link_hash_newfunc): Init them.
	(ppc64_elf_check_relocs): Only R_PPC24_REL24 syms starting with a
	dot are candidates for plt entries.  When processing .opd relocs,
	set function descriptor strings to point inside function code
	string, and set new ppc_link_hash_entry fields.
	(ppc64_elf_gc_sweep_hook): Don't sweep R_PPC64_REL24 relocs.
	(ppc64_elf_adjust_dynamic_symbol): Remove most code dealing with
	function descriptors.  It's now done in..
	(func_desc_adjust): New.
	(ppc64_elf_func_desc_adjust): New.
	(define elf_backend_always_size_sections): Define.
	(ppc64_elf_hide_symbol): New.
	(define elf_backend_hide_symbol): Define.
	(allocate_dynrelocs): Remove code looking up function descriptors
	as that has been done earlier.
	(ppc64_elf_size_dynamic_sections): Use htab shortcut to elf hash
	table.
	(ppc64_elf_finish_dynamic_symbol): Likewise.  Remove code looking
	up function descriptor.
	(build_one_stub): Look up the function code sym.  Check for
	invalid plt offsets.
	(ppc64_elf_relocate_section): Tweak calls to undefined weak syms.

After writing the above commentary, I decided it should go into the
source, so that's been added to the patch below.  Applying the lot
to mainline.

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.18
diff -u -p -r1.18 elf64-ppc.c
--- elf64-ppc.c	2002/01/18 01:22:02	1.18
+++ elf64-ppc.c	2002/01/21 08:34:37
@@ -66,8 +66,14 @@ static asection * ppc64_elf_gc_mark_hook
 static boolean ppc64_elf_gc_sweep_hook
   PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *sec,
 	   const Elf_Internal_Rela *relocs));
+static boolean func_desc_adjust
+  PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean ppc64_elf_func_desc_adjust
+  PARAMS ((bfd *, struct bfd_link_info *));
 static boolean ppc64_elf_adjust_dynamic_symbol
   PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
+static void ppc64_elf_hide_symbol
+  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, boolean));
 static boolean allocate_dynrelocs
   PARAMS ((struct elf_link_hash_entry *, PTR));
 static boolean readonly_dynrelocs
@@ -1623,6 +1629,10 @@ struct ppc_link_hash_entry
 
   /* Track dynamic relocs copied for this symbol.  */
   struct ppc_dyn_relocs *dyn_relocs;
+
+  /* Flag function code and descriptor symbols.  */
+  unsigned int is_func:1;
+  unsigned int is_func_descriptor:1;
 };
 
 /* ppc64 ELF linker hash table.  */
@@ -1677,6 +1687,8 @@ link_hash_newfunc (entry, table, string)
       struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) entry;
 
       eh->dyn_relocs = NULL;
+      eh->is_func = 0;
+      eh->is_func_descriptor = 0;
     }
 
   return entry;
@@ -1834,6 +1846,9 @@ ppc64_elf_copy_indirect_symbol (dir, ind
       eind->dyn_relocs = NULL;
     }
 
+  edir->is_func |= eind->is_func;
+  edir->is_func_descriptor |= eind->is_func_descriptor;
+
   _bfd_elf_link_hash_copy_indirect (dir, ind);
 }
 
@@ -1854,6 +1869,7 @@ ppc64_elf_check_relocs (abfd, info, sec,
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
   asection *sreloc;
+  boolean is_opd;
 
   if (info->relocateable)
     return true;
@@ -1868,6 +1884,7 @@ ppc64_elf_check_relocs (abfd, info, sec,
     sym_hashes_end -= symtab_hdr->sh_info;
 
   sreloc = NULL;
+  is_opd = strcmp (bfd_get_section_name (abfd, sec), ".opd") == 0;
 
   rel_end = relocs + sec->reloc_count;
   for (rel = relocs; rel < rel_end; rel++)
@@ -1948,6 +1965,7 @@ ppc64_elf_check_relocs (abfd, info, sec,
 
 	  h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
 	  h->plt.refcount += 1;
+	  ((struct ppc_link_hash_entry *) h)->is_func = 1;
 	  break;
 
 	  /* The following relocations don't need to propagate the
@@ -1982,15 +2000,41 @@ ppc64_elf_check_relocs (abfd, info, sec,
 	  break;
 
 	case R_PPC64_REL24:
-	  if (h != NULL)
+	  if (h != NULL
+	      && h->root.root.string[0] == '.'
+	      && h->root.root.string[1] != 0)
 	    {
 	      /* We may need a .plt entry if the function this reloc
 		 refers to is in a shared lib.  */
 	      h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
 	      h->plt.refcount += 1;
+	      ((struct ppc_link_hash_entry *) h)->is_func = 1;
 	    }
 	  break;
 
+	case R_PPC64_ADDR64:
+	  if (is_opd
+	      && h != NULL
+	      && h->root.root.string[0] == '.'
+	      && h->root.root.string[1] != 0)
+	    {
+	      struct elf_link_hash_entry *fdh;
+
+	      fdh = elf_link_hash_lookup (&htab->elf, h->root.root.string + 1,
+					  false, false, false);
+	      if (fdh != NULL)
+		{
+		  /* Ensure the function descriptor symbol string is
+		     part of the code symbol string.  We aren't
+		     changing the name here, just allowing some tricks
+		     in ppc64_elf_hide_symbol.  */
+		  fdh->root.root.string = h->root.root.string + 1;
+		  ((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1;
+		  ((struct ppc_link_hash_entry *) h)->is_func = 1;
+		}
+	    }
+	  /* Fall through.  */
+
 	case R_PPC64_REL64:
 	case R_PPC64_REL32:
 	case R_PPC64_REL14:
@@ -2012,11 +2056,16 @@ ppc64_elf_check_relocs (abfd, info, sec,
 	case R_PPC64_ADDR24:
 	case R_PPC64_ADDR30:
 	case R_PPC64_ADDR32:
-	case R_PPC64_ADDR64:
 	case R_PPC64_UADDR16:
 	case R_PPC64_UADDR32:
 	case R_PPC64_UADDR64:
 	case R_PPC64_TOC:
+#if 0
+	      /* Don't propagate .opd relocs.  */
+	  if (is_opd)
+	    break;
+#endif
+
 	  /* If we are creating a shared library, and this is a reloc
 	     against a global symbol, or a non PC relative reloc
 	     against a local symbol, then we need to copy the reloc
@@ -2056,12 +2105,6 @@ ppc64_elf_check_relocs (abfd, info, sec,
 	      struct ppc_dyn_relocs *p;
 	      struct ppc_dyn_relocs **head;
 
-#if 0
-	      /* Don't propagate .opd relocs.  */
-	      if (strcmp (bfd_get_section_name (abfd, sec), ".opd") == 0)
-		break;
-#endif
-
 	      /* We must copy these reloc types into the output file.
 		 Create a reloc section in dynobj and make room for
 		 this reloc.  */
@@ -2275,7 +2318,7 @@ ppc64_elf_gc_sweep_hook (abfd, info, sec
 	      if (h->plt.refcount > 0)
 		h->plt.refcount--;
 	    }
-	  /* Fall thru.  */
+	  break;
 
 	case R_PPC64_REL14:
 	case R_PPC64_REL14_BRNTAKEN:
@@ -2351,92 +2394,158 @@ ppc64_elf_gc_sweep_hook (abfd, info, sec
   return true;
 }
 
-/* Adjust a symbol defined by a dynamic object and referenced by a
-   regular object.  The current definition is in some section of the
-   dynamic object, but we're not including those sections.  We have to
-   change the definition to something the rest of the link can
-   understand.  */
-
+/* Called via elf_link_hash_traverse to transfer dynamic linking
+   information on function code symbol entries to their corresponding
+   function descriptor symbol entries.  */
 static boolean
-ppc64_elf_adjust_dynamic_symbol (info, h)
-     struct bfd_link_info *info;
+func_desc_adjust (h, inf)
      struct elf_link_hash_entry *h;
+     PTR inf;
 {
+  struct bfd_link_info *info;
   struct ppc_link_hash_table *htab;
-  struct ppc_link_hash_entry * eh;
-  struct ppc_dyn_relocs *p;
-  asection *s;
-  unsigned int power_of_two;
 
+  if (h->root.type == bfd_link_hash_indirect
+      || h->root.type == bfd_link_hash_warning)
+    return true;
+
+  info = (struct bfd_link_info *) inf;
   htab = ppc_hash_table (info);
 
-  /* If this is a function, put it in the procedure linkage table.  We
-     will fill in the contents of the procedure linkage table later.  */
-  if (h->type == STT_FUNC
-      || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
+  /* If this is a function code symbol, transfer dynamic linking
+     information to the function descriptor symbol.  */
+  if (!((struct ppc_link_hash_entry *) h)->is_func)
+    return true;
+
+  if (h->plt.refcount > 0
+      && h->root.root.string[0] == '.'
+      && h->root.root.string[1] != '\0')
     {
       struct elf_link_hash_entry *fdh;
-
-      /* If it's a function entry point, the name starts with a dot
-         unless someone has written some poor assembly code.  The ABI
-	 for .plt calls requires that there be a function descriptor
-	 sym which has the name of the function minus the dot.  */
-
-      if (h->plt.refcount <= 0
-	  || h->root.root.string[0] != '.'
-	  || h->root.root.string[1] == '\0')
-	{
-	  h->plt.offset = (bfd_vma) -1;
-	  h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
-	  return true;
-	}
+      boolean force_local;
 
       /* Find the corresponding function descriptor symbol.  Create it
-	 as undefined if necessary.  ppc_elf64_finish_dynamic_symbol
-	 will look it up again and create a JMP_SLOT reloc for it.  */
+	 as undefined if necessary.  */
 
-      fdh = elf_link_hash_lookup (elf_hash_table (info),
-				  h->root.root.string + 1,
-				  false, false, false);
+      fdh = elf_link_hash_lookup (&htab->elf, h->root.root.string + 1,
+				  false, false, true);
 
-      if (fdh == NULL)
+      if (fdh == NULL && info->shared)
 	{
+	  bfd *abfd;
 	  asymbol *newsym;
 
 	  /* Create it as undefined.  */
-	  newsym = bfd_make_empty_symbol (htab->elf.dynobj);
+	  if (h->root.type == bfd_link_hash_undefined
+	      || h->root.type == bfd_link_hash_undefweak)
+	    abfd = h->root.u.undef.abfd;
+	  else if (h->root.type == bfd_link_hash_defined
+		   || h->root.type == bfd_link_hash_defweak)
+	    abfd = h->root.u.def.section->owner;
+	  else
+	    abort ();
+	  newsym = bfd_make_empty_symbol (abfd);
 	  newsym->name = h->root.root.string + 1;
 	  newsym->section = bfd_und_section_ptr;
 	  newsym->value = 0;
-	  newsym->flags = BSF_DYNAMIC | BSF_OBJECT;
+	  newsym->flags = BSF_OBJECT;
+	  if (h->root.type == bfd_link_hash_undefweak)
+	    newsym->flags |= BSF_WEAK;
 
 	  if ( !(_bfd_generic_link_add_one_symbol
-		 (info, htab->elf.dynobj, newsym->name, newsym->flags,
+		 (info, abfd, newsym->name, newsym->flags,
 		  newsym->section, newsym->value, NULL, false, false,
 		  (struct bfd_link_hash_entry **) &fdh)))
 	    {
 	      return false;
 	    }
 	}
+
+      if (fdh != NULL
+	  && (fdh->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0
+	  && (info->shared
+	      || (fdh->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+	      || (fdh->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0))
+	{
+	  if (fdh->dynindx == -1)
+	    if (! bfd_elf64_link_record_dynamic_symbol (info, fdh))
+	      return false;
+	  fdh->plt.refcount = h->plt.refcount;
+	  fdh->elf_link_hash_flags |= (h->elf_link_hash_flags
+				       & (ELF_LINK_HASH_REF_REGULAR
+					  | ELF_LINK_HASH_REF_DYNAMIC
+					  | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+					  | ELF_LINK_NON_GOT_REF));
+	  fdh->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+	  ((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1;
+	  fdh->root.root.string = h->root.root.string + 1;
+	}
+
+      /* Now that the info is on the function descriptor, clear the
+	 function code sym info.  Any function code syms for which we
+	 don't have a definition in a regular file, we force local.
+	 This prevents a shared library from exporting syms that have
+	 been imported from another library.  Function code syms that
+	 are really in the library we must leave global to prevent the
+	 linker dragging a definition in from a static library.  */
+      force_local = (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0;
+      _bfd_elf_link_hash_hide_symbol (info, h, force_local);
+    }
+
+  return true;
+}
+
+/* Called near the start of bfd_elf_size_dynamic_sections.  We use
+   this hook to transfer dynamic linking information gathered so far
+   on function code symbol entries, to their corresponding function
+   descriptor symbol entries.  */
+static boolean
+ppc64_elf_func_desc_adjust (obfd, info)
+     bfd *obfd ATTRIBUTE_UNUSED;
+     struct bfd_link_info *info;
+{
+  struct ppc_link_hash_table *htab;
+
+  htab = ppc_hash_table (info);
+  elf_link_hash_traverse (&htab->elf, func_desc_adjust, (PTR) info);
+  return true;
+}
+
+/* Adjust a symbol defined by a dynamic object and referenced by a
+   regular object.  The current definition is in some section of the
+   dynamic object, but we're not including those sections.  We have to
+   change the definition to something the rest of the link can
+   understand.  */
+
+static boolean
+ppc64_elf_adjust_dynamic_symbol (info, h)
+     struct bfd_link_info *info;
+     struct elf_link_hash_entry *h;
+{
+  struct ppc_link_hash_table *htab;
+  struct ppc_link_hash_entry * eh;
+  struct ppc_dyn_relocs *p;
+  asection *s;
+  unsigned int power_of_two;
+
+  htab = ppc_hash_table (info);
 
-      while (fdh->root.type == bfd_link_hash_indirect
-	     || fdh->root.type == bfd_link_hash_warning)
-	fdh = (struct elf_link_hash_entry *) fdh->root.u.i.link;
-
-      if (! info->shared
-	  && (fdh->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
-	  && (fdh->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0)
-	{
-	  /* 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, or if all references were garbage collected.  In
-	     such a case, we don't actually need to build a procedure
-	     linkage table entry.  */
+  /* Deal with function syms.  */
+  if (h->type == STT_FUNC
+      || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
+    {
+      /* Clear procedure linkage table information for any symbol that
+	 won't need a .plt entry.  */
+      if (!((struct ppc_link_hash_entry *) h)->is_func_descriptor
+	  || h->plt.refcount <= 0
+	  || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 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->plt.offset = (bfd_vma) -1;
 	  h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
-	  return true;
 	}
-
       return true;
     }
   else
@@ -2530,6 +2639,30 @@ ppc64_elf_adjust_dynamic_symbol (info, h
   return true;
 }
 
+/* If given a function descriptor symbol, hide both the function code
+   sym and the descriptor.  */
+static void
+ppc64_elf_hide_symbol (info, h, force_local)
+     struct bfd_link_info *info;
+     struct elf_link_hash_entry *h;
+     boolean force_local;
+{
+  _bfd_elf_link_hash_hide_symbol (info, h, force_local);
+
+  if (((struct ppc_link_hash_entry *) h)->is_func_descriptor)
+    {
+      const char *name;
+      struct elf_link_hash_entry *fh;
+      struct ppc_link_hash_table *htab;
+
+      name = h->root.root.string - 1;
+      htab = ppc_hash_table (info);
+      fh = elf_link_hash_lookup (&htab->elf, name, false, false, false);
+      if (fh != NULL)
+	_bfd_elf_link_hash_hide_symbol (info, fh, force_local);
+    }
+}
+
 /* This is the condition under which ppc64_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
@@ -2563,44 +2696,13 @@ allocate_dynrelocs (h, inf)
   htab = ppc_hash_table (info);
 
   if (htab->elf.dynamic_sections_created
-      && h->plt.refcount > 0)
+      && h->plt.refcount > 0
+      && h->dynindx != -1)
     {
-      /* 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_elf64_link_record_dynamic_symbol (info, h))
-	    return false;
-	}
+      BFD_ASSERT (((struct ppc_link_hash_entry *) h)->is_func_descriptor);
 
-      BFD_ASSERT (h->root.root.string[0] == '.'
-		  && h->root.root.string[1] != '\0');
-
       if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info, h))
 	{
-	  /* Make sure the corresponding function descriptor symbol is
-	     dynamic too.  */
-
-	  if (h->dynindx != -1)
-	    {
-	      struct elf_link_hash_entry *fdh;
-
-	      fdh = elf_link_hash_lookup (elf_hash_table (info),
-					  h->root.root.string + 1,
-					  false, false, false);
-
-	      if (fdh == NULL)
-		abort ();
-
-	      if (fdh->dynindx == -1
-		  && (fdh->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
-		{
-		  if (! bfd_elf64_link_record_dynamic_symbol (info, fdh))
-		    return false;
-		}
-	    }
-
 	  /* If this is the first .plt entry, make room for the special
 	     first entry.  */
 	  s = htab->splt;
@@ -2608,7 +2710,6 @@ allocate_dynrelocs (h, inf)
 	    s->_raw_size += PLT_INITIAL_ENTRY_SIZE;
 
 	  h->plt.offset = s->_raw_size;
-	  h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
 
 	  /* Make room for this entry.  */
 	  s->_raw_size += PLT_ENTRY_SIZE;
@@ -2930,7 +3031,7 @@ ppc64_elf_size_dynamic_sections (output_
 	return false;
     }
 
-  if (elf_hash_table (info)->dynamic_sections_created)
+  if (htab->elf.dynamic_sections_created)
     {
       /* Add some entries to the .dynamic section.  We fill in the
 	 values later, in ppc64_elf_finish_dynamic_sections, but we
@@ -3151,18 +3252,29 @@ build_one_stub (h, inf)
   if (htab->elf.dynamic_sections_created
       && h->plt.offset != (bfd_vma) -1)
     {
+      struct elf_link_hash_entry *fh;
       asection *s;
       bfd_vma plt_r2;
       bfd_byte *p;
       unsigned int indx;
 
+      BFD_ASSERT (((struct ppc_link_hash_entry *) h)->is_func_descriptor);
+
+      fh = elf_link_hash_lookup (&htab->elf, h->root.root.string - 1,
+				 false, false, true);
+
+      if (fh == NULL)
+	abort ();
+
+      BFD_ASSERT (((struct ppc_link_hash_entry *) fh)->is_func);
+
       /* Point the function at the linkage stub.  This works because
 	 the only references to the function code sym are calls.
 	 Function pointer comparisons use the function descriptor.  */
       s = htab->sstub;
-      h->root.type = bfd_link_hash_defined;
-      h->root.u.def.section = s;
-      h->root.u.def.value = s->_cooked_size;
+      fh->root.type = bfd_link_hash_defined;
+      fh->root.u.def.section = s;
+      fh->root.u.def.value = s->_cooked_size;
 
       /* Build the .plt call stub.  */
       plt_r2 = (htab->splt->output_section->vma
@@ -3171,10 +3283,11 @@ build_one_stub (h, inf)
 		- elf_gp (htab->splt->output_section->owner)
 		- TOC_BASE_OFF);
 
-      if (plt_r2 + 0x80000000 > 0xffffffff)
+      if (plt_r2 + 0x80000000 > 0xffffffff
+	  || (plt_r2 & 3) != 0)
 	{
 	  (*_bfd_error_handler)
-	    (_("linkage table overflow against `%s'"),
+	    (_("linkage table error against `%s'"),
 	     h->root.root.string);
 	  bfd_set_error (bfd_error_bad_value);
 	  htab->plt_overflow = true;
@@ -3351,6 +3464,7 @@ ppc64_elf_relocate_section (output_bfd, 
       unsigned long r_symndx;
       bfd_vma relocation;
       boolean unresolved_reloc;
+      boolean has_nop;
       long insn;
 
       r_type = (enum elf_ppc_reloc_type) ELF64_R_TYPE (rel->r_info);
@@ -3480,6 +3594,7 @@ ppc64_elf_relocate_section (output_bfd, 
 	     order to restore the TOC base pointer.  Only calls to
 	     shared objects need to alter the TOC base.  These are
 	     recognized by their need for a PLT entry.  */
+	  has_nop = 0;
 	  if (h != NULL
 	      && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0
 	      /* Make sure that there really is an instruction after
@@ -3498,8 +3613,24 @@ ppc64_elf_relocate_section (output_bfd, 
 		  bfd_put_32 (input_bfd,
 			      (bfd_vma) 0xe8410028, /* ld r2,40(r1) */
 			      pnext);
+		  has_nop = 1;
 		}
 	    }
+
+	  if (h != NULL
+	      && h->root.type == bfd_link_hash_undefweak
+	      && r_type == R_PPC64_REL24
+	      && addend == 0
+	      && relocation == 0)
+	    {
+	      /* Tweak calls to undefined weak functions to behave as
+		 if the "called" function immediately returns.  We can
+		 thus call to a weak function without first checking
+		 whether the function is defined.  */
+	      relocation = 4;
+	      if (has_nop)
+		relocation = 8;
+	    }
 	  break;
 	}
 
@@ -3784,7 +3915,7 @@ ppc64_elf_relocate_section (output_bfd, 
 		  /* This symbol is local, or marked to become local.  */
 		  outrel.r_addend += relocation;
 		  relocate = true;
-		  if (r_type == R_PPC64_ADDR64)
+		  if (r_type == R_PPC64_ADDR64 || r_type == R_PPC64_TOC)
 		    {
 		      outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
 		    }
@@ -3993,7 +4124,6 @@ ppc64_elf_finish_dynamic_symbol (output_
 
   if (h->plt.offset != (bfd_vma) -1)
     {
-      struct elf_link_hash_entry *funcdesc_h;
       Elf_Internal_Rela rela;
       Elf64_External_Rela *loc;
 
@@ -4002,20 +4132,10 @@ ppc64_elf_finish_dynamic_symbol (output_
 
       if (htab->splt == NULL
 	  || htab->srelplt == NULL
-	  || htab->sglink == NULL
-	  || h->root.root.string[0] != '.'
-	  || h->root.root.string[1] == '\0')
+	  || htab->sglink == NULL)
 	abort ();
-
-      /* Find its corresponding function descriptor.
-	 ppc64_elf_adjust_dynamic_symbol has already set it up for us.  */
 
-      funcdesc_h = elf_link_hash_lookup (elf_hash_table (info),
-					 h->root.root.string + 1,
-					 false, false, false);
-
-      if (funcdesc_h == NULL || funcdesc_h->dynindx == -1)
-	abort ();
+      BFD_ASSERT (((struct ppc_link_hash_entry *) h)->is_func_descriptor);
 
       /* Create a JMP_SLOT reloc to inform the dynamic linker to
 	 fill in the PLT entry.  */
@@ -4023,7 +4143,7 @@ ppc64_elf_finish_dynamic_symbol (output_
       rela.r_offset = (htab->splt->output_section->vma
 		       + htab->splt->output_offset
 		       + h->plt.offset);
-      rela.r_info = ELF64_R_INFO (funcdesc_h->dynindx, R_PPC64_JMP_SLOT);
+      rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
       rela.r_addend = 0;
 
       loc = (Elf64_External_Rela *) htab->srelplt->contents;
@@ -4257,6 +4377,8 @@ ppc64_elf_finish_dynamic_sections (outpu
 #define elf_backend_gc_mark_hook	      ppc64_elf_gc_mark_hook
 #define elf_backend_gc_sweep_hook	      ppc64_elf_gc_sweep_hook
 #define elf_backend_adjust_dynamic_symbol     ppc64_elf_adjust_dynamic_symbol
+#define elf_backend_hide_symbol		      ppc64_elf_hide_symbol
+#define elf_backend_always_size_sections      ppc64_elf_func_desc_adjust
 #define elf_backend_size_dynamic_sections     ppc64_elf_size_dynamic_sections
 #define elf_backend_fake_sections	      ppc64_elf_fake_sections
 #define elf_backend_relocate_section	      ppc64_elf_relocate_section


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