about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--sysdeps/powerpc/powerpc64/dl-machine.h30
2 files changed, 32 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index 8e159ac507..38ac2ac26c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2015-03-26  Alan Modra  <amodra@gmail.com>
+
+	* sysdeps/powerpc/powerpc64/dl-machine.h (elf_machine_fixup_plt):
+	Don't segfault if ifunc resolver returns a NULL.  Do set plt to
+	zero for undefined weak.
+	(elf_machine_plt_conflict): Similarly.
+
 2015-03-25  Joseph Myers  <joseph@codesourcery.com>
 
 	* math/auto-libm-test-in: Add more tests of acosh, asinh and
diff --git a/sysdeps/powerpc/powerpc64/dl-machine.h b/sysdeps/powerpc/powerpc64/dl-machine.h
index 55ac73624b..0576781909 100644
--- a/sysdeps/powerpc/powerpc64/dl-machine.h
+++ b/sysdeps/powerpc/powerpc64/dl-machine.h
@@ -472,19 +472,32 @@ elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map,
   Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
   Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
   Elf64_Addr offset = 0;
+  Elf64_FuncDesc zero_fd = {0, 0, 0};
 
   PPC_DCBT (&plt->fd_aux);
   PPC_DCBT (&plt->fd_func);
-  PPC_DCBT (&rel->fd_aux);
-  PPC_DCBT (&rel->fd_func);
 
-  /* If sym_map is NULL, it's a weak undefined sym;  Leave the plt zero.  */
+  /* If sym_map is NULL, it's a weak undefined sym;  Set the plt to
+     zero.  finaladdr should be zero already in this case, but guard
+     against invalid plt relocations with non-zero addends.  */
   if (sym_map == NULL)
-    return 0;
+    finaladdr = 0;
+
+  /* Don't die here if finaladdr is zero, die if this plt entry is
+     actually called.  Makes a difference when LD_BIND_NOW=1.
+     finaladdr may be zero for a weak undefined symbol, or when an
+     ifunc resolver returns zero.  */
+  if (finaladdr == 0)
+    rel = &zero_fd;
+  else
+    {
+      PPC_DCBT (&rel->fd_aux);
+      PPC_DCBT (&rel->fd_func);
+    }
 
   /* If the opd entry is not yet relocated (because it's from a shared
      object that hasn't been processed yet), then manually reloc it.  */
-  if (map != sym_map && !sym_map->l_relocated
+  if (finaladdr != 0 && map != sym_map && !sym_map->l_relocated
 #if !defined RTLD_BOOTSTRAP && defined SHARED
       /* Bootstrap map doesn't have l_relocated set for it.  */
       && sym_map != &GL(dl_rtld_map)
@@ -522,6 +535,13 @@ elf_machine_plt_conflict (struct link_map *map, lookup_t sym_map,
 #if _CALL_ELF != 2
   Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
   Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
+  Elf64_FuncDesc zero_fd = {0, 0, 0};
+
+  if (sym_map == NULL)
+    finaladdr = 0;
+
+  if (finaladdr == 0)
+    rel = &zero_fd;
 
   plt->fd_func = rel->fd_func;
   plt->fd_aux = rel->fd_aux;