Blame SOURCES/gdb-rhbz1125820-ppc64le-enablement-13of37.patch

7ab123
commit a345bc8d317a159e3e887632d80c5a8282d34f07
7ab123
Author: Alan Modra <amodra@gmail.com>
7ab123
Date:   Fri Nov 1 19:24:20 2013 +1030
7ab123
7ab123
    PowerPC64 ELFv2 symbols defined in plt
7ab123
    
7ab123
    In a non-pic executable, ELFv2 like other targets, needs to emit a plt
7ab123
    entry even for non-call references to functions defined in shared
7ab123
    libraries, and define the function on the plt code.
7ab123
    
7ab123
    	* elf64-ppc.c (ppc64_elf_copy_indirect_symbol): Copy
7ab123
    	pointer_equality_needed flag.
7ab123
    	(ppc64_elf_check_relocs): For ELFv2 arrange to emit plt
7ab123
    	entries for references to functions in shared libraries on
7ab123
    	non-call relocs.
7ab123
    	(readonly_dynrelocs): Split into function of the same name and..
7ab123
    	(maybe_set_textrel): ..this new function.  Update call.
7ab123
    	(ppc64_elf_adjust_dynamic_symbol): Don't emit dynrelocs for
7ab123
    	ELFv2 in most cases if we have a plt entry.  Use new
7ab123
    	readonly_relocs.
7ab123
    	(allocate_dynrelocs): For ELFv2, don't allocate dynreloc space
7ab123
    	for ifunc in static executables.
7ab123
    	(size_global_entry_stubs): New function.
7ab123
    	(ppc64_elf_size_dynamic_sections): Call size_global_entry_stubs.
7ab123
    	Save end of glink branch table.
7ab123
    	(ppc64_elf_hash_symbol): New function.
7ab123
    	(build_global_entry_stubs): New function.
7ab123
    	(ppc64_elf_build_stubs): Call build_global_entry_stubs.  Adjust
7ab123
    	glink sizing.
7ab123
    	(ppc64_elf_relocate_section): Tidy plt16/32/64 reloc code.
7ab123
    	(ppc64_elf_finish_dynamic_symbol): For ELFv2, adjust symbols
7ab123
    	defined on plt code.
7ab123
7ab123
Index: gdb-7.6.1/bfd/elf64-ppc.c
7ab123
===================================================================
7ab123
--- gdb-7.6.1.orig/bfd/elf64-ppc.c
7ab123
+++ gdb-7.6.1/bfd/elf64-ppc.c
7ab123
@@ -109,6 +109,7 @@ static bfd_vma opd_entry_value
7ab123
 #define elf_backend_maybe_function_sym	      ppc64_elf_maybe_function_sym
7ab123
 #define elf_backend_always_size_sections      ppc64_elf_func_desc_adjust
7ab123
 #define elf_backend_size_dynamic_sections     ppc64_elf_size_dynamic_sections
7ab123
+#define elf_backend_hash_symbol		      ppc64_elf_hash_symbol
7ab123
 #define elf_backend_init_index_section	      _bfd_elf_init_2_index_sections
7ab123
 #define elf_backend_action_discarded	      ppc64_elf_action_discarded
7ab123
 #define elf_backend_relocate_section	      ppc64_elf_relocate_section
7ab123
@@ -174,6 +175,9 @@ static bfd_vma opd_entry_value
7ab123
 
7ab123
 #define LD_R2_0R1	0xe8410000	/* ld    %r2,0(%r1)      */
7ab123
 
7ab123
+#define ADDIS_R12_R12	0x3d8c0000	/* addis %r12,%r12,xxx@ha */
7ab123
+#define LD_R12_0R12	0xe98c0000	/* ld    %r12,xxx@l(%r12) */
7ab123
+
7ab123
 /* glink call stub instructions.  We enter with the index in R0.  */
7ab123
 #define GLINK_CALL_STUB_SIZE (16*4)
7ab123
 					/* 0:				*/
7ab123
@@ -4502,6 +4506,7 @@ ppc64_elf_copy_indirect_symbol (struct b
7ab123
   edir->elf.ref_regular |= eind->elf.ref_regular;
7ab123
   edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak;
7ab123
   edir->elf.needs_plt |= eind->elf.needs_plt;
7ab123
+  edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed;
7ab123
 
7ab123
   /* Copy over any dynamic relocs we may have on the indirect sym.  */
7ab123
   if (eind->dyn_relocs != NULL)
7ab123
@@ -5219,6 +5224,14 @@ ppc64_elf_check_relocs (bfd *abfd, struc
7ab123
 	    if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
7ab123
 					rel->r_addend, tls_type))
