diff options
-rw-r--r-- | libexec/ld.so/amd64/Makefile.inc | 4 | ||||
-rw-r--r-- | libexec/ld.so/amd64/archdep.h | 87 | ||||
-rw-r--r-- | libexec/ld.so/amd64/ldasm.S | 151 | ||||
-rw-r--r-- | libexec/ld.so/amd64/rtld_machine.c | 467 | ||||
-rw-r--r-- | libexec/ld.so/amd64/syscall.h | 63 | ||||
-rw-r--r-- | libexec/ld.so/x86_64/Makefile.inc | 4 | ||||
-rw-r--r-- | libexec/ld.so/x86_64/archdep.h | 87 | ||||
-rw-r--r-- | libexec/ld.so/x86_64/ldasm.S | 151 | ||||
-rw-r--r-- | libexec/ld.so/x86_64/rtld_machine.c | 467 | ||||
-rw-r--r-- | libexec/ld.so/x86_64/syscall.h | 63 |
10 files changed, 1544 insertions, 0 deletions
diff --git a/libexec/ld.so/amd64/Makefile.inc b/libexec/ld.so/amd64/Makefile.inc new file mode 100644 index 00000000000..8f7d51179b4 --- /dev/null +++ b/libexec/ld.so/amd64/Makefile.inc @@ -0,0 +1,4 @@ +# $OpenBSD: Makefile.inc,v 1.1 2004/02/10 14:18:14 drahn Exp $ + +CFLAGS += -fPIC -fno-stack-protector +AFLAGS += -fpic diff --git a/libexec/ld.so/amd64/archdep.h b/libexec/ld.so/amd64/archdep.h new file mode 100644 index 00000000000..d8e729b9b68 --- /dev/null +++ b/libexec/ld.so/amd64/archdep.h @@ -0,0 +1,87 @@ +/* $OpenBSD: archdep.h,v 1.1 2004/02/10 14:18:14 drahn Exp $ */ + +/* + * Copyright (c) 1998 Per Fogelstrom, Opsycon AB + * + * 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. + * + * 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. + * + */ + +#ifndef _X86_64_ARCHDEP_H_ +#define _X86_64_ARCHDEP_H_ + +#define DL_MALLOC_ALIGN 8 /* Arch constraint or otherwise */ + +#define MACHID EM_X86_64 /* ELF e_machine ID value checked */ + +#define RELTYPE Elf32_Rela +#define RELSIZE sizeof(Elf32_Rela) + +#include <sys/mman.h> +#include <elf_abi.h> +#include <machine/reloc.h> +#include "syscall.h" +#include "util.h" + +#define RTLD_TEXT_PLT + +static inline void * +_dl_mmap(void *addr, unsigned int len, unsigned int prot, + unsigned int flags, int fd, off_t offset) +{ + return((void *)_dl__syscall((quad_t)SYS_mmap, addr, len, prot, + flags, fd, 0, offset)); +} + +static inline void * +_dl_mquery(void *addr, unsigned int len, unsigned int prot, + unsigned int flags, int fd, off_t offset) +{ + return((void *)_dl__syscall((quad_t)SYS_mquery, addr, len, prot, + flags, fd, 0, offset)); +} + + +static inline void +RELOC_REL(Elf64_Rel *r, const Elf64_Sym *s, Elf64_Addr *p, unsigned long v) +{ + /* AMD64 is a rela architecture */ +} + +static inline void +RELOC_RELA(Elf64_Rela *r, const Elf64_Sym *s, Elf64_Addr *p, unsigned long v) +{ + if (ELF64_R_TYPE(r->r_info) == R_X86_64_RELATIVE) { + *p = v + r->r_addend; + } else if (ELF64_R_TYPE(r->r_info) == R_X86_64_GLOB_DAT) { + *p = v + s->st_value + r->r_addend; + } else { + _dl_printf("unknown bootstrap relocation\n"); + _dl_exit(6); + } +} + +#define RELOC_GOT(obj, offs) + +#define GOT_PERMS PROT_READ + +#endif /* _X86_64_ARCHDEP_H_ */ diff --git a/libexec/ld.so/amd64/ldasm.S b/libexec/ld.so/amd64/ldasm.S new file mode 100644 index 00000000000..11b30c866b4 --- /dev/null +++ b/libexec/ld.so/amd64/ldasm.S @@ -0,0 +1,151 @@ +/* $OpenBSD: ldasm.S,v 1.1 2004/02/10 14:18:14 drahn Exp $ */ + +/* + * Copyright (c) 2002,2004 Dale Rahn + * All rights reserved. + * + * 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. + * + * 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 DL_DATA_SIZE (16*8) /* 16 * sizeof(ELF_Addr) */ +#define DL_LOFF_OFFSET (7*8) /* index 7 */ +#include <sys/syscall.h> +#include <machine/asm.h> + + .text + .align 4 + .globl _dl_start + .type _dl_start,@function +_dl_start: + movq %rsp, %r12 # save stack pointer for _rtld + pushq %rbx # save ps_strings + subq $DL_DATA_SIZE, %rsp # allocate dl_data + + leaq _DYNAMIC(%rip),%rdx # &_DYNAMIC + movq %rsp, %rsi # dl_data for dl_boot_bind + movq %r12, %rdi # load saved SP for dl_boot_bind + call _dl_boot_bind@PLT # _dl_boot_bind(sp,dl_data,dynamicp) + + movq %rsi, %rcx # dl_data + movq DL_LOFF_OFFSET(%rsi), %rdx # loff from dl_data + + movq (%r12), %rdi + leaq 16(%r12,%rdi,8), %rsi # envp + movq %r12, %rdi + addq $8,%rdi # argv + call _dl_boot@PLT # _dl_boot(argv,envp,loff,dl_data) + + addq $DL_DATA_SIZE,%rsp # return dl_data + + popq %rbx # %rbx = ps_strings - XXXDSR + popq %rdx # %rdx = cleanup - XXXDSR + popq %rcx # %rcx = obj_main - XXXDSR + jmp *%rax + + .section ".text" + +#define DL_SYSCALL(n) DL_SYSCALL2(n,n) +#define DL_SYSCALL2(n,c) \ + .global __CONCAT(_dl_,n) ;\ + .type __CONCAT(_dl_,n), @function ;\ + .align 4 ;\ +__CONCAT(_dl_,n): ;\ + movl $(__CONCAT(SYS_,c)), %eax ;\ + movq %rcx, %r10 ;\ + syscall ;\ + jb 1f ;\ + ret + +DL_SYSCALL(open) +DL_SYSCALL(fcntl) +DL_SYSCALL(fstat) +DL_SYSCALL(stat) +DL_SYSCALL(read) +DL_SYSCALL(write) +DL_SYSCALL(close) +DL_SYSCALL(issetugid) +DL_SYSCALL(getdirentries) +DL_SYSCALL(mprotect) +DL_SYSCALL(munmap) +DL_SYSCALL(exit) +DL_SYSCALL2(_syscall,__syscall) +DL_SYSCALL2(sysctl,__sysctl) + +1: + /* error: result = -errno; - handled here. */ + neg %rax + ret + + + /* _dl_sigprocmask: does not handle NULL new set */ + + .align 4 + .global _dl_sigprocmask + .type _dl_sigprocmask,@function +_dl_sigprocmask: + movq (%rsi),%rsi # fetch indirect ... + movl $SYS_sigprocmask, %eax + movq %rcx, %r10 + syscall + jc 1b /* error: result = -errno */ + testq %rdx,%rdx # test if old mask requested + jz 2f + movq %rax,(%rdx) # store old mask + xorq %rax,%rax +2: ret + + .align 4 + .global _dl_bind_start + .type _dl_bind_start,@function +_dl_bind_start: + pushfq # save registers + pushq %rax + pushq %rcx + pushq %rdx + pushq %rsi + pushq %rdi + pushq %r8 + pushq %r9 + pushq %r10 + pushq %r11 + + movq 80(%rsp), %rdi # Copy of reloff + movq 88(%rsp), %rsi # Copy of obj + call _dl_bind@PLT # Call the binder + movq %rax,88(%rsp) # Store function to be called in obj + + popq %r11 # restore registers + popq %r10 + popq %r9 + popq %r8 + popq %rdi + popq %rsi + popq %rdx + popq %rcx + popq %rax + popfq + + leaq 8(%rsp),%rsp # Discard reloff, do not change eflags + ret + diff --git a/libexec/ld.so/amd64/rtld_machine.c b/libexec/ld.so/amd64/rtld_machine.c new file mode 100644 index 00000000000..0c8e18643bb --- /dev/null +++ b/libexec/ld.so/amd64/rtld_machine.c @@ -0,0 +1,467 @@ +/* $OpenBSD: rtld_machine.c,v 1.1 2004/02/10 14:18:14 drahn Exp $ */ + +/* + * Copyright (c) 2002,2004 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. + * + * 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. + */ +/*- + * Copyright (c) 2000 Eduardo Horvath. + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Paul Kranenburg. + * + * 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 by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 FOUNDATION OR CONTRIBUTORS + * 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 <signal.h> + +#include "syscall.h" +#include "archdep.h" +#include "resolve.h" + +void +_dl_bcopy(const void *src, void *dest, int size) +{ + const unsigned char *psrc = src; + unsigned char *pdest = dest; + int i; + + for (i = 0; i < size; i++) + pdest[i] = psrc[i]; +} + +/* + * The following table holds for each relocation type: + * - the width in bits of the memory location the relocation + * applies to (not currently used) + * - the number of bits the relocation value must be shifted to the + * right (i.e. discard least significant bits) to fit into + * the appropriate field in the instruction word. + * - flags indicating whether + * * the relocation involves a symbol + * * the relocation is relative to the current position + * * the relocation is for a GOT entry + * * the relocation is relative to the load address + * + */ +#define _RF_S 0x80000000 /* Resolve symbol */ +#define _RF_A 0x40000000 /* Use addend */ +#define _RF_P 0x20000000 /* Location relative */ +#define _RF_G 0x10000000 /* GOT offset */ +#define _RF_B 0x08000000 /* Load address relative */ +#define _RF_U 0x04000000 /* Unaligned */ +#define _RF_E 0x02000000 /* ERROR */ +#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */ +#define _RF_RS(s) ((s) & 0xff) /* right shift */ +static int reloc_target_flags[] = { + 0, /* 0 NONE */ + _RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* 1 _64*/ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* 2 PC32 */ + _RF_G|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 3 GOT32 */ + _RF_E|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 4 PLT32 */ + _RF_S| _RF_SZ(32) | _RF_RS(0), /* 5 COPY */ + _RF_S| _RF_SZ(64) | _RF_RS(0), /* 6 GLOB_DAT*/ + _RF_S| _RF_SZ(64) | _RF_RS(0), /* 7 JUMP_SLOT*/ + _RF_A| _RF_B| _RF_SZ(64) | _RF_RS(0), /* 8 RELATIVE*/ + _RF_E, /* 9 GOTPCREL*/ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 10 32 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 11 32S */ + _RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0), /* 12 16 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(16) | _RF_RS(0), /* 13 PC16 */ + _RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0), /* 14 8 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(8) | _RF_RS(0), /* 15 PC8 */ + _RF_E, /* 16 DPTMOD64*/ + _RF_E, /* 17 DTPOFF64*/ + _RF_E, /* 18 TPOFF64 */ + _RF_E, /* 19 TLSGD */ + _RF_E, /* 20 TLSLD */ + _RF_E, /* 21 DTPOFF32*/ + _RF_E, /* 22 GOTTPOFF*/ + _RF_E /* 23 TPOFF32*/ +}; + +#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0) +#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0) +#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0) +#define RELOC_UNALIGNED(t) ((reloc_target_flags[t] & _RF_U) != 0) +#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0) +#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff) +#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff) +#define RELOC_ERROR(t) (reloc_target_flags[t] & _RF_E) + +static long reloc_target_bitmask[] = { +#define _BM(x) (x == 64? ~0 : ~(-(1UL << (x)))) + 0, /* 0 NONE */ + _BM(64), /* 1 _64*/ + _BM(32), /* 2 PC32 */ + _BM(32), /* 3 GOT32 */ + _BM(32), /* 4 PLT32 */ + _BM(0), /* 5 COPY */ + _BM(64), /* 6 GLOB_DAT*/ + _BM(64), /* 7 JUMP_SLOT*/ + _BM(64), /* 8 RELATIVE*/ + _BM(32), /* 9 GOTPCREL*/ + _BM(32), /* 10 32 */ + _BM(32), /* 11 32S */ + _BM(16), /* 12 16 */ + _BM(16), /* 13 PC16 */ + _BM(8), /* 14 8 */ + _BM(8), /* 15 PC8 */ + 0, /* 16 DPTMOD64*/ + 0, /* 17 DTPOFF64*/ + 0, /* 18 TPOFF64 */ + 0, /* 19 TLSGD */ + 0, /* 20 TLSLD */ + 0, /* 21 DTPOFF32*/ + 0, /* 22 GOTTPOFF*/ + 0 /* 23 TPOFF32*/ +#undef _BM +}; +#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t]) + +void _dl_reloc_plt(Elf_Addr *where, Elf_Addr value); + +#define R_TYPE(x) R_X86_64_ ## x + +int +_dl_md_reloc(elf_object_t *object, int rel, int relsz) +{ + long i; + long numrel; + long fails = 0; + Elf_Addr loff; + Elf_RelA *rels; + struct load_list *llist; + + loff = object->load_offs; + numrel = object->Dyn.info[relsz] / sizeof(Elf_RelA); + rels = (Elf_RelA *)(object->Dyn.info[rel]); + if (rels == NULL) + return(0); + + /* + * unprotect some segments if we need it. + */ + 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 < numrel; i++, rels++) { + Elf_Addr *where, value, ooff, mask; + Elf_Word type; + const Elf_Sym *sym, *this; + const char *symn; + + type = ELF_R_TYPE(rels->r_info); + + if (RELOC_ERROR(type)) { + _dl_printf("relocation error %d idx %d\n", type, i); + _dl_exit(20); + } + + if (type == R_TYPE(NONE)) + continue; + + if (type == R_TYPE(JUMP_SLOT) && rel != DT_JMPREL) + continue; + + where = (Elf_Addr *)(rels->r_offset + loff); + + if (RELOC_USE_ADDEND(type)) +#if 1 + value = rels->r_addend; +#else + value = *where & RELOC_VALUE_BITMASK(type); +#endif + else + value = 0; + + sym = NULL; + symn = NULL; + if (RELOC_RESOLVE_SYMBOL(type)) { + sym = object->dyn.symtab; + sym += ELF_R_SYM(rels->r_info); + symn = object->dyn.strtab + sym->st_name; + + if (sym->st_shndx != SHN_UNDEF && + ELF_ST_BIND(sym->st_info) == STB_LOCAL) { + value += loff; + } else { + this = NULL; + ooff = _dl_find_symbol_bysym(object, + ELF_R_SYM(rels->r_info), _dl_objects, + &this, SYM_SEARCH_ALL|SYM_WARNNOTFOUND| + ((type == R_TYPE(JUMP_SLOT))? + SYM_PLT:SYM_NOTPLT), + sym->st_size); + if (this == NULL) { +resolve_failed: + _dl_printf("%s: %s: can't resolve " + "reference '%s'\n", + _dl_progname, object->load_name, + symn); + fails++; + continue; + } + value += (Elf_Addr)(ooff + this->st_value); + } + } + + if (type == R_TYPE(JUMP_SLOT)) { + _dl_reloc_plt(where, value); + continue; + } + + if (type == R_TYPE(COPY)) { + void *dstaddr = where; + const void *srcaddr; + const Elf_Sym *dstsym = sym, *srcsym = NULL; + size_t size = dstsym->st_size; + Elf_Addr soff; + + soff = _dl_find_symbol(symn, object->next, &srcsym, + SYM_SEARCH_ALL|SYM_WARNNOTFOUND| + ((type == R_TYPE(JUMP_SLOT)) ? SYM_PLT:SYM_NOTPLT), + size, object); + if (srcsym == NULL) + goto resolve_failed; + + srcaddr = (void *)(soff + srcsym->st_value); + _dl_bcopy(srcaddr, dstaddr, size); + continue; + } + + if (RELOC_PC_RELATIVE(type)) + value -= (Elf_Addr)where; + if (RELOC_BASE_RELATIVE(type)) + value += loff; + + mask = RELOC_VALUE_BITMASK(type); + value >>= RELOC_VALUE_RIGHTSHIFT(type); + value &= mask; + + if (RELOC_UNALIGNED(type)) { + /* Handle unaligned relocations. */ + Elf_Addr tmp = 0; + char *ptr = (char *)where; + int i, size = RELOC_TARGET_SIZE(type)/8; + + /* Read it in one byte at a time. */ + for (i=0; i<size; i++) + tmp = (tmp << 8) | ptr[i]; + + tmp &= ~mask; + tmp |= value; + + /* Write it back out. */ + for (i=0; i<size; i++) + ptr[i] = ((tmp >> (8*i)) & 0xff); + } else if (RELOC_TARGET_SIZE(type) > 32) { + *where &= ~mask; + *where |= value; + } else { + Elf32_Addr *where32 = (Elf32_Addr *)where; + + *where32 &= ~mask; + *where32 |= value; + } + } + + /* 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); +} + +#if 0 +struct jmpslot { + u_short opcode; + u_short addr[2]; + u_short reloc_index; +#define JMPSLOT_RELOC_MASK 0xffff +}; +#define JUMP 0xe990 /* NOP + JMP opcode */ +#endif + +void +_dl_reloc_plt(Elf_Addr *where, Elf_Addr value) +{ + *where = value; +} + +/* + * Resolve a symbol at run-time. + */ +Elf_Addr +_dl_bind(elf_object_t *object, int index) +{ + Elf_Rel *rel; + Elf_Word *addr; + const Elf_Sym *sym, *this; + const char *symn; + Elf_Addr ooff; + sigset_t omask, nmask; + + rel = (Elf_Rel *)(object->Dyn.info[DT_JMPREL]); + + rel += index/sizeof(Elf_Rel); + + sym = object->dyn.symtab; + sym += ELF_R_SYM(rel->r_info); + symn = object->dyn.strtab + sym->st_name; + + addr = (Elf_Word *)(object->load_offs + rel->r_offset); + this = NULL; + ooff = _dl_find_symbol(symn, _dl_objects, &this, + SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym->st_size, object); + if (this == NULL) { + _dl_printf("lazy binding failed!\n"); + *((int *)0) = 0; /* XXX */ + } + + /* if GOT is protected, allow the write */ + if (object->got_size != 0) { + sigfillset(&nmask); + _dl_sigprocmask(SIG_BLOCK, &nmask, &omask); + _dl_mprotect((void*)object->got_start, object->got_size, + PROT_READ|PROT_WRITE); + } + + _dl_reloc_plt((Elf_Addr *)addr, ooff + this->st_value); + + /* put the GOT back to RO */ + if (object->got_size != 0) { + _dl_mprotect((void*)object->got_start, object->got_size, + PROT_READ); + _dl_sigprocmask(SIG_SETMASK, &omask, NULL); + } + + return((Elf_Addr)ooff + this->st_value); +} + +void +_dl_md_reloc_got(elf_object_t *object, int lazy) +{ + extern void _dl_bind_start(void); /* XXX */ + Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT]; + int i, num; + Elf_RelA *rel; + Elf_Addr ooff; + const Elf_Sym *this; + + if (pltgot == NULL) + return; /* it is possible to have no PLT/GOT relocations */ + + pltgot[1] = (Elf_Addr)object; + pltgot[2] = (Elf_Addr)&_dl_bind_start; + + if (object->Dyn.info[DT_PLTREL] != DT_RELA) + return; + + object->got_addr = NULL; + object->got_size = 0; + this = NULL; + ooff = _dl_find_symbol("__got_start", object, &this, + SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, 0, object); + if (this != NULL) + object->got_addr = ooff + this->st_value; + + this = NULL; + ooff = _dl_find_symbol("__got_end", object, &this, + SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, 0, object); + if (this != NULL) + object->got_size = ooff + this->st_value - object->got_addr; + + if (object->got_addr == NULL) + object->got_start = NULL; + else { + object->got_start = ELF_TRUNC(object->got_addr, _dl_pagesz); + object->got_size += object->got_addr - object->got_start; + object->got_size = ELF_ROUND(object->got_size, _dl_pagesz); + } + + if (!lazy) { + _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); + } else { + rel = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]); + num = (object->Dyn.info[DT_PLTRELSZ]); + for (i = 0; i < num/sizeof(Elf_RelA); i++, rel++) { + Elf_Addr *where; + where = (Elf_Addr *)(rel->r_offset + object->load_offs); + *where = object->load_offs + rel->r_addend; + } + + } + /* PLT is already RO on i386, no point in mprotecting it, just GOT */ + if (object->got_size != 0) + _dl_mprotect((void*)object->got_start, object->got_size, + PROT_READ); +} diff --git a/libexec/ld.so/amd64/syscall.h b/libexec/ld.so/amd64/syscall.h new file mode 100644 index 00000000000..91436a14f2f --- /dev/null +++ b/libexec/ld.so/amd64/syscall.h @@ -0,0 +1,63 @@ +/* $OpenBSD: syscall.h,v 1.1 2004/02/10 14:18:14 drahn Exp $ */ + +/* + * Copyright (c) 2001 Niklas Hallqvist + * + * 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. + * + * 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. + * + */ + +#ifndef __DL_SYSCALL_H__ +#define __DL_SYSCALL_H__ + +#include <sys/syscall.h> +#include <sys/stat.h> +#include <sys/signal.h> + +#ifndef _dl_MAX_ERRNO +#define _dl_MAX_ERRNO 4096 +#endif +#define _dl_check_error(__res) \ + ((int) __res < 0 && (int) __res >= -_dl_MAX_ERRNO) + +int _dl_close(int); +int _dl_exit(int); +int _dl_issetugid(void); +long _dl__syscall(quad_t, ...); +int _dl_mprotect(const void *, int, int); +int _dl_munmap(const void *, unsigned int); +int _dl_open(const char *, unsigned int); +int _dl_read(int, const char *, int); +int _dl_stat(const char *, struct stat *); +int _dl_fstat(int, struct stat *); +int _dl_fcntl(int, int, ...); +int _dl_getdirentries(int, char*, int, long *); +int _dl_sigprocmask(int, const sigset_t *, sigset_t *); +int _dl_sysctl(int *, u_int, void *, size_t *, void *, size_t); + +static inline off_t +_dl_lseek(int fildes, off_t offset, int whence) +{ + return _dl__syscall((quad_t)SYS_lseek, fildes, 0, offset, whence); +} + +#endif /*__DL_SYSCALL_H__*/ diff --git a/libexec/ld.so/x86_64/Makefile.inc b/libexec/ld.so/x86_64/Makefile.inc new file mode 100644 index 00000000000..8f7d51179b4 --- /dev/null +++ b/libexec/ld.so/x86_64/Makefile.inc @@ -0,0 +1,4 @@ +# $OpenBSD: Makefile.inc,v 1.1 2004/02/10 14:18:14 drahn Exp $ + +CFLAGS += -fPIC -fno-stack-protector +AFLAGS += -fpic diff --git a/libexec/ld.so/x86_64/archdep.h b/libexec/ld.so/x86_64/archdep.h new file mode 100644 index 00000000000..d8e729b9b68 --- /dev/null +++ b/libexec/ld.so/x86_64/archdep.h @@ -0,0 +1,87 @@ +/* $OpenBSD: archdep.h,v 1.1 2004/02/10 14:18:14 drahn Exp $ */ + +/* + * Copyright (c) 1998 Per Fogelstrom, Opsycon AB + * + * 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. + * + * 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. + * + */ + +#ifndef _X86_64_ARCHDEP_H_ +#define _X86_64_ARCHDEP_H_ + +#define DL_MALLOC_ALIGN 8 /* Arch constraint or otherwise */ + +#define MACHID EM_X86_64 /* ELF e_machine ID value checked */ + +#define RELTYPE Elf32_Rela +#define RELSIZE sizeof(Elf32_Rela) + +#include <sys/mman.h> +#include <elf_abi.h> +#include <machine/reloc.h> +#include "syscall.h" +#include "util.h" + +#define RTLD_TEXT_PLT + +static inline void * +_dl_mmap(void *addr, unsigned int len, unsigned int prot, + unsigned int flags, int fd, off_t offset) +{ + return((void *)_dl__syscall((quad_t)SYS_mmap, addr, len, prot, + flags, fd, 0, offset)); +} + +static inline void * +_dl_mquery(void *addr, unsigned int len, unsigned int prot, + unsigned int flags, int fd, off_t offset) +{ + return((void *)_dl__syscall((quad_t)SYS_mquery, addr, len, prot, + flags, fd, 0, offset)); +} + + +static inline void +RELOC_REL(Elf64_Rel *r, const Elf64_Sym *s, Elf64_Addr *p, unsigned long v) +{ + /* AMD64 is a rela architecture */ +} + +static inline void +RELOC_RELA(Elf64_Rela *r, const Elf64_Sym *s, Elf64_Addr *p, unsigned long v) +{ + if (ELF64_R_TYPE(r->r_info) == R_X86_64_RELATIVE) { + *p = v + r->r_addend; + } else if (ELF64_R_TYPE(r->r_info) == R_X86_64_GLOB_DAT) { + *p = v + s->st_value + r->r_addend; + } else { + _dl_printf("unknown bootstrap relocation\n"); + _dl_exit(6); + } +} + +#define RELOC_GOT(obj, offs) + +#define GOT_PERMS PROT_READ + +#endif /* _X86_64_ARCHDEP_H_ */ diff --git a/libexec/ld.so/x86_64/ldasm.S b/libexec/ld.so/x86_64/ldasm.S new file mode 100644 index 00000000000..11b30c866b4 --- /dev/null +++ b/libexec/ld.so/x86_64/ldasm.S @@ -0,0 +1,151 @@ +/* $OpenBSD: ldasm.S,v 1.1 2004/02/10 14:18:14 drahn Exp $ */ + +/* + * Copyright (c) 2002,2004 Dale Rahn + * All rights reserved. + * + * 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. + * + * 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 DL_DATA_SIZE (16*8) /* 16 * sizeof(ELF_Addr) */ +#define DL_LOFF_OFFSET (7*8) /* index 7 */ +#include <sys/syscall.h> +#include <machine/asm.h> + + .text + .align 4 + .globl _dl_start + .type _dl_start,@function +_dl_start: + movq %rsp, %r12 # save stack pointer for _rtld + pushq %rbx # save ps_strings + subq $DL_DATA_SIZE, %rsp # allocate dl_data + + leaq _DYNAMIC(%rip),%rdx # &_DYNAMIC + movq %rsp, %rsi # dl_data for dl_boot_bind + movq %r12, %rdi # load saved SP for dl_boot_bind + call _dl_boot_bind@PLT # _dl_boot_bind(sp,dl_data,dynamicp) + + movq %rsi, %rcx # dl_data + movq DL_LOFF_OFFSET(%rsi), %rdx # loff from dl_data + + movq (%r12), %rdi + leaq 16(%r12,%rdi,8), %rsi # envp + movq %r12, %rdi + addq $8,%rdi # argv + call _dl_boot@PLT # _dl_boot(argv,envp,loff,dl_data) + + addq $DL_DATA_SIZE,%rsp # return dl_data + + popq %rbx # %rbx = ps_strings - XXXDSR + popq %rdx # %rdx = cleanup - XXXDSR + popq %rcx # %rcx = obj_main - XXXDSR + jmp *%rax + + .section ".text" + +#define DL_SYSCALL(n) DL_SYSCALL2(n,n) +#define DL_SYSCALL2(n,c) \ + .global __CONCAT(_dl_,n) ;\ + .type __CONCAT(_dl_,n), @function ;\ + .align 4 ;\ +__CONCAT(_dl_,n): ;\ + movl $(__CONCAT(SYS_,c)), %eax ;\ + movq %rcx, %r10 ;\ + syscall ;\ + jb 1f ;\ + ret + +DL_SYSCALL(open) +DL_SYSCALL(fcntl) +DL_SYSCALL(fstat) +DL_SYSCALL(stat) +DL_SYSCALL(read) +DL_SYSCALL(write) +DL_SYSCALL(close) +DL_SYSCALL(issetugid) +DL_SYSCALL(getdirentries) +DL_SYSCALL(mprotect) +DL_SYSCALL(munmap) +DL_SYSCALL(exit) +DL_SYSCALL2(_syscall,__syscall) +DL_SYSCALL2(sysctl,__sysctl) + +1: + /* error: result = -errno; - handled here. */ + neg %rax + ret + + + /* _dl_sigprocmask: does not handle NULL new set */ + + .align 4 + .global _dl_sigprocmask + .type _dl_sigprocmask,@function +_dl_sigprocmask: + movq (%rsi),%rsi # fetch indirect ... + movl $SYS_sigprocmask, %eax + movq %rcx, %r10 + syscall + jc 1b /* error: result = -errno */ + testq %rdx,%rdx # test if old mask requested + jz 2f + movq %rax,(%rdx) # store old mask + xorq %rax,%rax +2: ret + + .align 4 + .global _dl_bind_start + .type _dl_bind_start,@function +_dl_bind_start: + pushfq # save registers + pushq %rax + pushq %rcx + pushq %rdx + pushq %rsi + pushq %rdi + pushq %r8 + pushq %r9 + pushq %r10 + pushq %r11 + + movq 80(%rsp), %rdi # Copy of reloff + movq 88(%rsp), %rsi # Copy of obj + call _dl_bind@PLT # Call the binder + movq %rax,88(%rsp) # Store function to be called in obj + + popq %r11 # restore registers + popq %r10 + popq %r9 + popq %r8 + popq %rdi + popq %rsi + popq %rdx + popq %rcx + popq %rax + popfq + + leaq 8(%rsp),%rsp # Discard reloff, do not change eflags + ret + diff --git a/libexec/ld.so/x86_64/rtld_machine.c b/libexec/ld.so/x86_64/rtld_machine.c new file mode 100644 index 00000000000..0c8e18643bb --- /dev/null +++ b/libexec/ld.so/x86_64/rtld_machine.c @@ -0,0 +1,467 @@ +/* $OpenBSD: rtld_machine.c,v 1.1 2004/02/10 14:18:14 drahn Exp $ */ + +/* + * Copyright (c) 2002,2004 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. + * + * 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. + */ +/*- + * Copyright (c) 2000 Eduardo Horvath. + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Paul Kranenburg. + * + * 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 by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 FOUNDATION OR CONTRIBUTORS + * 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 <signal.h> + +#include "syscall.h" +#include "archdep.h" +#include "resolve.h" + +void +_dl_bcopy(const void *src, void *dest, int size) +{ + const unsigned char *psrc = src; + unsigned char *pdest = dest; + int i; + + for (i = 0; i < size; i++) + pdest[i] = psrc[i]; +} + +/* + * The following table holds for each relocation type: + * - the width in bits of the memory location the relocation + * applies to (not currently used) + * - the number of bits the relocation value must be shifted to the + * right (i.e. discard least significant bits) to fit into + * the appropriate field in the instruction word. + * - flags indicating whether + * * the relocation involves a symbol + * * the relocation is relative to the current position + * * the relocation is for a GOT entry + * * the relocation is relative to the load address + * + */ +#define _RF_S 0x80000000 /* Resolve symbol */ +#define _RF_A 0x40000000 /* Use addend */ +#define _RF_P 0x20000000 /* Location relative */ +#define _RF_G 0x10000000 /* GOT offset */ +#define _RF_B 0x08000000 /* Load address relative */ +#define _RF_U 0x04000000 /* Unaligned */ +#define _RF_E 0x02000000 /* ERROR */ +#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */ +#define _RF_RS(s) ((s) & 0xff) /* right shift */ +static int reloc_target_flags[] = { + 0, /* 0 NONE */ + _RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* 1 _64*/ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* 2 PC32 */ + _RF_G|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 3 GOT32 */ + _RF_E|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 4 PLT32 */ + _RF_S| _RF_SZ(32) | _RF_RS(0), /* 5 COPY */ + _RF_S| _RF_SZ(64) | _RF_RS(0), /* 6 GLOB_DAT*/ + _RF_S| _RF_SZ(64) | _RF_RS(0), /* 7 JUMP_SLOT*/ + _RF_A| _RF_B| _RF_SZ(64) | _RF_RS(0), /* 8 RELATIVE*/ + _RF_E, /* 9 GOTPCREL*/ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 10 32 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 11 32S */ + _RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0), /* 12 16 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(16) | _RF_RS(0), /* 13 PC16 */ + _RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0), /* 14 8 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(8) | _RF_RS(0), /* 15 PC8 */ + _RF_E, /* 16 DPTMOD64*/ + _RF_E, /* 17 DTPOFF64*/ + _RF_E, /* 18 TPOFF64 */ + _RF_E, /* 19 TLSGD */ + _RF_E, /* 20 TLSLD */ + _RF_E, /* 21 DTPOFF32*/ + _RF_E, /* 22 GOTTPOFF*/ + _RF_E /* 23 TPOFF32*/ +}; + +#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0) +#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0) +#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0) +#define RELOC_UNALIGNED(t) ((reloc_target_flags[t] & _RF_U) != 0) +#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0) +#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff) +#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff) +#define RELOC_ERROR(t) (reloc_target_flags[t] & _RF_E) + +static long reloc_target_bitmask[] = { +#define _BM(x) (x == 64? ~0 : ~(-(1UL << (x)))) + 0, /* 0 NONE */ + _BM(64), /* 1 _64*/ + _BM(32), /* 2 PC32 */ + _BM(32), /* 3 GOT32 */ + _BM(32), /* 4 PLT32 */ + _BM(0), /* 5 COPY */ + _BM(64), /* 6 GLOB_DAT*/ + _BM(64), /* 7 JUMP_SLOT*/ + _BM(64), /* 8 RELATIVE*/ + _BM(32), /* 9 GOTPCREL*/ + _BM(32), /* 10 32 */ + _BM(32), /* 11 32S */ + _BM(16), /* 12 16 */ + _BM(16), /* 13 PC16 */ + _BM(8), /* 14 8 */ + _BM(8), /* 15 PC8 */ + 0, /* 16 DPTMOD64*/ + 0, /* 17 DTPOFF64*/ + 0, /* 18 TPOFF64 */ + 0, /* 19 TLSGD */ + 0, /* 20 TLSLD */ + 0, /* 21 DTPOFF32*/ + 0, /* 22 GOTTPOFF*/ + 0 /* 23 TPOFF32*/ +#undef _BM +}; +#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t]) + +void _dl_reloc_plt(Elf_Addr *where, Elf_Addr value); + +#define R_TYPE(x) R_X86_64_ ## x + +int +_dl_md_reloc(elf_object_t *object, int rel, int relsz) +{ + long i; + long numrel; + long fails = 0; + Elf_Addr loff; + Elf_RelA *rels; + struct load_list *llist; + + loff = object->load_offs; + numrel = object->Dyn.info[relsz] / sizeof(Elf_RelA); + rels = (Elf_RelA *)(object->Dyn.info[rel]); + if (rels == NULL) + return(0); + + /* + * unprotect some segments if we need it. + */ + 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 < numrel; i++, rels++) { + Elf_Addr *where, value, ooff, mask; + Elf_Word type; + const Elf_Sym *sym, *this; + const char *symn; + + type = ELF_R_TYPE(rels->r_info); + + if (RELOC_ERROR(type)) { + _dl_printf("relocation error %d idx %d\n", type, i); + _dl_exit(20); + } + + if (type == R_TYPE(NONE)) + continue; + + if (type == R_TYPE(JUMP_SLOT) && rel != DT_JMPREL) + continue; + + where = (Elf_Addr *)(rels->r_offset + loff); + + if (RELOC_USE_ADDEND(type)) +#if 1 + value = rels->r_addend; +#else + value = *where & RELOC_VALUE_BITMASK(type); +#endif + else + value = 0; + + sym = NULL; + symn = NULL; + if (RELOC_RESOLVE_SYMBOL(type)) { + sym = object->dyn.symtab; + sym += ELF_R_SYM(rels->r_info); + symn = object->dyn.strtab + sym->st_name; + + if (sym->st_shndx != SHN_UNDEF && + ELF_ST_BIND(sym->st_info) == STB_LOCAL) { + value += loff; + } else { + this = NULL; + ooff = _dl_find_symbol_bysym(object, + ELF_R_SYM(rels->r_info), _dl_objects, + &this, SYM_SEARCH_ALL|SYM_WARNNOTFOUND| + ((type == R_TYPE(JUMP_SLOT))? + SYM_PLT:SYM_NOTPLT), + sym->st_size); + if (this == NULL) { +resolve_failed: + _dl_printf("%s: %s: can't resolve " + "reference '%s'\n", + _dl_progname, object->load_name, + symn); + fails++; + continue; + } + value += (Elf_Addr)(ooff + this->st_value); + } + } + + if (type == R_TYPE(JUMP_SLOT)) { + _dl_reloc_plt(where, value); + continue; + } + + if (type == R_TYPE(COPY)) { + void *dstaddr = where; + const void *srcaddr; + const Elf_Sym *dstsym = sym, *srcsym = NULL; + size_t size = dstsym->st_size; + Elf_Addr soff; + + soff = _dl_find_symbol(symn, object->next, &srcsym, + SYM_SEARCH_ALL|SYM_WARNNOTFOUND| + ((type == R_TYPE(JUMP_SLOT)) ? SYM_PLT:SYM_NOTPLT), + size, object); + if (srcsym == NULL) + goto resolve_failed; + + srcaddr = (void *)(soff + srcsym->st_value); + _dl_bcopy(srcaddr, dstaddr, size); + continue; + } + + if (RELOC_PC_RELATIVE(type)) + value -= (Elf_Addr)where; + if (RELOC_BASE_RELATIVE(type)) + value += loff; + + mask = RELOC_VALUE_BITMASK(type); + value >>= RELOC_VALUE_RIGHTSHIFT(type); + value &= mask; + + if (RELOC_UNALIGNED(type)) { + /* Handle unaligned relocations. */ + Elf_Addr tmp = 0; + char *ptr = (char *)where; + int i, size = RELOC_TARGET_SIZE(type)/8; + + /* Read it in one byte at a time. */ + for (i=0; i<size; i++) + tmp = (tmp << 8) | ptr[i]; + + tmp &= ~mask; + tmp |= value; + + /* Write it back out. */ + for (i=0; i<size; i++) + ptr[i] = ((tmp >> (8*i)) & 0xff); + } else if (RELOC_TARGET_SIZE(type) > 32) { + *where &= ~mask; + *where |= value; + } else { + Elf32_Addr *where32 = (Elf32_Addr *)where; + + *where32 &= ~mask; + *where32 |= value; + } + } + + /* 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); +} + +#if 0 +struct jmpslot { + u_short opcode; + u_short addr[2]; + u_short reloc_index; +#define JMPSLOT_RELOC_MASK 0xffff +}; +#define JUMP 0xe990 /* NOP + JMP opcode */ +#endif + +void +_dl_reloc_plt(Elf_Addr *where, Elf_Addr value) +{ + *where = value; +} + +/* + * Resolve a symbol at run-time. + */ +Elf_Addr +_dl_bind(elf_object_t *object, int index) +{ + Elf_Rel *rel; + Elf_Word *addr; + const Elf_Sym *sym, *this; + const char *symn; + Elf_Addr ooff; + sigset_t omask, nmask; + + rel = (Elf_Rel *)(object->Dyn.info[DT_JMPREL]); + + rel += index/sizeof(Elf_Rel); + + sym = object->dyn.symtab; + sym += ELF_R_SYM(rel->r_info); + symn = object->dyn.strtab + sym->st_name; + + addr = (Elf_Word *)(object->load_offs + rel->r_offset); + this = NULL; + ooff = _dl_find_symbol(symn, _dl_objects, &this, + SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym->st_size, object); + if (this == NULL) { + _dl_printf("lazy binding failed!\n"); + *((int *)0) = 0; /* XXX */ + } + + /* if GOT is protected, allow the write */ + if (object->got_size != 0) { + sigfillset(&nmask); + _dl_sigprocmask(SIG_BLOCK, &nmask, &omask); + _dl_mprotect((void*)object->got_start, object->got_size, + PROT_READ|PROT_WRITE); + } + + _dl_reloc_plt((Elf_Addr *)addr, ooff + this->st_value); + + /* put the GOT back to RO */ + if (object->got_size != 0) { + _dl_mprotect((void*)object->got_start, object->got_size, + PROT_READ); + _dl_sigprocmask(SIG_SETMASK, &omask, NULL); + } + + return((Elf_Addr)ooff + this->st_value); +} + +void +_dl_md_reloc_got(elf_object_t *object, int lazy) +{ + extern void _dl_bind_start(void); /* XXX */ + Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT]; + int i, num; + Elf_RelA *rel; + Elf_Addr ooff; + const Elf_Sym *this; + + if (pltgot == NULL) + return; /* it is possible to have no PLT/GOT relocations */ + + pltgot[1] = (Elf_Addr)object; + pltgot[2] = (Elf_Addr)&_dl_bind_start; + + if (object->Dyn.info[DT_PLTREL] != DT_RELA) + return; + + object->got_addr = NULL; + object->got_size = 0; + this = NULL; + ooff = _dl_find_symbol("__got_start", object, &this, + SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, 0, object); + if (this != NULL) + object->got_addr = ooff + this->st_value; + + this = NULL; + ooff = _dl_find_symbol("__got_end", object, &this, + SYM_SEARCH_SELF|SYM_NOWARNNOTFOUND|SYM_PLT, 0, object); + if (this != NULL) + object->got_size = ooff + this->st_value - object->got_addr; + + if (object->got_addr == NULL) + object->got_start = NULL; + else { + object->got_start = ELF_TRUNC(object->got_addr, _dl_pagesz); + object->got_size += object->got_addr - object->got_start; + object->got_size = ELF_ROUND(object->got_size, _dl_pagesz); + } + + if (!lazy) { + _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); + } else { + rel = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]); + num = (object->Dyn.info[DT_PLTRELSZ]); + for (i = 0; i < num/sizeof(Elf_RelA); i++, rel++) { + Elf_Addr *where; + where = (Elf_Addr *)(rel->r_offset + object->load_offs); + *where = object->load_offs + rel->r_addend; + } + + } + /* PLT is already RO on i386, no point in mprotecting it, just GOT */ + if (object->got_size != 0) + _dl_mprotect((void*)object->got_start, object->got_size, + PROT_READ); +} diff --git a/libexec/ld.so/x86_64/syscall.h b/libexec/ld.so/x86_64/syscall.h new file mode 100644 index 00000000000..91436a14f2f --- /dev/null +++ b/libexec/ld.so/x86_64/syscall.h @@ -0,0 +1,63 @@ +/* $OpenBSD: syscall.h,v 1.1 2004/02/10 14:18:14 drahn Exp $ */ + +/* + * Copyright (c) 2001 Niklas Hallqvist + * + * 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. + * + * 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. + * + */ + +#ifndef __DL_SYSCALL_H__ +#define __DL_SYSCALL_H__ + +#include <sys/syscall.h> +#include <sys/stat.h> +#include <sys/signal.h> + +#ifndef _dl_MAX_ERRNO +#define _dl_MAX_ERRNO 4096 +#endif +#define _dl_check_error(__res) \ + ((int) __res < 0 && (int) __res >= -_dl_MAX_ERRNO) + +int _dl_close(int); +int _dl_exit(int); +int _dl_issetugid(void); +long _dl__syscall(quad_t, ...); +int _dl_mprotect(const void *, int, int); +int _dl_munmap(const void *, unsigned int); +int _dl_open(const char *, unsigned int); +int _dl_read(int, const char *, int); +int _dl_stat(const char *, struct stat *); +int _dl_fstat(int, struct stat *); +int _dl_fcntl(int, int, ...); +int _dl_getdirentries(int, char*, int, long *); +int _dl_sigprocmask(int, const sigset_t *, sigset_t *); +int _dl_sysctl(int *, u_int, void *, size_t *, void *, size_t); + +static inline off_t +_dl_lseek(int fildes, off_t offset, int whence) +{ + return _dl__syscall((quad_t)SYS_lseek, fildes, 0, offset, whence); +} + +#endif /*__DL_SYSCALL_H__*/ |