summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2017-06-14 10:47:25 +0930
committerAlan Modra <amodra@gmail.com>2017-06-14 10:47:25 +0930
commit0572433b5beb636de1a49ec6b4fdab830c38cdc5 (patch)
tree718b3b7cd3011961b409a8233dfac4f2b0c6c487
parentd5b411854f0a3135c931921dfa8a33af395acfd3 (diff)
downloadglibc-0572433b5beb636de1a49ec6b4fdab830c38cdc5.tar.gz
glibc-0572433b5beb636de1a49ec6b4fdab830c38cdc5.tar.xz
glibc-0572433b5beb636de1a49ec6b4fdab830c38cdc5.zip
PowerPC64 ELFv2 PPC64_OPT_LOCALENTRY
ELFv2 functions with localentry:0 are those with a single entry point,
ie. global entry == local entry, that have no requirement on r2 or
r12 and guarantee r2 is unchanged on return.  Such an external
function can be called via the PLT without saving r2 or restoring it
on return, avoiding a common load-hit-store for small functions.

This patch implements the ld.so changes necessary for this
optimization.  ld.so needs to check that an optimized plt call
sequence is in fact calling a function implemented with localentry:0,
end emit a fatal error otherwise.

The elf/testobj6.c change is to stop "error while loading shared
libraries: expected localentry:0 `preload'" when running
elf/preloadtest, which we'd get otherwise.

	* elf/elf.h (PPC64_OPT_LOCALENTRY): Define.
	* sysdeps/alpha/dl-machine.h (elf_machine_fixup_plt): Add
	refsym and sym parameters.  Adjust callers.
	* sysdeps/aarch64/dl-machine.h (elf_machine_fixup_plt): Likewise.
	* sysdeps/arm/dl-machine.h (elf_machine_fixup_plt): Likewise.
	* sysdeps/generic/dl-machine.h (elf_machine_fixup_plt): Likewise.
	* sysdeps/hppa/dl-machine.h (elf_machine_fixup_plt): Likewise.
	* sysdeps/i386/dl-machine.h (elf_machine_fixup_plt): Likewise.
	* sysdeps/ia64/dl-machine.h (elf_machine_fixup_plt): Likewise.
	* sysdeps/m68k/dl-machine.h (elf_machine_fixup_plt): Likewise.
	* sysdeps/microblaze/dl-machine.h (elf_machine_fixup_plt): Likewise.
	* sysdeps/mips/dl-machine.h (elf_machine_fixup_plt): Likewise.
	* sysdeps/nios2/dl-machine.h (elf_machine_fixup_plt): Likewise.
	* sysdeps/powerpc/powerpc32/dl-machine.h (elf_machine_fixup_plt):
	Likewise.
	* sysdeps/s390/s390-32/dl-machine.h (elf_machine_fixup_plt): Likewise.
	* sysdeps/s390/s390-64/dl-machine.h (elf_machine_fixup_plt): Likewise.
	* sysdeps/sh/dl-machine.h (elf_machine_fixup_plt): Likewise.
	* sysdeps/sparc/sparc32/dl-machine.h (elf_machine_fixup_plt): Likewise.
	* sysdeps/sparc/sparc64/dl-machine.h (elf_machine_fixup_plt): Likewise.
	* sysdeps/tile/dl-machine.h (elf_machine_fixup_plt): Likewise.
	* sysdeps/x86_64/dl-machine.h (elf_machine_fixup_plt): Likewise.
	* sysdeps/powerpc/powerpc64/dl-machine.c (_dl_error_localentry): New.
	(_dl_reloc_overflow): Increase buffser size.  Formatting.
	* sysdeps/powerpc/powerpc64/dl-machine.h (ppc64_local_entry_offset):
	Delete reloc param, add refsym and sym.  Check optimized plt
	call stubs for localentry:0 functions.  Adjust callers.
	(elf_machine_fixup_plt, elf_machine_plt_conflict): Add refsym
	and sym parameters.  Adjust callers.
	(_dl_reloc_overflow): Move attribute.
	(_dl_error_localentry): Declare.
	* elf/dl-runtime.c (_dl_fixup): Save original sym.  Pass
	refsym and sym to elf_machine_fixup_plt.
	* elf/testobj6.c (preload): Call printf.
-rw-r--r--ChangeLog37
-rw-r--r--elf/dl-runtime.c3
-rw-r--r--elf/elf.h3
-rw-r--r--elf/testobj6.c3
-rw-r--r--sysdeps/aarch64/dl-machine.h1
-rw-r--r--sysdeps/alpha/dl-machine.h5
-rw-r--r--sysdeps/arm/dl-machine.h1
-rw-r--r--sysdeps/generic/dl-machine.h7
-rw-r--r--sysdeps/hppa/dl-machine.h5
-rw-r--r--sysdeps/i386/dl-machine.h1
-rw-r--r--sysdeps/ia64/dl-machine.h3
-rw-r--r--sysdeps/m68k/dl-machine.h1
-rw-r--r--sysdeps/microblaze/dl-machine.h1
-rw-r--r--sysdeps/mips/dl-machine.h1
-rw-r--r--sysdeps/nios2/dl-machine.h1
-rw-r--r--sysdeps/powerpc/powerpc32/dl-machine.h1
-rw-r--r--sysdeps/powerpc/powerpc64/dl-machine.c24
-rw-r--r--sysdeps/powerpc/powerpc64/dl-machine.h54
-rw-r--r--sysdeps/s390/s390-32/dl-machine.h1
-rw-r--r--sysdeps/s390/s390-64/dl-machine.h1
-rw-r--r--sysdeps/sh/dl-machine.h1
-rw-r--r--sysdeps/sparc/sparc32/dl-machine.h1
-rw-r--r--sysdeps/sparc/sparc64/dl-machine.h1
-rw-r--r--sysdeps/tile/dl-machine.h3
-rw-r--r--sysdeps/x86_64/dl-machine.h1
25 files changed, 124 insertions, 37 deletions
diff --git a/ChangeLog b/ChangeLog
index af5756112d..a06a70c939 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,42 @@
 2017-06-14  Alan Modra  <amodra@gmail.com>
 
+	* elf/elf.h (PPC64_OPT_LOCALENTRY): Define.
+	* sysdeps/alpha/dl-machine.h (elf_machine_fixup_plt): Add
+	refsym and sym parameters.  Adjust callers.
+	* sysdeps/aarch64/dl-machine.h (elf_machine_fixup_plt): Likewise.
+	* sysdeps/arm/dl-machine.h (elf_machine_fixup_plt): Likewise.
+	* sysdeps/generic/dl-machine.h (elf_machine_fixup_plt): Likewise.
+	* sysdeps/hppa/dl-machine.h (elf_machine_fixup_plt): Likewise.
+	* sysdeps/i386/dl-machine.h (elf_machine_fixup_plt): Likewise.
+	* sysdeps/ia64/dl-machine.h (elf_machine_fixup_plt): Likewise.
+	* sysdeps/m68k/dl-machine.h (elf_machine_fixup_plt): Likewise.
+	* sysdeps/microblaze/dl-machine.h (elf_machine_fixup_plt): Likewise.
+	* sysdeps/mips/dl-machine.h (elf_machine_fixup_plt): Likewise.
+	* sysdeps/nios2/dl-machine.h (elf_machine_fixup_plt): Likewise.
+	* sysdeps/powerpc/powerpc32/dl-machine.h (elf_machine_fixup_plt):
+	Likewise.
+	* sysdeps/s390/s390-32/dl-machine.h (elf_machine_fixup_plt): Likewise.
+	* sysdeps/s390/s390-64/dl-machine.h (elf_machine_fixup_plt): Likewise.
+	* sysdeps/sh/dl-machine.h (elf_machine_fixup_plt): Likewise.
+	* sysdeps/sparc/sparc32/dl-machine.h (elf_machine_fixup_plt): Likewise.
+	* sysdeps/sparc/sparc64/dl-machine.h (elf_machine_fixup_plt): Likewise.
+	* sysdeps/tile/dl-machine.h (elf_machine_fixup_plt): Likewise.
+	* sysdeps/x86_64/dl-machine.h (elf_machine_fixup_plt): Likewise.
+	* sysdeps/powerpc/powerpc64/dl-machine.c (_dl_error_localentry): New.
+	(_dl_reloc_overflow): Increase buffser size.  Formatting.
+	* sysdeps/powerpc/powerpc64/dl-machine.h (ppc64_local_entry_offset):
+	Delete reloc param, add refsym and sym.  Check optimized plt
+	call stubs for localentry:0 functions.  Adjust callers.
+	(elf_machine_fixup_plt, elf_machine_plt_conflict): Add refsym
+	and sym parameters.  Adjust callers.
+	(_dl_reloc_overflow): Move attribute.
+	(_dl_error_localentry): Declare.
+	* elf/dl-runtime.c (_dl_fixup): Save original sym.  Pass
+	refsym and sym to elf_machine_fixup_plt.
+	* elf/testobj6.c (preload): Call printf.
+
+2017-06-14  Alan Modra  <amodra@gmail.com>
+
 	* sysdeps/powerpc/powerpc64/sysdep.h: Formatting.
 	(NOPS, ENTRY_3): New macros.
 	(ENTRY): Rewrite.
diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
index 7d1d240403..51d3819d4a 100644
--- a/elf/dl-runtime.c
+++ b/elf/dl-runtime.c
@@ -71,6 +71,7 @@ _dl_fixup (
   const PLTREL *const reloc
     = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
   const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
+  const ElfW(Sym) *refsym = sym;
   void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
   lookup_t result;
   DL_FIXUP_VALUE_TYPE value;
@@ -145,7 +146,7 @@ _dl_fixup (
   if (__glibc_unlikely (GLRO(dl_bind_not)))
     return value;
 
-  return elf_machine_fixup_plt (l, result, reloc, rel_addr, value);
+  return elf_machine_fixup_plt (l, result, refsym, sym, reloc, rel_addr, value);
 }
 
 #ifndef PROF
diff --git a/elf/elf.h b/elf/elf.h
index fff893d433..3900b4c9f0 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -2544,9 +2544,10 @@ enum
 #define DT_PPC64_OPT	(DT_LOPROC + 3)
 #define DT_PPC64_NUM    4
 
-/* PowerPC64 specific values for the DT_PPC64_OPT Dyn entry.  */
+/* PowerPC64 specific bits in the DT_PPC64_OPT Dyn entry.  */
 #define PPC64_OPT_TLS		1
 #define PPC64_OPT_MULTI_TOC	2
+#define PPC64_OPT_LOCALENTRY	4
 
 /* PowerPC64 specific values for the Elf64_Sym st_other field.  */
 #define STO_PPC64_LOCAL_BIT	5
diff --git a/elf/testobj6.c b/elf/testobj6.c
index fcba01631d..84da4c9e22 100644
--- a/elf/testobj6.c
+++ b/elf/testobj6.c
@@ -1,3 +1,5 @@
+#include <stdio.h>
+
 #include "testobj.h"
 
 int
@@ -15,5 +17,6 @@ obj6func2 (int a)
 int
 preload (int a)
 {
+  printf ("testobj6 preload\n");
   return a;
 }
diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h
index 15d79a6961..02fab04f40 100644
--- a/sysdeps/aarch64/dl-machine.h
+++ b/sysdeps/aarch64/dl-machine.h
@@ -245,6 +245,7 @@ dl_platform_init (void)
 
 static inline ElfW(Addr)
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const ElfW(Rela) *reloc,
 		       ElfW(Addr) *reloc_addr,
 		       ElfW(Addr) value)
diff --git a/sysdeps/alpha/dl-machine.h b/sysdeps/alpha/dl-machine.h
index 7580cd29b6..7077796d2e 100644
--- a/sysdeps/alpha/dl-machine.h
+++ b/sysdeps/alpha/dl-machine.h
@@ -260,6 +260,7 @@ dl_platform_init (void)
    rather than the dynamic linker.  */
 static inline Elf64_Addr
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const Elf64_Rela *reloc,
 		       Elf64_Addr *got_addr, Elf64_Addr value)
 {
@@ -434,11 +435,11 @@ elf_machine_rela (struct link_map *map,
 	  RESOLVE_CONFLICT_FIND_MAP (map, reloc_addr);
 	  reloc = ((const Elf64_Rela *) D_PTR (map, l_info[DT_JMPREL]))
 		  + (r_type >> 8);
-	  elf_machine_fixup_plt (map, 0, reloc, reloc_addr, sym_value);
+	  elf_machine_fixup_plt (map, 0, 0, 0, reloc, reloc_addr, sym_value);
 	}
 #else
       else if (r_type == R_ALPHA_JMP_SLOT)
-	elf_machine_fixup_plt (map, 0, reloc, reloc_addr, sym_value);
+	elf_machine_fixup_plt (map, 0, 0, 0, reloc, reloc_addr, sym_value);
 #endif
 #ifndef RTLD_BOOTSTRAP
       else if (r_type == R_ALPHA_REFQUAD)
diff --git a/sysdeps/arm/dl-machine.h b/sysdeps/arm/dl-machine.h
index 2c72972bd2..7053ead16e 100644
--- a/sysdeps/arm/dl-machine.h
+++ b/sysdeps/arm/dl-machine.h
@@ -263,6 +263,7 @@ dl_platform_init (void)
 
 static inline Elf32_Addr
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const Elf32_Rel *reloc,
 		       Elf32_Addr *reloc_addr, Elf32_Addr value)
 {
diff --git a/sysdeps/generic/dl-machine.h b/sysdeps/generic/dl-machine.h
index 59749bd84f..41537601d2 100644
--- a/sysdeps/generic/dl-machine.h
+++ b/sysdeps/generic/dl-machine.h
@@ -51,10 +51,11 @@ elf_machine_load_address (void)
 
 /* Fixup a PLT entry to bounce directly to the function at VALUE.  */
 
-static inline Elf32_Addr
+static inline ElfW(Addr)
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
-		       const Elf32_Rel *reloc,
-		       Elf32_Addr *reloc_addr, Elf32_Addr value)
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
+		       const ElfW(Rel) *reloc,
+		       ElfW(Addr) *reloc_addr, ElfW(Addr) value)
 {
   return *reloc_addr = value;
 }
diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h
index 787b95f502..b7bdf871f1 100644
--- a/sysdeps/hppa/dl-machine.h
+++ b/sysdeps/hppa/dl-machine.h
@@ -112,6 +112,7 @@ elf_machine_load_address (void)
 /* Fixup a PLT entry to bounce directly to the function at VALUE. */
 static inline struct fdesc __attribute__ ((always_inline))
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const Elf32_Rela *reloc,
 		       Elf32_Addr *reloc_addr, struct fdesc value)
 {
@@ -652,13 +653,13 @@ elf_machine_rela (struct link_map *map,
     case R_PARISC_IPLT:
       if (__builtin_expect (sym_map != NULL, 1))
 	{
-	  elf_machine_fixup_plt (NULL, sym_map, reloc, reloc_addr,
+	  elf_machine_fixup_plt (NULL, sym_map, NULL, NULL reloc, reloc_addr,
 				 DL_FIXUP_MAKE_VALUE(sym_map, value));
 	}
       else
 	{
 	  /* If we get here, it's a (weak) undefined sym.  */
-	  elf_machine_fixup_plt (NULL, map, reloc, reloc_addr,
+	  elf_machine_fixup_plt (NULL, map, NULL, NULL, reloc, reloc_addr,
 				 DL_FIXUP_MAKE_VALUE(map, value));
 	}
       return;
diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
index 57d4a0bdbd..9ee9d02c36 100644
--- a/sysdeps/i386/dl-machine.h
+++ b/sysdeps/i386/dl-machine.h
@@ -246,6 +246,7 @@ dl_platform_init (void)
 
 static inline Elf32_Addr
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const Elf32_Rel *reloc,
 		       Elf32_Addr *reloc_addr, Elf32_Addr value)
 {
diff --git a/sysdeps/ia64/dl-machine.h b/sysdeps/ia64/dl-machine.h
index 9c08161d65..8d0d3c97dd 100644
--- a/sysdeps/ia64/dl-machine.h
+++ b/sysdeps/ia64/dl-machine.h
@@ -333,6 +333,7 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
 /* Fixup a PLT entry to bounce directly to the function at VALUE.  */
 static inline struct fdesc __attribute__ ((always_inline))
 elf_machine_fixup_plt (struct link_map *l, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const Elf64_Rela *reloc,
 		       Elf64_Addr *reloc_addr, struct fdesc value)
 {
@@ -424,7 +425,7 @@ elf_machine_rela (struct link_map *map,
 	    ;/* No adjustment.  */
 	  else if (r_type == R_IA64_IPLTLSB)
 	    {
-	      elf_machine_fixup_plt (NULL, NULL, reloc, reloc_addr,
+	      elf_machine_fixup_plt (NULL, NULL, NULL, NULL, reloc, reloc_addr,
 				     DL_FIXUP_MAKE_VALUE (sym_map, value));
 	      return;
 	    }
diff --git a/sysdeps/m68k/dl-machine.h b/sysdeps/m68k/dl-machine.h
index 8f457cea5a..fd8fb00103 100644
--- a/sysdeps/m68k/dl-machine.h
+++ b/sysdeps/m68k/dl-machine.h
@@ -182,6 +182,7 @@ _dl_start_user:\n\
 
 static inline Elf32_Addr
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const Elf32_Rela *reloc,
 		       Elf32_Addr *reloc_addr, Elf32_Addr value)
 {
diff --git a/sysdeps/microblaze/dl-machine.h b/sysdeps/microblaze/dl-machine.h
index cc80b30868..9481ff1efa 100644
--- a/sysdeps/microblaze/dl-machine.h
+++ b/sysdeps/microblaze/dl-machine.h
@@ -174,6 +174,7 @@ _dl_start_user:\n\
 
 static inline Elf32_Addr
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const Elf32_Rela *reloc,
 		       Elf32_Addr *reloc_addr, Elf32_Addr value)
 {
diff --git a/sysdeps/mips/dl-machine.h b/sysdeps/mips/dl-machine.h
index ed47513ccc..74ead7f524 100644
--- a/sysdeps/mips/dl-machine.h
+++ b/sysdeps/mips/dl-machine.h
@@ -453,6 +453,7 @@ dl_platform_init (void)
    the corresponding PLT entry instead.  */
 static inline ElfW(Addr)
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const ElfW(Rel) *reloc,
 		       ElfW(Addr) *reloc_addr, ElfW(Addr) value)
 {
diff --git a/sysdeps/nios2/dl-machine.h b/sysdeps/nios2/dl-machine.h
index 8d2b18de23..b5fdd9b2bd 100644
--- a/sysdeps/nios2/dl-machine.h
+++ b/sysdeps/nios2/dl-machine.h
@@ -207,6 +207,7 @@ _start:\n\
 
 static inline Elf32_Addr
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const Elf32_Rela *reloc,
 		       Elf32_Addr *reloc_addr, Elf32_Addr value)
 {
diff --git a/sysdeps/powerpc/powerpc32/dl-machine.h b/sysdeps/powerpc/powerpc32/dl-machine.h
index 28eb50f92d..1f8437ed9c 100644
--- a/sysdeps/powerpc/powerpc32/dl-machine.h
+++ b/sysdeps/powerpc/powerpc32/dl-machine.h
@@ -235,6 +235,7 @@ extern Elf32_Addr __elf_machine_fixup_plt (struct link_map *map,
 
 static inline Elf32_Addr
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const Elf32_Rela *reloc,
 		       Elf32_Addr *reloc_addr, Elf64_Addr finaladdr)
 {
diff --git a/sysdeps/powerpc/powerpc64/dl-machine.c b/sysdeps/powerpc/powerpc64/dl-machine.c
index 0eccc6621a..2cfd43b21b 100644
--- a/sysdeps/powerpc/powerpc64/dl-machine.c
+++ b/sysdeps/powerpc/powerpc64/dl-machine.c
@@ -24,11 +24,11 @@
 
 void
 _dl_reloc_overflow (struct link_map *map,
-		   const char *name,
-		   Elf64_Addr *const reloc_addr,
-		   const Elf64_Sym *refsym)
+		    const char *name,
+		    Elf64_Addr *const reloc_addr,
+		    const Elf64_Sym *refsym)
 {
-  char buffer[128];
+  char buffer[1024];
   char *t;
   t = stpcpy (buffer, name);
   t = stpcpy (t, " reloc at 0x");
@@ -45,3 +45,19 @@ _dl_reloc_overflow (struct link_map *map,
   t = stpcpy (t, " out of range");
   _dl_signal_error (0, map->l_name, NULL, buffer);
 }
+
+#if _CALL_ELF == 2
+void
+_dl_error_localentry (struct link_map *map, const Elf64_Sym *refsym)
+{
+  char buffer[1024];
+  char *t;
+  const char *strtab;
+
+  strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+  t = stpcpy (buffer, "expected localentry:0 `");
+  t = stpcpy (t, strtab + refsym->st_name);
+  t = stpcpy (t, "'");
+  _dl_signal_error (0, map->l_name, NULL, buffer);
+}
+#endif
diff --git a/sysdeps/powerpc/powerpc64/dl-machine.h b/sysdeps/powerpc/powerpc64/dl-machine.h
index 6391b3a558..aeb91b8f69 100644
--- a/sysdeps/powerpc/powerpc64/dl-machine.h
+++ b/sysdeps/powerpc/powerpc64/dl-machine.h
@@ -440,20 +440,30 @@ elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
 }
 
 #if _CALL_ELF == 2