7ab123
 	      return FALSE;
7ab123
+
7ab123
+	  /* We may also need a plt entry if the symbol turns out to be
7ab123
+	     an ifunc.  */
7ab123
+	  if (h != NULL && !info->shared && abiversion (abfd) == 2)
7ab123
+	    {
7ab123
+	      if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
7ab123
+		return FALSE;
7ab123
+	    }
7ab123
 	  break;
7ab123
 
7ab123
 	case R_PPC64_PLT16_HA:
7ab123
@@ -5467,12 +5480,6 @@ ppc64_elf_check_relocs (bfd *abfd, struc
7ab123
 	    }
7ab123
 	  /* Fall through.  */
7ab123
 
7ab123
-	case R_PPC64_REL30:
7ab123
-	case R_PPC64_REL32:
7ab123
-	case R_PPC64_REL64:
7ab123
-	case R_PPC64_ADDR14:
7ab123
-	case R_PPC64_ADDR14_BRNTAKEN:
7ab123
-	case R_PPC64_ADDR14_BRTAKEN:
7ab123
 	case R_PPC64_ADDR16:
7ab123
 	case R_PPC64_ADDR16_DS:
7ab123
 	case R_PPC64_ADDR16_HA:
7ab123
@@ -5483,6 +5490,23 @@ ppc64_elf_check_relocs (bfd *abfd, struc
7ab123
 	case R_PPC64_ADDR16_HIGHESTA:
7ab123
 	case R_PPC64_ADDR16_LO:
7ab123
 	case R_PPC64_ADDR16_LO_DS:
7ab123
+	  if (h != NULL && !info->shared && abiversion (abfd) == 2
7ab123
+	      && rel->r_addend == 0)
7ab123
+	    {
7ab123
+	      /* We may need a .plt entry if this reloc refers to a
7ab123
+		 function in a shared lib.  */
7ab123
+	      if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
7ab123
+		return FALSE;
7ab123
+	      h->pointer_equality_needed = 1;
7ab123
+	    }
7ab123
+	  /* Fall through.  */
7ab123
+
7ab123
+	case R_PPC64_REL30:
7ab123
+	case R_PPC64_REL32:
7ab123
+	case R_PPC64_REL64:
7ab123
+	case R_PPC64_ADDR14:
7ab123
+	case R_PPC64_ADDR14_BRNTAKEN:
7ab123
+	case R_PPC64_ADDR14_BRTAKEN:
7ab123
 	case R_PPC64_ADDR24:
7ab123
 	case R_PPC64_ADDR32:
7ab123
 	case R_PPC64_UADDR16:
7ab123
@@ -6667,6 +6691,25 @@ ppc64_elf_func_desc_adjust (bfd *obfd AT
7ab123
   return TRUE;
7ab123
 }
7ab123
 
7ab123
+/* Return true if we have dynamic relocs that apply to read-only sections.  */
7ab123
+
7ab123
+static bfd_boolean
7ab123
+readonly_dynrelocs (struct elf_link_hash_entry *h)
7ab123
+{
7ab123
+  struct ppc_link_hash_entry *eh;
7ab123
+  struct elf_dyn_relocs *p;
7ab123
+
7ab123
+  eh = (struct ppc_link_hash_entry *) h;
7ab123
+  for (p = eh->dyn_relocs; p != NULL; p = p->next)
7ab123
+    {
7ab123
+      asection *s = p->sec->output_section;
7ab123
+
7ab123
+      if (s != NULL && (s->flags & SEC_READONLY) != 0)
7ab123
+	return TRUE;
7ab123
+    }
7ab123
+  return FALSE;
7ab123
+}
7ab123
+
7ab123
 /* Adjust a symbol defined by a dynamic object and referenced by a
7ab123
    regular object.  The current definition is in some section of the
7ab123
    dynamic object, but we're not including those sections.  We have to
7ab123
@@ -6704,6 +6747,26 @@ ppc64_elf_adjust_dynamic_symbol (struct
7ab123
 	  h->plt.plist = NULL;
7ab123
 	  h->needs_plt = 0;
7ab123
 	}
7ab123
+      else if (abiversion (info->output_bfd) == 2)
7ab123
+	{
7ab123
+	  /* After adjust_dynamic_symbol, non_got_ref set in the
7ab123
+	     non-shared case means that we have allocated space in
7ab123
+	     .dynbss for the symbol and thus dyn_relocs for this
7ab123
+	     symbol should be discarded.
7ab123
+	     If we get here we know we are making a PLT entry for this
7ab123
+	     symbol, and in an executable we'd normally resolve
7ab123
+	     relocations against this symbol to the PLT entry.  Allow
7ab123
+	     dynamic relocs if the reference is weak, and the dynamic
7ab123
+	     relocs will not cause text relocation.  */
7ab123
+	  if (!h->ref_regular_nonweak
7ab123
+	      && h->non_got_ref
7ab123
+	      && h->type != STT_GNU_IFUNC
7ab123
+	      && !readonly_dynrelocs (h))
7ab123
+	    h->non_got_ref = 0;
7ab123
+
7ab123
+	  /* If making a plt entry, then we don't need copy relocs.  */
7ab123
+	  return TRUE;
7ab123
+	}
7ab123
     }
