diff options
author | 2010-01-03 22:18:04 +0000 | |
---|---|---|
committer | 2010-01-03 22:18:04 +0000 | |
commit | 8cd9acbbc7c62d06bb2ca70c10977f9a5d8e8e1f (patch) | |
tree | bfc1d398263d7e375e341a6e312f30ea3f826f1d | |
parent | Install mandoc_char(7), a comprehensive overview of mandoc(1) special (diff) | |
download | wireguard-openbsd-8cd9acbbc7c62d06bb2ca70c10977f9a5d8e8e1f.tar.xz wireguard-openbsd-8cd9acbbc7c62d06bb2ca70c10977f9a5d8e8e1f.zip |
Make lazy binding work on hppa.
ok miod@
-rw-r--r-- | libexec/ld.so/hppa/ldasm.S | 11 | ||||
-rw-r--r-- | libexec/ld.so/hppa/rtld_machine.c | 82 |
2 files changed, 81 insertions, 12 deletions
diff --git a/libexec/ld.so/hppa/ldasm.S b/libexec/ld.so/hppa/ldasm.S index 6f5f6e6446c..69827916c1e 100644 --- a/libexec/ld.so/hppa/ldasm.S +++ b/libexec/ld.so/hppa/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.4 2006/05/03 16:10:52 drahn Exp $ */ +/* $OpenBSD: ldasm.S,v 1.5 2010/01/03 22:18:04 kettenis Exp $ */ /* * Copyright (c) 2004 Michael Shalayeff @@ -123,6 +123,13 @@ ENTRY(hppa_call,0) ldwm -HPPA_FRAME_SIZE(sp), r3 EXIT(hppa_call) +/* + * This is a magic branch instruction that is used by GCC's + * __canonicalize_funcptr_for_compare() function to fixup relocations + * in order to do function pointer comparisons. + */ + bl _dl_bind, rp + ENTRY(_dl_bind_start,32) copy r3, r1 copy sp, r3 @@ -133,6 +140,7 @@ ENTRY(_dl_bind_start,32) stw arg1, HPPA_FRAME_ARG(1)(r3) stw arg2, HPPA_FRAME_ARG(2)(r3) stw arg3, HPPA_FRAME_ARG(3)(r3) + stw t1, 4(r3) stw ret0, 8(r3) stw ret1, 12(r3) @@ -150,6 +158,7 @@ ENTRY(_dl_bind_start,32) ldw HPPA_FRAME_ARG(1)(r3), arg1 ldw HPPA_FRAME_ARG(2)(r3), arg2 ldw HPPA_FRAME_ARG(3)(r3), arg3 + ldw 4(r3), t1 ldw 8(r3), ret0 ldw 12(r3), ret0 diff --git a/libexec/ld.so/hppa/rtld_machine.c b/libexec/ld.so/hppa/rtld_machine.c index 89bc37c4e4f..ab0714b8c21 100644 --- a/libexec/ld.so/hppa/rtld_machine.c +++ b/libexec/ld.so/hppa/rtld_machine.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtld_machine.c,v 1.16 2008/11/09 12:34:47 tobias Exp $ */ +/* $OpenBSD: rtld_machine.c,v 1.17 2010/01/03 22:18:04 kettenis Exp $ */ /* * Copyright (c) 2004 Michael Shalayeff @@ -285,6 +285,18 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz) return (fails); } +extern void _dl_bind_start(void); + +#define PLT_STUB_SIZE (7 * 4) +#define PLT_ENTRY_SIZE (2 * 4) +#define PLT_STUB_GOTOFF (4 * 4) + +#define PLT_STUB_MAGIC1 0x00c0ffee +#define PLT_STUB_MAGIC2 0xdeadbeef + +#define PLT_STUB_INSN1 0x0e801081 /* ldw 0(%r20), %r1 */ +#define PLT_STUB_INSN2 0xe820c000 /* bv %r0(%r1) */ + int _dl_md_reloc_got(elf_object_t *object, int lazy) { @@ -296,8 +308,6 @@ _dl_md_reloc_got(elf_object_t *object, int lazy) if (object->dyn.pltrel != DT_RELA) return (0); - lazy = 0; /* force busy binding */ - object->got_addr = NULL; object->got_size = 0; this = NULL; @@ -323,17 +333,66 @@ _dl_md_reloc_got(elf_object_t *object, int lazy) if (!lazy) { fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); } else { + register Elf_Addr ltp __asm ("%r19"); + Elf_Addr *got = NULL; + rela = (Elf_RelA *)(object->dyn.jmprel); numrela = object->dyn.pltrelsz / sizeof(Elf_RelA); ooff = object->obj_base; + /* + * Find the PLT stub by looking at all the + * relocations. The PLT stub should be at the end of + * the .plt section so we start with the last + * relocation, since the linker should have emitted + * them in order. + */ + for (i = numrela - 1; i >= 0; i--) { + got = (Elf_Addr *)(ooff + rela[i].r_offset + + PLT_ENTRY_SIZE + PLT_STUB_SIZE); + if (got[-2] == PLT_STUB_MAGIC1 || + got[-1] == PLT_STUB_MAGIC2) + break; + got = NULL; + } + if (got == NULL) + return (1); + + /* + * Patch up the PLT stub such that it doesn't clobber + * %r22, which is used to pass on the errno values + * from failed system calls to __cerrno() in libc. + */ + got[-7] = PLT_STUB_INSN1; + got[-6] = PLT_STUB_INSN2; + __asm __volatile("fdc 0(%0)" :: "r" (&got[-7])); + __asm __volatile("fdc 0(%0)" :: "r" (&got[-6])); + __asm __volatile("sync"); + __asm __volatile("fic 0(%0)" :: "r" (&got[-7])); + __asm __volatile("fic 0(%0)" :: "r" (&got[-6])); + __asm __volatile("sync"); + + /* + * Fill in the PLT stub such that it invokes the + * _dl_bind_start() trampoline to fix up the + * relocation. + */ + got[1] = (Elf_Addr)object; + got[-2] = (Elf_Addr)&_dl_bind_start; + got[-1] = ltp; for (i = 0; i < numrela; i++, rela++) { Elf_Addr *r_addr = (Elf_Addr *)(ooff + rela->r_offset); + if (ELF_R_TYPE(rela->r_info) != RELOC_IPLT) { + _dl_printf("unexpected reloc 0x%x\n", + ELF_R_TYPE(rela->r_info)); + return (1); + } + if (ELF_R_SYM(rela->r_info)) { - r_addr[0] = 0; /* TODO */ - r_addr[1] = (Elf_Addr) ((void *)rela - - (void *)object->dyn.jmprel); + r_addr[0] = (Elf_Addr)got - PLT_STUB_GOTOFF; + r_addr[1] = (Elf_Addr) (rela - + (Elf_RelA *)object->dyn.jmprel); } else { r_addr[0] = ooff + rela->r_addend; r_addr[1] = (Elf_Addr)object->dyn.pltgot; @@ -342,7 +401,7 @@ _dl_md_reloc_got(elf_object_t *object, int lazy) } if (object->got_size != 0) _dl_mprotect((void *)object->got_start, object->got_size, - GOT_PERMS); + GOT_PERMS|PROT_EXEC); return (fails); } @@ -361,7 +420,7 @@ _dl_bind(elf_object_t *object, int reloff) Elf_RelA *rela; sigset_t omask, nmask; - rela = (Elf_RelA *)(object->dyn.jmprel + reloff); + rela = (Elf_RelA *)object->dyn.jmprel + reloff; sym = object->dyn.symtab; sym += ELF_R_SYM(rela->r_info); @@ -375,8 +434,9 @@ _dl_bind(elf_object_t *object, int reloff) _dl_printf("lazy binding failed!\n"); *((int *)0) = 0; /* XXX */ } + DL_DEB(("%s: %s\n", symn, sobj->load_name)); - value = ooff + this->st_value; + value = ooff + this->st_value + rela->r_addend; /* if PLT+GOT is protected, allow the write */ if (object->got_size != 0) { @@ -395,10 +455,10 @@ _dl_bind(elf_object_t *object, int reloff) if (object->got_size != 0) { /* mprotect the actual modified region, not the whole plt */ _dl_mprotect((void*)addr, sizeof (Elf_Addr) * 3, - PROT_READ); + PROT_READ|PROT_EXEC); _dl_thread_bind_lock(1); _dl_sigprocmask(SIG_SETMASK, &omask, NULL); } - return (value); + return ((Elf_Addr)addr); } |