-/* If the PLT entry whose reloc is 'reloc' resolves to a function in
-   the same object, return the target function's local entry point
-   offset if usable.  */
+extern void attribute_hidden _dl_error_localentry (struct link_map *map,
+						   const Elf64_Sym *refsym);
+
+/* If the PLT entry resolves to a function in the same object, return
+   the target function's local entry point offset if usable.  */
 static inline Elf64_Addr __attribute__ ((always_inline))
 ppc64_local_entry_offset (struct link_map *map, lookup_t sym_map,
-			  const Elf64_Rela *reloc)
+			  const ElfW(Sym) *refsym, const ElfW(Sym) *sym)
 {
-  const Elf64_Sym *symtab;
-  const Elf64_Sym *sym;
-
   /* If the target function is in a different object, we cannot
      use the local entry point.  */
   if (sym_map != map)
-    return 0;
+    {
+      /* Check that optimized plt call stubs for localentry:0 functions
+	 are not being satisfied by a non-zero localentry symbol.  */
+      if (map->l_info[DT_PPC64(OPT)]
+	  && (map->l_info[DT_PPC64(OPT)]->d_un.d_val & PPC64_OPT_LOCALENTRY) != 0
+	  && refsym->st_info == ELFW(ST_INFO) (STB_GLOBAL, STT_FUNC)
+	  && (STO_PPC64_LOCAL_MASK & refsym->st_other) == 0
+	  && (STO_PPC64_LOCAL_MASK & sym->st_other) != 0)
+	_dl_error_localentry (map, refsym);
+
+      return 0;
+    }
 
   /* If the linker inserted multiple TOCs, we cannot use the
      local entry point.  */
@@ -461,16 +471,13 @@ ppc64_local_entry_offset (struct link_map *map, lookup_t sym_map,
       && (map->l_info[DT_PPC64(OPT)]->d_un.d_val & PPC64_OPT_MULTI_TOC))
     return 0;
 
-  /* Otherwise, we can use the local entry point.  Retrieve its offset
-     from the symbol's ELF st_other field.  */
-  symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
-  sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
-
   /* If the target function is an ifunc then the local entry offset is
      for the resolver, not the final destination.  */
   if (__builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0))
     return 0;
 