7ab123
   else
7ab123
     h->plt.plist = NULL;
7ab123
@@ -6738,26 +6801,12 @@ ppc64_elf_adjust_dynamic_symbol (struct
7ab123
   if (!h->def_dynamic || !h->ref_regular || h->def_regular)
7ab123
     return TRUE;
7ab123
 
7ab123
-  if (ELIMINATE_COPY_RELOCS)
7ab123
+  /* If we didn't find any dynamic relocs in read-only sections, then
7ab123
+     we'll be keeping the dynamic relocs and avoiding the copy reloc.  */
7ab123
+  if (ELIMINATE_COPY_RELOCS && !readonly_dynrelocs (h))
7ab123
     {
7ab123
-      struct ppc_link_hash_entry * eh;
7ab123
-      struct elf_dyn_relocs *p;
7ab123
-
7ab123
-      eh = (struct ppc_link_hash_entry *) h;
7ab123
-      for (p = eh->dyn_relocs; p != NULL; p = p->next)
7ab123
-	{
7ab123
-	  s = p->sec->output_section;
7ab123
-	  if (s != NULL && (s->flags & SEC_READONLY) != 0)
7ab123
-	    break;
7ab123
-	}
7ab123
-
7ab123
-      /* If we didn't find any dynamic relocs in read-only sections, then
7ab123
-	 we'll be keeping the dynamic relocs and avoiding the copy reloc.  */
7ab123
-      if (p == NULL)
7ab123
-	{
7ab123
-	  h->non_got_ref = 0;
7ab123
-	  return TRUE;
7ab123
-	}
7ab123
+      h->non_got_ref = 0;
7ab123
+      return TRUE;
7ab123
     }
7ab123
 
7ab123
   if (h->plt.plist != NULL)
7ab123
@@ -9167,7 +9216,8 @@ allocate_dynrelocs (struct elf_link_hash
7ab123
 
7ab123
   if (eh->dyn_relocs == NULL
7ab123
       || (!htab->elf.dynamic_sections_created
7ab123
-	  && h->type != STT_GNU_IFUNC))
7ab123
+	  && (h->type != STT_GNU_IFUNC
7ab123
+	      || !htab->opd_abi)))
7ab123
     return TRUE;
7ab123
 
7ab123
   /* In the shared -Bsymbolic case, discard space allocated for
7ab123
@@ -9263,28 +9313,59 @@ allocate_dynrelocs (struct elf_link_hash
7ab123
   return TRUE;
7ab123
 }
7ab123
 
7ab123
-/* Find any dynamic relocs that apply to read-only sections.  */
7ab123
+/* Called via elf_link_hash_traverse from ppc64_elf_size_dynamic_sections
7ab123
+   to set up space for global entry stubs.  These are put in glink,
7ab123
+   after the branch table.  */
7ab123
 
7ab123
 static bfd_boolean
