diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2010-03-27 20:16:16 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2010-03-27 20:16:16 +0000 |
commit | df315f56bf9147d202f3c714cb0fb50d85295e3c (patch) | |
tree | f4840e589b0868efe3368fbf08bfb9ee5f4e18b8 /libexec | |
parent | 21b0b497188e035770e07570c2576e6b17f6162b (diff) |
Implement lazy binding on mips64. This implementation relies on having two
reserved entries in the GOT, which is a GNU extension to the 64-bit MIPS
SVR4 ABI. That's fine; all existing OpenBSD/mips64 binaries have the extra
slot.
ok miod@, jsing@, drahn@
Diffstat (limited to 'libexec')
-rw-r--r-- | libexec/ld.so/mips64/ldasm.S | 57 | ||||
-rw-r--r-- | libexec/ld.so/mips64/rtld_machine.c | 62 | ||||
-rw-r--r-- | libexec/ld.so/resolve.h | 4 |
3 files changed, 106 insertions, 17 deletions
diff --git a/libexec/ld.so/mips64/ldasm.S b/libexec/ld.so/mips64/ldasm.S index d2d9568d798..fa96800fa1b 100644 --- a/libexec/ld.so/mips64/ldasm.S +++ b/libexec/ld.so/mips64/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.4 2004/09/21 09:54:08 pefo Exp $ */ +/* $OpenBSD: ldasm.S,v 1.5 2010/03/27 20:16:15 kettenis Exp $ */ /* * Copyright (c) 1998-2002 Opsycon AB, Sweden. @@ -102,9 +102,54 @@ LEAF(_dl__syscall, 0) j ra END(_dl__syscall) - .globl _dl_rt_resolve - .ent _dl_rt_resolve, 0 -_dl_rt_resolve: +FRAMESZ= MKFSIZ(4,16) +GPOFF= FRAMESZ-2*REGSZ +RAOFF= FRAMESZ-1*REGSZ +A0OFF= FRAMESZ-3*REGSZ +A1OFF= FRAMESZ-4*REGSZ +A2OFF= FRAMESZ-5*REGSZ +A3OFF= FRAMESZ-6*REGSZ +A4OFF= FRAMESZ-7*REGSZ +A5OFF= FRAMESZ-8*REGSZ +A6OFF= FRAMESZ-9*REGSZ +A7OFF= FRAMESZ-10*REGSZ +S0OFF= FRAMESZ-11*REGSZ -/* XXX Fix when lazy binding works */ - .end _dl_rt_resolve + .globl _dl_bind_start + .ent _dl_bind_start, 0 +_dl_bind_start: + ld v1, -32744(gp) + PTR_SUBU sp, FRAMESZ + SETUP_GP64(GPOFF, _dl_bind_start) + REG_S a0, A0OFF(sp) + REG_S a1, A1OFF(sp) + REG_S a2, A2OFF(sp) + REG_S a3, A3OFF(sp) + REG_S a4, A4OFF(sp) + REG_S a5, A5OFF(sp) + REG_S a6, A6OFF(sp) + REG_S a7, A7OFF(sp) + REG_S $15, RAOFF(sp) + REG_S s0, S0OFF(sp) + move s0, sp + move a0, v1 + move a1, t8 + jal _dl_bind + nop + move sp, s0 + REG_L ra, RAOFF(sp) + REG_L s0, S0OFF(sp) + REG_L a0, A0OFF(sp) + REG_L a1, A1OFF(sp) + REG_L a2, A2OFF(sp) + REG_L a3, A3OFF(sp) + REG_L a4, A4OFF(sp) + REG_L a5, A5OFF(sp) + REG_L a6, A6OFF(sp) + REG_L a7, A7OFF(sp) + RESTORE_GP64 + PTR_ADDU sp, FRAMESZ + move t9, v0 + jr t9 + nop + .end _dl_bind_start diff --git a/libexec/ld.so/mips64/rtld_machine.c b/libexec/ld.so/mips64/rtld_machine.c index 024a3270c4d..3a4bd1b88f1 100644 --- a/libexec/ld.so/mips64/rtld_machine.c +++ b/libexec/ld.so/mips64/rtld_machine.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtld_machine.c,v 1.11 2008/04/09 21:45:26 kurt Exp $ */ +/* $OpenBSD: rtld_machine.c,v 1.12 2010/03/27 20:16:15 kettenis Exp $ */ /* * Copyright (c) 1998-2004 Opsycon AB, Sweden. @@ -32,6 +32,8 @@ #include <sys/mman.h> #include <link.h> +#include <signal.h> + #include "resolve.h" #include "syscall.h" #include "archdep.h" @@ -159,6 +161,8 @@ _dl_md_reloc(elf_object_t *object, int rel, int relsz) return(fails); } +extern void _dl_bind_start(void); + /* * Relocate the Global Offset Table (GOT). Currently we don't * do lazy evaluation here because the GNU linker doesn't @@ -182,7 +186,6 @@ _dl_md_reloc_got(elf_object_t *object, int lazy) if (object->status & STAT_GOT_DONE) return (0); - lazy = 0; /* XXX Fix ld before enabling lazy */ loff = object->obj_base; strt = object->dyn.strtab; gotp = object->dyn.pltgot; @@ -192,13 +195,11 @@ _dl_md_reloc_got(elf_object_t *object, int lazy) /* * Set up pointers for run time (lazy) resolving. */ - gotp[0] = (long)_dl_rt_resolve; - if (gotp[1] & 0x0000000080000000) { - gotp[1] = (long)object | 0x0000000080000000; - } + gotp[0] = (long)_dl_bind_start; + gotp[1] = (long)object; /* First do all local references. */ - for (i = ((gotp[1] & 0x0000000080000000) ? 2 : 1); i < n; i++) { + for (i = 2; i < n; i++) { gotp[i] += loff; } @@ -239,7 +240,7 @@ _dl_md_reloc_got(elf_object_t *object, int lazy) if (this) *gotp = this->st_value + ooff; } else - *gotp = symp->st_value + ooff; + *gotp = symp->st_value + loff; } else if (symp->st_shndx == SHN_COMMON || symp->st_shndx == SHN_UNDEF) { this = 0; @@ -273,3 +274,48 @@ _dl_md_reloc_got(elf_object_t *object, int lazy) return (0); } + +Elf_Addr +_dl_bind(elf_object_t *object, int symidx) +{ + Elf_Addr *gotp = object->dyn.pltgot; + Elf_Addr *addr, ooff; + const Elf_Sym *sym, *this; + const char *symn; + sigset_t omask, nmask; + int n; + + sym = object->dyn.symtab; + sym += symidx; + symn = object->dyn.strtab + sym->st_name; + n = object->Dyn.info[DT_MIPS_LOCAL_GOTNO - DT_LOPROC + DT_NUM] - + object->Dyn.info[DT_MIPS_GOTSYM - DT_LOPROC + DT_NUM]; + + ooff = _dl_find_symbol(symn, &this, + SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym, object, NULL); + if (this == NULL) { + _dl_printf("lazy binding failed\n"); + *((int *)0) = 0; /* XXX */ + } + + addr = &gotp[n + symidx]; + + /* if GOT is protected, allow the write */ + if (object->got_size != 0) { + sigfillset(&nmask); + _dl_sigprocmask(SIG_BLOCK, &nmask, &omask); + _dl_thread_bind_lock(0); + _dl_mprotect(addr, sizeof(Elf_Addr), PROT_READ|PROT_WRITE); + } + + *addr = ooff + this->st_value; + + /* if GOT is (to be protected, change back to RO */ + if (object->got_size != 0) { + _dl_mprotect(addr, sizeof (Elf_Addr), PROT_READ); + _dl_thread_bind_lock(1); + _dl_sigprocmask(SIG_SETMASK, &omask, NULL); + } + + return *addr; +} diff --git a/libexec/ld.so/resolve.h b/libexec/ld.so/resolve.h index 29eb09f3dcc..8500a6703c9 100644 --- a/libexec/ld.so/resolve.h +++ b/libexec/ld.so/resolve.h @@ -1,4 +1,4 @@ -/* $OpenBSD: resolve.h,v 1.57 2008/05/05 02:29:02 kurt Exp $ */ +/* $OpenBSD: resolve.h,v 1.58 2010/03/27 20:16:15 kettenis Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -148,8 +148,6 @@ struct dep_node { elf_object_t *data; }; -void _dl_rt_resolve(void); - void _dl_add_object(elf_object_t *object); elf_object_t *_dl_finalize_object(const char *objname, Elf_Dyn *dynp, Elf_Phdr *phdrp, int phdrc, const int objtype, const long lbase, |