+  /* Otherwise, we can use the local entry point.  Retrieve its offset
+     from the symbol's ELF st_other field.  */
   return PPC64_LOCAL_ENTRY_OFFSET (sym->st_other);
 }
 #endif
@@ -479,6 +486,7 @@ ppc64_local_entry_offset (struct link_map *map, lookup_t sym_map,
    routine.  */
 static inline Elf64_Addr __attribute__ ((always_inline))
 elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const Elf64_Rela *reloc,
 		       Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
 {
@@ -534,7 +542,7 @@ elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
   PPC_DCBST (&plt->fd_func);
   PPC_ISYNC;
 #else
-  finaladdr += ppc64_local_entry_offset (map, sym_map, reloc);
+  finaladdr += ppc64_local_entry_offset (map, sym_map, refsym, sym);
   *reloc_addr = finaladdr;
 #endif
 
@@ -543,6 +551,7 @@ elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
 
 static inline void __attribute__ ((always_inline))
 elf_machine_plt_conflict (struct link_map *map, lookup_t sym_map,
+			  const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 			  const Elf64_Rela *reloc,
 			  Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
 {
@@ -565,7 +574,7 @@ elf_machine_plt_conflict (struct link_map *map, lookup_t sym_map,
   PPC_DCBST (&plt->fd_toc);
   PPC_SYNC;
 #else
-  finaladdr += ppc64_local_entry_offset (map, sym_map, reloc);
+  finaladdr += ppc64_local_entry_offset (map, sym_map, refsym, sym);
   *reloc_addr = finaladdr;
 #endif
 }
@@ -604,11 +613,10 @@ elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
 
 #define dont_expect(X) __builtin_expect ((X), 0)
 
-extern void _dl_reloc_overflow (struct link_map *map,
-				const char *name,
-				Elf64_Addr *const reloc_addr,
-				const Elf64_Sym *refsym)
-				attribute_hidden;
+extern void attribute_hidden _dl_reloc_overflow (struct link_map *map,
+						 const char *name,
+						 Elf64_Addr *const reloc_addr,
+						 const Elf64_Sym *refsym);
 
 auto inline void __attribute__ ((always_inline))
 elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
@@ -728,9 +736,11 @@ elf_machine_rela (struct link_map *map,
       /* Fall thru */
     case R_PPC64_JMP_SLOT:
 #ifdef RESOLVE_CONFLICT_FIND_MAP
-      elf_machine_plt_conflict (map, sym_map, reloc, reloc_addr, value);
+      elf_machine_plt_conflict (map, sym_map, refsym, sym,
+				reloc, reloc_addr, value);
 #else
-      elf_machine_fixup_plt (map, sym_map, reloc, reloc_addr, value);
+      elf_machine_fixup_plt (map, sym_map, refsym, sym,
+			     reloc, reloc_addr, value);
 #endif
       return;
 
diff --git a/sysdeps/s390/s390-32/dl-machine.h b/sysdeps/s390/s390-32/dl-machine.h
index 2e3c77c58e..c302c9d2ce 100644
--- a/sysdeps/s390/s390-32/dl-machine.h
+++ b/sysdeps/s390/s390-32/dl-machine.h
@@ -294,6 +294,7 @@ dl_platform_init (void)
 
 static inline Elf32_Addr
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const Elf32_Rela *reloc,
 		       Elf32_Addr *reloc_addr, Elf32_Addr value)
 {
diff --git a/sysdeps/s390/s390-64/dl-machine.h b/sysdeps/s390/s390-64/dl-machine.h
index f2aeb1e78e..7513520417 100644
--- a/sysdeps/s390/s390-64/dl-machine.h
+++ b/sysdeps/s390/s390-64/dl-machine.h
@@ -242,6 +242,7 @@ dl_platform_init (void)
 
 static inline Elf64_Addr
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const Elf64_Rela *reloc,
 		       Elf64_Addr *reloc_addr, Elf64_Addr value)
 {
diff --git a/sysdeps/sh/dl-machine.h b/sysdeps/sh/dl-machine.h
index 2b468af6fa..7106afbdbd 100644
--- a/sysdeps/sh/dl-machine.h
+++ b/sysdeps/sh/dl-machine.h
@@ -230,6 +230,7 @@ dl_platform_init (void)
 
 static inline Elf32_Addr
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const Elf32_Rela *reloc,
 		       Elf32_Addr *reloc_addr, Elf32_Addr value)
 {
diff --git a/sysdeps/sparc/sparc32/dl-machine.h b/sysdeps/sparc/sparc32/dl-machine.h
index 95f673270e..436e4e6cc3 100644
--- a/sysdeps/sparc/sparc32/dl-machine.h
+++ b/sysdeps/sparc/sparc32/dl-machine.h
@@ -294,6 +294,7 @@ _dl_start_user:\n\
 
 static inline Elf32_Addr
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const Elf32_Rela *reloc,
 		       Elf32_Addr *reloc_addr, Elf32_Addr value)
 {
diff --git a/sysdeps/sparc/sparc64/dl-machine.h b/sysdeps/sparc/sparc64/dl-machine.h
index 1b59d78a25..c2871dca3a 100644
--- a/sysdeps/sparc/sparc64/dl-machine.h
+++ b/sysdeps/sparc/sparc64/dl-machine.h
@@ -85,6 +85,7 @@ elf_machine_load_address (void)
 
 static inline Elf64_Addr __attribute__ ((always_inline))
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const Elf64_Rela *reloc,
 		       Elf64_Addr *reloc_addr, Elf64_Addr value)
 {
diff --git a/sysdeps/tile/dl-machine.h b/sysdeps/tile/dl-machine.h
index c1d784548c..ae92673ac8 100644
--- a/sysdeps/tile/dl-machine.h
+++ b/sysdeps/tile/dl-machine.h
@@ -239,6 +239,7 @@ dl_platform_init (void)
 
 static inline ElfW(Addr)
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const ElfW(Rela) *reloc,
 		       ElfW(Addr) *reloc_addr, ElfW(Addr) value)
 {
@@ -569,7 +570,7 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
   switch (r_type)
     {
     case R_TILE(JMP_SLOT):
-      elf_machine_fixup_plt (map, 0, reloc, reloc_addr,
+      elf_machine_fixup_plt (map, 0, 0, 0, reloc, reloc_addr,
                              value + reloc->r_addend);
       return;
 
diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
index 0015db4d6a..6a04cbcdc9 100644
--- a/sysdeps/x86_64/dl-machine.h
+++ b/sysdeps/x86_64/dl-machine.h
@@ -253,6 +253,7 @@ dl_platform_init (void)
 
 static inline ElfW(Addr)
 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
 		       const ElfW(Rela) *reloc,
 		       ElfW(Addr) *reloc_addr, ElfW(Addr) value)
 {