7ab123
-readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf)
7ab123
+size_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
7ab123
 {
7ab123
-  struct ppc_link_hash_entry *eh;
7ab123
-  struct elf_dyn_relocs *p;
7ab123
+  struct bfd_link_info *info;
7ab123
+  struct ppc_link_hash_table *htab;
7ab123
+  struct plt_entry *pent;
7ab123
+  asection *s;
7ab123
 
7ab123
-  eh = (struct ppc_link_hash_entry *) h;
7ab123
-  for (p = eh->dyn_relocs; p != NULL; p = p->next)
7ab123
-    {
7ab123
-      asection *s = p->sec->output_section;
7ab123
+  if (h->root.type == bfd_link_hash_indirect)
7ab123
+    return TRUE;
7ab123
 
7ab123
-      if (s != NULL && (s->flags & SEC_READONLY) != 0)
7ab123
-	{
7ab123
-	  struct bfd_link_info *info = inf;
7ab123
+  if (!h->pointer_equality_needed)
7ab123
+    return TRUE;
7ab123
 
7ab123
-	  info->flags |= DF_TEXTREL;
7ab123
+  if (h->def_regular)
7ab123
+    return TRUE;
7ab123
 
7ab123
-	  /* Not an error, just cut short the traversal.  */
7ab123
-	  return FALSE;
7ab123
-	}
7ab123
+  info = inf;
7ab123
+  htab = ppc_hash_table (info);
7ab123
+  if (htab == NULL)
7ab123
+    return FALSE;
7ab123
+
7ab123
+  s = htab->glink;
7ab123
+  for (pent = h->plt.plist; pent != NULL; pent = pent->next)
7ab123
+    if (pent->plt.offset != (bfd_vma) -1
7ab123
+	&& pent->addend == 0)
7ab123
+      {
7ab123
+	s->size = (s->size + 15) & -16;
7ab123
+	s->size += 16;
7ab123
+	break;
7ab123
+      }
7ab123
+  return TRUE;
7ab123
+}
7ab123
+
7ab123
+/* Set DF_TEXTREL if we find any dynamic relocs that apply to
7ab123
+   read-only sections.  */
7ab123
+
7ab123
+static bfd_boolean
7ab123
+maybe_set_textrel (struct elf_link_hash_entry *h, void *info)
7ab123
+{
7ab123
+  if (h->root.type == bfd_link_hash_indirect)
7ab123
+    return TRUE;
7ab123
+
7ab123
+  if (readonly_dynrelocs (h))
7ab123
+    {
7ab123
+      ((struct bfd_link_info *) info)->flags |= DF_TEXTREL;
7ab123
+
7ab123
+      /* Not an error, just cut short the traversal.  */
7ab123
+      return FALSE;
7ab123
     }
7ab123
   return TRUE;
7ab123
 }
7ab123
@@ -9435,6 +9516,12 @@ ppc64_elf_size_dynamic_sections (bfd *ou
7ab123
   /* Allocate global sym .plt and .got entries, and space for global
7ab123
      sym dynamic relocs.  */
7ab123
   elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info);
7ab123
+  /* Stash the end of glink branch table.  */
7ab123
+  if (htab->glink != NULL)
7ab123
+    htab->glink->rawsize = htab->glink->size;
7ab123
+
7ab123
+  if (!htab->opd_abi && !info->shared)
7ab123
+    elf_link_hash_traverse (&htab->elf, size_global_entry_stubs, info);
7ab123
 
7ab123
   first_tlsld = NULL;
7ab123
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
7ab123
@@ -9632,7 +9719,7 @@ ppc64_elf_size_dynamic_sections (bfd *ou
7ab123
 	  /* If any dynamic relocs apply to a read-only section,
7ab123
 	     then we need a DT_TEXTREL entry.  */
7ab123
 	  if ((info->flags & DF_TEXTREL) == 0)
7ab123
-	    elf_link_hash_traverse (&htab->elf, readonly_dynrelocs, info);
7ab123
+	    elf_link_hash_traverse (&htab->elf, maybe_set_textrel, info);
7ab123
 
7ab123
 	  if ((info->flags & DF_TEXTREL) != 0)
7ab123
 	    {
7ab123
@@ -9646,6 +9733,19 @@ ppc64_elf_size_dynamic_sections (bfd *ou
7ab123
   return TRUE;
7ab123
 }
7ab123
 
7ab123
+/* Return TRUE if symbol should be hashed in the `.gnu.hash' section.  */
7ab123
+
7ab123
+static bfd_boolean
7ab123
+ppc64_elf_hash_symbol (struct elf_link_hash_entry *h)
7ab123
+{
7ab123
+  if (h->plt.plist != NULL
7ab123
+      && !h->def_regular
7ab123
+      && !h->pointer_equality_needed)
7ab123
+    return FALSE;
7ab123
+
7ab123
+  return _bfd_elf_hash_symbol (h);
7ab123
+}
7ab123
+
7ab123
 /* Determine the type of stub needed, if any, for a call.  */
7ab123
 
7ab123
 static inline enum ppc_stub_type
7ab123
@@ -12049,6 +12149,79 @@ ppc64_elf_toc (bfd *obfd)
7ab123
   return TOCstart;
7ab123
 }
7ab123
 
7ab123
+/* Called via elf_link_hash_traverse from ppc64_elf_build_stubs to
7ab123
+   write out any global entry stubs.  */
7ab123
+
7ab123
+static bfd_boolean
7ab123
+build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
7ab123
+{
7ab123
+  struct bfd_link_info *info;
7ab123
+  struct ppc_link_hash_table *htab;
7ab123
+  struct plt_entry *pent;
7ab123
+  asection *s;
7ab123
+
7ab123
+  if (h->root.type == bfd_link_hash_indirect)
7ab123
+    return TRUE;
7ab123
+
7ab123
+  if (!h->pointer_equality_needed)
7ab123
+    return TRUE;
7ab123
+
7ab123
+  if (h->def_regular)
7ab123
+    return TRUE;
7ab123
+
7ab123
+  info = inf;
7ab123
+  htab = ppc_hash_table (info);
7ab123
+  if (htab == NULL)
7ab123
+    return FALSE;
7ab123
+
7ab123
+  s = htab->glink;
7ab123
+  for (pent = h->plt.plist; pent != NULL; pent = pent->next)
7ab123
+    if (pent->plt.offset != (bfd_vma) -1
7ab123
+	&& pent->addend == 0)
7ab123
+      {
7ab123
+	bfd_byte *p;
7ab123
+	asection *plt;
7ab123
+	bfd_vma off;
7ab123
+
7ab123
+	/* For ELFv2, if this symbol is not defined in a regular file
7ab123
+	   and we are not generating a shared library or pie, then we
7ab123
+	   need to define the symbol in the executable on a call stub.
7ab123
+	   This is to avoid text relocations.  */
7ab123
+	h->root.u.def.section = s;
7ab123
+	h->root.u.def.value = s->size;
7ab123
+	s->size += 16;
7ab123
+	p = s->contents + h->root.u.def.value;
7ab123
+	plt = htab->plt;
7ab123
+	if (!htab->elf.dynamic_sections_created
7ab123
+	    || h->dynindx == -1)
7ab123
+	  plt = htab->iplt;
7ab123
+	off = pent->plt.offset + plt->output_offset + plt->output_section->vma;
7ab123
+	off -= h->root.u.def.value + s->output_offset + s->output_section->vma;
7ab123
+
7ab123
+	if (off + 0x80008000 > 0xffffffff || (off & 3) != 0)
7ab123
+	  {
7ab123
+	    info->callbacks->einfo
7ab123
+	      (_("%P: linkage table error against `%T'\n"),
7ab123
+	       h->root.root.string);
7ab123
+	    bfd_set_error (bfd_error_bad_value);
7ab123
+	    htab->stub_error = TRUE;
7ab123
+	  }
7ab123
+
7ab123
+	if (PPC_HA (off) != 0)
7ab123
+	  {
7ab123
+	    bfd_put_32 (s->owner, ADDIS_R12_R12 | PPC_HA (off), p);
7ab123
+	    p += 4;
7ab123
+	  }
7ab123
+	bfd_put_32 (s->owner, LD_R12_0R12 | PPC_LO (off), p);
7ab123
+	p += 4;
7ab123
+	bfd_put_32 (s->owner, MTCTR_R12, p);
7ab123
+	p += 4;
7ab123
+	bfd_put_32 (s->owner, BCTR, p);
7ab123
+	break;
7ab123
+      }
7ab123
+  return TRUE;
7ab123
+}
7ab123
+
7ab123
 /* Build all the stubs associated with the current output file.
7ab123
    The stubs are kept in a hash table attached to the main linker
7ab123
    hash table.  This function is called via gldelf64ppc_finish.  */
7ab123
@@ -12184,7 +12357,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_
7ab123
 
7ab123
       /* Build the .glink lazy link call stubs.  */
7ab123
       indx = 0;
7ab123
-      while (p < htab->glink->contents + htab->glink->size)
7ab123
+      while (p < htab->glink->contents + htab->glink->rawsize)
7ab123
 	{
7ab123
 	  if (htab->opd_abi)
7ab123
 	    {
7ab123
@@ -12207,7 +12380,13 @@ ppc64_elf_build_stubs (bfd_boolean emit_
7ab123
 	  indx++;
7ab123
 	  p += 4;
7ab123
 	}
7ab123
-      htab->glink->rawsize = p - htab->glink->contents;
7ab123
+
7ab123
+      /* Build .glink global entry stubs.  */
7ab123
+      if (htab->glink->size > htab->glink->rawsize)
7ab123
+	{
7ab123
+	  htab->glink->size = (htab->glink->rawsize + 15) & -16;
7ab123
+	  elf_link_hash_traverse (&htab->elf, build_global_entry_stubs, info);
7ab123
+	}
7ab123
     }
7ab123
 
7ab123
   if (htab->brlt->size != 0)
7ab123
@@ -12311,7 +12490,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_
7ab123
 	  bfd_put_32 (htab->elf.dynobj, val, p);
7ab123
 	  p += 4;
7ab123
 	  /* .glink size.  */
7ab123
-	  bfd_put_32 (htab->elf.dynobj, htab->glink->rawsize - 8, p);
7ab123
+	  bfd_put_32 (htab->elf.dynobj, htab->glink->size - 8, p);
7ab123
 	  p += 4;
7ab123
 	  /* Augmentation.  */
7ab123
 	  p += 1;
7ab123
@@ -12361,7 +12540,6 @@ ppc64_elf_build_stubs (bfd_boolean emit_
7ab123
       }
7ab123
 
7ab123
   if (stub_sec != NULL
7ab123
-      || htab->glink->rawsize != htab->glink->size
7ab123
       || (htab->glink_eh_frame != NULL
7ab123
 	  && htab->glink_eh_frame->rawsize != htab->glink_eh_frame->size))
7ab123
     {
7ab123
@@ -13588,13 +13766,14 @@ ppc64_elf_relocate_section (bfd *output_
7ab123
 	    {
7ab123
 	      struct plt_entry *ent;
7ab123
 	      for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
7ab123
-		if (ent->addend == orig_rel.r_addend
7ab123
-		    && ent->plt.offset != (bfd_vma) -1)
7ab123
+		if (ent->plt.offset != (bfd_vma) -1
7ab123
+		    && ent->addend == orig_rel.r_addend)
7ab123
 		  {
7ab123
 		    relocation = (htab->plt->output_section->vma
7ab123
 				  + htab->plt->output_offset
7ab123
 				  + ent->plt.offset);
7ab123
 		    unresolved_reloc = FALSE;
7ab123
+		    break;
7ab123
 		  }
7ab123
 	    }
7ab123
 	  break;
7ab123
@@ -14297,6 +14476,30 @@ ppc64_elf_finish_dynamic_symbol (bfd *ou
7ab123
 		      / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
7ab123
 	  }
7ab123
 	bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
7ab123
+
7ab123
+	if (!htab->opd_abi)
7ab123
+	  {
7ab123
+	    if (!h->def_regular)
7ab123
+	      {
7ab123
+		/* Mark the symbol as undefined, rather than as
7ab123
+		   defined in glink.  Leave the value if there were
7ab123
+		   any relocations where pointer equality matters
7ab123
+		   (this is a clue for the dynamic linker, to make
7ab123
+		   function pointer comparisons work between an
7ab123
+		   application and shared library), otherwise set it
7ab123
+		   to zero.  */
7ab123
+		sym->st_shndx = SHN_UNDEF;
7ab123
+		if (!h->pointer_equality_needed)
7ab123
+		  sym->st_value = 0;
7ab123
+		else if (!h->ref_regular_nonweak)
7ab123
+		  {
7ab123
+		    /* This breaks function pointer comparisons, but
7ab123
+		       that is better than breaking tests for a NULL
7ab123
+		       function pointer.  */
7ab123
+		    sym->st_value = 0;
7ab123
+		  }
7ab123
+	      }
7ab123
+	  }
7ab123
       }
7ab123
 
7ab123
   if (h->needs_copy)