summaryrefslogtreecommitdiff
path: root/libexec
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2010-03-27 20:16:16 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2010-03-27 20:16:16 +0000
commitdf315f56bf9147d202f3c714cb0fb50d85295e3c (patch)
treef4840e589b0868efe3368fbf08bfb9ee5f4e18b8 /libexec
parent21b0b497188e035770e07570c2576e6b17f6162b (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.S57
-rw-r--r--libexec/ld.so/mips64/rtld_machine.c62
-rw-r--r--libexec/ld.so/resolve.h4
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,