Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
hppa: fix dladdr [BZ #19415]
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.
  • Loading branch information
John David Anglin authored and Mike Frysinger committed Jan 8, 2016
1 parent 6e76c11 commit 48025aa
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 17 deletions.
9 changes: 9 additions & 0 deletions 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
Expand Down
59 changes: 45 additions & 14 deletions sysdeps/hppa/dl-fptr.c
Expand Up @@ -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];
}
4 changes: 1 addition & 3 deletions sysdeps/hppa/dl-lookupcfg.h
Expand Up @@ -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);

Expand Down

0 comments on commit 48025aa

Please sign in to comment.