diff options
Diffstat (limited to 'libexec')
-rw-r--r-- | libexec/ld.so/sparc64/archdep.h | 12 | ||||
-rw-r--r-- | libexec/ld.so/sparc64/ldasm.S | 43 | ||||
-rw-r--r-- | libexec/ld.so/sparc64/rtld_machine.c | 244 |
3 files changed, 278 insertions, 21 deletions
diff --git a/libexec/ld.so/sparc64/archdep.h b/libexec/ld.so/sparc64/archdep.h index 5013f14413c..14936fa9bce 100644 --- a/libexec/ld.so/sparc64/archdep.h +++ b/libexec/ld.so/sparc64/archdep.h @@ -1,4 +1,4 @@ -/* $OpenBSD: archdep.h,v 1.1 2001/09/21 14:57:43 jason Exp $ */ +/* $OpenBSD: archdep.h,v 1.2 2001/09/23 00:14:56 drahn Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -128,19 +128,21 @@ _dl_strchr(const char *p, const int c) static inline void RELOC_RELA(Elf64_Rela *r, const Elf64_Sym *s, Elf64_Addr *p, unsigned long v) { -#error "haven't fixed for sparc64 yet..." extern Elf_Addr _GLOBAL_OFFSET_TABLE_[]; - if (ELF64_R_TYPE(r->r_info) == RELOC_RELATIVE) { + if (ELF64_R_TYPE(r->r_info) == R_SPARC_RELATIVE) { if ((caddr_t)p < (caddr_t)_GLOBAL_OFFSET_TABLE_ || (caddr_t)p >= (caddr_t)&_DYNAMIC) *p += (Elf_Addr)v; - } else if (ELF64_R_TYPE(r->r_info) == RELOC_JMP_SLOT) { + } else if (ELF64_R_TYPE(r->r_info) == R_SPARC_JMP_SLOT) { Elf64_Addr val = v + s->st_value + r->r_addend - (Elf64_Addr)(p); *p = val; + /* + * need instruction cache flush? - XXX __asm __volatile("imb" : : : "memory"); - } else if (ELF64_R_TYPE(r->r_info) == RELOC_GLOB_DAT) { + */ + } else if (ELF64_R_TYPE(r->r_info) == R_SPARC_64) { *p = v + s->st_value + r->r_addend; } else { _dl_printf("unknown bootstrap relocation\n"); diff --git a/libexec/ld.so/sparc64/ldasm.S b/libexec/ld.so/sparc64/ldasm.S index 67148b06b67..f86f4b2a312 100644 --- a/libexec/ld.so/sparc64/ldasm.S +++ b/libexec/ld.so/sparc64/ldasm.S @@ -1,4 +1,4 @@ -/* $OpenBSD: ldasm.S,v 1.1 2001/09/21 14:52:45 jason Exp $ */ +/* $OpenBSD: ldasm.S,v 1.2 2001/09/23 00:14:56 drahn Exp $ */ /* $NetBSD: rtld_start.S,v 1.5 2001/08/14 22:17:48 eeh Exp $ */ /* @@ -131,21 +131,21 @@ _dl_start: * We have two separate entry points to the runtime linker. * I'm implementing this following the SPARC v9 ABI spec. * - * _rtld_bind_start_0(x, y) is called from .PLT0, and is used for + * _dl_bind_start_0(x, y) is called from .PLT0, and is used for * PLT entries above 32768. * - * _rtld_bind_start_1(x, y) is called from .PLT1, and is used for + * _dl_bind_start_1(x, y) is called from .PLT1, and is used for * PLT entries below 32768. * * The first two entries of PLT2 contain the xword object pointer. * * These routines are called with two longword arguments, * x and y. To calculate the address of the entry, - * _rtld_bind_start_1(x, y) does: + * _dl_bind_start_1(x, y) does: * * n = x >> 15; * - * and _rtld_bind_start_0(x, y) does: + * and _dl_bind_start_0(x, y) does: * * i = x - y + 1048596; * n = 32768 + (i/5120)*160 + (i%5120)/24; @@ -154,15 +154,15 @@ _dl_start: * done in the PLT entry. */ - /* NOTE: _rtld_bind_start_0 is untested. Hence the debug stuff */ + /* NOTE: _dl_bind_start_0 is untested. Hence the debug stuff */ .section ".text" .align 4 - .global _rtld_bind_start_0 - .type _rtld_bind_start_0,@function -_rtld_bind_start_0: # (x, y) + .global _dl_bind_start_0 + .type _dl_bind_start_0,@function +_dl_bind_start_0: # (x, y) #if 0 - call _rtld_bind_start_0_stub + call _dl_bind_start_0_stub ldx [%o1 + (10*4)], %l7 mov %o0, %l5 @@ -170,7 +170,7 @@ _rtld_bind_start_0: # (x, y) add %l6, %l5, %l5 /* is 3 longwords or 24 bytes. */ sllx %l5, 3, %o1 /* So multiply by 24. */ - call _rtld_bind + call _dl_bind mov %l7, %o0 #else sethi %hi(1048596), %l1 @@ -198,7 +198,7 @@ _rtld_bind_start_0: # (x, y) add %l6, %l5, %l5 /* is 3 longwords or 24 bytes. */ sllx %l5, 3, %l5 /* So multiply by 24. */ - call _rtld_bind /* Call _rtld_bind(obj, offset) */ + call _dl_bind /* Call _dl_bind(obj, offset) */ mov %l5, %o1 jmp %o0 /* return value == function address */ @@ -207,9 +207,9 @@ _rtld_bind_start_0: # (x, y) .section ".text" .align 4 - .global _rtld_bind_start_1 - .type _rtld_bind_start_1,@function -_rtld_bind_start_1: # (x, y) + .global _dl_bind_start_1 + .type _dl_bind_start_1,@function +_dl_bind_start_1: # (x, y) srax %o0, 15, %o2 /* %o0 is the index to our PLT slot */ sllx %o2, 1, %o3 /* Each element is an Elf_Rela which */ @@ -218,7 +218,7 @@ _rtld_bind_start_1: # (x, y) ldx [%o1 + 8], %o0 /* The object pointer is at [%o1 + 8] */ - call _rtld_bind /* Call _rtld_bind(obj, offset) */ + call _dl_bind /* Call _dl_bind(obj, offset) */ mov %o2, %o1 jmp %o0 /* return value == function address */ @@ -308,6 +308,17 @@ _dl_mmap: retl sub %g0, %o0, %o0 ! error: result = -errno + .section ".text" + .align 4 + .global _dl_munmap + .type _dl_munmap,@function +_dl_munmap: + mov SYS_munmap | SYSCALL_G2RFLAG, %g1 ! calling sys_mmap + add %o7, 8, %g2 ! just return on sucess + t ST_SYSCALL ! off to wonderland + retl + sub %g0, %o0, %o0 ! error: result = -errno + .section ".text" .align 4 diff --git a/libexec/ld.so/sparc64/rtld_machine.c b/libexec/ld.so/sparc64/rtld_machine.c new file mode 100644 index 00000000000..2296ffd2ea9 --- /dev/null +++ b/libexec/ld.so/sparc64/rtld_machine.c @@ -0,0 +1,244 @@ +/* $OpenBSD: rtld_machine.c,v 1.1 2001/09/23 00:14:56 drahn Exp $ */ + +/* + * Copyright (c) 1999 Dale Rahn + * Copyright (c) 2001 Niklas Hallqvist + * Copyright (c) 2001 Artur Grabowski + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed under OpenBSD by + * Dale Rahn. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#define _DYN_LOADER + +#include <sys/types.h> +#include <sys/cdefs.h> +#include <sys/mman.h> + +#include <nlist.h> +#include <link.h> + +#include "syscall.h" +#include "archdep.h" +#include "resolve.h" + +void +_dl_bcopy(void *src, void *dest, int size) +{ + unsigned char *psrc, *pdest; + int i; + psrc = src; + pdest = dest; + for (i = 0; i < size; i++) { + pdest[i] = psrc[i]; + } +} + +int +_dl_md_reloc(elf_object_t *object, int rel, int relasz) +{ + long i; + long numrela; + long fails = 0; + Elf64_Addr loff; + Elf64_Rela *relas; + load_list_t *llist; + + loff = object->load_offs; + numrela = object->Dyn.info[relasz] / sizeof(Elf64_Rela); + relas = (Elf64_Rela *)(object->Dyn.info[rel]); + + if ((object->status & STAT_RELOC_DONE) || !relas) { + return(0); + } + + /* + * unprotect some segments if we need it. + * XXX - we unprotect waay to much. only the text can have cow + * relocations. + */ + if ((rel == DT_REL || rel == DT_RELA)) { + for (llist = object->load_list; llist != NULL; llist = llist->next) { + if (!(llist->prot & PROT_WRITE)) { + _dl_mprotect(llist->start, llist->size, + llist->prot|PROT_WRITE); + } + } + } + + for (i = 0; i < numrela; i++, relas++) { + Elf64_Addr *r_addr; + Elf64_Addr ooff; + const Elf64_Sym *sym, *this; + const char *symn; + + r_addr = (Elf64_Addr *)(relas->r_offset + loff); + + if (ELF64_R_SYM(relas->r_info) == 0xffffffff) { + continue; + } + + sym = object->dyn.symtab; + sym += ELF64_R_SYM(relas->r_info); + symn = object->dyn.strtab + sym->st_name; + + this = NULL; + switch (ELF64_R_TYPE(relas->r_info)) { + case R_TYPE(64): + ooff = _dl_find_symbol(symn, _dl_objects, &this, 0, 1); + if (this == NULL) + goto resolve_failed; + *r_addr += ooff + this->st_value + relas->r_addend; + break; + case R_TYPE(RELATIVE): + /* + * There is a lot of unaligned RELATIVE + * relocs generated by gcc in the exception handlers. + */ + if ((((Elf_Addr) r_addr) & 0x7) != 0) { + Elf_Addr tmp; +#if 0 +_dl_printf("unaligned RELATIVE: %p type: %d %s 0x%lx -> 0x%lx\n", r_addr, +ELF_R_TYPE(relas->r_info), object->load_name, *r_addr, *r_addr+loff); +#endif + _dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr)); + tmp += loff; + _dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr)); + } else { + *r_addr += loff; + } + break; + case R_TYPE(JMP_SLOT): + ooff = _dl_find_symbol(symn, _dl_objects, &this, 0, 1); + if (this == NULL) + goto resolve_failed; + *r_addr = ooff + this->st_value + relas->r_addend; + break; + case R_TYPE(GLOB_DAT): + ooff = _dl_find_symbol(symn, _dl_objects, &this, 0, 1); + if (this == NULL) + goto resolve_failed; + *r_addr = ooff + this->st_value + relas->r_addend; + break; + case R_TYPE(NONE): + break; + default: + _dl_printf("%s:" + " %s: unsupported relocation '%s' %d at %lx\n", + _dl_progname, object->load_name, symn, + ELF64_R_TYPE(relas->r_info), r_addr ); + _dl_exit(1); + } + continue; +resolve_failed: + _dl_printf("%s: %s :can't resolve reference '%s'\n", + _dl_progname, object->load_name, symn); + fails++; + } + /* + * flush ?? - XXX + __asm __volatile("imb" : : : "memory"); + */ + + /* reprotect the unprotected segments */ + if ((rel == DT_REL || rel == DT_RELA)) { + for (llist = object->load_list; llist != NULL; llist = llist->next) { + if (!(llist->prot & PROT_WRITE)) { + _dl_mprotect(llist->start, llist->size, + llist->prot); + } + } + } + + return (fails); +} + +/* + * Resolve a symbol at run-time. + */ +void * +_dl_bind(elf_object_t *object, Elf_Word reloff) +{ + Elf_RelA *rela; + Elf_Addr *addr, ooff; + const Elf_Sym *sym, *this; + const char *symn; + + rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL] + reloff); + + sym = object->dyn.symtab; + sym += ELF64_R_SYM(rela->r_info); + symn = object->dyn.strtab + sym->st_name; + + addr = (Elf_Addr *)(object->load_offs + rela->r_offset); + ooff = _dl_find_symbol(symn, _dl_objects, &this, 0, 1); + if (this == NULL) { + _dl_printf("lazy binding failed!\n"); + *((int *)0) = 0; /* XXX */ + } + *addr = ooff + this->st_value + rela->r_addend; + + return (void *)*addr; +} + +/* + * Relocate the Global Offset Table (GOT). + */ +void +_dl_md_reloc_got(elf_object_t *object, int lazy) +{ + Elf_Addr *pltgot; + extern void _dl_bind_start(void); /* XXX */ + + lazy = 0; /* not yet */ + pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT]; + + if (object->obj_type == OBJTYPE_LDR || !lazy || pltgot == NULL) { + _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); + return; + } + +#ifdef SUPPORT_LAZY + if (object->obj_type != OBJTYPE_EXE) { + int i, size; + Elf_Addr *addr; + Elf_RelA *rela; + + size = object->Dyn.info[DT_PLTRELSZ] / sizeof(Elf_RelA); + rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]); + + for (i = 0; i < size; i++) { + addr = (Elf_Addr *)(object->load_offs + rela[i].r_offset); + *addr += object->load_offs; + } + } + + pltgot[2] = (Elf_Addr)_dl_bind_start; + pltgot[3] = (Elf_Addr)object; +#endif /* SUPPORT_LAZY */ +} |