From patchwork Sat Jan 2 14:48:18 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John David Anglin X-Patchwork-Id: 10194 Received: (qmail 1122 invoked by alias); 2 Jan 2016 14:48:27 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 1075 invoked by uid 89); 2 Jan 2016 14:48:22 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD, SPF_PASS, UNPARSEABLE_RELAY autolearn=ham version=3.3.2 spammy=319, bl, ltp, resolver X-HELO: torfep01.bell.net From: John David Anglin Mime-Version: 1.0 (Apple Message framework v1085) Date: Sat, 2 Jan 2016 09:48:18 -0500 Subject: [PATCH] Fix dladdr on hppa Cc: Carlos O'Donell , Mike Frysinger , Helge Deller To: GNU C Library Message-Id: <6F97DB2A-5F4F-4C30-9F7C-395E49DB18FA@bell.net> X-Opwv-CommTouchExtSvcRefID: str=0001.0A020201.5687E333.0061, ss=1, re=0.000, fgs=0 The attached patch fixes dladdr on hppa. Instead of using the generic version of _dl_lookup_address, we use an implementation more or less modelled 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. Please install if okay. Thanks, Dave --- John David Anglin dave.anglin@bell.net 2016-01-02 John David Anglin [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. diff --git a/sysdeps/hppa/dl-fptr.c b/sysdeps/hppa/dl-fptr.c index bb12ab2..ddb9db7 100644 --- a/sysdeps/hppa/dl-fptr.c +++ b/sysdeps/hppa/dl-fptr.c @@ -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]; +} diff --git a/sysdeps/hppa/dl-lookupcfg.h b/sysdeps/hppa/dl-lookupcfg.h index c36928c..0b4dc45 100644 --- a/sysdeps/hppa/dl-lookupcfg.h +++ b/sysdeps/hppa/dl-lookupcfg.h @@ -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);