about summary refs log tree commit diff
path: root/sysdeps/powerpc/powerpc64/dl-machine.h
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/powerpc/powerpc64/dl-machine.h')
-rw-r--r--sysdeps/powerpc/powerpc64/dl-machine.h54
1 files changed, 32 insertions, 22 deletions
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;