]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
hppa: fix dladdr [BZ #19415]
authorJohn David Anglin <dave.anglin@bell.net>
Sat, 2 Jan 2016 14:48:18 +0000 (09:48 -0500)
committerMike Frysinger <vapier@gentoo.org>
Fri, 8 Jan 2016 07:19:26 +0000 (02:19 -0500)
The attached patch fixes dladdr on hppa.

Instead of using the generic version of _dl_lookup_address, we use an
implementation more or less modeled after __canonicalize_funcptr_for_compare()
in gcc.  The function pointer is analyzed and if it points to the
trampoline used to call _dl_runtime_resolve just before the global
offset table, then we call _dl_fixup to resolve the function pointer.
Then, we return the instruction pointer from the first word of the
descriptor.

The change fixes the testcase provided in [BZ #19415] and the Debian
nss package now builds successfully.

ChangeLog
sysdeps/hppa/dl-fptr.c
sysdeps/hppa/dl-lookupcfg.h

index 4db27e679f3838efca30fb681e88d8b3d148527a..56298db37c8d6b4bd46574519c994aab07c46711 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2016-01-08  John David Anglin  <danglin@gcc.gnu.org>
+
+       [BZ #19415]
+       * sysdeps/hppa/dl-fptr.c (_dl_fixup): Declare.
+       (elf_machine_resolve): New.  Return address of _dl_runtime_resolve.
+       (_dl_lookup_address): Rewrite using function resolver trampoline.
+       * sysdeps/hppa/dl-lookupcfg.h (DL_LOOKUP_ADDRESS): Don't clear bottom
+       two bits in address.
+
 2016-01-07  Mike Frysinger  <vapier@gentoo.org>
 
        * longlong.h: Change !__SHMEDIA__ to
index 6b2e331f280e69de4e096e04f4f7429c3ba08627..083242b7e319f52509e04cc75fe137d5f7e32305 100644 (file)
@@ -315,23 +315,54 @@ _dl_unmap (struct link_map *map)
   map->l_mach.fptr_table = NULL;
 }
 
+extern ElfW(Addr) _dl_fixup (struct link_map *, ElfW(Word)) attribute_hidden;
 
-ElfW(Addr)
-_dl_lookup_address (const void *address)
+static inline Elf32_Addr
+elf_machine_resolve (void)
 {
-  ElfW(Addr) addr = (ElfW(Addr)) address;
-  struct fdesc_table *t;
-  unsigned long int i;
+  Elf32_Addr addr;
 
-  for (t = local.root; t != NULL; t = t->next)
-    {
-      i = (struct fdesc *) addr - &t->fdesc[0];
-      if (i < t->first_unused && addr == (ElfW(Addr)) &t->fdesc[i])
-       {
-         addr = t->fdesc[i].ip;
-         break;
-       }
-    }
+  asm ("b,l     1f,%0\n"
+"      depi    0,31,2,%0\n"
+"1:    addil   L'_dl_runtime_resolve - ($PIC_pcrel$0 - 8),%0\n"
+"      ldo     R'_dl_runtime_resolve - ($PIC_pcrel$0 - 12)(%%r1),%0\n"
+       : "=r" (addr) : : "r1");
 
   return addr;
 }
+
+ElfW(Addr)
+_dl_lookup_address (const void *address)
+{
+  ElfW(Addr) addr = (ElfW(Addr)) address;
+  unsigned int *desc, *gptr;
+
+  /* Check for special cases.  */
+  if ((int) addr == -1
+      || (unsigned int) addr < 4096
+      || !((unsigned int) addr & 2))
+    return addr;
+
+  /* Clear least-significant two bits from descriptor address.  */
+  desc = (unsigned int *) ((unsigned int) addr & ~3);
+
+  /* Check if descriptor requires resolution.  The following trampoline is
+     used in each global offset table for function resolution:
+
+               ldw 0(r20),r22
+               bv r0(r22)
+               ldw 4(r20),r21
+     tramp:    b,l .-12,r20
+               depwi 0,31,2,r20
+               .word _dl_runtime_resolve
+               .word "_dl_runtime_resolve ltp"
+     got:      .word _DYNAMIC
+               .word "struct link map address" */
+  gptr = (unsigned int *) desc[0];
+  if (gptr[0] == 0xea9f1fdd                    /* b,l .-12,r20     */
+      && gptr[1] == 0xd6801c1e                 /* depwi 0,31,2,r20 */
+      && (ElfW(Addr)) gptr[2] == elf_machine_resolve ())
+    _dl_fixup ((struct link_map *) gptr[5], (ElfW(Word)) desc[1]);
+
+  return (ElfW(Addr)) desc[0];
+}
index 998180c81dc430469441f0bc7975b0b2428605b4..3f1d14aa2f876bcd580ac4b1e91a719922be3215 100644 (file)
@@ -31,9 +31,7 @@ rtld_hidden_proto (_dl_symbol_address)
 
 Elf32_Addr _dl_lookup_address (const void *address);
 
-/* Clear the bottom two bits so generic code can find the fdesc entry */
-#define DL_LOOKUP_ADDRESS(addr) \
-  (_dl_lookup_address ((void *)((unsigned long)addr & ~3)))
+#define DL_LOOKUP_ADDRESS(addr) _dl_lookup_address ((const void *) addr)
 
 void attribute_hidden _dl_unmap (struct link_map *map);