diff --git a/libexec/rtld-elf/Makefile.depend b/libexec/rtld-elf/Makefile.depend new file mode 100644 index 0000000..4bf7180 --- /dev/null +++ b/libexec/rtld-elf/Makefile.depend @@ -0,0 +1,14 @@ +# $FreeBSD: releng/11.1/libexec/rtld-elf/Makefile.depend 284481 2015-06-16 23:37:19Z sjg $ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + include \ + include/xlocale \ + lib/libc \ + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/libexec/rtld-elf/Symbol.map b/libexec/rtld-elf/Symbol.map new file mode 100644 index 0000000..51c7438 --- /dev/null +++ b/libexec/rtld-elf/Symbol.map @@ -0,0 +1,35 @@ +/* + * $FreeBSD: releng/11.1/libexec/rtld-elf/Symbol.map 276627 2015-01-03 18:09:53Z kib $ + */ + +FBSD_1.0 { + _rtld_error; + dlclose; + dlerror; + dlopen; + dlsym; + dlfunc; + dlvsym; + dladdr; + dllockinit; + dlinfo; + dl_iterate_phdr; + r_debug_state; + __tls_get_addr; +}; + +FBSD_1.3 { + fdlopen; +}; + +FBSDprivate_1.0 { + _rtld_thread_init; + _rtld_allocate_tls; + _rtld_free_tls; + _rtld_atfork_pre; + _rtld_atfork_post; + _rtld_addr_phdr; + _rtld_get_stack_prot; + _rtld_is_dlopened; + _r_debug_postinit; +}; diff --git a/libexec/rtld-elf/aarch64/reloc.c b/libexec/rtld-elf/aarch64/reloc.c new file mode 100644 index 0000000..6dd0109 --- /dev/null +++ b/libexec/rtld-elf/aarch64/reloc.c @@ -0,0 +1,427 @@ +/*- + * Copyright (c) 2014-2015 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Andrew Turner + * under sponsorship from the FreeBSD Foundation. + * + * 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 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD: releng/11.1/libexec/rtld-elf/aarch64/reloc.c 317189 2017-04-20 12:48:01Z andrew $"); + +#include + +#include + +#include "debug.h" +#include "rtld.h" +#include "rtld_printf.h" + +/* + * It is possible for the compiler to emit relocations for unaligned data. + * We handle this situation with these inlines. + */ +#define RELOC_ALIGNED_P(x) \ + (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0) + +/* + * This is not the correct prototype, but we only need it for + * a function pointer to a simple asm function. + */ +void *_rtld_tlsdesc(void *); +void *_rtld_tlsdesc_dynamic(void *); + +void _exit(int); + +void +init_pltgot(Obj_Entry *obj) +{ + + if (obj->pltgot != NULL) { + obj->pltgot[1] = (Elf_Addr) obj; + obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start; + } +} + +int +do_copy_relocations(Obj_Entry *dstobj) +{ + const Obj_Entry *srcobj, *defobj; + const Elf_Rela *relalim; + const Elf_Rela *rela; + const Elf_Sym *srcsym; + const Elf_Sym *dstsym; + const void *srcaddr; + const char *name; + void *dstaddr; + SymLook req; + size_t size; + int res; + + /* + * COPY relocs are invalid outside of the main program + */ + assert(dstobj->mainprog); + + relalim = (const Elf_Rela *)((char *)dstobj->rela + + dstobj->relasize); + for (rela = dstobj->rela; rela < relalim; rela++) { + if (ELF_R_TYPE(rela->r_info) != R_AARCH64_COPY) + continue; + + dstaddr = (void *)(dstobj->relocbase + rela->r_offset); + dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); + name = dstobj->strtab + dstsym->st_name; + size = dstsym->st_size; + + symlook_init(&req, name); + req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); + req.flags = SYMLOOK_EARLY; + + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { + res = symlook_obj(&req, srcobj); + if (res == 0) { + srcsym = req.sym_out; + defobj = req.defobj_out; + break; + } + } + if (srcobj == NULL) { + _rtld_error( +"Undefined symbol \"%s\" referenced from COPY relocation in %s", + name, dstobj->path); + return (-1); + } + + srcaddr = (const void *)(defobj->relocbase + srcsym->st_value); + memcpy(dstaddr, srcaddr, size); + } + + return (0); +} + +struct tls_data { + int64_t index; + Obj_Entry *obj; + const Elf_Rela *rela; +}; + +static struct tls_data * +reloc_tlsdesc_alloc(Obj_Entry *obj, const Elf_Rela *rela) +{ + struct tls_data *tlsdesc; + + tlsdesc = xmalloc(sizeof(struct tls_data)); + tlsdesc->index = -1; + tlsdesc->obj = obj; + tlsdesc->rela = rela; + + return (tlsdesc); +} + +/* + * Look up the symbol to find its tls index + */ +static int64_t +rtld_tlsdesc_handle_locked(struct tls_data *tlsdesc, int flags, + RtldLockState *lockstate) +{ + const Elf_Rela *rela; + const Elf_Sym *def; + const Obj_Entry *defobj; + Obj_Entry *obj; + + rela = tlsdesc->rela; + obj = tlsdesc->obj; + + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, flags, NULL, + lockstate); + if (def == NULL) + rtld_die(); + + tlsdesc->index = defobj->tlsoffset + def->st_value + rela->r_addend; + + return (tlsdesc->index); +} + +int64_t +rtld_tlsdesc_handle(struct tls_data *tlsdesc, int flags) +{ + RtldLockState lockstate; + + /* We have already found the index, return it */ + if (tlsdesc->index >= 0) + return (tlsdesc->index); + + wlock_acquire(rtld_bind_lock, &lockstate); + /* tlsdesc->index may have been set by another thread */ + if (tlsdesc->index == -1) + rtld_tlsdesc_handle_locked(tlsdesc, flags, &lockstate); + lock_release(rtld_bind_lock, &lockstate); + + return (tlsdesc->index); +} + +static void +reloc_tlsdesc(Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *where) +{ + if (ELF_R_SYM(rela->r_info) == 0) { + where[0] = (Elf_Addr)_rtld_tlsdesc; + where[1] = obj->tlsoffset + rela->r_addend; + } else { + where[0] = (Elf_Addr)_rtld_tlsdesc_dynamic; + where[1] = (Elf_Addr)reloc_tlsdesc_alloc(obj, rela); + } +} + +/* + * Process the PLT relocations. + */ +int +reloc_plt(Obj_Entry *obj) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + + relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); + for (rela = obj->pltrela; rela < relalim; rela++) { + Elf_Addr *where; + + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + + switch(ELF_R_TYPE(rela->r_info)) { + case R_AARCH64_JUMP_SLOT: + *where += (Elf_Addr)obj->relocbase; + break; + case R_AARCH64_TLSDESC: + reloc_tlsdesc(obj, rela, where); + break; + default: + _rtld_error("Unknown relocation type %u in PLT", + (unsigned int)ELF_R_TYPE(rela->r_info)); + return (-1); + } + } + + return (0); +} + +/* + * LD_BIND_NOW was set - force relocation for all jump slots + */ +int +reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) +{ + const Obj_Entry *defobj; + const Elf_Rela *relalim; + const Elf_Rela *rela; + const Elf_Sym *def; + struct tls_data *tlsdesc; + + relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); + for (rela = obj->pltrela; rela < relalim; rela++) { + Elf_Addr *where; + + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + switch(ELF_R_TYPE(rela->r_info)) { + case R_AARCH64_JUMP_SLOT: + def = find_symdef(ELF_R_SYM(rela->r_info), obj, + &defobj, SYMLOOK_IN_PLT | flags, NULL, lockstate); + if (def == NULL) { + dbg("reloc_jmpslots: sym not found"); + return (-1); + } + + *where = (Elf_Addr)(defobj->relocbase + def->st_value); + break; + case R_AARCH64_TLSDESC: + if (ELF_R_SYM(rela->r_info) != 0) { + tlsdesc = (struct tls_data *)where[1]; + if (tlsdesc->index == -1) + rtld_tlsdesc_handle_locked(tlsdesc, + SYMLOOK_IN_PLT | flags, lockstate); + } + break; + default: + _rtld_error("Unknown relocation type %x in jmpslot", + (unsigned int)ELF_R_TYPE(rela->r_info)); + return (-1); + } + } + + return (0); +} + +int +reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +int +reloc_gnu_ifunc(Obj_Entry *obj, int flags, + struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +Elf_Addr +reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj, + const Obj_Entry *obj, const Elf_Rel *rel) +{ + + assert(ELF_R_TYPE(rel->r_info) == R_AARCH64_JUMP_SLOT); + + if (*where != target && !ld_bind_not) + *where = target; + return (target); +} + +void +ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) +{ +} + +/* + * Process non-PLT relocations + */ +int +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, + RtldLockState *lockstate) +{ + const Obj_Entry *defobj; + const Elf_Rela *relalim; + const Elf_Rela *rela; + const Elf_Sym *def; + SymCache *cache; + Elf_Addr *where; + unsigned long symnum; + + if ((flags & SYMLOOK_IFUNC) != 0) + /* XXX not implemented */ + return (0); + + /* + * The dynamic loader may be called from a thread, we have + * limited amounts of stack available so we cannot use alloca(). + */ + if (obj == obj_rtld) + cache = NULL; + else + cache = calloc(obj->dynsymcount, sizeof(SymCache)); + /* No need to check for NULL here */ + + relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize); + for (rela = obj->rela; rela < relalim; rela++) { + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + symnum = ELF_R_SYM(rela->r_info); + + switch (ELF_R_TYPE(rela->r_info)) { + case R_AARCH64_ABS64: + case R_AARCH64_GLOB_DAT: + def = find_symdef(symnum, obj, &defobj, flags, cache, + lockstate); + if (def == NULL) + return (-1); + + *where = (Elf_Addr)defobj->relocbase + def->st_value + + rela->r_addend; + break; + case R_AARCH64_COPY: + /* + * These are deferred until all other relocations have + * been done. All we do here is make sure that the + * COPY relocation is not in a shared library. They + * are allowed only in executable files. + */ + if (!obj->mainprog) { + _rtld_error("%s: Unexpected R_AARCH64_COPY " + "relocation in shared library", obj->path); + return (-1); + } + break; + case R_AARCH64_TLSDESC: + reloc_tlsdesc(obj, rela, where); + break; + case R_AARCH64_TLS_TPREL64: + def = find_symdef(symnum, obj, &defobj, flags, cache, + lockstate); + if (def == NULL) + return (-1); + + /* + * We lazily allocate offsets for static TLS as we + * see the first relocation that references the + * TLS block. This allows us to support (small + * amounts of) static TLS in dynamically loaded + * modules. If we run out of space, we generate an + * error. + */ + if (!defobj->tls_done) { + if (!allocate_tls_offset((Obj_Entry*) defobj)) { + _rtld_error( + "%s: No space available for static " + "Thread Local Storage", obj->path); + return (-1); + } + } + + *where = def->st_value + rela->r_addend + + defobj->tlsoffset; + break; + case R_AARCH64_RELATIVE: + *where = (Elf_Addr)(obj->relocbase + rela->r_addend); + break; + default: + rtld_printf("%s: Unhandled relocation %lu\n", + obj->path, ELF_R_TYPE(rela->r_info)); + return (-1); + } + } + + return (0); +} + +void +allocate_initial_tls(Obj_Entry *objs) +{ + Elf_Addr **tp; + + /* + * Fix the size of the static TLS block by using the maximum + * offset allocated so far and adding a bit for dynamic modules to + * use. + */ + tls_static_space = tls_last_offset + tls_last_size + + RTLD_STATIC_TLS_EXTRA; + + tp = (Elf_Addr **) allocate_tls(objs, NULL, TLS_TCB_SIZE, 16); + + asm volatile("msr tpidr_el0, %0" : : "r"(tp)); +} diff --git a/libexec/rtld-elf/aarch64/rtld_machdep.h b/libexec/rtld-elf/aarch64/rtld_machdep.h new file mode 100644 index 0000000..25b1914 --- /dev/null +++ b/libexec/rtld-elf/aarch64/rtld_machdep.h @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 1999, 2000 John D. Polstra. + * Copyright (c) 2014 the FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Andrew Turner + * under sponsorship from the FreeBSD Foundation. + * + * 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 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 AUTHOR 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/aarch64/rtld_machdep.h 316135 2017-03-29 11:03:08Z kib $ + */ + +#ifndef RTLD_MACHDEP_H +#define RTLD_MACHDEP_H 1 + +#include +#include + +struct Struct_Obj_Entry; + +/* Return the address of the .dynamic section in the dynamic linker. */ +#define rtld_dynamic(obj) \ +({ \ + Elf_Addr _dynamic_addr; \ + asm volatile("adr %0, _DYNAMIC" : "=&r"(_dynamic_addr)); \ + (const Elf_Dyn *)_dynamic_addr; \ +}) + +Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target, + const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *obj, + const Elf_Rel *rel); + +#define make_function_pointer(def, defobj) \ + ((defobj)->relocbase + (def)->st_value) + +#define call_initfini_pointer(obj, target) \ + (((InitFunc)(target))()) + +#define call_init_pointer(obj, target) \ + (((InitArrFunc)(target))(main_argc, main_argv, environ)) + +#define call_ifunc_resolver(ptr) \ + (((Elf_Addr (*)(void))ptr)()) + +#define round(size, align) \ + (((size) + (align) - 1) & ~((align) - 1)) +#define calculate_first_tls_offset(size, align) \ + round(16, align) +#define calculate_tls_offset(prev_offset, prev_size, size, align) \ + round(prev_offset + prev_size, align) +#define calculate_tls_end(off, size) ((off) + (size)) + +#define TLS_TCB_SIZE 16 +typedef struct { + unsigned long ti_module; + unsigned long ti_offset; +} tls_index; + +extern void *__tls_get_addr(tls_index *ti); + +#define RTLD_DEFAULT_STACK_PF_EXEC PF_X +#define RTLD_DEFAULT_STACK_EXEC PROT_EXEC + +#define md_abi_variant_hook(x) + +#endif diff --git a/libexec/rtld-elf/aarch64/rtld_start.S b/libexec/rtld-elf/aarch64/rtld_start.S new file mode 100644 index 0000000..627ae0c --- /dev/null +++ b/libexec/rtld-elf/aarch64/rtld_start.S @@ -0,0 +1,162 @@ +/*- + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Andrew Turner under + * sponsorship from the FreeBSD Foundation. + * + * 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 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD: releng/11.1/libexec/rtld-elf/aarch64/rtld_start.S 293832 2016-01-13 15:54:17Z andrew $"); + +ENTRY(.rtld_start) + mov x19, x0 /* Put ps_strings in a callee-saved register */ + mov x20, sp /* And the stack pointer */ + + sub sp, sp, #16 /* Make room for obj_main & exit proc */ + + mov x1, sp /* exit_proc */ + add x2, x1, #8 /* obj_main */ + bl _rtld /* Call the loader */ + mov x8, x0 /* Backup the entry point */ + + ldr x2, [sp] /* Load cleanup */ + ldr x1, [sp, #8] /* Load obj_main */ + mov x0, x19 /* Restore ps_strings */ + mov sp, x20 /* Restore the stack pointer */ + br x8 /* Jump to the entry point */ +END(.rtld_start) + +/* + * sp + 0 = &GOT[x + 3] + * sp + 8 = RA + * x16 = &GOT[2] + * x17 = &_rtld_bind_start + */ +ENTRY(_rtld_bind_start) + mov x17, sp + + /* Save the arguments */ + stp x0, x1, [sp, #-16]! + stp x2, x3, [sp, #-16]! + stp x4, x5, [sp, #-16]! + stp x6, x7, [sp, #-16]! + stp x8, xzr, [sp, #-16]! + + /* Save any floating-point arguments */ + stp q0, q1, [sp, #-32]! + stp q2, q3, [sp, #-32]! + stp q4, q5, [sp, #-32]! + stp q6, q7, [sp, #-32]! + + /* Calculate reloff */ + ldr x2, [x17, #0] /* Get the address of the entry */ + sub x1, x2, x16 /* Find its offset */ + sub x1, x1, #8 /* Adjust for x16 not being at offset 0 */ + /* Each rela item has 3 entriesso we need reloff = 3 * index */ + lsl x3, x1, #1 /* x3 = 2 * offset */ + add x1, x1, x3 /* x1 = x3 + offset = 3 * offset */ + + /* Load obj */ + ldr x0, [x16, #-8] + + /* Call into rtld */ + bl _rtld_bind + + /* Restore the registers saved by the plt code */ + ldp xzr, x30, [sp, #(5 * 16 + 4 * 32)] + + /* Backup the address to branch to */ + mov x16, x0 + + /* restore the arguments */ + ldp q6, q7, [sp], #32 + ldp q4, q5, [sp], #32 + ldp q2, q3, [sp], #32 + ldp q0, q1, [sp], #32 + ldp x8, xzr, [sp], #16 + ldp x6, x7, [sp], #16 + ldp x4, x5, [sp], #16 + ldp x2, x3, [sp], #16 + ldp x0, x1, [sp], #16 + /* And the part of the stack the plt entry handled */ + add sp, sp, #16 + + /* Call into the correct function */ + br x16 +END(_rtld_bind_start) + +/* + * uint64_t _rtld_tlsdesc(struct tlsdesc *); + * + * struct tlsdesc { + * uint64_t ptr; + * uint64_t data; + * }; + * + * Returns the data. + */ +ENTRY(_rtld_tlsdesc) + ldr x0, [x0, #8] + ret +END(_rtld_tlsdesc) + +/* + * uint64_t _rtld_tlsdesc_dynamic(struct tlsdesc *); + * + * TODO: We could lookup the saved index here to skip saving the entire stack. + */ +ENTRY(_rtld_tlsdesc_dynamic) + /* Store any registers we may use in rtld_tlsdesc_handle */ + stp x29, x30, [sp, #-(10 * 16)]! + mov x29, sp + stp x1, x2, [sp, #(1 * 16)] + stp x3, x4, [sp, #(2 * 16)] + stp x5, x6, [sp, #(3 * 16)] + stp x7, x8, [sp, #(4 * 16)] + stp x9, x10, [sp, #(5 * 16)] + stp x11, x12, [sp, #(6 * 16)] + stp x13, x14, [sp, #(7 * 16)] + stp x15, x16, [sp, #(8 * 16)] + stp x17, x18, [sp, #(9 * 16)] + + /* Find the tls offset */ + ldr x0, [x0, #8] + mov x1, #1 + bl rtld_tlsdesc_handle + + /* Restore the registers */ + ldp x17, x18, [sp, #(9 * 16)] + ldp x15, x16, [sp, #(8 * 16)] + ldp x13, x14, [sp, #(7 * 16)] + ldp x11, x12, [sp, #(6 * 16)] + ldp x9, x10, [sp, #(5 * 16)] + ldp x7, x8, [sp, #(4 * 16)] + ldp x5, x6, [sp, #(3 * 16)] + ldp x3, x4, [sp, #(2 * 16)] + ldp x1, x2, [sp, #(1 * 16)] + ldp x29, x30, [sp], #(10 * 16) + + ret +END(_rtld_tlsdesc_dynamic) diff --git a/libexec/rtld-elf/amd64/Makefile.inc b/libexec/rtld-elf/amd64/Makefile.inc new file mode 100644 index 0000000..b845219 --- /dev/null +++ b/libexec/rtld-elf/amd64/Makefile.inc @@ -0,0 +1,6 @@ +# $FreeBSD: releng/11.1/libexec/rtld-elf/amd64/Makefile.inc 286317 2015-08-05 12:53:55Z vangyzen $ + +CFLAGS+= ${CFLAGS_NO_SIMD} -msoft-float +# Uncomment this to build the dynamic linker as an executable instead +# of a shared library: +#LDSCRIPT= ${.CURDIR}/${MACHINE_CPUARCH}/elf_rtld.x diff --git a/libexec/rtld-elf/amd64/elf_rtld.x b/libexec/rtld-elf/amd64/elf_rtld.x new file mode 100644 index 0000000..e19168c --- /dev/null +++ b/libexec/rtld-elf/amd64/elf_rtld.x @@ -0,0 +1,131 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", + "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) +SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/obj/usr/src/tmp/usr/i386-unknown-freebsdelf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x08000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + .text : + { + *(.text) + *(.stub) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x9090 + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x9090 + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x1000) + (. & (0x1000 - 1)); + .data : + { + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + . = ALIGN(32 / 8); + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} diff --git a/libexec/rtld-elf/amd64/reloc.c b/libexec/rtld-elf/amd64/reloc.c new file mode 100644 index 0000000..40fd216 --- /dev/null +++ b/libexec/rtld-elf/amd64/reloc.c @@ -0,0 +1,507 @@ +/*- + * Copyright 1996, 1997, 1998, 1999 John D. Polstra. + * 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/amd64/reloc.c 316135 2017-03-29 11:03:08Z kib $ + */ + +/* + * Dynamic linker for ELF. + * + * John Polstra . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "rtld.h" +#include "rtld_tls.h" + +/* + * Process the special R_X86_64_COPY relocations in the main program. These + * copy data from a shared object into a region in the main program's BSS + * segment. + * + * Returns 0 on success, -1 on failure. + */ +int +do_copy_relocations(Obj_Entry *dstobj) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + + assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */ + + relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela + dstobj->relasize); + for (rela = dstobj->rela; rela < relalim; rela++) { + if (ELF_R_TYPE(rela->r_info) == R_X86_64_COPY) { + void *dstaddr; + const Elf_Sym *dstsym; + const char *name; + size_t size; + const void *srcaddr; + const Elf_Sym *srcsym; + const Obj_Entry *srcobj, *defobj; + SymLook req; + int res; + + dstaddr = (void *) (dstobj->relocbase + rela->r_offset); + dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); + name = dstobj->strtab + dstsym->st_name; + size = dstsym->st_size; + symlook_init(&req, name); + req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); + req.flags = SYMLOOK_EARLY; + + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { + res = symlook_obj(&req, srcobj); + if (res == 0) { + srcsym = req.sym_out; + defobj = req.defobj_out; + break; + } + } + + if (srcobj == NULL) { + _rtld_error("Undefined symbol \"%s\" referenced from COPY" + " relocation in %s", name, dstobj->path); + return -1; + } + + srcaddr = (const void *) (defobj->relocbase + srcsym->st_value); + memcpy(dstaddr, srcaddr, size); + } + } + + return 0; +} + +/* Initialize the special GOT entries. */ +void +init_pltgot(Obj_Entry *obj) +{ + if (obj->pltgot != NULL) { + obj->pltgot[1] = (Elf_Addr) obj; + obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start; + } +} + +/* Process the non-PLT relocations. */ +int +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, + RtldLockState *lockstate) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + SymCache *cache; + const Elf_Sym *def; + const Obj_Entry *defobj; + Elf_Addr *where, symval; + Elf32_Addr *where32; + int r; + + r = -1; + /* + * The dynamic loader may be called from a thread, we have + * limited amounts of stack available so we cannot use alloca(). + */ + if (obj != obj_rtld) { + cache = calloc(obj->dynsymcount, sizeof(SymCache)); + /* No need to check for NULL here */ + } else + cache = NULL; + + relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize); + for (rela = obj->rela; rela < relalim; rela++) { + /* + * First, resolve symbol for relocations which + * reference symbols. + */ + switch (ELF_R_TYPE(rela->r_info)) { + case R_X86_64_64: + case R_X86_64_PC32: + case R_X86_64_GLOB_DAT: + case R_X86_64_TPOFF64: + case R_X86_64_TPOFF32: + case R_X86_64_DTPMOD64: + case R_X86_64_DTPOFF64: + case R_X86_64_DTPOFF32: + def = find_symdef(ELF_R_SYM(rela->r_info), obj, + &defobj, flags, cache, lockstate); + if (def == NULL) + goto done; + /* + * If symbol is IFUNC, only perform relocation + * when caller allowed it by passing + * SYMLOOK_IFUNC flag. Skip the relocations + * otherwise. + * + * Also error out in case IFUNC relocations + * are specified for TLS, which cannot be + * usefully interpreted. + */ + if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { + switch (ELF_R_TYPE(rela->r_info)) { + case R_X86_64_64: + case R_X86_64_PC32: + case R_X86_64_GLOB_DAT: + if ((flags & SYMLOOK_IFUNC) == 0) { + obj->non_plt_gnu_ifunc = true; + continue; + } + symval = (Elf_Addr)rtld_resolve_ifunc( + defobj, def); + break; + case R_X86_64_TPOFF64: + case R_X86_64_TPOFF32: + case R_X86_64_DTPMOD64: + case R_X86_64_DTPOFF64: + case R_X86_64_DTPOFF32: + _rtld_error("%s: IFUNC for TLS reloc", + obj->path); + goto done; + } + } else { + if ((flags & SYMLOOK_IFUNC) != 0) + continue; + symval = (Elf_Addr)defobj->relocbase + + def->st_value; + } + break; + default: + if ((flags & SYMLOOK_IFUNC) != 0) + continue; + break; + } + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + where32 = (Elf32_Addr *)where; + + switch (ELF_R_TYPE(rela->r_info)) { + case R_X86_64_NONE: + break; + case R_X86_64_64: + *where = symval + rela->r_addend; + break; + case R_X86_64_PC32: + /* + * I don't think the dynamic linker should + * ever see this type of relocation. But the + * binutils-2.6 tools sometimes generate it. + */ + *where32 = (Elf32_Addr)(unsigned long)(symval + + rela->r_addend - (Elf_Addr)where); + break; + /* missing: R_X86_64_GOT32 R_X86_64_PLT32 */ + case R_X86_64_COPY: + /* + * These are deferred until all other relocations have + * been done. All we do here is make sure that the COPY + * relocation is not in a shared library. They are + * allowed only in executable files. + */ + if (!obj->mainprog) { + _rtld_error("%s: Unexpected R_X86_64_COPY " + "relocation in shared library", obj->path); + goto done; + } + break; + case R_X86_64_GLOB_DAT: + *where = symval; + break; + case R_X86_64_TPOFF64: + /* + * We lazily allocate offsets for static TLS + * as we see the first relocation that + * references the TLS block. This allows us to + * support (small amounts of) static TLS in + * dynamically loaded modules. If we run out + * of space, we generate an error. + */ + if (!defobj->tls_done) { + if (!allocate_tls_offset((Obj_Entry*) defobj)) { + _rtld_error("%s: No space available " + "for static Thread Local Storage", + obj->path); + goto done; + } + } + *where = (Elf_Addr)(def->st_value - defobj->tlsoffset + + rela->r_addend); + break; + case R_X86_64_TPOFF32: + /* + * We lazily allocate offsets for static TLS + * as we see the first relocation that + * references the TLS block. This allows us to + * support (small amounts of) static TLS in + * dynamically loaded modules. If we run out + * of space, we generate an error. + */ + if (!defobj->tls_done) { + if (!allocate_tls_offset((Obj_Entry*) defobj)) { + _rtld_error("%s: No space available " + "for static Thread Local Storage", + obj->path); + goto done; + } + } + *where32 = (Elf32_Addr)(def->st_value - + defobj->tlsoffset + rela->r_addend); + break; + case R_X86_64_DTPMOD64: + *where += (Elf_Addr)defobj->tlsindex; + break; + case R_X86_64_DTPOFF64: + *where += (Elf_Addr)(def->st_value + rela->r_addend); + break; + case R_X86_64_DTPOFF32: + *where32 += (Elf32_Addr)(def->st_value + + rela->r_addend); + break; + case R_X86_64_RELATIVE: + *where = (Elf_Addr)(obj->relocbase + rela->r_addend); + break; + /* + * missing: + * R_X86_64_GOTPCREL, R_X86_64_32, R_X86_64_32S, R_X86_64_16, + * R_X86_64_PC16, R_X86_64_8, R_X86_64_PC8 + */ + default: + _rtld_error("%s: Unsupported relocation type %u" + " in non-PLT relocations\n", obj->path, + (unsigned int)ELF_R_TYPE(rela->r_info)); + goto done; + } + } + r = 0; +done: + free(cache); + return (r); +} + +/* Process the PLT relocations. */ +int +reloc_plt(Obj_Entry *obj) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + + relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); + for (rela = obj->pltrela; rela < relalim; rela++) { + Elf_Addr *where; + + switch(ELF_R_TYPE(rela->r_info)) { + case R_X86_64_JMP_SLOT: + /* Relocate the GOT slot pointing into the PLT. */ + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + *where += (Elf_Addr)obj->relocbase; + break; + + case R_X86_64_IRELATIVE: + obj->irelative = true; + break; + + default: + _rtld_error("Unknown relocation type %x in PLT", + (unsigned int)ELF_R_TYPE(rela->r_info)); + return (-1); + } + } + return 0; +} + +/* Relocate the jump slots in an object. */ +int +reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + + if (obj->jmpslots_done) + return 0; + relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); + for (rela = obj->pltrela; rela < relalim; rela++) { + Elf_Addr *where, target; + const Elf_Sym *def; + const Obj_Entry *defobj; + + switch (ELF_R_TYPE(rela->r_info)) { + case R_X86_64_JMP_SLOT: + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, + SYMLOOK_IN_PLT | flags, NULL, lockstate); + if (def == NULL) + return (-1); + if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { + obj->gnu_ifunc = true; + continue; + } + target = (Elf_Addr)(defobj->relocbase + def->st_value + rela->r_addend); + reloc_jmpslot(where, target, defobj, obj, (const Elf_Rel *)rela); + break; + + case R_X86_64_IRELATIVE: + break; + + default: + _rtld_error("Unknown relocation type %x in PLT", + (unsigned int)ELF_R_TYPE(rela->r_info)); + return (-1); + } + } + obj->jmpslots_done = true; + return 0; +} + +/* Fixup the jump slot at "where" to transfer control to "target". */ +Elf_Addr +reloc_jmpslot(Elf_Addr *where, Elf_Addr target, + const struct Struct_Obj_Entry *obj, const struct Struct_Obj_Entry *refobj, + const Elf_Rel *rel) +{ +#ifdef dbg + dbg("reloc_jmpslot: *%p = %p", where, (void *)target); +#endif + if (!ld_bind_not) + *where = target; + return (target); +} + +int +reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + + if (!obj->irelative) + return (0); + relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); + for (rela = obj->pltrela; rela < relalim; rela++) { + Elf_Addr *where, target, *ptr; + + switch (ELF_R_TYPE(rela->r_info)) { + case R_X86_64_JMP_SLOT: + break; + + case R_X86_64_IRELATIVE: + ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend); + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + lock_release(rtld_bind_lock, lockstate); + target = call_ifunc_resolver(ptr); + wlock_acquire(rtld_bind_lock, lockstate); + *where = target; + break; + } + } + obj->irelative = false; + return (0); +} + +int +reloc_gnu_ifunc(Obj_Entry *obj, int flags, RtldLockState *lockstate) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + + if (!obj->gnu_ifunc) + return (0); + relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); + for (rela = obj->pltrela; rela < relalim; rela++) { + Elf_Addr *where, target; + const Elf_Sym *def; + const Obj_Entry *defobj; + + switch (ELF_R_TYPE(rela->r_info)) { + case R_X86_64_JMP_SLOT: + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, + SYMLOOK_IN_PLT | flags, NULL, lockstate); + if (def == NULL) + return (-1); + if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC) + continue; + lock_release(rtld_bind_lock, lockstate); + target = (Elf_Addr)rtld_resolve_ifunc(defobj, def); + wlock_acquire(rtld_bind_lock, lockstate); + reloc_jmpslot(where, target, defobj, obj, (const Elf_Rel *)rela); + break; + } + } + obj->gnu_ifunc = false; + return (0); +} + +uint32_t cpu_feature, cpu_feature2, cpu_stdext_feature, cpu_stdext_feature2; + +void +ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) +{ + u_int p[4], cpu_high; + + do_cpuid(1, p); + cpu_feature = p[3]; + cpu_feature2 = p[2]; + do_cpuid(0, p); + cpu_high = p[0]; + if (cpu_high >= 7) { + cpuid_count(7, 0, p); + cpu_stdext_feature = p[1]; + cpu_stdext_feature2 = p[2]; + } +} + +void +allocate_initial_tls(Obj_Entry *objs) +{ + /* + * Fix the size of the static TLS block by using the maximum + * offset allocated so far and adding a bit for dynamic modules to + * use. + */ + tls_static_space = tls_last_offset + RTLD_STATIC_TLS_EXTRA; + amd64_set_fsbase(allocate_tls(objs, 0, + 3*sizeof(Elf_Addr), sizeof(Elf_Addr))); +} + +void *__tls_get_addr(tls_index *ti) +{ + Elf_Addr** segbase; + + __asm __volatile("movq %%fs:0, %0" : "=r" (segbase)); + + return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset); +} diff --git a/libexec/rtld-elf/amd64/rtld_machdep.h b/libexec/rtld-elf/amd64/rtld_machdep.h new file mode 100644 index 0000000..47285e0 --- /dev/null +++ b/libexec/rtld-elf/amd64/rtld_machdep.h @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 1999, 2000 John D. Polstra. + * 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 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 AUTHOR 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/amd64/rtld_machdep.h 316135 2017-03-29 11:03:08Z kib $ + */ + +#ifndef RTLD_MACHDEP_H +#define RTLD_MACHDEP_H 1 + +#include +#include + +struct Struct_Obj_Entry; + +/* Return the address of the .dynamic section in the dynamic linker. */ +Elf_Dyn *rtld_dynamic_addr(void); +#define rtld_dynamic(obj) rtld_dynamic_addr() + +Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target, + const struct Struct_Obj_Entry *obj, const struct Struct_Obj_Entry *refobj, + const Elf_Rel *rel); + +#define make_function_pointer(def, defobj) \ + ((defobj)->relocbase + (def)->st_value) + +#define call_initfini_pointer(obj, target) \ + (((InitFunc)(target))()) + +#define call_init_pointer(obj, target) \ + (((InitArrFunc)(target))(main_argc, main_argv, environ)) + +extern uint32_t cpu_feature; +extern uint32_t cpu_feature2; +extern uint32_t cpu_stdext_feature; +extern uint32_t cpu_stdext_feature2; +#define call_ifunc_resolver(ptr) \ + (((Elf_Addr (*)(uint32_t, uint32_t, uint32_t, uint32_t))ptr)( \ + cpu_feature, cpu_feature2, cpu_stdext_feature, cpu_stdext_feature2)) + +#define round(size, align) \ + (((size) + (align) - 1) & ~((align) - 1)) +#define calculate_first_tls_offset(size, align) \ + round(size, align) +#define calculate_tls_offset(prev_offset, prev_size, size, align) \ + round((prev_offset) + (size), align) +#define calculate_tls_end(off, size) (off) + +typedef struct { + unsigned long ti_module; + unsigned long ti_offset; +} tls_index; + +void *__tls_get_addr(tls_index *ti) __exported; + +#define RTLD_DEFAULT_STACK_PF_EXEC PF_X +#define RTLD_DEFAULT_STACK_EXEC PROT_EXEC + +#define md_abi_variant_hook(x) + +#endif diff --git a/libexec/rtld-elf/amd64/rtld_start.S b/libexec/rtld-elf/amd64/rtld_start.S new file mode 100644 index 0000000..a3551dd --- /dev/null +++ b/libexec/rtld-elf/amd64/rtld_start.S @@ -0,0 +1,171 @@ +/*- + * Copyright 1996-1998 John D. Polstra. + * 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/amd64/rtld_start.S 312789 2017-01-26 03:05:27Z emaste $ + */ + + .text + .align 4 + .globl .rtld_start + .type .rtld_start,@function +.rtld_start: + xorq %rbp,%rbp # Clear frame pointer for good form + subq $24,%rsp # A place to store exit procedure addr + movq %rdi,%r12 + movq %rsp,%rsi # save address of exit proc + movq %rsp,%rdx # construct address of obj_main + addq $8,%rdx + call _rtld # Call rtld(sp); returns entry point + popq %rsi # Get exit procedure address + movq %r12,%rdi # *ap +/* + * At this point, %rax contains the entry point of the main program, and + * %rdx contains a pointer to a termination function that should be + * registered with atexit(). (crt1.o registers it.) + */ +.globl .rtld_goto_main +.rtld_goto_main: # This symbol exists just to make debugging easier. + jmp *%rax # Enter main program + + +/* + * Binder entry point. Control is transferred to here by code in the PLT. + * On entry, there are two arguments on the stack. In ascending address + * order, they are (1) "obj", a pointer to the calling object's Obj_Entry, + * and (2) "reloff", the byte offset of the appropriate relocation entry + * in the PLT relocation table. + * + * We are careful to preserve all registers, even the caller-save + * registers. That is because this code may be invoked by low-level + * assembly-language code that is not ABI-compliant. + * + * Stack map: + * reloff 0x60 + * obj 0x58 + * spare 0x50 + * rflags 0x48 + * rax 0x40 + * rdx 0x38 + * rcx 0x30 + * rsi 0x28 + * rdi 0x20 + * r8 0x18 + * r9 0x10 + * r10 0x8 + * r11 0x0 + */ + .align 4 + .globl _rtld_bind_start + .type _rtld_bind_start,@function +_rtld_bind_start: + .cfi_startproc + .cfi_adjust_cfa_offset 16 + subq $8,%rsp + .cfi_adjust_cfa_offset 8 + pushfq # Save rflags + .cfi_adjust_cfa_offset 8 + pushq %rax # Save %rax + .cfi_adjust_cfa_offset 8 + .cfi_offset %rax,-32 + pushq %rdx # Save %rdx + .cfi_adjust_cfa_offset 8 + .cfi_offset %rdx,-40 + pushq %rcx # Save %rcx + .cfi_adjust_cfa_offset 8 + .cfi_offset %rcx,-48 + pushq %rsi # Save %rsi + .cfi_adjust_cfa_offset 8 + .cfi_offset %rsi,-56 + pushq %rdi # Save %rdi + .cfi_adjust_cfa_offset 8 + .cfi_offset %rdi,-64 + pushq %r8 # Save %r8 + .cfi_adjust_cfa_offset 8 + .cfi_offset %r8,-72 + pushq %r9 # Save %r9 + .cfi_adjust_cfa_offset 8 + .cfi_offset %r9,-80 + pushq %r10 # Save %r10 + .cfi_adjust_cfa_offset 8 + .cfi_offset %r10,-88 + pushq %r11 # Save %r11 + .cfi_adjust_cfa_offset 8 + .cfi_offset %r11,-96 + + movq 0x58(%rsp),%rdi # Fetch obj argument + movq 0x60(%rsp),%rsi # Fetch reloff argument + leaq (%rsi,%rsi,2),%rsi # multiply by 3 + leaq (,%rsi,8),%rsi # now 8, for 24 (sizeof Elf_Rela) + + call _rtld_bind # Transfer control to the binder + /* Now %rax contains the entry point of the function being called. */ + + movq %rax,0x60(%rsp) # Store target over reloff argument + popq %r11 # Restore %r11 + .cfi_adjust_cfa_offset -8 + .cfi_restore %r11 + popq %r10 # Restore %r10 + .cfi_adjust_cfa_offset -8 + .cfi_restore %r10 + popq %r9 # Restore %r9 + .cfi_adjust_cfa_offset -8 + .cfi_restore %r9 + popq %r8 # Restore %r8 + .cfi_adjust_cfa_offset -8 + .cfi_restore %r8 + popq %rdi # Restore %rdi + .cfi_adjust_cfa_offset -8 + .cfi_restore %rdi + popq %rsi # Restore %rsi + .cfi_adjust_cfa_offset -8 + .cfi_restore %rsi + popq %rcx # Restore %rcx + .cfi_adjust_cfa_offset -8 + .cfi_restore %rcx + popq %rdx # Restore %rdx + .cfi_adjust_cfa_offset -8 + .cfi_restore %rdx + popq %rax # Restore %rax + .cfi_adjust_cfa_offset -8 + .cfi_restore %rax + popfq # Restore rflags + .cfi_adjust_cfa_offset -8 + leaq 16(%rsp),%rsp # Discard spare, obj, do not change rflags + ret # "Return" to target address + .cfi_endproc + .size _rtld_bind_start, . - _rtld_bind_start + + .align 4 + .globl rtld_dynamic_addr + .type rtld_dynamic_addr,@function +rtld_dynamic_addr: + .cfi_startproc + .weak _DYNAMIC + .hidden _DYNAMIC + lea _DYNAMIC(%rip),%rax + ret + .cfi_endproc + .size rtld_dynamic_addr, . - rtld_dynamic_addr + + .section .note.GNU-stack,"",%progbits diff --git a/libexec/rtld-elf/arm/Makefile.inc b/libexec/rtld-elf/arm/Makefile.inc new file mode 100644 index 0000000..dc02a7a --- /dev/null +++ b/libexec/rtld-elf/arm/Makefile.inc @@ -0,0 +1 @@ +# $FreeBSD: releng/11.1/libexec/rtld-elf/arm/Makefile.inc 130646 2004-06-17 17:53:16Z cognet $ diff --git a/libexec/rtld-elf/arm/reloc.c b/libexec/rtld-elf/arm/reloc.c new file mode 100644 index 0000000..a456a8e --- /dev/null +++ b/libexec/rtld-elf/arm/reloc.c @@ -0,0 +1,524 @@ +/* $NetBSD: mdreloc.c,v 1.23 2003/07/26 15:04:38 mrg Exp $ */ + +#include +__FBSDID("$FreeBSD: releng/11.1/libexec/rtld-elf/arm/reloc.c 316135 2017-03-29 11:03:08Z kib $"); +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "machine/sysarch.h" + +#include "debug.h" +#include "rtld.h" +#include "paths.h" + +void +arm_abi_variant_hook(Elf_Auxinfo **aux_info) +{ + Elf_Word ehdr; + struct stat sb; + + /* + * If we're running an old kernel that doesn't provide any data fail + * safe by doing nothing. + */ + if (aux_info[AT_EHDRFLAGS] == NULL) + return; + ehdr = aux_info[AT_EHDRFLAGS]->a_un.a_val; + + /* + * Hard float ABI binaries are the default, and use the default paths + * and such. + */ + if ((ehdr & EF_ARM_VFP_FLOAT) != 0) + return; + + /* + * If there's no /usr/libsoft, then we don't have a system with both + * hard and soft float. In that case, hope for the best and just + * return. Such systems are required to have all soft or all hard + * float ABI binaries and libraries. This is, at best, a transition + * compatibility hack. Once we're fully hard-float, this should + * be removed. + */ + if (stat("/usr/libsoft", &sb) != 0 || !S_ISDIR(sb.st_mode)) + return; + + /* + * This is a soft float ABI binary. We need to use the soft float + * settings. + */ + ld_elf_hints_default = _PATH_SOFT_ELF_HINTS; + ld_path_libmap_conf = _PATH_SOFT_LIBMAP_CONF; + ld_path_rtld = _PATH_SOFT_RTLD; + ld_standard_library_path = SOFT_STANDARD_LIBRARY_PATH; + ld_env_prefix = LD_SOFT_; +} + +void +init_pltgot(Obj_Entry *obj) +{ + if (obj->pltgot != NULL) { + obj->pltgot[1] = (Elf_Addr) obj; + obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start; + } +} + +int +do_copy_relocations(Obj_Entry *dstobj) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + + assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */ + + rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize); + for (rel = dstobj->rel; rel < rellim; rel++) { + if (ELF_R_TYPE(rel->r_info) == R_ARM_COPY) { + void *dstaddr; + const Elf_Sym *dstsym; + const char *name; + size_t size; + const void *srcaddr; + const Elf_Sym *srcsym; + const Obj_Entry *srcobj, *defobj; + SymLook req; + int res; + + dstaddr = (void *) (dstobj->relocbase + rel->r_offset); + dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info); + name = dstobj->strtab + dstsym->st_name; + size = dstsym->st_size; + + symlook_init(&req, name); + req.ventry = fetch_ventry(dstobj, + ELF_R_SYM(rel->r_info)); + req.flags = SYMLOOK_EARLY; + + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { + res = symlook_obj(&req, srcobj); + if (res == 0) { + srcsym = req.sym_out; + defobj = req.defobj_out; + break; + } + } + if (srcobj == NULL) { + _rtld_error( +"Undefined symbol \"%s\" referenced from COPY relocation in %s", + name, dstobj->path); + return (-1); + } + + srcaddr = (const void *)(defobj->relocbase + + srcsym->st_value); + memcpy(dstaddr, srcaddr, size); + } + } + return 0; +} + +void _rtld_bind_start(void); +void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); + +int open(); +int _open(); +void +_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) +{ + const Elf_Rel *rel = NULL, *rellim; + Elf_Addr relsz = 0; + Elf_Addr *where; + uint32_t size; + + for (; dynp->d_tag != DT_NULL; dynp++) { + switch (dynp->d_tag) { + case DT_REL: + rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr); + break; + case DT_RELSZ: + relsz = dynp->d_un.d_val; + break; + } + } + rellim = (const Elf_Rel *)((caddr_t)rel + relsz); + size = (rellim - 1)->r_offset - rel->r_offset; + for (; rel < rellim; rel++) { + where = (Elf_Addr *)(relocbase + rel->r_offset); + + *where += (Elf_Addr)relocbase; + } +} +/* + * It is possible for the compiler to emit relocations for unaligned data. + * We handle this situation with these inlines. + */ +#define RELOC_ALIGNED_P(x) \ + (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0) + +static __inline Elf_Addr +load_ptr(void *where) +{ + Elf_Addr res; + + memcpy(&res, where, sizeof(res)); + + return (res); +} + +static __inline void +store_ptr(void *where, Elf_Addr val) +{ + + memcpy(where, &val, sizeof(val)); +} + +static int +reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache, + int flags, RtldLockState *lockstate) +{ + Elf_Addr *where; + const Elf_Sym *def; + const Obj_Entry *defobj; + Elf_Addr tmp; + unsigned long symnum; + + where = (Elf_Addr *)(obj->relocbase + rel->r_offset); + symnum = ELF_R_SYM(rel->r_info); + + switch (ELF_R_TYPE(rel->r_info)) { + case R_ARM_NONE: + break; + +#if 1 /* XXX should not occur */ + case R_ARM_PC24: { /* word32 S - P + A */ + Elf32_Sword addend; + + /* + * Extract addend and sign-extend if needed. + */ + addend = *where; + if (addend & 0x00800000) + addend |= 0xff000000; + + def = find_symdef(symnum, obj, &defobj, flags, cache, + lockstate); + if (def == NULL) + return -1; + tmp = (Elf_Addr)obj->relocbase + def->st_value + - (Elf_Addr)where + (addend << 2); + if ((tmp & 0xfe000000) != 0xfe000000 && + (tmp & 0xfe000000) != 0) { + _rtld_error( + "%s: R_ARM_PC24 relocation @ %p to %s failed " + "(displacement %ld (%#lx) out of range)", + obj->path, where, + obj->strtab + obj->symtab[symnum].st_name, + (long) tmp, (long) tmp); + return -1; + } + tmp >>= 2; + *where = (*where & 0xff000000) | (tmp & 0x00ffffff); + dbg("PC24 %s in %s --> %p @ %p in %s", + obj->strtab + obj->symtab[symnum].st_name, + obj->path, (void *)*where, where, defobj->path); + break; + } +#endif + + case R_ARM_ABS32: /* word32 B + S + A */ + case R_ARM_GLOB_DAT: /* word32 B + S */ + def = find_symdef(symnum, obj, &defobj, flags, cache, + lockstate); + if (def == NULL) + return -1; + if (__predict_true(RELOC_ALIGNED_P(where))) { + tmp = *where + (Elf_Addr)defobj->relocbase + + def->st_value; + *where = tmp; + } else { + tmp = load_ptr(where) + + (Elf_Addr)defobj->relocbase + + def->st_value; + store_ptr(where, tmp); + } + dbg("ABS32/GLOB_DAT %s in %s --> %p @ %p in %s", + obj->strtab + obj->symtab[symnum].st_name, + obj->path, (void *)tmp, where, defobj->path); + break; + + case R_ARM_RELATIVE: /* word32 B + A */ + if (__predict_true(RELOC_ALIGNED_P(where))) { + tmp = *where + (Elf_Addr)obj->relocbase; + *where = tmp; + } else { + tmp = load_ptr(where) + + (Elf_Addr)obj->relocbase; + store_ptr(where, tmp); + } + dbg("RELATIVE in %s --> %p", obj->path, + (void *)tmp); + break; + + case R_ARM_COPY: + /* + * These are deferred until all other relocations have + * been done. All we do here is make sure that the + * COPY relocation is not in a shared library. They + * are allowed only in executable files. + */ + if (!obj->mainprog) { + _rtld_error( + "%s: Unexpected R_COPY relocation in shared library", + obj->path); + return -1; + } + dbg("COPY (avoid in main)"); + break; + + case R_ARM_TLS_DTPOFF32: + def = find_symdef(symnum, obj, &defobj, flags, cache, + lockstate); + if (def == NULL) + return -1; + + tmp = (Elf_Addr)(def->st_value); + if (__predict_true(RELOC_ALIGNED_P(where))) + *where = tmp; + else + store_ptr(where, tmp); + + dbg("TLS_DTPOFF32 %s in %s --> %p", + obj->strtab + obj->symtab[symnum].st_name, + obj->path, (void *)tmp); + + break; + case R_ARM_TLS_DTPMOD32: + def = find_symdef(symnum, obj, &defobj, flags, cache, + lockstate); + if (def == NULL) + return -1; + + tmp = (Elf_Addr)(defobj->tlsindex); + if (__predict_true(RELOC_ALIGNED_P(where))) + *where = tmp; + else + store_ptr(where, tmp); + + dbg("TLS_DTPMOD32 %s in %s --> %p", + obj->strtab + obj->symtab[symnum].st_name, + obj->path, (void *)tmp); + + break; + + case R_ARM_TLS_TPOFF32: + def = find_symdef(symnum, obj, &defobj, flags, cache, + lockstate); + if (def == NULL) + return -1; + + if (!defobj->tls_done && allocate_tls_offset(obj)) + return -1; + + /* XXX: FIXME */ + tmp = (Elf_Addr)def->st_value + defobj->tlsoffset + + TLS_TCB_SIZE; + if (__predict_true(RELOC_ALIGNED_P(where))) + *where = tmp; + else + store_ptr(where, tmp); + dbg("TLS_TPOFF32 %s in %s --> %p", + obj->strtab + obj->symtab[symnum].st_name, + obj->path, (void *)tmp); + break; + + + default: + dbg("sym = %lu, type = %lu, offset = %p, " + "contents = %p, symbol = %s", + symnum, (u_long)ELF_R_TYPE(rel->r_info), + (void *)rel->r_offset, (void *)load_ptr(where), + obj->strtab + obj->symtab[symnum].st_name); + _rtld_error("%s: Unsupported relocation type %ld " + "in non-PLT relocations\n", + obj->path, (u_long) ELF_R_TYPE(rel->r_info)); + return -1; + } + return 0; +} + +/* + * * Process non-PLT relocations + * */ +int +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, + RtldLockState *lockstate) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + SymCache *cache; + int r = -1; + + /* The relocation for the dynamic loader has already been done. */ + if (obj == obj_rtld) + return (0); + if ((flags & SYMLOOK_IFUNC) != 0) + /* XXX not implemented */ + return (0); + + /* + * The dynamic loader may be called from a thread, we have + * limited amounts of stack available so we cannot use alloca(). + */ + cache = calloc(obj->dynsymcount, sizeof(SymCache)); + /* No need to check for NULL here */ + + rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize); + for (rel = obj->rel; rel < rellim; rel++) { + if (reloc_nonplt_object(obj, rel, cache, flags, lockstate) < 0) + goto done; + } + r = 0; +done: + if (cache != NULL) + free(cache); + return (r); +} + +/* + * * Process the PLT relocations. + * */ +int +reloc_plt(Obj_Entry *obj) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + + rellim = (const Elf_Rel *)((char *)obj->pltrel + + obj->pltrelsize); + for (rel = obj->pltrel; rel < rellim; rel++) { + Elf_Addr *where; + + assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); + + where = (Elf_Addr *)(obj->relocbase + rel->r_offset); + *where += (Elf_Addr )obj->relocbase; + } + + return (0); +} + +/* + * * LD_BIND_NOW was set - force relocation for all jump slots + * */ +int +reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) +{ + const Obj_Entry *defobj; + const Elf_Rel *rellim; + const Elf_Rel *rel; + const Elf_Sym *def; + Elf_Addr *where; + Elf_Addr target; + + rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); + for (rel = obj->pltrel; rel < rellim; rel++) { + assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); + where = (Elf_Addr *)(obj->relocbase + rel->r_offset); + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, + SYMLOOK_IN_PLT | flags, NULL, lockstate); + if (def == NULL) { + dbg("reloc_jmpslots: sym not found"); + return (-1); + } + + target = (Elf_Addr)(defobj->relocbase + def->st_value); + reloc_jmpslot(where, target, defobj, obj, + (const Elf_Rel *) rel); + } + + obj->jmpslots_done = true; + + return (0); +} + +int +reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +int +reloc_gnu_ifunc(Obj_Entry *obj, int flags, + struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +Elf_Addr +reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj, + const Obj_Entry *obj, const Elf_Rel *rel) +{ + + assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); + + if (*where != target && !ld_bind_not) + *where = target; + return (target); +} + +void +ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) +{ +} + +void +allocate_initial_tls(Obj_Entry *objs) +{ +#ifdef ARM_TP_ADDRESS + void **_tp = (void **)ARM_TP_ADDRESS; +#endif + + /* + * Fix the size of the static TLS block by using the maximum + * offset allocated so far and adding a bit for dynamic modules to + * use. + */ + + tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA; + +#ifdef ARM_TP_ADDRESS + (*_tp) = (void *) allocate_tls(objs, NULL, TLS_TCB_SIZE, 8); +#else + sysarch(ARM_SET_TP, allocate_tls(objs, NULL, TLS_TCB_SIZE, 8)); +#endif +} + +void * +__tls_get_addr(tls_index* ti) +{ + char *p; +#ifdef ARM_TP_ADDRESS + void **_tp = (void **)ARM_TP_ADDRESS; + + p = tls_get_addr_common((Elf_Addr **)(*_tp), ti->ti_module, ti->ti_offset); +#else + void *_tp; + __asm __volatile("mrc p15, 0, %0, c13, c0, 3" \ + : "=r" (_tp)); + p = tls_get_addr_common((Elf_Addr **)(_tp), ti->ti_module, ti->ti_offset); +#endif + + return (p); +} diff --git a/libexec/rtld-elf/arm/rtld_machdep.h b/libexec/rtld-elf/arm/rtld_machdep.h new file mode 100644 index 0000000..9c323db --- /dev/null +++ b/libexec/rtld-elf/arm/rtld_machdep.h @@ -0,0 +1,80 @@ +/*- + * Copyright (c) 1999, 2000 John D. Polstra. + * 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 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 AUTHOR 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/arm/rtld_machdep.h 319434 2017-06-01 15:12:51Z vangyzen $ + */ + +#ifndef RTLD_MACHDEP_H +#define RTLD_MACHDEP_H 1 + +#include +#include + +struct Struct_Obj_Entry; + +/* Return the address of the .dynamic section in the dynamic linker. */ +#define rtld_dynamic(obj) (&_DYNAMIC) + +Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target, + const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *obj, + const Elf_Rel *rel); + +#define make_function_pointer(def, defobj) \ + ((defobj)->relocbase + (def)->st_value) + +#define call_initfini_pointer(obj, target) \ + (((InitFunc)(target))()) + +#define call_init_pointer(obj, target) \ + (((InitArrFunc)(target))(main_argc, main_argv, environ)) + +#define call_ifunc_resolver(ptr) \ + (((Elf_Addr (*)(void))ptr)()) + +#define TLS_TCB_SIZE 8 +typedef struct { + unsigned long ti_module; + unsigned long ti_offset; +} tls_index; + +#define round(size, align) \ + (((size) + (align) - 1) & ~((align) - 1)) +#define calculate_first_tls_offset(size, align) \ + round(8, align) +#define calculate_tls_offset(prev_offset, prev_size, size, align) \ + round(prev_offset + prev_size, align) +#define calculate_tls_end(off, size) ((off) + (size)) + +extern void *__tls_get_addr(tls_index *ti); + +#define RTLD_DEFAULT_STACK_PF_EXEC PF_X +#define RTLD_DEFAULT_STACK_EXEC PROT_EXEC + +extern void arm_abi_variant_hook(Elf_Auxinfo **); + +#define md_abi_variant_hook(x) arm_abi_variant_hook(x) +#define RTLD_VARIANT_ENV_NAMES + +#endif diff --git a/libexec/rtld-elf/arm/rtld_start.S b/libexec/rtld-elf/arm/rtld_start.S new file mode 100644 index 0000000..181e8a6 --- /dev/null +++ b/libexec/rtld-elf/arm/rtld_start.S @@ -0,0 +1,100 @@ +/* $NetBSD: rtld_start.S,v 1.7 2002/09/12 17:18:38 mycroft Exp $ */ + +/*- + * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas and by Charles M. Hannum. + * + * 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 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. + */ + +#include +__FBSDID("$FreeBSD: releng/11.1/libexec/rtld-elf/arm/rtld_start.S 288373 2015-09-29 16:09:58Z kib $"); + + .text + .align 0 + .globl .rtld_start + .type .rtld_start,%function +.rtld_start: + mov r6, sp /* save the stack pointer */ + bic sp, sp, #7 /* align the stack pointer */ + sub sp, sp, #8 /* make room for obj_main & exit proc */ + mov r4, r0 /* save ps_strings */ + ldr sl, .L2 + ldr r5, .L2+4 + ldr r0, .L2+8 +.L1: + add sl, pc, sl + ldr r5, [sl, r5] + ldr r0, [sl, r0] + + sub r1, sl, r5 /* relocbase */ + add r0, r1, r0 /* &_DYNAMIC */ + bl _rtld_relocate_nonplt_self + mov r1, sp + add r2, sp, #4 + mov r0, r6 /* load the sp the kernel gave us */ + bl _rtld /* call the shared loader */ + mov r3, r0 /* save entry point */ + + ldr r2, [sp, #0] /* r2 = cleanup */ + ldr r1, [sp, #4] /* r1 = obj_main */ + mov sp, r6 /* restore stack */ + mov r0, r4 /* restore ps_strings */ + mov pc, r3 /* jump to the entry point */ +.L2: + .word _GLOBAL_OFFSET_TABLE_ - (.L1+8) + .word _GLOBAL_OFFSET_TABLE_(GOT) + .word _DYNAMIC(GOT) + + .align 0 + .globl _rtld_bind_start + .type _rtld_bind_start,%function +/* + * stack[0] = RA + * ip = &GOT[n+3] + * lr = &GOT[2] + */ +_rtld_bind_start: + stmdb sp!,{r0-r5,sl,fp} + + sub r1, ip, lr /* r1 = 4 * (n + 1) */ + sub r1, r1, #4 /* r1 = 4 * n */ + add r1, r1, r1 /* r1 = 8 * n */ + + ldr r0, [lr, #-4] /* get obj ptr from GOT[1] */ + mov r4, ip /* save GOT location */ + + mov r5, sp /* Save the stack pointer */ + bic sp, sp, #7 /* Align the stack pointer */ + bl _rtld_bind /* Call the binder */ + mov sp, r5 /* Restore the old stack pointer */ + + str r0, [r4] /* save address in GOT */ + mov ip, r0 /* save new address */ + + ldmia sp!,{r0-r5,sl,fp,lr} /* restore the stack */ + mov pc, ip /* jump to the new address */ + + .section .note.GNU-stack,"",%progbits diff --git a/libexec/rtld-elf/i386/Makefile.inc b/libexec/rtld-elf/i386/Makefile.inc new file mode 100644 index 0000000..bb887a4 --- /dev/null +++ b/libexec/rtld-elf/i386/Makefile.inc @@ -0,0 +1,6 @@ +# $FreeBSD: releng/11.1/libexec/rtld-elf/i386/Makefile.inc 286317 2015-08-05 12:53:55Z vangyzen $ + +CFLAGS+= ${CFLAGS_NO_SIMD} -msoft-float +# Uncomment this to build the dynamic linker as an executable instead +# of a shared library: +#LDSCRIPT= ${.CURDIR}/${MACHINE_CPUARCH}/elf_rtld.x diff --git a/libexec/rtld-elf/i386/Symbol.map b/libexec/rtld-elf/i386/Symbol.map new file mode 100644 index 0000000..6d66b9b --- /dev/null +++ b/libexec/rtld-elf/i386/Symbol.map @@ -0,0 +1,7 @@ +/* + * $FreeBSD: releng/11.1/libexec/rtld-elf/i386/Symbol.map 169092 2007-04-29 14:05:22Z deischen $ + */ + +FBSD_1.0 { + ___tls_get_addr; +}; diff --git a/libexec/rtld-elf/i386/elf_rtld.x b/libexec/rtld-elf/i386/elf_rtld.x new file mode 100644 index 0000000..e19168c --- /dev/null +++ b/libexec/rtld-elf/i386/elf_rtld.x @@ -0,0 +1,131 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", + "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) +SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/obj/usr/src/tmp/usr/i386-unknown-freebsdelf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x08000000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + .text : + { + *(.text) + *(.stub) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x9090 + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x9090 + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x1000) + (. & (0x1000 - 1)); + .data : + { + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + . = ALIGN(32 / 8); + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} diff --git a/libexec/rtld-elf/i386/reloc.c b/libexec/rtld-elf/i386/reloc.c new file mode 100644 index 0000000..5073931 --- /dev/null +++ b/libexec/rtld-elf/i386/reloc.c @@ -0,0 +1,507 @@ +/*- + * Copyright 1996, 1997, 1998, 1999 John D. Polstra. + * 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/i386/reloc.c 316135 2017-03-29 11:03:08Z kib $ + */ + +/* + * Dynamic linker for ELF. + * + * John Polstra . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "rtld.h" +#include "rtld_tls.h" + +/* + * Process the special R_386_COPY relocations in the main program. These + * copy data from a shared object into a region in the main program's BSS + * segment. + * + * Returns 0 on success, -1 on failure. + */ +int +do_copy_relocations(Obj_Entry *dstobj) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + + assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */ + + rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize); + for (rel = dstobj->rel; rel < rellim; rel++) { + if (ELF_R_TYPE(rel->r_info) == R_386_COPY) { + void *dstaddr; + const Elf_Sym *dstsym; + const char *name; + size_t size; + const void *srcaddr; + const Elf_Sym *srcsym; + const Obj_Entry *srcobj, *defobj; + SymLook req; + int res; + + dstaddr = (void *) (dstobj->relocbase + rel->r_offset); + dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info); + name = dstobj->strtab + dstsym->st_name; + size = dstsym->st_size; + symlook_init(&req, name); + req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info)); + req.flags = SYMLOOK_EARLY; + + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { + res = symlook_obj(&req, srcobj); + if (res == 0) { + srcsym = req.sym_out; + defobj = req.defobj_out; + break; + } + } + + if (srcobj == NULL) { + _rtld_error("Undefined symbol \"%s\" referenced from COPY" + " relocation in %s", name, dstobj->path); + return -1; + } + + srcaddr = (const void *) (defobj->relocbase + srcsym->st_value); + memcpy(dstaddr, srcaddr, size); + } + } + + return 0; +} + +/* Initialize the special GOT entries. */ +void +init_pltgot(Obj_Entry *obj) +{ + if (obj->pltgot != NULL) { + obj->pltgot[1] = (Elf_Addr) obj; + obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start; + } +} + +/* Process the non-PLT relocations. */ +int +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, + RtldLockState *lockstate) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + SymCache *cache; + const Elf_Sym *def; + const Obj_Entry *defobj; + Elf_Addr *where, symval, add; + int r; + + r = -1; + /* + * The dynamic loader may be called from a thread, we have + * limited amounts of stack available so we cannot use alloca(). + */ + if (obj != obj_rtld) { + cache = calloc(obj->dynsymcount, sizeof(SymCache)); + /* No need to check for NULL here */ + } else + cache = NULL; + + rellim = (const Elf_Rel *)((caddr_t) obj->rel + obj->relsize); + for (rel = obj->rel; rel < rellim; rel++) { + switch (ELF_R_TYPE(rel->r_info)) { + case R_386_32: + case R_386_PC32: + case R_386_GLOB_DAT: + case R_386_TLS_TPOFF: + case R_386_TLS_TPOFF32: + case R_386_TLS_DTPMOD32: + case R_386_TLS_DTPOFF32: + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, + flags, cache, lockstate); + if (def == NULL) + goto done; + if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { + switch (ELF_R_TYPE(rel->r_info)) { + case R_386_32: + case R_386_PC32: + case R_386_GLOB_DAT: + if ((flags & SYMLOOK_IFUNC) == 0) { + obj->non_plt_gnu_ifunc = true; + continue; + } + symval = (Elf_Addr)rtld_resolve_ifunc( + defobj, def); + break; + case R_386_TLS_TPOFF: + case R_386_TLS_TPOFF32: + case R_386_TLS_DTPMOD32: + case R_386_TLS_DTPOFF32: + _rtld_error("%s: IFUNC for TLS reloc", + obj->path); + goto done; + } + } else { + if ((flags & SYMLOOK_IFUNC) != 0) + continue; + symval = (Elf_Addr)defobj->relocbase + + def->st_value; + } + break; + default: + if ((flags & SYMLOOK_IFUNC) != 0) + continue; + break; + } + where = (Elf_Addr *)(obj->relocbase + rel->r_offset); + + switch (ELF_R_TYPE(rel->r_info)) { + case R_386_NONE: + break; + case R_386_32: + *where += symval; + break; + case R_386_PC32: + /* + * I don't think the dynamic linker should ever + * see this type of relocation. But the + * binutils-2.6 tools sometimes generate it. + */ + *where += symval - (Elf_Addr)where; + break; + case R_386_COPY: + /* + * These are deferred until all other + * relocations have been done. All we do here + * is make sure that the COPY relocation is + * not in a shared library. They are allowed + * only in executable files. + */ + if (!obj->mainprog) { + _rtld_error("%s: Unexpected R_386_COPY " + "relocation in shared library", obj->path); + goto done; + } + break; + case R_386_GLOB_DAT: + *where = symval; + break; + case R_386_RELATIVE: + *where += (Elf_Addr)obj->relocbase; + break; + case R_386_TLS_TPOFF: + case R_386_TLS_TPOFF32: + /* + * We lazily allocate offsets for static TLS + * as we see the first relocation that + * references the TLS block. This allows us to + * support (small amounts of) static TLS in + * dynamically loaded modules. If we run out + * of space, we generate an error. + */ + if (!defobj->tls_done) { + if (!allocate_tls_offset((Obj_Entry*) defobj)) { + _rtld_error("%s: No space available " + "for static Thread Local Storage", + obj->path); + goto done; + } + } + add = (Elf_Addr)(def->st_value - defobj->tlsoffset); + if (ELF_R_TYPE(rel->r_info) == R_386_TLS_TPOFF) + *where += add; + else + *where -= add; + break; + case R_386_TLS_DTPMOD32: + *where += (Elf_Addr)defobj->tlsindex; + break; + case R_386_TLS_DTPOFF32: + *where += (Elf_Addr) def->st_value; + break; + default: + _rtld_error("%s: Unsupported relocation type %d" + " in non-PLT relocations\n", obj->path, + ELF_R_TYPE(rel->r_info)); + goto done; + } + } + r = 0; +done: + free(cache); + return (r); +} + +/* Process the PLT relocations. */ +int +reloc_plt(Obj_Entry *obj) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + + rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); + for (rel = obj->pltrel; rel < rellim; rel++) { + Elf_Addr *where/*, val*/; + + switch (ELF_R_TYPE(rel->r_info)) { + case R_386_JMP_SLOT: + /* Relocate the GOT slot pointing into the PLT. */ + where = (Elf_Addr *)(obj->relocbase + rel->r_offset); + *where += (Elf_Addr)obj->relocbase; + break; + + case R_386_IRELATIVE: + obj->irelative = true; + break; + + default: + _rtld_error("Unknown relocation type %x in PLT", + ELF_R_TYPE(rel->r_info)); + return (-1); + } + } + return 0; +} + +/* Relocate the jump slots in an object. */ +int +reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + + if (obj->jmpslots_done) + return 0; + rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); + for (rel = obj->pltrel; rel < rellim; rel++) { + Elf_Addr *where, target; + const Elf_Sym *def; + const Obj_Entry *defobj; + + switch (ELF_R_TYPE(rel->r_info)) { + case R_386_JMP_SLOT: + where = (Elf_Addr *)(obj->relocbase + rel->r_offset); + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, + SYMLOOK_IN_PLT | flags, NULL, lockstate); + if (def == NULL) + return (-1); + if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { + obj->gnu_ifunc = true; + continue; + } + target = (Elf_Addr)(defobj->relocbase + def->st_value); + reloc_jmpslot(where, target, defobj, obj, rel); + break; + + case R_386_IRELATIVE: + break; + + default: + _rtld_error("Unknown relocation type %x in PLT", + ELF_R_TYPE(rel->r_info)); + return (-1); + } + } + + obj->jmpslots_done = true; + return 0; +} + +/* Fixup the jump slot at "where" to transfer control to "target". */ +Elf_Addr +reloc_jmpslot(Elf_Addr *where, Elf_Addr target, + const struct Struct_Obj_Entry *obj, const struct Struct_Obj_Entry *refobj, + const Elf_Rel *rel) +{ +#ifdef dbg + dbg("reloc_jmpslot: *%p = %p", where, (void *)target); +#endif + if (!ld_bind_not) + *where = target; + return (target); +} + +int +reloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + Elf_Addr *where, target; + + if (!obj->irelative) + return (0); + rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); + for (rel = obj->pltrel; rel < rellim; rel++) { + switch (ELF_R_TYPE(rel->r_info)) { + case R_386_IRELATIVE: + where = (Elf_Addr *)(obj->relocbase + rel->r_offset); + lock_release(rtld_bind_lock, lockstate); + target = call_ifunc_resolver(obj->relocbase + *where); + wlock_acquire(rtld_bind_lock, lockstate); + *where = target; + break; + } + } + obj->irelative = false; + return (0); +} + +int +reloc_gnu_ifunc(Obj_Entry *obj, int flags, RtldLockState *lockstate) +{ + const Elf_Rel *rellim; + const Elf_Rel *rel; + + if (!obj->gnu_ifunc) + return (0); + rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); + for (rel = obj->pltrel; rel < rellim; rel++) { + Elf_Addr *where, target; + const Elf_Sym *def; + const Obj_Entry *defobj; + + switch (ELF_R_TYPE(rel->r_info)) { + case R_386_JMP_SLOT: + where = (Elf_Addr *)(obj->relocbase + rel->r_offset); + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, + SYMLOOK_IN_PLT | flags, NULL, lockstate); + if (def == NULL) + return (-1); + if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC) + continue; + lock_release(rtld_bind_lock, lockstate); + target = (Elf_Addr)rtld_resolve_ifunc(defobj, def); + wlock_acquire(rtld_bind_lock, lockstate); + reloc_jmpslot(where, target, defobj, obj, rel); + break; + } + } + + obj->gnu_ifunc = false; + return (0); +} + +uint32_t cpu_feature, cpu_feature2, cpu_stdext_feature, cpu_stdext_feature2; + +static void +rtld_cpuid_count(int idx, int cnt, u_int *p) +{ + + __asm __volatile( + " pushl %%ebx\n" + " cpuid\n" + " movl %%ebx,%1\n" + " popl %%ebx\n" + : "=a" (p[0]), "=r" (p[1]), "=c" (p[2]), "=d" (p[3]) + : "0" (idx), "2" (cnt)); +} + +void +ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) +{ + u_int p[4], cpu_high; + int cpuid_supported; + + __asm __volatile( + " pushfl\n" + " popl %%eax\n" + " movl %%eax,%%ecx\n" + " xorl $0x200000,%%eax\n" + " pushl %%eax\n" + " popfl\n" + " pushfl\n" + " popl %%eax\n" + " xorl %%eax,%%ecx\n" + " je 1f\n" + " movl $1,%0\n" + " jmp 2f\n" + "1: movl $0,%0\n" + "2:\n" + : "=r" (cpuid_supported) : : "eax", "ecx"); + if (!cpuid_supported) + return; + + rtld_cpuid_count(1, 0, p); + cpu_feature = p[3]; + cpu_feature2 = p[2]; + rtld_cpuid_count(0, 0, p); + cpu_high = p[0]; + if (cpu_high >= 7) { + rtld_cpuid_count(7, 0, p); + cpu_stdext_feature = p[1]; + cpu_stdext_feature2 = p[2]; + } +} + +void +allocate_initial_tls(Obj_Entry *objs) +{ + void* tls; + + /* + * Fix the size of the static TLS block by using the maximum + * offset allocated so far and adding a bit for dynamic modules to + * use. + */ + tls_static_space = tls_last_offset + RTLD_STATIC_TLS_EXTRA; + tls = allocate_tls(objs, NULL, 3*sizeof(Elf_Addr), sizeof(Elf_Addr)); + i386_set_gsbase(tls); +} + +/* GNU ABI */ +__attribute__((__regparm__(1))) +void *___tls_get_addr(tls_index *ti) +{ + Elf_Addr** segbase; + + __asm __volatile("movl %%gs:0, %0" : "=r" (segbase)); + + return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset); +} + +/* Sun ABI */ +void *__tls_get_addr(tls_index *ti) +{ + Elf_Addr** segbase; + + __asm __volatile("movl %%gs:0, %0" : "=r" (segbase)); + + return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset); +} diff --git a/libexec/rtld-elf/i386/rtld_machdep.h b/libexec/rtld-elf/i386/rtld_machdep.h new file mode 100644 index 0000000..c78261c --- /dev/null +++ b/libexec/rtld-elf/i386/rtld_machdep.h @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 1999, 2000 John D. Polstra. + * 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 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 AUTHOR 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/i386/rtld_machdep.h 316135 2017-03-29 11:03:08Z kib $ + */ + +#ifndef RTLD_MACHDEP_H +#define RTLD_MACHDEP_H 1 + +#include +#include + +struct Struct_Obj_Entry; + +/* Return the address of the .dynamic section in the dynamic linker. */ +#define rtld_dynamic(obj) \ + ((const Elf_Dyn *)((obj)->relocbase + (Elf_Addr)&_DYNAMIC)) + +Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target, + const struct Struct_Obj_Entry *obj, const struct Struct_Obj_Entry *refobj, + const Elf_Rel *rel); + +#define make_function_pointer(def, defobj) \ + ((defobj)->relocbase + (def)->st_value) + +#define call_initfini_pointer(obj, target) \ + (((InitFunc)(target))()) + +#define call_init_pointer(obj, target) \ + (((InitArrFunc)(target))(main_argc, main_argv, environ)) + +extern uint32_t cpu_feature; +extern uint32_t cpu_feature2; +extern uint32_t cpu_stdext_feature; +extern uint32_t cpu_stdext_feature2; +#define call_ifunc_resolver(ptr) \ + (((Elf_Addr (*)(uint32_t, uint32_t, uint32_t, uint32_t))ptr)( \ + cpu_feature, cpu_feature2, cpu_stdext_feature, cpu_stdext_feature2)) + +#define round(size, align) \ + (((size) + (align) - 1) & ~((align) - 1)) +#define calculate_first_tls_offset(size, align) \ + round(size, align) +#define calculate_tls_offset(prev_offset, prev_size, size, align) \ + round((prev_offset) + (size), align) +#define calculate_tls_end(off, size) (off) + +typedef struct { + unsigned long ti_module; + unsigned long ti_offset; +} tls_index; + +void *___tls_get_addr(tls_index *ti) __attribute__((__regparm__(1))) __exported; +void *__tls_get_addr(tls_index *ti) __exported; + +#define RTLD_DEFAULT_STACK_PF_EXEC PF_X +#define RTLD_DEFAULT_STACK_EXEC PROT_EXEC + +#define md_abi_variant_hook(x) + +#endif diff --git a/libexec/rtld-elf/i386/rtld_start.S b/libexec/rtld-elf/i386/rtld_start.S new file mode 100644 index 0000000..1e7662e --- /dev/null +++ b/libexec/rtld-elf/i386/rtld_start.S @@ -0,0 +1,93 @@ +/*- + * Copyright 1996-1998 John D. Polstra. + * 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/i386/rtld_start.S 280816 2015-03-29 18:53:21Z kib $ + */ + + .text + .align 4 + .globl .rtld_start + .type .rtld_start,@function +.rtld_start: + xorl %ebp,%ebp # Clear frame pointer for good form + movl %esp,%eax # Save initial stack pointer + movl %esp,%esi # Save initial stack pointer + andl $0xfffffff0,%esp # Align stack pointer + subl $16,%esp # A place to store exit procedure addr + movl %esp,%ebx # save address of exit proc + movl %esp,%ecx # construct address of obj_main + addl $4,%ecx + subl $4,%esp # Keep stack aligned + pushl %ecx # Pass address of obj_main + pushl %ebx # Pass address of exit proc + pushl %eax # Pass initial stack pointer to rtld + call _rtld # Call rtld(sp); returns entry point + addl $16,%esp # Remove arguments from stack + popl %edx # Get exit procedure address + movl %esi,%esp # Ignore obj_main +/* + * At this point, %eax contains the entry point of the main program, and + * %edx contains a pointer to a termination function that should be + * registered with atexit(). (crt1.o registers it.) + */ +.globl .rtld_goto_main +.rtld_goto_main: # This symbol exists just to make debugging easier. + jmp *%eax # Enter main program + + +/* + * Binder entry point. Control is transferred to here by code in the PLT. + * On entry, there are two arguments on the stack. In ascending address + * order, they are (1) "obj", a pointer to the calling object's Obj_Entry, + * and (2) "reloff", the byte offset of the appropriate relocation entry + * in the PLT relocation table. + * + * We are careful to preserve all registers, even the caller-save + * registers. That is because this code may be invoked by low-level + * assembly-language code that is not ABI-compliant. + */ + .align 4 + .globl _rtld_bind_start + .type _rtld_bind_start,@function +_rtld_bind_start: + pushf # Save eflags + pushl %eax # Save %eax + pushl %edx # Save %edx + pushl %ecx # Save %ecx + pushl 20(%esp) # Copy reloff argument + pushl 20(%esp) # Copy obj argument + + call _rtld_bind # Transfer control to the binder + /* Now %eax contains the entry point of the function being called. */ + + addl $8,%esp # Discard binder arguments + movl %eax,20(%esp) # Store target over obj argument + popl %ecx # Restore %ecx + popl %edx # Restore %edx + popl %eax # Restore %eax + popf # Restore eflags + leal 4(%esp),%esp # Discard reloff, do not change eflags + ret # "Return" to target address + + .section .note.GNU-stack,"",%progbits diff --git a/libexec/rtld-elf/mips/reloc.c b/libexec/rtld-elf/mips/reloc.c new file mode 100644 index 0000000..4fefeeb --- /dev/null +++ b/libexec/rtld-elf/mips/reloc.c @@ -0,0 +1,661 @@ +/* $NetBSD: mips_reloc.c,v 1.58 2010/01/14 11:57:06 skrll Exp $ */ + +/* + * Copyright 1997 Michael L. Hitch + * Portions copyright 2002 Charles M. Hannum + * 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. + * 3. 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. + */ + +#include +__FBSDID("$FreeBSD: releng/11.1/libexec/rtld-elf/mips/reloc.c 316135 2017-03-29 11:03:08Z kib $"); + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "debug.h" +#include "rtld.h" + +#ifdef __mips_n64 +#define GOT1_MASK 0x8000000000000000UL +#else +#define GOT1_MASK 0x80000000UL +#endif + +void +init_pltgot(Obj_Entry *obj) +{ + if (obj->pltgot != NULL) { + obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start; + if (obj->pltgot[1] & 0x80000000) + obj->pltgot[1] = (Elf_Addr) obj | GOT1_MASK; + } +} + +int +do_copy_relocations(Obj_Entry *dstobj) +{ + /* Do nothing */ + return 0; +} + +void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); + +/* + * It is possible for the compiler to emit relocations for unaligned data. + * We handle this situation with these inlines. + */ +#ifdef __mips_n64 +/* + * ELF64 MIPS encodes the relocs uniquely. The first 32-bits of info contain + * the symbol index. The top 32-bits contain three relocation types encoded + * in big-endian integer with first relocation in LSB. This means for little + * endian we have to byte swap that integer (r_type). + */ +#define Elf_Sxword Elf64_Sxword +#define ELF_R_NXTTYPE_64_P(r_type) ((((r_type) >> 8) & 0xff) == R_TYPE(64)) +#if BYTE_ORDER == LITTLE_ENDIAN +#undef ELF_R_SYM +#undef ELF_R_TYPE +#define ELF_R_SYM(r_info) ((r_info) & 0xffffffff) +#define ELF_R_TYPE(r_info) bswap32((r_info) >> 32) +#endif +#else +#define ELF_R_NXTTYPE_64_P(r_type) (0) +#define Elf_Sxword Elf32_Sword +#endif + +static __inline Elf_Sxword +load_ptr(void *where, size_t len) +{ + Elf_Sxword val; + + if (__predict_true(((uintptr_t)where & (len - 1)) == 0)) { +#ifdef __mips_n64 + if (len == sizeof(Elf_Sxword)) + return *(Elf_Sxword *)where; +#endif + return *(Elf_Sword *)where; + } + + val = 0; +#if BYTE_ORDER == LITTLE_ENDIAN + (void)memcpy(&val, where, len); +#endif +#if BYTE_ORDER == BIG_ENDIAN + (void)memcpy((uint8_t *)((&val)+1) - len, where, len); +#endif + return (len == sizeof(Elf_Sxword)) ? val : (Elf_Sword)val; +} + +static __inline void +store_ptr(void *where, Elf_Sxword val, size_t len) +{ + if (__predict_true(((uintptr_t)where & (len - 1)) == 0)) { +#ifdef __mips_n64 + if (len == sizeof(Elf_Sxword)) { + *(Elf_Sxword *)where = val; + return; + } +#endif + *(Elf_Sword *)where = val; + return; + } +#if BYTE_ORDER == LITTLE_ENDIAN + (void)memcpy(where, &val, len); +#endif +#if BYTE_ORDER == BIG_ENDIAN + (void)memcpy(where, (const uint8_t *)((&val)+1) - len, len); +#endif +} + +void +_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) +{ + const Elf_Rel *rel = NULL, *rellim; + Elf_Addr relsz = 0; + const Elf_Sym *symtab = NULL, *sym; + Elf_Addr *where; + Elf_Addr *got = NULL; + Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0; + size_t i; + + for (; dynp->d_tag != DT_NULL; dynp++) { + switch (dynp->d_tag) { + case DT_REL: + rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr); + break; + case DT_RELSZ: + relsz = dynp->d_un.d_val; + break; + case DT_SYMTAB: + symtab = (const Elf_Sym *)(relocbase + dynp->d_un.d_ptr); + break; + case DT_PLTGOT: + got = (Elf_Addr *)(relocbase + dynp->d_un.d_ptr); + break; + case DT_MIPS_LOCAL_GOTNO: + local_gotno = dynp->d_un.d_val; + break; + case DT_MIPS_SYMTABNO: + symtabno = dynp->d_un.d_val; + break; + case DT_MIPS_GOTSYM: + gotsym = dynp->d_un.d_val; + break; + } + } + + i = (got[1] & GOT1_MASK) ? 2 : 1; + /* Relocate the local GOT entries */ + got += i; + for (; i < local_gotno; i++) { + *got++ += relocbase; + } + + sym = symtab + gotsym; + /* Now do the global GOT entries */ + for (i = gotsym; i < symtabno; i++) { + *got = sym->st_value + relocbase; + ++sym; + ++got; + } + + rellim = (const Elf_Rel *)((caddr_t)rel + relsz); + for (; rel < rellim; rel++) { + Elf_Word r_symndx, r_type; + + where = (void *)(relocbase + rel->r_offset); + + r_symndx = ELF_R_SYM(rel->r_info); + r_type = ELF_R_TYPE(rel->r_info); + + switch (r_type & 0xff) { + case R_TYPE(REL32): { + const size_t rlen = + ELF_R_NXTTYPE_64_P(r_type) + ? sizeof(Elf_Sxword) + : sizeof(Elf_Sword); + Elf_Sxword old = load_ptr(where, rlen); + Elf_Sxword val = old; +#ifdef __mips_n64 + assert(r_type == R_TYPE(REL32) + || r_type == (R_TYPE(REL32)|(R_TYPE(64) << 8))); +#endif + assert(r_symndx < gotsym); + sym = symtab + r_symndx; + assert(ELF_ST_BIND(sym->st_info) == STB_LOCAL); + val += relocbase; + store_ptr(where, val, sizeof(Elf_Sword)); + dbg("REL32/L(%p) %p -> %p in ", + where, (void *)old, (void *)val); + store_ptr(where, val, rlen); + break; + } + + case R_TYPE(GPREL32): + case R_TYPE(NONE): + break; + + + default: + abort(); + break; + } + } +} + +Elf_Addr +_mips_rtld_bind(Obj_Entry *obj, Elf_Size reloff) +{ + Elf_Addr *got = obj->pltgot; + const Elf_Sym *def; + const Obj_Entry *defobj; + Elf_Addr *where; + Elf_Addr target; + RtldLockState lockstate; + + rlock_acquire(rtld_bind_lock, &lockstate); + if (sigsetjmp(lockstate.env, 0) != 0) + lock_upgrade(rtld_bind_lock, &lockstate); + + where = &got[obj->local_gotno + reloff - obj->gotsym]; + def = find_symdef(reloff, obj, &defobj, SYMLOOK_IN_PLT, NULL, + &lockstate); + if (def == NULL) + rtld_die(); + + target = (Elf_Addr)(defobj->relocbase + def->st_value); + dbg("bind now/fixup at %s sym # %jd in %s --> was=%p new=%p", + obj->path, + (intmax_t)reloff, defobj->strtab + def->st_name, + (void *)*where, (void *)target); + if (!ld_bind_not) + *where = target; + lock_release(rtld_bind_lock, &lockstate); + return (Elf_Addr)target; +} + +int +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, + RtldLockState *lockstate) +{ + const Elf_Rel *rel; + const Elf_Rel *rellim; + Elf_Addr *got = obj->pltgot; + const Elf_Sym *sym, *def; + const Obj_Entry *defobj; + Elf_Word i; +#ifdef SUPPORT_OLD_BROKEN_LD + int broken; +#endif + + /* The relocation for the dynamic loader has already been done. */ + if (obj == obj_rtld) + return (0); + + if ((flags & SYMLOOK_IFUNC) != 0) + /* XXX not implemented */ + return (0); + +#ifdef SUPPORT_OLD_BROKEN_LD + broken = 0; + sym = obj->symtab; + for (i = 1; i < 12; i++) + if (sym[i].st_info == ELF_ST_INFO(STB_LOCAL, STT_NOTYPE)) + broken = 1; + dbg("%s: broken=%d", obj->path, broken); +#endif + + i = (got[1] & GOT1_MASK) ? 2 : 1; + + /* Relocate the local GOT entries */ + got += i; + dbg("got:%p for %d entries adding %p", + got, obj->local_gotno, obj->relocbase); + for (; i < obj->local_gotno; i++) { + *got += (Elf_Addr)obj->relocbase; + got++; + } + sym = obj->symtab + obj->gotsym; + + dbg("got:%p for %d entries", + got, obj->symtabno); + /* Now do the global GOT entries */ + for (i = obj->gotsym; i < obj->symtabno; i++) { + dbg(" doing got %d sym %p (%s, %lx)", i - obj->gotsym, sym, + sym->st_name + obj->strtab, (u_long) *got); + +#ifdef SUPPORT_OLD_BROKEN_LD + if (ELF_ST_TYPE(sym->st_info) == STT_FUNC && + broken && sym->st_shndx == SHN_UNDEF) { + /* + * XXX DANGER WILL ROBINSON! + * You might think this is stupid, as it intentionally + * defeats lazy binding -- and you'd be right. + * Unfortunately, for lazy binding to work right, we + * need to a way to force the GOT slots used for + * function pointers to be resolved immediately. This + * is supposed to be done automatically by the linker, + * by not outputting a PLT slot and setting st_value + * to 0 if there are non-PLT references, but older + * versions of GNU ld do not do this. + */ + def = find_symdef(i, obj, &defobj, flags, NULL, + lockstate); + if (def == NULL) + return -1; + *got = def->st_value + (Elf_Addr)defobj->relocbase; + } else +#endif + if (ELF_ST_TYPE(sym->st_info) == STT_FUNC && + sym->st_value != 0 && sym->st_shndx == SHN_UNDEF) { + /* + * If there are non-PLT references to the function, + * st_value should be 0, forcing us to resolve the + * address immediately. + * + * XXX DANGER WILL ROBINSON! + * The linker is not outputting PLT slots for calls to + * functions that are defined in the same shared + * library. This is a bug, because it can screw up + * link ordering rules if the symbol is defined in + * more than one module. For now, if there is a + * definition, we fail the test above and force a full + * symbol lookup. This means that all intra-module + * calls are bound immediately. - mycroft, 2003/09/24 + */ + *got = sym->st_value + (Elf_Addr)obj->relocbase; + if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) { + dbg("Warning2, i:%d maps to relocbase address:%p", + i, obj->relocbase); + } + + } else if (sym->st_info == ELF_ST_INFO(STB_GLOBAL, STT_SECTION)) { + /* Symbols with index SHN_ABS are not relocated. */ + if (sym->st_shndx != SHN_ABS) { + *got = sym->st_value + + (Elf_Addr)obj->relocbase; + if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) { + dbg("Warning3, i:%d maps to relocbase address:%p", + i, obj->relocbase); + } + } + } else { + /* TODO: add cache here */ + def = find_symdef(i, obj, &defobj, flags, NULL, + lockstate); + if (def == NULL) { + dbg("Warning4, can't find symbole %d", i); + return -1; + } + *got = def->st_value + (Elf_Addr)defobj->relocbase; + if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) { + dbg("Warning4, i:%d maps to relocbase address:%p", + i, obj->relocbase); + dbg("via first obj symbol %s", + obj->strtab + obj->symtab[i].st_name); + dbg("found in obj %p:%s", + defobj, defobj->path); + } + } + + dbg(" --> now %lx", (u_long) *got); + ++sym; + ++got; + } + + got = obj->pltgot; + rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize); + for (rel = obj->rel; rel < rellim; rel++) { + Elf_Word r_symndx, r_type; + void *where; + + where = obj->relocbase + rel->r_offset; + r_symndx = ELF_R_SYM(rel->r_info); + r_type = ELF_R_TYPE(rel->r_info); + + switch (r_type & 0xff) { + case R_TYPE(NONE): + break; + + case R_TYPE(REL32): { + /* 32-bit PC-relative reference */ + const size_t rlen = + ELF_R_NXTTYPE_64_P(r_type) + ? sizeof(Elf_Sxword) + : sizeof(Elf_Sword); + Elf_Sxword old = load_ptr(where, rlen); + Elf_Sxword val = old; + + def = obj->symtab + r_symndx; + + if (r_symndx >= obj->gotsym) { + val += got[obj->local_gotno + r_symndx - obj->gotsym]; + dbg("REL32/G(%p) %p --> %p (%s) in %s", + where, (void *)old, (void *)val, + obj->strtab + def->st_name, + obj->path); + } else { + /* + * XXX: ABI DIFFERENCE! + * + * Old NetBSD binutils would generate shared + * libs with section-relative relocations being + * already adjusted for the start address of + * the section. + * + * New binutils, OTOH, generate shared libs + * with the same relocations being based at + * zero, so we need to add in the start address + * of the section. + * + * --rkb, Oct 6, 2001 + */ + + if (def->st_info == + ELF_ST_INFO(STB_LOCAL, STT_SECTION) +#ifdef SUPPORT_OLD_BROKEN_LD + && !broken +#endif + ) + val += (Elf_Addr)def->st_value; + + val += (Elf_Addr)obj->relocbase; + + dbg("REL32/L(%p) %p -> %p (%s) in %s", + where, (void *)old, (void *)val, + obj->strtab + def->st_name, obj->path); + } + store_ptr(where, val, rlen); + break; + } + +#ifdef __mips_n64 + case R_TYPE(TLS_DTPMOD64): +#else + case R_TYPE(TLS_DTPMOD32): +#endif + { + + const size_t rlen = sizeof(Elf_Addr); + Elf_Addr old = load_ptr(where, rlen); + Elf_Addr val = old; + + def = find_symdef(r_symndx, obj, &defobj, flags, NULL, + lockstate); + if (def == NULL) + return -1; + + val += (Elf_Addr)defobj->tlsindex; + + store_ptr(where, val, rlen); + dbg("DTPMOD %s in %s %p --> %p in %s", + obj->strtab + obj->symtab[r_symndx].st_name, + obj->path, (void *)old, (void*)val, defobj->path); + break; + } + +#ifdef __mips_n64 + case R_TYPE(TLS_DTPREL64): +#else + case R_TYPE(TLS_DTPREL32): +#endif + { + const size_t rlen = sizeof(Elf_Addr); + Elf_Addr old = load_ptr(where, rlen); + Elf_Addr val = old; + + def = find_symdef(r_symndx, obj, &defobj, flags, NULL, + lockstate); + if (def == NULL) + return -1; + + if (!defobj->tls_done && allocate_tls_offset(obj)) + return -1; + + val += (Elf_Addr)def->st_value - TLS_DTP_OFFSET; + store_ptr(where, val, rlen); + + dbg("DTPREL %s in %s %p --> %p in %s", + obj->strtab + obj->symtab[r_symndx].st_name, + obj->path, (void*)old, (void *)val, defobj->path); + break; + } + +#ifdef __mips_n64 + case R_TYPE(TLS_TPREL64): +#else + case R_TYPE(TLS_TPREL32): +#endif + { + const size_t rlen = sizeof(Elf_Addr); + Elf_Addr old = load_ptr(where, rlen); + Elf_Addr val = old; + + def = find_symdef(r_symndx, obj, &defobj, flags, NULL, + lockstate); + + if (def == NULL) + return -1; + + if (!defobj->tls_done && allocate_tls_offset(obj)) + return -1; + + val += (Elf_Addr)(def->st_value + defobj->tlsoffset + - TLS_TP_OFFSET - TLS_TCB_SIZE); + store_ptr(where, val, rlen); + + dbg("TPREL %s in %s %p --> %p in %s", + obj->strtab + obj->symtab[r_symndx].st_name, + obj->path, (void*)old, (void *)val, defobj->path); + break; + } + + + + default: + dbg("sym = %lu, type = %lu, offset = %p, " + "contents = %p, symbol = %s", + (u_long)r_symndx, (u_long)ELF_R_TYPE(rel->r_info), + (void *)rel->r_offset, + (void *)load_ptr(where, sizeof(Elf_Sword)), + obj->strtab + obj->symtab[r_symndx].st_name); + _rtld_error("%s: Unsupported relocation type %ld " + "in non-PLT relocations", + obj->path, (u_long) ELF_R_TYPE(rel->r_info)); + return -1; + } + } + + return 0; +} + +/* + * Process the PLT relocations. + */ +int +reloc_plt(Obj_Entry *obj) +{ +#if 0 + const Elf_Rel *rellim; + const Elf_Rel *rel; + + dbg("reloc_plt obj:%p pltrel:%p sz:%s", obj, obj->pltrel, (int)obj->pltrelsize); + dbg("gottable %p num syms:%s", obj->pltgot, obj->symtabno ); + dbg("*****************************************************"); + rellim = (const Elf_Rel *)((char *)obj->pltrel + + obj->pltrelsize); + for (rel = obj->pltrel; rel < rellim; rel++) { + Elf_Addr *where; + where = (Elf_Addr *)(obj->relocbase + rel->r_offset); + *where += (Elf_Addr )obj->relocbase; + } + +#endif + /* PLT fixups were done above in the GOT relocation. */ + return (0); +} + +/* + * LD_BIND_NOW was set - force relocation for all jump slots + */ +int +reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) +{ + /* Do nothing */ + obj->jmpslots_done = true; + + return (0); +} + +int +reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +int +reloc_gnu_ifunc(Obj_Entry *obj, int flags, + struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +Elf_Addr +reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj, + const Obj_Entry *obj, const Elf_Rel *rel) +{ + + /* Do nothing */ + + return target; +} + +void +ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) +{ +} + +void +allocate_initial_tls(Obj_Entry *objs) +{ + char *tls; + + /* + * Fix the size of the static TLS block by using the maximum + * offset allocated so far and adding a bit for dynamic modules to + * use. + */ + tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA; + + tls = (char *) allocate_tls(objs, NULL, TLS_TCB_SIZE, 8); + + sysarch(MIPS_SET_TLS, tls); +} + +void * +__tls_get_addr(tls_index* ti) +{ + Elf_Addr** tls; + char *p; + + sysarch(MIPS_GET_TLS, &tls); + + p = tls_get_addr_common(tls, ti->ti_module, ti->ti_offset + TLS_DTP_OFFSET); + + return (p); +} diff --git a/libexec/rtld-elf/mips/rtld_machdep.h b/libexec/rtld-elf/mips/rtld_machdep.h new file mode 100644 index 0000000..c838b49 --- /dev/null +++ b/libexec/rtld-elf/mips/rtld_machdep.h @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 1999, 2000 John D. Polstra. + * 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 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 AUTHOR 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/mips/rtld_machdep.h 319434 2017-06-01 15:12:51Z vangyzen $ + */ + +#ifndef RTLD_MACHDEP_H +#define RTLD_MACHDEP_H 1 + +#include +#include +#include + +struct Struct_Obj_Entry; + +/* Return the address of the .dynamic section in the dynamic linker. */ +#define rtld_dynamic(obj) (&_DYNAMIC) + +Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target, + const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *obj, + const Elf_Rel *rel); + +#define make_function_pointer(def, defobj) \ + ((defobj)->relocbase + (def)->st_value) + +#define call_initfini_pointer(obj, target) \ + (((InitFunc)(target))()) + +#define call_init_pointer(obj, target) \ + (((InitArrFunc)(target))(main_argc, main_argv, environ)) + +#define call_ifunc_resolver(ptr) \ + (((Elf_Addr (*)(void))ptr)()) + +typedef struct { + unsigned long ti_module; + unsigned long ti_offset; +} tls_index; + +#define round(size, align) \ + (((size) + (align) - 1) & ~((align) - 1)) +#define calculate_first_tls_offset(size, align) \ + round(TLS_TCB_SIZE, align) +#define calculate_tls_offset(prev_offset, prev_size, size, align) \ + round(prev_offset + prev_size, align) +#define calculate_tls_end(off, size) ((off) + (size)) + +extern void *__tls_get_addr(tls_index *ti); + +#define RTLD_DEFAULT_STACK_PF_EXEC PF_X +#define RTLD_DEFAULT_STACK_EXEC PROT_EXEC + +#define md_abi_variant_hook(x) + +#endif diff --git a/libexec/rtld-elf/mips/rtld_start.S b/libexec/rtld-elf/mips/rtld_start.S new file mode 100644 index 0000000..8177a79 --- /dev/null +++ b/libexec/rtld-elf/mips/rtld_start.S @@ -0,0 +1,166 @@ +/* $NetBSD: rtld_start.S,v 1.10 2009/12/14 00:41:19 matt Exp $ */ + +/* + * Copyright 1997 Michael L. Hitch + * Portions copyright 2002 Charles M. Hannum + * 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. + * 3. 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/mips/rtld_start.S 233378 2012-03-23 17:54:06Z gonzo $ + */ + +#include + +.globl _C_LABEL(_rtld_relocate_nonplt_self) +.globl _C_LABEL(_rtld) + +#define PTR_SIZE (1< 1*PTR_SIZE(sp) for atexit */ + /* -> 2*PTR_SIZE(sp) for obj_main */ + move s0, a0 /* save stack pointer from a0 */ + move s3, a3 /* save ps_strings pointer */ + + PTR_LA a1, 1f + bal 1f + PTR_LA t0, _C_LABEL(_rtld_relocate_nonplt_self) +1: PTR_SUBU a1, ra, a1 /* relocbase */ + PTR_LA a0, _DYNAMIC + PTR_ADDU t9, a1, t0 + jalr t9 /* _rtld_relocate_nonplt_self(dynp, relocabase) */ + PTR_ADDU a0, a1, a0 /* &_DYNAMIC */ + + move a0, s0 /* sp */ + PTR_ADDU a1, sp, 2*PTR_SIZE /* &our atexit function */ + PTR_ADDU a2, sp, 3*PTR_SIZE /* obj_main entry */ + PTR_SUBU sp, 4*SZREG /* ABI requires to reserve memory for 4 regs */ + PTR_LA t9, _C_LABEL(_rtld) + jalr t9 /* v0 = _rtld(sp, cleanup, objp) */ + nop + PTR_ADDU sp, 4*SZREG + + PTR_L a1, 2*PTR_SIZE(sp) /* our atexit function */ + PTR_L a2, 3*PTR_SIZE(sp) /* obj_main entry */ + PTR_ADDU sp, 4*PTR_SIZE /* readjust stack */ + move a0, s0 /* stack pointer */ + move t9, v0 + PTR_SUBU sp, 4*SZREG /* ABI requires to reserve memory for 4 regs */ + move ra,t9 /* RA == PC signals backtrace routine to stop */ + j t9 /* _start(sp, cleanup, obj); */ + move a3, s3 /* restore ps_strings */ +END(rtld_start) + +#define XCALLFRAME_SIZ (12*SZREG) +#define XCALLFRAME_RA (10*SZREG) +#define XCALLFRAME_GP (9*SZREG) +#define XCALLFRAME_S0 (8*SZREG) +#define XCALLFRAME_A3 (7*SZREG) +#define XCALLFRAME_A2 (6*SZREG) +#define XCALLFRAME_A1 (5*SZREG) +#define XCALLFRAME_A0 (4*SZREG) +#if defined(__mips_n32) || defined(__mips_n64) +#define XCALLFRAME_A7 (3*SZREG) +#define XCALLFRAME_A6 (2*SZREG) +#define XCALLFRAME_A5 (1*SZREG) +#define XCALLFRAME_A4 (0*SZREG) +#endif + + .globl _rtld_bind_start + .ent _rtld_bind_start +_rtld_bind_start: + .frame sp, XCALLFRAME_SIZ, $15 + move v1, gp /* save old GP */ +#if defined(__mips_o32) || defined(__mips_o64) + PTR_ADDU t9, 8 /* modify T9 to point at .cpload */ +#endif + SETUP_GP + PTR_SUBU sp, XCALLFRAME_SIZ /* save arguments and sp value in stack */ + SETUP_GP64(XCALLFRAME_GP, _rtld_bind_start) + SAVE_GP(XCALLFRAME_GP) +#if defined(__mips_n32) || defined(__mips_n64) + REG_S a4, XCALLFRAME_A4(sp) + REG_S a5, XCALLFRAME_A5(sp) + REG_S a6, XCALLFRAME_A6(sp) + REG_S a7, XCALLFRAME_A7(sp) +#endif + REG_S a0, XCALLFRAME_A0(sp) + REG_S a1, XCALLFRAME_A1(sp) + REG_S a2, XCALLFRAME_A2(sp) + REG_S a3, XCALLFRAME_A3(sp) + REG_S $15, XCALLFRAME_RA(sp) /* ra is in t7/t3 */ + REG_S s0, XCALLFRAME_S0(sp) + move s0, sp + + move a0, v1 /* old GP */ + PTR_SUBU a0, a0, 0x7ff0 /* The offset of $gp from the */ + /* beginning of the .got section: */ + /* $gp = .got + 0x7ff0, so */ + /* .got = $gp - 0x7ff0 */ + /* Simple math as you can see. */ +#if defined(__mips_n64) + ld a0, 8(a0) /* object = pltgot[1] */ + and a0, a0, 0x7fffffffffffffff +#else + lw a0, 4(a0) /* object = pltgot[1] & 0x7fffffff */ + and a0, a0, 0x7fffffff +#endif + move a1, t8 /* symbol index */ + + PTR_LA t9, _C_LABEL(_mips_rtld_bind) + jalr t9 + nop + + move sp, s0 + REG_L ra, XCALLFRAME_RA(sp) + REG_L s0, XCALLFRAME_S0(sp) + REG_L a0, XCALLFRAME_A0(sp) + REG_L a1, XCALLFRAME_A1(sp) + REG_L a2, XCALLFRAME_A2(sp) + REG_L a3, XCALLFRAME_A3(sp) +#if defined(__mips_n32) || defined(__mips_n64) + REG_L a4, XCALLFRAME_A4(sp) + REG_L a5, XCALLFRAME_A5(sp) + REG_L a6, XCALLFRAME_A6(sp) + REG_L a7, XCALLFRAME_A7(sp) +#endif + RESTORE_GP64 + PTR_ADDU sp, XCALLFRAME_SIZ + move t9, v0 + jr t9 + nop +END(_rtld_bind_start) diff --git a/libexec/rtld-elf/paths.h b/libexec/rtld-elf/paths.h new file mode 100644 index 0000000..c49c8f4 --- /dev/null +++ b/libexec/rtld-elf/paths.h @@ -0,0 +1,74 @@ +/*- + * Copyright 1996, 1997, 1998, 1999, 2000 John D. Polstra. + * Copyright 2003 Alexander Kabaev . + * 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/paths.h 296047 2016-02-25 18:23:40Z oshogbo $ + */ + +#ifndef PATHS_H +#define PATHS_H + +#undef _PATH_ELF_HINTS + +#ifdef COMPAT_32BIT +#define _PATH_ELF_HINTS "/var/run/ld-elf32.so.hints" +#define _PATH_LIBMAP_CONF "/etc/libmap32.conf" +#define _PATH_RTLD "/libexec/ld-elf32.so.1" +#define STANDARD_LIBRARY_PATH "/lib32:/usr/lib32" +#define LD_ "LD_32_" +#endif + +#ifndef _PATH_ELF_HINTS +#define _PATH_ELF_HINTS "/var/run/ld-elf.so.hints" +#endif + +#ifndef _PATH_LIBMAP_CONF +#define _PATH_LIBMAP_CONF "/etc/libmap.conf" +#endif + +#ifndef _PATH_RTLD +#define _PATH_RTLD "/libexec/ld-elf.so.1" +#endif + +#ifndef STANDARD_LIBRARY_PATH +#define STANDARD_LIBRARY_PATH "/lib/casper:/lib:/usr/lib" +#endif + +#ifndef LD_ +#define LD_ "LD_" +#endif + +#define _PATH_SOFT_ELF_HINTS "/var/run/ld-elf-soft.so.hints" +#define _PATH_SOFT_LIBMAP_CONF "/etc/libmap-soft.conf" +#define _PATH_SOFT_RTLD "/libexec/ld-elf.so.1" +#define SOFT_STANDARD_LIBRARY_PATH "/usr/libsoft" +#define LD_SOFT_ "LD_SOFT_" + +extern char *ld_elf_hints_default; +extern char *ld_path_libmap_conf; +extern char *ld_path_rtld; +extern char *ld_standard_library_path; +extern char *ld_env_prefix; + +#endif /* PATHS_H */ diff --git a/libexec/rtld-elf/powerpc/Makefile.inc b/libexec/rtld-elf/powerpc/Makefile.inc new file mode 100644 index 0000000..4ba9b75 --- /dev/null +++ b/libexec/rtld-elf/powerpc/Makefile.inc @@ -0,0 +1 @@ +# $FreeBSD: releng/11.1/libexec/rtld-elf/powerpc/Makefile.inc 107572 2002-12-04 07:32:20Z grehan $ diff --git a/libexec/rtld-elf/powerpc/reloc.c b/libexec/rtld-elf/powerpc/reloc.c new file mode 100644 index 0000000..bb24b0b --- /dev/null +++ b/libexec/rtld-elf/powerpc/reloc.c @@ -0,0 +1,665 @@ +/* $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $ */ + +/*- + * Copyright (C) 1998 Tsubai Masanari + * 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. + * 3. 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/powerpc/reloc.c 316135 2017-03-29 11:03:08Z kib $ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "rtld.h" + +#define _ppc_ha(x) ((((u_int32_t)(x) & 0x8000) ? \ + ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16) +#define _ppc_la(x) ((u_int32_t)(x) & 0xffff) + +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define max(a,b) (((a) > (b)) ? (a) : (b)) + +#define PLT_EXTENDED_BEGIN (1 << 13) +#define JMPTAB_BASE(N) (18 + N*2 + ((N > PLT_EXTENDED_BEGIN) ? \ + (N - PLT_EXTENDED_BEGIN)*2 : 0)) + +/* + * Process the R_PPC_COPY relocations + */ +int +do_copy_relocations(Obj_Entry *dstobj) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + + /* + * COPY relocs are invalid outside of the main program + */ + assert(dstobj->mainprog); + + relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela + + dstobj->relasize); + for (rela = dstobj->rela; rela < relalim; rela++) { + void *dstaddr; + const Elf_Sym *dstsym; + const char *name; + size_t size; + const void *srcaddr; + const Elf_Sym *srcsym = NULL; + const Obj_Entry *srcobj, *defobj; + SymLook req; + int res; + + if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) { + continue; + } + + dstaddr = (void *) (dstobj->relocbase + rela->r_offset); + dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); + name = dstobj->strtab + dstsym->st_name; + size = dstsym->st_size; + symlook_init(&req, name); + req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); + req.flags = SYMLOOK_EARLY; + + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { + res = symlook_obj(&req, srcobj); + if (res == 0) { + srcsym = req.sym_out; + defobj = req.defobj_out; + break; + } + } + + if (srcobj == NULL) { + _rtld_error("Undefined symbol \"%s\" " + " referenced from COPY" + " relocation in %s", name, dstobj->path); + return (-1); + } + + srcaddr = (const void *) (defobj->relocbase+srcsym->st_value); + memcpy(dstaddr, srcaddr, size); + dbg("copy_reloc: src=%p,dst=%p,size=%d\n",srcaddr,dstaddr,size); + } + + return (0); +} + + +/* + * Perform early relocation of the run-time linker image + */ +void +reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase) +{ + const Elf_Rela *rela = NULL, *relalim; + Elf_Addr relasz = 0; + Elf_Addr *where; + + /* + * Extract the rela/relasz values from the dynamic section + */ + for (; dynp->d_tag != DT_NULL; dynp++) { + switch (dynp->d_tag) { + case DT_RELA: + rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr); + break; + case DT_RELASZ: + relasz = dynp->d_un.d_val; + break; + } + } + + /* + * Relocate these values + */ + relalim = (const Elf_Rela *)((caddr_t)rela + relasz); + for (; rela < relalim; rela++) { + where = (Elf_Addr *)(relocbase + rela->r_offset); + *where = (Elf_Addr)(relocbase + rela->r_addend); + } +} + + +/* + * Relocate a non-PLT object with addend. + */ +static int +reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, + SymCache *cache, int flags, RtldLockState *lockstate) +{ + Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + const Elf_Sym *def; + const Obj_Entry *defobj; + Elf_Addr tmp; + + switch (ELF_R_TYPE(rela->r_info)) { + + case R_PPC_NONE: + break; + + case R_PPC_ADDR32: /* word32 S + A */ + case R_PPC_GLOB_DAT: /* word32 S + A */ + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, + flags, cache, lockstate); + if (def == NULL) { + return (-1); + } + + tmp = (Elf_Addr)(defobj->relocbase + def->st_value + + rela->r_addend); + + /* Don't issue write if unnecessary; avoid COW page fault */ + if (*where != tmp) { + *where = tmp; + } + break; + + case R_PPC_RELATIVE: /* word32 B + A */ + tmp = (Elf_Addr)(obj->relocbase + rela->r_addend); + + /* As above, don't issue write unnecessarily */ + if (*where != tmp) { + *where = tmp; + } + break; + + case R_PPC_COPY: + /* + * These are deferred until all other relocations + * have been done. All we do here is make sure + * that the COPY relocation is not in a shared + * library. They are allowed only in executable + * files. + */ + if (!obj->mainprog) { + _rtld_error("%s: Unexpected R_COPY " + " relocation in shared library", + obj->path); + return (-1); + } + break; + + case R_PPC_JMP_SLOT: + /* + * These will be handled by the plt/jmpslot routines + */ + break; + + case R_PPC_DTPMOD32: + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, + flags, cache, lockstate); + + if (def == NULL) + return (-1); + + *where = (Elf_Addr) defobj->tlsindex; + + break; + + case R_PPC_TPREL32: + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, + flags, cache, lockstate); + + if (def == NULL) + return (-1); + + /* + * We lazily allocate offsets for static TLS as we + * see the first relocation that references the + * TLS block. This allows us to support (small + * amounts of) static TLS in dynamically loaded + * modules. If we run out of space, we generate an + * error. + */ + if (!defobj->tls_done) { + if (!allocate_tls_offset((Obj_Entry*) defobj)) { + _rtld_error("%s: No space available for static " + "Thread Local Storage", obj->path); + return (-1); + } + } + + *(Elf_Addr **)where = *where * sizeof(Elf_Addr) + + (Elf_Addr *)(def->st_value + rela->r_addend + + defobj->tlsoffset - TLS_TP_OFFSET); + + break; + + case R_PPC_DTPREL32: + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, + flags, cache, lockstate); + + if (def == NULL) + return (-1); + + *where += (Elf_Addr)(def->st_value + rela->r_addend + - TLS_DTV_OFFSET); + + break; + + default: + _rtld_error("%s: Unsupported relocation type %d" + " in non-PLT relocations\n", obj->path, + ELF_R_TYPE(rela->r_info)); + return (-1); + } + return (0); +} + + +/* + * Process non-PLT relocations + */ +int +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, + RtldLockState *lockstate) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + SymCache *cache; + int r = -1; + + if ((flags & SYMLOOK_IFUNC) != 0) + /* XXX not implemented */ + return (0); + + /* + * The dynamic loader may be called from a thread, we have + * limited amounts of stack available so we cannot use alloca(). + */ + if (obj != obj_rtld) { + cache = calloc(obj->dynsymcount, sizeof(SymCache)); + /* No need to check for NULL here */ + } else + cache = NULL; + + /* + * From the SVR4 PPC ABI: + * "The PowerPC family uses only the Elf32_Rela relocation + * entries with explicit addends." + */ + relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize); + for (rela = obj->rela; rela < relalim; rela++) { + if (reloc_nonplt_object(obj_rtld, obj, rela, cache, flags, + lockstate) < 0) + goto done; + } + r = 0; +done: + if (cache != NULL) + free(cache); + + /* Synchronize icache for text seg in case we made any changes */ + __syncicache(obj->mapbase, obj->textsize); + + return (r); +} + +/* + * Initialise a PLT slot to the resolving trampoline + */ +static int +reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) +{ + Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset); + Elf_Addr *pltresolve, *pltlongresolve, *jmptab; + Elf_Addr distance; + int N = obj->pltrelasize / sizeof(Elf_Rela); + int reloff; + + reloff = rela - obj->pltrela; + + if (reloff < 0) + return (-1); + + pltlongresolve = obj->pltgot + 5; + pltresolve = pltlongresolve + 5; + + distance = (Elf_Addr)pltresolve - (Elf_Addr)(where + 1); + + dbg(" reloc_plt_object: where=%p,pltres=%p,reloff=%x,distance=%x", + (void *)where, (void *)pltresolve, reloff, distance); + + if (reloff < PLT_EXTENDED_BEGIN) { + /* li r11,reloff */ + /* b pltresolve */ + where[0] = 0x39600000 | reloff; + where[1] = 0x48000000 | (distance & 0x03fffffc); + } else { + jmptab = obj->pltgot + JMPTAB_BASE(N); + jmptab[reloff] = (u_int)pltlongresolve; + + /* lis r11,jmptab[reloff]@ha */ + /* lwzu r12,jmptab[reloff]@l(r11) */ + /* mtctr r12 */ + /* bctr */ + where[0] = 0x3d600000 | _ppc_ha(&jmptab[reloff]); + where[1] = 0x858b0000 | _ppc_la(&jmptab[reloff]); + where[2] = 0x7d8903a6; + where[3] = 0x4e800420; + } + + + /* + * The icache will be sync'd in reloc_plt, which is called + * after all the slots have been updated + */ + + return (0); +} + + +/* + * Process the PLT relocations. + */ +int +reloc_plt(Obj_Entry *obj) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + int N = obj->pltrelasize / sizeof(Elf_Rela); + + if (obj->pltrelasize != 0) { + + relalim = (const Elf_Rela *)((char *)obj->pltrela + + obj->pltrelasize); + for (rela = obj->pltrela; rela < relalim; rela++) { + assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); + + if (reloc_plt_object(obj, rela) < 0) { + return (-1); + } + } + } + + /* + * Sync the icache for the byte range represented by the + * trampoline routines and call slots. + */ + if (obj->pltgot != NULL) + __syncicache(obj->pltgot, JMPTAB_BASE(N)*4); + + return (0); +} + + +/* + * LD_BIND_NOW was set - force relocation for all jump slots + */ +int +reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) +{ + const Obj_Entry *defobj; + const Elf_Rela *relalim; + const Elf_Rela *rela; + const Elf_Sym *def; + Elf_Addr *where; + Elf_Addr target; + + relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); + for (rela = obj->pltrela; rela < relalim; rela++) { + assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, + SYMLOOK_IN_PLT | flags, NULL, lockstate); + if (def == NULL) { + dbg("reloc_jmpslots: sym not found"); + return (-1); + } + + target = (Elf_Addr)(defobj->relocbase + def->st_value); + +#if 0 + /* PG XXX */ + dbg("\"%s\" in \"%s\" --> %p in \"%s\"", + defobj->strtab + def->st_name, basename(obj->path), + (void *)target, basename(defobj->path)); +#endif + + reloc_jmpslot(where, target, defobj, obj, + (const Elf_Rel *) rela); + } + + obj->jmpslots_done = true; + + return (0); +} + + +/* + * Update the value of a PLT jump slot. Branch directly to the target if + * it is within +/- 32Mb, otherwise go indirectly via the pltcall + * trampoline call and jump table. + */ +Elf_Addr +reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj, + const Obj_Entry *obj, const Elf_Rel *rel) +{ + Elf_Addr offset; + const Elf_Rela *rela = (const Elf_Rela *) rel; + + dbg(" reloc_jmpslot: where=%p, target=%p", + (void *)wherep, (void *)target); + + if (ld_bind_not) + goto out; + + /* + * At the PLT entry pointed at by `wherep', construct + * a direct transfer to the now fully resolved function + * address. + */ + offset = target - (Elf_Addr)wherep; + + if (abs((int)offset) < 32*1024*1024) { /* inside 32MB? */ + /* b value # branch directly */ + *wherep = 0x48000000 | (offset & 0x03fffffc); + __syncicache(wherep, 4); + } else { + Elf_Addr *pltcall, *jmptab; + int distance; + int N = obj->pltrelasize / sizeof(Elf_Rela); + int reloff = rela - obj->pltrela; + + if (reloff < 0) + return (-1); + + pltcall = obj->pltgot; + + dbg(" reloc_jmpslot: indir, reloff=%x, N=%x\n", + reloff, N); + + jmptab = obj->pltgot + JMPTAB_BASE(N); + jmptab[reloff] = target; + mb(); /* Order jmptab update before next changes */ + + if (reloff < PLT_EXTENDED_BEGIN) { + /* for extended PLT entries, we keep the old code */ + + distance = (Elf_Addr)pltcall - (Elf_Addr)(wherep + 1); + + /* li r11,reloff */ + /* b pltcall # use indirect pltcall routine */ + + /* first instruction same as before */ + wherep[1] = 0x48000000 | (distance & 0x03fffffc); + __syncicache(wherep, 8); + } + } + +out: + return (target); +} + +int +reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +int +reloc_gnu_ifunc(Obj_Entry *obj, int flags, + struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +/* + * Setup the plt glue routines. + */ +#define PLTCALL_SIZE 20 +#define PLTLONGRESOLVE_SIZE 20 +#define PLTRESOLVE_SIZE 24 + +void +init_pltgot(Obj_Entry *obj) +{ + Elf_Word *pltcall, *pltresolve, *pltlongresolve; + Elf_Word *jmptab; + int N = obj->pltrelasize / sizeof(Elf_Rela); + + pltcall = obj->pltgot; + + if (pltcall == NULL) { + return; + } + + /* + * From the SVR4 PPC ABI: + * + * 'The first 18 words (72 bytes) of the PLT are reserved for + * use by the dynamic linker. + * ... + * 'If the executable or shared object requires N procedure + * linkage table entries, the link editor shall reserve 3*N + * words (12*N bytes) following the 18 reserved words. The + * first 2*N of these words are the procedure linkage table + * entries themselves. The static linker directs calls to bytes + * (72 + (i-1)*8), for i between 1 and N inclusive. The remaining + * N words (4*N bytes) are reserved for use by the dynamic linker.' + */ + + /* + * Copy the absolute-call assembler stub into the first part of + * the reserved PLT area. + */ + memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE); + + /* + * Determine the address of the jumptable, which is the dyn-linker + * reserved area after the call cells. Write the absolute address + * of the jumptable into the absolute-call assembler code so it + * can determine this address. + */ + jmptab = obj->pltgot + JMPTAB_BASE(N); + pltcall[1] |= _ppc_ha(jmptab); /* addis 11,11,jmptab@ha */ + pltcall[2] |= _ppc_la(jmptab); /* lwz 11,jmptab@l(11) */ + + /* + * Skip down 20 bytes into the initial reserved area and copy + * in the standard resolving assembler call. Into this assembler, + * insert the absolute address of the _rtld_bind_start routine + * and the address of the relocation object. + * + * We place pltlongresolve first, so it can fix up its arguments + * and then fall through to the regular PLT resolver. + */ + pltlongresolve = obj->pltgot + 5; + + memcpy(pltlongresolve, _rtld_powerpc_pltlongresolve, + PLTLONGRESOLVE_SIZE); + pltlongresolve[0] |= _ppc_ha(jmptab); /* lis 12,jmptab@ha */ + pltlongresolve[1] |= _ppc_la(jmptab); /* addi 12,12,jmptab@l */ + + pltresolve = pltlongresolve + PLTLONGRESOLVE_SIZE/sizeof(uint32_t); + memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE); + pltresolve[0] |= _ppc_ha(_rtld_bind_start); + pltresolve[1] |= _ppc_la(_rtld_bind_start); + pltresolve[3] |= _ppc_ha(obj); + pltresolve[4] |= _ppc_la(obj); + + /* + * The icache will be sync'd in reloc_plt, which is called + * after all the slots have been updated + */ +} + +void +ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) +{ +} + +void +allocate_initial_tls(Obj_Entry *list) +{ + Elf_Addr **tp; + + /* + * Fix the size of the static TLS block by using the maximum + * offset allocated so far and adding a bit for dynamic modules to + * use. + */ + + tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA; + + tp = (Elf_Addr **) ((char *) allocate_tls(list, NULL, TLS_TCB_SIZE, 8) + + TLS_TP_OFFSET + TLS_TCB_SIZE); + + /* + * XXX gcc seems to ignore 'tp = _tp;' + */ + + __asm __volatile("mr 2,%0" :: "r"(tp)); +} + +void* +__tls_get_addr(tls_index* ti) +{ + register Elf_Addr **tp; + char *p; + + __asm __volatile("mr %0,2" : "=r"(tp)); + p = tls_get_addr_common((Elf_Addr**)((Elf_Addr)tp - TLS_TP_OFFSET + - TLS_TCB_SIZE), ti->ti_module, ti->ti_offset); + + return (p + TLS_DTV_OFFSET); +} diff --git a/libexec/rtld-elf/powerpc/rtld_machdep.h b/libexec/rtld-elf/powerpc/rtld_machdep.h new file mode 100644 index 0000000..9dc5fba --- /dev/null +++ b/libexec/rtld-elf/powerpc/rtld_machdep.h @@ -0,0 +1,92 @@ +/*- + * Copyright (c) 1999, 2000 John D. Polstra. + * 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 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 AUTHOR 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/powerpc/rtld_machdep.h 319434 2017-06-01 15:12:51Z vangyzen $ + */ + +#ifndef RTLD_MACHDEP_H +#define RTLD_MACHDEP_H 1 + +#include +#include + +struct Struct_Obj_Entry; + +/* Return the address of the .dynamic section in the dynamic linker. */ +#define rtld_dynamic(obj) (&_DYNAMIC) + +Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target, + const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *obj, + const Elf_Rel *rel); + +#define make_function_pointer(def, defobj) \ + ((defobj)->relocbase + (def)->st_value) + +#define call_initfini_pointer(obj, target) \ + (((InitFunc)(target))()) + +#define call_init_pointer(obj, target) \ + (((InitArrFunc)(target))(main_argc, main_argv, environ)) + +#define call_ifunc_resolver(ptr) \ + (((Elf_Addr (*)(void))ptr)()) + +/* + * PLT functions. Not really correct prototypes, but the + * symbol values are needed. + */ +void _rtld_powerpc_pltlongresolve(void); +void _rtld_powerpc_pltresolve(void); +void _rtld_powerpc_pltcall(void); + +/* + * TLS + */ + +#define TLS_TP_OFFSET 0x7000 +#define TLS_DTV_OFFSET 0x8000 +#define TLS_TCB_SIZE 8 + +#define round(size, align) \ + (((size) + (align) - 1) & ~((align) - 1)) +#define calculate_first_tls_offset(size, align) \ + round(8, align) +#define calculate_tls_offset(prev_offset, prev_size, size, align) \ + round(prev_offset + prev_size, align) +#define calculate_tls_end(off, size) ((off) + (size)) + +typedef struct { + unsigned long ti_module; + unsigned long ti_offset; +} tls_index; + +extern void *__tls_get_addr(tls_index* ti); + +#define RTLD_DEFAULT_STACK_PF_EXEC PF_X +#define RTLD_DEFAULT_STACK_EXEC PROT_EXEC + +#define md_abi_variant_hook(x) + +#endif diff --git a/libexec/rtld-elf/powerpc/rtld_start.S b/libexec/rtld-elf/powerpc/rtld_start.S new file mode 100644 index 0000000..a649937 --- /dev/null +++ b/libexec/rtld-elf/powerpc/rtld_start.S @@ -0,0 +1,200 @@ +/* $NetBSD: rtld_start.S,v 1.4 2001/09/26 04:06:43 mycroft Exp $ */ + +/*- + * Copyright (C) 1998 Tsubai Masanari + * 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. + * 3. 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/powerpc/rtld_start.S 217397 2011-01-14 11:32:31Z kib $ + */ + +#include + +.extern _GLOBAL_OFFSET_TABLE_ +.extern _DYNAMIC + +_ENTRY(.rtld_start) + stwu %r1,-48(%r1) /* 16-byte aligned stack for reg saves + + exit_proc & obj _rtld args + + backchain & lrsave stack frame */ + stw %r3,16(%r1) /* argc */ + stw %r4,20(%r1) /* argv */ + stw %r5,24(%r1) /* envp */ +/* stw %r6,28(%r1) *//* obj (always 0) */ +/* stw %r7,32(%r1) *//* cleanup (always 0) */ + stw %r8,36(%r1) /* ps_strings */ + + /* + * Perform initial relocation of ld-elf.so. Not as easy as it + * sounds. + * - perform small forward branch to put PC into link reg + * - use link-time constants to determine offset to the + * _DYNAMIC section and the GOT. Add these to the PC to + * convert to absolute addresses. + * - sync icache to allow execution of the SVR4 ABI-specified + * blrl instruction preceding the GOT + * - Use this instruction to determine the GOT absolute address + * - read GOT[0], which is the SVR4 ABI-specified link-time + * value of _DYNAMIC. Subtract this value from the absolute + * value to determine the load address + * - call reloc_non_plt_self() to fix up ld-elf.so's relocations + */ + bl 1f + .long _DYNAMIC-. + .long _GLOBAL_OFFSET_TABLE_-. /* branch lr + 4 */ +1: + mflr %r3 /* PC value at .long */ + lwz %r4,4(%r3) + add %r4,%r4,%r3 /* &_GLOBAL_OFFSET_TABLE-4, blrl insn. */ + dcbst %r0,%r4 /* sync i-cache with d-cache */ + sync + icbi %r0,%r4 + isync + + lwz %r4,0(%r3) /* offset to _DYNAMIC */ + add %r3,%r4,%r3 /* r3 = &_DYNAMIC, absolute value */ + + bl _GLOBAL_OFFSET_TABLE_@local-4 + mflr %r4 /* &_GLOBAL_OFFSET_TABLE_, absolute value */ + lwz %r4,0(%r4) /* linker &_DYNAMIC, from got[0] */ + subf %r4,%r4,%r3 /* subtract to calculate relocbase */ + + bl reloc_non_plt_self@plt /* reloc_non_plt_self(&_DYNAMIC,base) */ + + /* + * The _rtld() function likes to see a stack layout containing + * { argc, argv[0], argv[1] ... argv[N], 0, env[0], ... , env[N] } + * Since the PowerPC stack was 16-byte aligned at exec time, the + * original stack layout has to be found by moving back a word + * from the argv pointer. + */ + lwz %r4,20(%r1) /* restore argv */ + addi %r3,%r4,-4 /* locate argc ptr, &argv[-1] */ + + addi %r4,%r1,8 /* &exit_proc on stack */ + addi %r5,%r1,12 /* &obj_main on stack */ + + bl _rtld@plt /* &_start = _rtld(sp, &exit_proc, &obj_main)*/ + mtlr %r3 + + /* + * Restore args, with new obj/exit proc + */ + lwz %r3,16(%r1) /* argc */ + lwz %r4,20(%r1) /* argv */ + lwz %r5,24(%r1) /* envp */ + lwz %r6,12(%r1) /* obj */ + lwz %r7,8(%r1) /* exit proc */ + lwz %r8,36(%r1) /* ps_strings */ + addi %r1,%r1,48 /* restore original stackptr */ + + blrl /* _start(argc, argv, envp, obj, cleanup, ps_strings) */ + + li %r0,1 /* _exit() */ + sc + +/* + * _rtld_bind_start() + * + * Call into the MI binder. This routine is reached via the PLT call cell, + * and then _rtld_powerpc_pltresolve(). + * On entry, %r11 contains the index of the PLT cell, and %r12 contains + * a pointer to the ELF object for the file. + * Save all registers, call into the binder to resolve and fixup the external + * routine, and then transfer to the external routine on return. + */ + .globl _rtld_bind + +_ENTRY(_rtld_bind_start) + stwu %r1,-160(%r1) # stack space for 29 regs + r0/lr/cr + stw %r0,20(%r1) # save r0 + mflr %r0 + stw %r0,16(%r1) # save lr + mfcr %r0 + stw %r0,12(%r1) # save cr + stmw %r3,24(%r1) # save r3-r31 + + mr %r3,%r12 # obj + mulli %r4,%r11,12 # rela index * sizeof(Elf_Rela) + bl _rtld_bind@PLT # target addr = _rtld_bind(obj, reloff) + mtctr %r3 # move absolute target addr into ctr + + lmw %r3,24(%r1) # restore r3-r31 + lwz %r0,12(%r1) # restore cr + mtcr %r0 + lwz %r0,16(%r1) # restore lr + mtlr %r0 + lwz %r0,20(%r1) # restore r0 + + addi %r1,%r1,160 # restore stack + bctr # jump to target + + +/* + * _rtld_powerpc_pltresolve() + * + * This routine is copied into the latter part of the 72-byte reserved + * area at the start of the PLT. The absolute address of the _rtld_bind_start + * routine, and the ELF object for the loaded file, are inserted into + * the code by the reloc.c:init_pltgot() routine. + * The first time an external routine is called, the PLT slot will + * set up %r11 to the offset of the slot, and will jump to this routine. + * The ELF object is shifted into %r11, and _rtld_bind_start is called + * to complete the binding. + */ +_ENTRY(_rtld_powerpc_pltlongresolve) + lis %r12,0 # lis 12,jmptab@ha + addi %r12,%r12,0 # addi 12,12,jmptab@l + subf %r11,%r12,%r11 # reloff + li %r12,2 + srw %r11,%r11,%r12 # index = reloff/sizeof(Elf_Addr) +_ENTRY(_rtld_powerpc_pltresolve) + lis %r12,0 # lis 12,_rtld_bind_start@ha + addi %r12,%r12,0 # addi 12,12,_rtld_bind_start@l + mtctr %r12 + lis %r12,0 # lis 12,obj@ha + addi %r12,%r12,0 # addi 12,12,obj@l + bctr + +/* + * _rtld_powerpc_pltcall() + * + * This routine is copied into the 72-byte reserved area at the + * start of the PLT. The reloc.c:init_pltgot() routine inserts + * the absolute address of the jumptable. + * Control is transferred to this routine when the binder has + * located the external routine, but determined that it is > 32Mb + * from the PLT slot. Code is inserted into the PLT slot to set up + * %r11 with the jumptable index, and jump to here, where the + * absolute address of the external routine is loaded from the + * jumptable and transferred to + */ +_ENTRY(_rtld_powerpc_pltcall) + slwi %r11,%r11,2 # jmptab offset = index * 4 + addis %r11,%r11,0 # addis 11,11,jmptab@ha + lwz %r11,0(%r11) # lwz 11,jmptab@l(11) + mtctr %r11 + bctr # (*jmptab[index])() + + .section .note.GNU-stack,"",%progbits diff --git a/libexec/rtld-elf/powerpc64/Makefile.inc b/libexec/rtld-elf/powerpc64/Makefile.inc new file mode 100644 index 0000000..249a945 --- /dev/null +++ b/libexec/rtld-elf/powerpc64/Makefile.inc @@ -0,0 +1 @@ +# $FreeBSD: releng/11.1/libexec/rtld-elf/powerpc64/Makefile.inc 107572 2002-12-04 07:32:20Z grehan $ diff --git a/libexec/rtld-elf/powerpc64/reloc.c b/libexec/rtld-elf/powerpc64/reloc.c new file mode 100644 index 0000000..a3fda5e --- /dev/null +++ b/libexec/rtld-elf/powerpc64/reloc.c @@ -0,0 +1,566 @@ +/* $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $ */ + +/*- + * Copyright (C) 1998 Tsubai Masanari + * 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. + * 3. 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/powerpc64/reloc.c 316135 2017-03-29 11:03:08Z kib $ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "rtld.h" + +#if !defined(_CALL_ELF) || _CALL_ELF == 1 +struct funcdesc { + Elf_Addr addr; + Elf_Addr toc; + Elf_Addr env; +}; +#endif + +/* + * Process the R_PPC_COPY relocations + */ +int +do_copy_relocations(Obj_Entry *dstobj) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + + /* + * COPY relocs are invalid outside of the main program + */ + assert(dstobj->mainprog); + + relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela + + dstobj->relasize); + for (rela = dstobj->rela; rela < relalim; rela++) { + void *dstaddr; + const Elf_Sym *dstsym; + const char *name; + size_t size; + const void *srcaddr; + const Elf_Sym *srcsym = NULL; + const Obj_Entry *srcobj, *defobj; + SymLook req; + int res; + + if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) { + continue; + } + + dstaddr = (void *) (dstobj->relocbase + rela->r_offset); + dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); + name = dstobj->strtab + dstsym->st_name; + size = dstsym->st_size; + symlook_init(&req, name); + req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); + req.flags = SYMLOOK_EARLY; + + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { + res = symlook_obj(&req, srcobj); + if (res == 0) { + srcsym = req.sym_out; + defobj = req.defobj_out; + break; + } + } + + if (srcobj == NULL) { + _rtld_error("Undefined symbol \"%s\" " + " referenced from COPY" + " relocation in %s", name, dstobj->path); + return (-1); + } + + srcaddr = (const void *) (defobj->relocbase+srcsym->st_value); + memcpy(dstaddr, srcaddr, size); + dbg("copy_reloc: src=%p,dst=%p,size=%zd\n",srcaddr,dstaddr,size); + } + + return (0); +} + + +/* + * Perform early relocation of the run-time linker image + */ +void +reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase) +{ + const Elf_Rela *rela = NULL, *relalim; + Elf_Addr relasz = 0; + Elf_Addr *where; + + /* + * Extract the rela/relasz values from the dynamic section + */ + for (; dynp->d_tag != DT_NULL; dynp++) { + switch (dynp->d_tag) { + case DT_RELA: + rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr); + break; + case DT_RELASZ: + relasz = dynp->d_un.d_val; + break; + } + } + + /* + * Relocate these values + */ + relalim = (const Elf_Rela *)((caddr_t)rela + relasz); + for (; rela < relalim; rela++) { + where = (Elf_Addr *)(relocbase + rela->r_offset); + *where = (Elf_Addr)(relocbase + rela->r_addend); + } +} + + +/* + * Relocate a non-PLT object with addend. + */ +static int +reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, + SymCache *cache, int flags, RtldLockState *lockstate) +{ + Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + const Elf_Sym *def; + const Obj_Entry *defobj; + Elf_Addr tmp; + + switch (ELF_R_TYPE(rela->r_info)) { + + case R_PPC_NONE: + break; + + case R_PPC64_UADDR64: /* doubleword64 S + A */ + case R_PPC64_ADDR64: + case R_PPC_GLOB_DAT: + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, + flags, cache, lockstate); + if (def == NULL) { + return (-1); + } + + tmp = (Elf_Addr)(defobj->relocbase + def->st_value + + rela->r_addend); + + /* Don't issue write if unnecessary; avoid COW page fault */ + if (*where != tmp) { + *where = tmp; + } + break; + + case R_PPC_RELATIVE: /* doubleword64 B + A */ + tmp = (Elf_Addr)(obj->relocbase + rela->r_addend); + + /* As above, don't issue write unnecessarily */ + if (*where != tmp) { + *where = tmp; + } + break; + + case R_PPC_COPY: + /* + * These are deferred until all other relocations + * have been done. All we do here is make sure + * that the COPY relocation is not in a shared + * library. They are allowed only in executable + * files. + */ + if (!obj->mainprog) { + _rtld_error("%s: Unexpected R_COPY " + " relocation in shared library", + obj->path); + return (-1); + } + break; + + case R_PPC_JMP_SLOT: + /* + * These will be handled by the plt/jmpslot routines + */ + break; + + case R_PPC64_DTPMOD64: + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, + flags, cache, lockstate); + + if (def == NULL) + return (-1); + + *where = (Elf_Addr) defobj->tlsindex; + + break; + + case R_PPC64_TPREL64: + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, + flags, cache, lockstate); + + if (def == NULL) + return (-1); + + /* + * We lazily allocate offsets for static TLS as we + * see the first relocation that references the + * TLS block. This allows us to support (small + * amounts of) static TLS in dynamically loaded + * modules. If we run out of space, we generate an + * error. + */ + if (!defobj->tls_done) { + if (!allocate_tls_offset((Obj_Entry*) defobj)) { + _rtld_error("%s: No space available for static " + "Thread Local Storage", obj->path); + return (-1); + } + } + + *(Elf_Addr **)where = *where * sizeof(Elf_Addr) + + (Elf_Addr *)(def->st_value + rela->r_addend + + defobj->tlsoffset - TLS_TP_OFFSET); + + break; + + case R_PPC64_DTPREL64: + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, + flags, cache, lockstate); + + if (def == NULL) + return (-1); + + *where += (Elf_Addr)(def->st_value + rela->r_addend + - TLS_DTV_OFFSET); + + break; + + default: + _rtld_error("%s: Unsupported relocation type %ld" + " in non-PLT relocations\n", obj->path, + ELF_R_TYPE(rela->r_info)); + return (-1); + } + return (0); +} + + +/* + * Process non-PLT relocations + */ +int +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, + RtldLockState *lockstate) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + SymCache *cache; + int bytes = obj->dynsymcount * sizeof(SymCache); + int r = -1; + + if ((flags & SYMLOOK_IFUNC) != 0) + /* XXX not implemented */ + return (0); + + /* + * The dynamic loader may be called from a thread, we have + * limited amounts of stack available so we cannot use alloca(). + */ + if (obj != obj_rtld) { + cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, + -1, 0); + if (cache == MAP_FAILED) + cache = NULL; + } else + cache = NULL; + + /* + * From the SVR4 PPC ABI: + * "The PowerPC family uses only the Elf32_Rela relocation + * entries with explicit addends." + */ + relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize); + for (rela = obj->rela; rela < relalim; rela++) { + if (reloc_nonplt_object(obj_rtld, obj, rela, cache, flags, + lockstate) < 0) + goto done; + } + r = 0; +done: + if (cache) + munmap(cache, bytes); + + /* Synchronize icache for text seg in case we made any changes */ + __syncicache(obj->mapbase, obj->textsize); + + return (r); +} + + +/* + * Initialise a PLT slot to the resolving trampoline + */ +static int +reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) +{ + Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + long reloff; + + reloff = rela - obj->pltrela; + + dbg(" reloc_plt_object: where=%p,reloff=%lx,glink=%#lx", (void *)where, + reloff, obj->glink); + +#if !defined(_CALL_ELF) || _CALL_ELF == 1 + /* Glink code is 3 instructions after the first 32k, 2 before */ + *where = (Elf_Addr)obj->glink + 32 + + 8*((reloff < 0x8000) ? reloff : 0x8000) + + 12*((reloff < 0x8000) ? 0 : (reloff - 0x8000)); +#else + *where = (Elf_Addr)obj->glink + 4*reloff + 32; +#endif + + return (0); +} + + +/* + * Process the PLT relocations. + */ +int +reloc_plt(Obj_Entry *obj) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + + if (obj->pltrelasize != 0) { + relalim = (const Elf_Rela *)((char *)obj->pltrela + + obj->pltrelasize); + for (rela = obj->pltrela; rela < relalim; rela++) { + assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); + + if (reloc_plt_object(obj, rela) < 0) { + return (-1); + } + } + } + + return (0); +} + + +/* + * LD_BIND_NOW was set - force relocation for all jump slots + */ +int +reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) +{ + const Obj_Entry *defobj; + const Elf_Rela *relalim; + const Elf_Rela *rela; + const Elf_Sym *def; + Elf_Addr *where; + Elf_Addr target; + + relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); + for (rela = obj->pltrela; rela < relalim; rela++) { + assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, + SYMLOOK_IN_PLT | flags, NULL, lockstate); + if (def == NULL) { + dbg("reloc_jmpslots: sym not found"); + return (-1); + } + + target = (Elf_Addr)(defobj->relocbase + def->st_value); + + if (def == &sym_zero) { + /* Zero undefined weak symbols */ +#if !defined(_CALL_ELF) || _CALL_ELF == 1 + bzero(where, sizeof(struct funcdesc)); +#else + *where = 0; +#endif + } else { + reloc_jmpslot(where, target, defobj, obj, + (const Elf_Rel *) rela); + } + } + + obj->jmpslots_done = true; + + return (0); +} + + +/* + * Update the value of a PLT jump slot. + */ +Elf_Addr +reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj, + const Obj_Entry *obj, const Elf_Rel *rel) +{ + + /* + * At the PLT entry pointed at by `wherep', construct + * a direct transfer to the now fully resolved function + * address. + */ + +#if !defined(_CALL_ELF) || _CALL_ELF == 1 + dbg(" reloc_jmpslot: where=%p, target=%p (%#lx + %#lx)", + (void *)wherep, (void *)target, *(Elf_Addr *)target, + (Elf_Addr)defobj->relocbase); + + if (ld_bind_not) + goto out; + + /* + * For the trampoline, the second two elements of the function + * descriptor are unused, so we are fine replacing those at any time + * with the real ones with no thread safety implications. However, we + * need to make sure the main entry point pointer ([0]) is seen to be + * modified *after* the second two elements. This can't be done in + * general, since there are no barriers in the reading code, but put in + * some isyncs to at least make it a little better. + */ + memcpy(wherep, (void *)target, sizeof(struct funcdesc)); + wherep[2] = ((Elf_Addr *)target)[2]; + wherep[1] = ((Elf_Addr *)target)[1]; + __asm __volatile ("isync" : : : "memory"); + wherep[0] = ((Elf_Addr *)target)[0]; + __asm __volatile ("isync" : : : "memory"); + + if (((struct funcdesc *)(wherep))->addr < (Elf_Addr)defobj->relocbase) { + /* + * It is possible (LD_BIND_NOW) that the function + * descriptor we are copying has not yet been relocated. + * If this happens, fix it. Don't worry about threading in + * this case since LD_BIND_NOW makes it irrelevant. + */ + + ((struct funcdesc *)(wherep))->addr += + (Elf_Addr)defobj->relocbase; + ((struct funcdesc *)(wherep))->toc += + (Elf_Addr)defobj->relocbase; + } +out: +#else + dbg(" reloc_jmpslot: where=%p, target=%p", (void *)wherep, + (void *)target); + + if (!ld_bind_not) + *wherep = target; +#endif + + return (target); +} + +int +reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +int +reloc_gnu_ifunc(Obj_Entry *obj, int flags, + struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +void +init_pltgot(Obj_Entry *obj) +{ + Elf_Addr *pltcall; + + pltcall = obj->pltgot; + + if (pltcall == NULL) { + return; + } + +#if defined(_CALL_ELF) && _CALL_ELF == 2 + pltcall[0] = (Elf_Addr)&_rtld_bind_start; + pltcall[1] = (Elf_Addr)obj; +#else + memcpy(pltcall, _rtld_bind_start, sizeof(struct funcdesc)); + pltcall[2] = (Elf_Addr)obj; +#endif +} + +void +ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) +{ +} + +void +allocate_initial_tls(Obj_Entry *list) +{ + Elf_Addr **tp; + + /* + * Fix the size of the static TLS block by using the maximum + * offset allocated so far and adding a bit for dynamic modules to + * use. + */ + + tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA; + + tp = (Elf_Addr **) ((char *)allocate_tls(list, NULL, TLS_TCB_SIZE, 16) + + TLS_TP_OFFSET + TLS_TCB_SIZE); + + __asm __volatile("mr 13,%0" :: "r"(tp)); +} + +void* +__tls_get_addr(tls_index* ti) +{ + Elf_Addr **tp; + char *p; + + __asm __volatile("mr %0,13" : "=r"(tp)); + p = tls_get_addr_common((Elf_Addr**)((Elf_Addr)tp - TLS_TP_OFFSET + - TLS_TCB_SIZE), ti->ti_module, ti->ti_offset); + + return (p + TLS_DTV_OFFSET); +} diff --git a/libexec/rtld-elf/powerpc64/rtld_machdep.h b/libexec/rtld-elf/powerpc64/rtld_machdep.h new file mode 100644 index 0000000..1b33f2e --- /dev/null +++ b/libexec/rtld-elf/powerpc64/rtld_machdep.h @@ -0,0 +1,84 @@ +/*- + * Copyright (c) 1999, 2000 John D. Polstra. + * 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 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 AUTHOR 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/powerpc64/rtld_machdep.h 319434 2017-06-01 15:12:51Z vangyzen $ + */ + +#ifndef RTLD_MACHDEP_H +#define RTLD_MACHDEP_H 1 + +#include +#include + +struct Struct_Obj_Entry; + +/* Return the address of the .dynamic section in the dynamic linker. */ +#define rtld_dynamic(obj) (&_DYNAMIC) + +Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target, + const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *obj, + const Elf_Rel *rel); + +#define make_function_pointer(def, defobj) \ + ((defobj)->relocbase + (def)->st_value) + +#define call_initfini_pointer(obj, target) \ + (((InitFunc)(target))()) + +#define call_init_pointer(obj, target) \ + (((InitArrFunc)(target))(main_argc, main_argv, environ)) + +#define call_ifunc_resolver(ptr) \ + (((Elf_Addr (*)(void))ptr)()) + +/* + * TLS + */ + +#define TLS_TP_OFFSET 0x7000 +#define TLS_DTV_OFFSET 0x8000 +#define TLS_TCB_SIZE 16 + +#define round(size, align) \ + (((size) + (align) - 1) & ~((align) - 1)) +#define calculate_first_tls_offset(size, align) \ + round(16, align) +#define calculate_tls_offset(prev_offset, prev_size, size, align) \ + round(prev_offset + prev_size, align) +#define calculate_tls_end(off, size) ((off) + (size)) + +typedef struct { + unsigned long ti_module; + unsigned long ti_offset; +} tls_index; + +extern void *__tls_get_addr(tls_index* ti); + +#define RTLD_DEFAULT_STACK_PF_EXEC PF_X +#define RTLD_DEFAULT_STACK_EXEC PROT_EXEC + +#define md_abi_variant_hook(x) + +#endif diff --git a/libexec/rtld-elf/powerpc64/rtld_start.S b/libexec/rtld-elf/powerpc64/rtld_start.S new file mode 100644 index 0000000..2757c4f --- /dev/null +++ b/libexec/rtld-elf/powerpc64/rtld_start.S @@ -0,0 +1,171 @@ +/* $NetBSD: rtld_start.S,v 1.4 2001/09/26 04:06:43 mycroft Exp $ */ + +/*- + * Copyright (C) 1998 Tsubai Masanari + * 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. + * 3. 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/powerpc64/rtld_start.S 293018 2016-01-01 00:11:29Z nwhitehorn $ + */ + +#include + +.extern _GLOBAL_OFFSET_TABLE_ +.extern _DYNAMIC + +_ENTRY(_rtld_start) + stdu %r1,-144(%r1) /* 16-byte aligned stack for reg saves + + exit_proc & obj _rtld args + + backchain & lrsave stack frame */ + std %r3,96(%r1) /* argc */ + std %r4,104(%r1) /* argv */ + std %r5,112(%r1) /* envp */ +/* std %r6,120(%r1) *//* obj (always 0) */ +/* std %r7,128(%r1) *//* cleanup (always 0) */ + std %r8,136(%r1) /* ps_strings */ + + /* + * Perform initial relocation of ld-elf.so. Not as easy as it + * sounds. + * - perform small forward branch to put PC into link reg + * - use link-time constants to determine offset to the + * _DYNAMIC section and the GOT. Add these to the PC to + * convert to absolute addresses. + * - call reloc_non_plt_self() to fix up ld-elf.so's relocations + */ + + bl 1f + .llong _DYNAMIC-. +1: + mflr %r3 /* PC value at .llong */ + ld %r4,0(%r3) /* offset to _DYNAMIC */ + add %r3,%r4,%r3 /* r3 = &_DYNAMIC, absolute value */ + + ld %r4,-0x8000(%r2) /* First TOC entry is TOC base */ + subf %r4,%r4,%r2 /* Subtract from real TOC base to get base */ + + bl reloc_non_plt_self /* reloc_non_plt_self(&_DYNAMIC,base) */ + nop + + /* + * The _rtld() function likes to see a stack layout containing + * { argc, argv[0], argv[1] ... argv[N], 0, env[0], ... , env[N] } + * Since the PowerPC stack was 16-byte aligned at exec time, the + * original stack layout has to be found by moving back a word + * from the argv pointer. + */ + ld %r4,104(%r1) + addi %r3,%r4,-8 /* locate argc ptr, &argv[-1] */ + addi %r4,%r1,128 /* &exit_proc on stack */ + addi %r5,%r1,120 /* &obj_main on stack */ + + bl _rtld /* &_start = _rtld(sp, &exit_proc, &obj_main)*/ + nop +#if !defined(_CALL_ELF) || _CALL_ELF == 1 + ld %r2,8(%r3) + ld %r11,16(%r3) + ld %r3,0(%r3) +#else + mr %r12,%r3 +#endif + mtlr %r3 + + /* + * Restore args, with new obj/exit proc + */ + ld %r3,96(%r1) /* argc */ + ld %r4,104(%r1) /* argv */ + ld %r5,112(%r1) /* envp */ + ld %r6,120(%r1) /* obj */ + ld %r7,128(%r1) /* exit proc */ + ld %r8,136(%r1) /* ps_strings */ + + blrl /* _start(argc, argv, envp, obj, cleanup, ps_strings) */ + + li %r0,1 /* _exit() */ + sc + +/* + * _rtld_bind_start() + * + * Call into the MI binder. This routine is reached via the PLT call cell + * + * On entry, %r11 contains an object pointer and %r0 contains the PLT index. + * + * Save all registers, call into the binder to resolve and fixup the external + * routine, and then transfer to the external routine on return. + */ + .globl _rtld_bind + +_ENTRY(_rtld_bind_start) + mr %r12,%r0 # save r0 (index) immediately to r12 + mflr %r0 + std %r0,16(%r1) # save lr + mfcr %r0 + std %r0,8(%r1) # save cr + + stdu %r1,-48-12*8(%r1) # stack space for 8 regs + header + # + 2 save regs + std %r3,64+0*8(%r1) # save r3-r10 (arguments) + std %r4,64+1*8(%r1) + std %r5,64+2*8(%r1) + std %r6,64+3*8(%r1) + std %r7,64+4*8(%r1) + std %r8,64+5*8(%r1) + std %r9,64+6*8(%r1) + std %r10,64+7*8(%r1) + + mr %r3,%r11 + mulli %r4,%r12,24 # Multiply index by sizeof(Elf_Rela) + + bl _rtld_bind # target addr = _rtld_bind(obj, reloff) + nop + +#if !defined(_CALL_ELF) || _CALL_ELF == 1 + ld %r2,8(%r3) + ld %r11,16(%r3) + ld %r3,0(%r3) +#else + mr %r12,%r3 +#endif + mtctr %r3 # move absolute target addr into ctr + + ld %r3,64+0*8(%r1) # restore r3-r10 + ld %r4,64+1*8(%r1) + ld %r5,64+2*8(%r1) + ld %r6,64+3*8(%r1) + ld %r7,64+4*8(%r1) + ld %r8,64+5*8(%r1) + ld %r9,64+6*8(%r1) + ld %r10,64+7*8(%r1) + + ld %r1,0(%r1) # restore stack + ld %r0,8(%r1) # restore cr + mtcr %r0 + ld %r0,16(%r1) # restore lr + mtlr %r0 + + bctr # jump to target + + .section .note.GNU-stack,"",%progbits diff --git a/libexec/rtld-elf/riscv/reloc.c b/libexec/rtld-elf/riscv/reloc.c new file mode 100644 index 0000000..eb62b71 --- /dev/null +++ b/libexec/rtld-elf/riscv/reloc.c @@ -0,0 +1,404 @@ +/*- + * Copyright (c) 2015 Ruslan Bukin + * All rights reserved. + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 + * ("CTSRD"), as part of the DARPA CRASH research programme. + * + * This software was developed by the University of Cambridge Computer + * Laboratory as part of the CTSRD Project, with support from the UK Higher + * Education Innovation Fund (HEIF). + * + * 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 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD: releng/11.1/libexec/rtld-elf/riscv/reloc.c 316135 2017-03-29 11:03:08Z kib $"); + +#include + +#include + +#include "debug.h" +#include "rtld.h" +#include "rtld_printf.h" + +/* + * It is possible for the compiler to emit relocations for unaligned data. + * We handle this situation with these inlines. + */ +#define RELOC_ALIGNED_P(x) \ + (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0) + +void _exit(int); + +uint64_t +set_gp(Obj_Entry *obj) +{ + uint64_t old; + SymLook req; + uint64_t gp; + int res; + + __asm __volatile("mv %0, gp" : "=r"(old)); + + symlook_init(&req, "_gp"); + req.ventry = NULL; + req.flags = SYMLOOK_EARLY; + res = symlook_obj(&req, obj); + + if (res == 0) { + gp = req.sym_out->st_value; + __asm __volatile("mv gp, %0" :: "r"(gp)); + } + + return (old); +} + +void +init_pltgot(Obj_Entry *obj) +{ + + if (obj->pltgot != NULL) { + obj->pltgot[0] = (Elf_Addr)&_rtld_bind_start; + obj->pltgot[1] = (Elf_Addr)obj; + } +} + +int +do_copy_relocations(Obj_Entry *dstobj) +{ + const Obj_Entry *srcobj, *defobj; + const Elf_Rela *relalim; + const Elf_Rela *rela; + const Elf_Sym *srcsym; + const Elf_Sym *dstsym; + const void *srcaddr; + const char *name; + void *dstaddr; + SymLook req; + size_t size; + int res; + + /* + * COPY relocs are invalid outside of the main program + */ + assert(dstobj->mainprog); + + relalim = (const Elf_Rela *)((char *)dstobj->rela + + dstobj->relasize); + for (rela = dstobj->rela; rela < relalim; rela++) { + if (ELF_R_TYPE(rela->r_info) != R_RISCV_COPY) + continue; + + dstaddr = (void *)(dstobj->relocbase + rela->r_offset); + dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); + name = dstobj->strtab + dstsym->st_name; + size = dstsym->st_size; + + symlook_init(&req, name); + req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); + req.flags = SYMLOOK_EARLY; + + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { + res = symlook_obj(&req, srcobj); + if (res == 0) { + srcsym = req.sym_out; + defobj = req.defobj_out; + break; + } + } + if (srcobj == NULL) { + _rtld_error( +"Undefined symbol \"%s\" referenced from COPY relocation in %s", + name, dstobj->path); + return (-1); + } + + srcaddr = (const void *)(defobj->relocbase + srcsym->st_value); + memcpy(dstaddr, srcaddr, size); + } + + return (0); +} + +/* + * Process the PLT relocations. + */ +int +reloc_plt(Obj_Entry *obj) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + + relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); + for (rela = obj->pltrela; rela < relalim; rela++) { + Elf_Addr *where; + + assert(ELF_R_TYPE(rela->r_info) == R_RISCV_JUMP_SLOT); + + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + *where += (Elf_Addr)obj->relocbase; + } + + return (0); +} + +/* + * LD_BIND_NOW was set - force relocation for all jump slots + */ +int +reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) +{ + const Obj_Entry *defobj; + const Elf_Rela *relalim; + const Elf_Rela *rela; + const Elf_Sym *def; + + relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); + for (rela = obj->pltrela; rela < relalim; rela++) { + Elf_Addr *where; + + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + switch(ELF_R_TYPE(rela->r_info)) { + case R_RISCV_JUMP_SLOT: + def = find_symdef(ELF_R_SYM(rela->r_info), obj, + &defobj, SYMLOOK_IN_PLT | flags, NULL, lockstate); + if (def == NULL) { + dbg("reloc_jmpslots: sym not found"); + return (-1); + } + + *where = (Elf_Addr)(defobj->relocbase + def->st_value); + break; + default: + _rtld_error("Unknown relocation type %x in jmpslot", + (unsigned int)ELF_R_TYPE(rela->r_info)); + return (-1); + } + } + + return (0); +} + +int +reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +int +reloc_gnu_ifunc(Obj_Entry *obj, int flags, + struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +Elf_Addr +reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj, + const Obj_Entry *obj, const Elf_Rel *rel) +{ + + assert(ELF_R_TYPE(rel->r_info) == R_RISCV_JUMP_SLOT); + + if (*where != target && !ld_bind_not) + *where = target; + return (target); +} + +/* + * Process non-PLT relocations + */ +int +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, + RtldLockState *lockstate) +{ + const Obj_Entry *defobj; + const Elf_Rela *relalim; + const Elf_Rela *rela; + const Elf_Sym *def; + SymCache *cache; + Elf_Addr *where; + unsigned long symnum; + + if ((flags & SYMLOOK_IFUNC) != 0) + /* XXX not implemented */ + return (0); + + /* + * The dynamic loader may be called from a thread, we have + * limited amounts of stack available so we cannot use alloca(). + */ + if (obj == obj_rtld) + cache = NULL; + else + cache = calloc(obj->dynsymcount, sizeof(SymCache)); + /* No need to check for NULL here */ + + relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize); + for (rela = obj->rela; rela < relalim; rela++) { + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + symnum = ELF_R_SYM(rela->r_info); + + switch (ELF_R_TYPE(rela->r_info)) { + case R_RISCV_JUMP_SLOT: + /* This will be handled by the plt/jmpslot routines */ + break; + case R_RISCV_NONE: + break; + case R_RISCV_64: + def = find_symdef(symnum, obj, &defobj, flags, cache, + lockstate); + if (def == NULL) + return (-1); + + *where = (Elf_Addr)(defobj->relocbase + def->st_value + + rela->r_addend); + break; + case R_RISCV_TLS_DTPMOD64: + def = find_symdef(symnum, obj, &defobj, flags, cache, + lockstate); + if (def == NULL) + return -1; + + *where += (Elf_Addr)defobj->tlsindex; + break; + case R_RISCV_COPY: + /* + * These are deferred until all other relocations have + * been done. All we do here is make sure that the + * COPY relocation is not in a shared library. They + * are allowed only in executable files. + */ + if (!obj->mainprog) { + _rtld_error("%s: Unexpected R_RISCV_COPY " + "relocation in shared library", obj->path); + return (-1); + } + break; + case R_RISCV_TLS_DTPREL64: + def = find_symdef(symnum, obj, &defobj, flags, cache, + lockstate); + if (def == NULL) + return (-1); + /* + * We lazily allocate offsets for static TLS as we + * see the first relocation that references the + * TLS block. This allows us to support (small + * amounts of) static TLS in dynamically loaded + * modules. If we run out of space, we generate an + * error. + */ + if (!defobj->tls_done) { + if (!allocate_tls_offset((Obj_Entry*) defobj)) { + _rtld_error( + "%s: No space available for static " + "Thread Local Storage", obj->path); + return (-1); + } + } + + *where += (Elf_Addr)(def->st_value + rela->r_addend + - TLS_DTV_OFFSET); + break; + case R_RISCV_TLS_TPREL64: + def = find_symdef(symnum, obj, &defobj, flags, cache, + lockstate); + if (def == NULL) + return (-1); + + /* + * We lazily allocate offsets for static TLS as we + * see the first relocation that references the + * TLS block. This allows us to support (small + * amounts of) static TLS in dynamically loaded + * modules. If we run out of space, we generate an + * error. + */ + if (!defobj->tls_done) { + if (!allocate_tls_offset((Obj_Entry*) defobj)) { + _rtld_error( + "%s: No space available for static " + "Thread Local Storage", obj->path); + return (-1); + } + } + + *where = (def->st_value + rela->r_addend + + defobj->tlsoffset - TLS_TP_OFFSET); + break; + case R_RISCV_RELATIVE: + *where = (Elf_Addr)(obj->relocbase + rela->r_addend); + break; + default: + rtld_printf("%s: Unhandled relocation %lu\n", + obj->path, ELF_R_TYPE(rela->r_info)); + return (-1); + } + } + + return (0); +} + +void +ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) +{ +} + +void +allocate_initial_tls(Obj_Entry *objs) +{ + Elf_Addr **tp; + + /* + * Fix the size of the static TLS block by using the maximum + * offset allocated so far and adding a bit for dynamic modules to + * use. + */ + tls_static_space = tls_last_offset + tls_last_size + + RTLD_STATIC_TLS_EXTRA; + + tp = (Elf_Addr **) ((char *)allocate_tls(objs, NULL, TLS_TCB_SIZE, 16) + + TLS_TP_OFFSET + TLS_TCB_SIZE); + + __asm __volatile("mv tp, %0" :: "r"(tp)); +} + +void * +__tls_get_addr(tls_index* ti) +{ + char *_tp; + void *p; + + __asm __volatile("mv %0, tp" : "=r" (_tp)); + + p = tls_get_addr_common((Elf_Addr**)((Elf_Addr)_tp - TLS_TP_OFFSET + - TLS_TCB_SIZE), ti->ti_module, ti->ti_offset); + + return (p + TLS_DTV_OFFSET); +} diff --git a/libexec/rtld-elf/riscv/rtld_machdep.h b/libexec/rtld-elf/riscv/rtld_machdep.h new file mode 100644 index 0000000..a8be9a6 --- /dev/null +++ b/libexec/rtld-elf/riscv/rtld_machdep.h @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 1999, 2000 John D. Polstra. + * Copyright (c) 2015 Ruslan Bukin + * All rights reserved. + * + * Portions of this software were developed by SRI International and the + * University of Cambridge Computer Laboratory under DARPA/AFRL contract + * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Portions of this software were developed by the University of Cambridge + * Computer Laboratory as part of the CTSRD Project, with support from the + * UK Higher Education Innovation Fund (HEIF). + * + * 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 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 AUTHOR 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/riscv/rtld_machdep.h 319434 2017-06-01 15:12:51Z vangyzen $ + */ + +#ifndef RTLD_MACHDEP_H +#define RTLD_MACHDEP_H 1 + +#include +#include + +struct Struct_Obj_Entry; + +uint64_t set_gp(struct Struct_Obj_Entry *obj); + +/* Return the address of the .dynamic section in the dynamic linker. */ +#define rtld_dynamic(obj) \ +({ \ + Elf_Addr _dynamic_addr; \ + __asm __volatile("lla %0, _DYNAMIC" : "=r"(_dynamic_addr)); \ + (const Elf_Dyn *)_dynamic_addr; \ +}) + +Elf_Addr reloc_jmpslot(Elf_Addr *where, Elf_Addr target, + const struct Struct_Obj_Entry *defobj, const struct Struct_Obj_Entry *obj, + const Elf_Rel *rel); + +#define make_function_pointer(def, defobj) \ + ((defobj)->relocbase + (def)->st_value) + +#define call_initfini_pointer(obj, target) \ +({ \ + uint64_t old0; \ + old0 = set_gp(obj); \ + (((InitFunc)(target))()); \ + __asm __volatile("mv gp, %0" :: "r"(old0)); \ +}) + +#define call_init_pointer(obj, target) \ +({ \ + uint64_t old1; \ + old1 = set_gp(obj); \ + (((InitArrFunc)(target))(main_argc, main_argv, environ)); \ + __asm __volatile("mv gp, %0" :: "r"(old1)); \ +}) + +#define call_ifunc_resolver(ptr) \ + (((Elf_Addr (*)(void))ptr)()) + +/* + * TLS + */ +#define TLS_TP_OFFSET 0x0 +#define TLS_DTV_OFFSET 0x800 +#define TLS_TCB_SIZE 16 + +#define round(size, align) \ + (((size) + (align) - 1) & ~((align) - 1)) +#define calculate_first_tls_offset(size, align) \ + round(16, align) +#define calculate_tls_offset(prev_offset, prev_size, size, align) \ + round(prev_offset + prev_size, align) +#define calculate_tls_end(off, size) ((off) + (size)) + +typedef struct { + unsigned long ti_module; + unsigned long ti_offset; +} tls_index; + +extern void *__tls_get_addr(tls_index* ti); + +#define RTLD_DEFAULT_STACK_PF_EXEC PF_X +#define RTLD_DEFAULT_STACK_EXEC PROT_EXEC + +#define md_abi_variant_hook(x) + +#endif diff --git a/libexec/rtld-elf/riscv/rtld_start.S b/libexec/rtld-elf/riscv/rtld_start.S new file mode 100644 index 0000000..69f28e2 --- /dev/null +++ b/libexec/rtld-elf/riscv/rtld_start.S @@ -0,0 +1,129 @@ +/*- + * Copyright (c) 2015 Ruslan Bukin + * All rights reserved. + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 + * ("CTSRD"), as part of the DARPA CRASH research programme. + * + * This software was developed by the University of Cambridge Computer + * Laboratory as part of the CTSRD Project, with support from the UK Higher + * Education Innovation Fund (HEIF). + * + * 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 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD: releng/11.1/libexec/rtld-elf/riscv/rtld_start.S 292691 2015-12-24 15:47:51Z br $"); + +/* + * func_ptr_type + * _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) + */ + +ENTRY(.rtld_start) + mv s0, a0 /* Put ps_strings in a callee-saved register */ + mv s1, sp /* And the stack pointer */ + + addi sp, sp, -16 /* Make room for obj_main & exit proc */ + + mv a1, sp /* exit_proc */ + addi a2, a1, 8 /* obj_main */ + jal _rtld /* Call the loader */ + mv t0, a0 /* Backup the entry point */ + + ld a2, 0(sp) /* Load cleanup */ + ld a1, 8(sp) /* Load obj_main */ + mv a0, s0 /* Restore ps_strings */ + mv sp, s1 /* Restore the stack pointer */ + jr t0 /* Jump to the entry point */ +END(.rtld_start) + +/* + * t0 = obj pointer + * t1 = reloc offset + */ +ENTRY(_rtld_bind_start) + /* Save the arguments and ra */ + addi sp, sp, -(8 * 25) + sd a0, (8 * 0)(sp) + sd a1, (8 * 1)(sp) + sd a2, (8 * 2)(sp) + sd a3, (8 * 3)(sp) + sd a4, (8 * 4)(sp) + sd a5, (8 * 5)(sp) + sd a6, (8 * 6)(sp) + sd a7, (8 * 7)(sp) + sd ra, (8 * 8)(sp) +#if 0 + /* RISCVTODO VFP */ + /* Save any floating-point arguments */ + fsq fa0, (8 * 9)(sp) + fsq fa1, (8 * 11)(sp) + fsq fa2, (8 * 13)(sp) + fsq fa3, (8 * 15)(sp) + fsq fa4, (8 * 17)(sp) + fsq fa5, (8 * 19)(sp) + fsq fa6, (8 * 21)(sp) + fsq fa7, (8 * 23)(sp) +#endif + + /* Reloc offset is 3x of the .got.plt offset */ + slli a1, t1, 1 /* Mult items by 2 */ + add a1, a1, t1 /* Plus item */ + + /* Load obj */ + mv a0, t0 + + /* Call into rtld */ + jal _rtld_bind + + /* Backup the address to branch to */ + mv t0, a0 + + /* Restore the arguments and ra */ + ld a0, (8 * 0)(sp) + ld a1, (8 * 1)(sp) + ld a2, (8 * 2)(sp) + ld a3, (8 * 3)(sp) + ld a4, (8 * 4)(sp) + ld a5, (8 * 5)(sp) + ld a6, (8 * 6)(sp) + ld a7, (8 * 7)(sp) + ld ra, (8 * 8)(sp) +#if 0 + /* RISCVTODO VFP */ + /* Restore floating-point arguments */ + flq fa0, (8 * 9)(sp) + flq fa1, (8 * 11)(sp) + flq fa2, (8 * 13)(sp) + flq fa3, (8 * 15)(sp) + flq fa4, (8 * 17)(sp) + flq fa5, (8 * 19)(sp) + flq fa6, (8 * 21)(sp) + flq fa7, (8 * 23)(sp) +#endif + addi sp, sp, (8 * 25) + + /* Call into the correct function */ + jr t0 +END(_rtld_bind_start) diff --git a/libexec/rtld-elf/rtld.1 b/libexec/rtld-elf/rtld.1 new file mode 100644 index 0000000..75763f1 --- /dev/null +++ b/libexec/rtld-elf/rtld.1 @@ -0,0 +1,374 @@ +.\" Copyright (c) 1995 Paul Kranenburg +.\" 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. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgment: +.\" This product includes software developed by Paul Kranenburg. +.\" 3. 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. +.\" +.\" $FreeBSD: releng/11.1/libexec/rtld-elf/rtld.1 319367 2017-06-01 00:50:58Z kib $ +.\" +.Dd May 20, 2017 +.Dt RTLD 1 +.Os +.Sh NAME +.Nm ld-elf.so.1 , +.Nm ld.so , +.Nm rtld +.Nd run-time link-editor +.Sh DESCRIPTION +The +.Nm +utility is a self-contained shared object providing run-time +support for loading and link-editing shared objects into a process' +address space. +It is also commonly known as the dynamic linker. +It uses the data structures +contained within dynamically linked programs to determine which shared +libraries are needed and loads them using the +.Xr mmap 2 +system call. +.Pp +After all shared libraries have been successfully loaded, +.Nm +proceeds to resolve external references from both the main program and +all objects loaded. +A mechanism is provided for initialization routines +to be called on a per-object basis, giving a shared object an opportunity +to perform any extra set-up before execution of the program proper begins. +This is useful for C++ libraries that contain static constructors. +.Pp +When resolving dependencies for the loaded objects, +.Nm +translates dynamic token strings in rpath and soname. +If the +.Fl "z origin" +option of the static linker was set when linking the binary, +the token expansion is performed at the object load time, see +.Xr ld 1 . +The following strings are recognized now: +.Bl -tag -width ".Pa $PLATFORM" +.It Pa $ORIGIN +Translated to the full path of the loaded object. +.It Pa $OSNAME +Translated to the name of the operating system implementation. +.It Pa $OSREL +Translated to the release level of the operating system. +.It Pa $PLATFORM +Translated to the machine hardware platform. +.El +.Pp +The +.Nm +utility itself is loaded by the kernel together with any dynamically-linked +program that is to be executed. +The kernel transfers control to the +dynamic linker. +After the dynamic linker has finished loading, +relocating, and initializing the program and its required shared +objects, it transfers control to the entry point of the program. +The following search order is used to locate required shared objects: +.Pp +.Bl -enum -offset indent -compact +.It +.Dv DT_RPATH +of the referencing object unless that object also contains a +.Dv DT_RUNPATH +tag +.It +.Dv DT_RPATH +of the program unless the referencing object contains a +.Dv DT_RUNPATH +tag +.It +Path indicated by +.Ev LD_LIBRARY_PATH +environment variable +.It +.Dv DT_RUNPATH +of the referencing object +.It +Hints file produced by the +.Xr ldconfig 8 +utility +.It +The +.Pa /lib +and +.Pa /usr/lib +directories, unless the referencing object was linked using the +.Dq Fl z Ar nodefaultlib +option +.El +.Pp +The +.Nm +utility +recognizes a number of environment variables that can be used to modify +its behaviour. +On 64-bit architectures, the linker for 32-bit objects recognizes +all the environment variables listed below, but is being prefixed with +.Ev LD_32_ , +for example: +.Ev LD_32_TRACE_LOADED_OBJECTS . +.Bl -tag -width ".Ev LD_LIBMAP_DISABLE" +.It Ev LD_DUMP_REL_POST +If set, +.Nm +will print a table containing all relocations after symbol +binding and relocation. +.It Ev LD_DUMP_REL_PRE +If set, +.Nm +will print a table containing all relocations before symbol +binding and relocation. +.It Ev LD_LIBMAP +A library replacement list in the same format as +.Xr libmap.conf 5 . +For convenience, the characters +.Ql = +and +.Ql \&, +can be used instead of a space and a newline. +This variable is parsed after +.Xr libmap.conf 5 , +and will override its entries. +This variable is unset for set-user-ID and set-group-ID programs. +.It Ev LD_LIBMAP_DISABLE +If set, disables the use of +.Xr libmap.conf 5 +and +.Ev LD_LIBMAP . +This variable is unset for set-user-ID and set-group-ID programs. +.It Ev LD_ELF_HINTS_PATH +This variable will override the default location of +.Dq hints +file. +This variable is unset for set-user-ID and set-group-ID programs. +.It Ev LD_LIBRARY_PATH +A colon separated list of directories, overriding the default search path +for shared libraries. +This variable is unset for set-user-ID and set-group-ID programs. +.It Ev LD_LIBRARY_PATH_RPATH +If the variable is specified and has a value starting with +any of \'y\', \'Y\' or \'1\' symbols, the path specified by +.Ev LD_LIBRARY_PATH +variable is allowed to override the path from +.Dv DT_RPATH +for binaries which does not contain +.Dv DT_RUNPATH +tag. +For such binaries, when the variable +.Ev LD_LIBRARY_PATH_RPATH +is set, +.Dq Fl z Ar nodefaultlib +link-time option is ignored as well. +.It Ev LD_PRELOAD +A list of shared libraries, separated by colons and/or white space, +to be linked in before any +other shared libraries. +If the directory is not specified then +the directories specified by +.Ev LD_LIBRARY_PATH +will be searched first +followed by the set of built-in standard directories. +This variable is unset for set-user-ID and set-group-ID programs. +.Ev LD_LIBRARY_PATH_FDS +A colon separated list of file descriptor numbers for library directories. +This is intended for use within +.Xr capsicum 4 +sandboxes, when global namespaces such as the filesystem are unavailable. +It is consulted just after LD_LIBRARY_PATH. +This variable is unset for set-user-ID and set-group-ID programs. +.It Ev LD_BIND_NOT +When set to a nonempty string, prevents modifications of the PLT slots when +doing bindings. +As result, each call of the PLT-resolved function is resolved. +In combination with debug output, this provides complete account of +all bind actions at runtime. +This variable is unset for set-user-ID and set-group-ID programs. +.It Ev LD_BIND_NOW +When set to a nonempty string, causes +.Nm +to relocate all external function calls before starting execution of the +program. +Normally, function calls are bound lazily, at the first call +of each function. +.Ev LD_BIND_NOW +increases the start-up time of a program, but it avoids run-time +surprises caused by unexpectedly undefined functions. +.It Ev LD_TRACE_LOADED_OBJECTS +When set to a nonempty string, causes +.Nm +to exit after loading the shared objects and printing a summary which includes +the absolute pathnames of all objects, to standard output. +.It Ev LD_TRACE_LOADED_OBJECTS_ALL +When set to a nonempty string, causes +.Nm +to expand the summary to indicate which objects caused each object to +be loaded. +.It Ev LD_TRACE_LOADED_OBJECTS_FMT1 +.It Ev LD_TRACE_LOADED_OBJECTS_FMT2 +When set, these variables are interpreted as format strings a la +.Xr printf 3 +to customize the trace output and are used by +.Xr ldd 1 Ns 's +.Fl f +option and allows +.Xr ldd 1 +to be operated as a filter more conveniently. +If the dependency name starts with string +.Pa lib , +.Ev LD_TRACE_LOADED_OBJECTS_FMT1 +is used, otherwise +.Ev LD_TRACE_LOADED_OBJECTS_FMT2 +is used. +The following conversions can be used: +.Bl -tag -width 4n +.It Li %a +The main program's name +(also known as +.Dq __progname ) . +.It Li \&%A +The value of the environment variable +.Ev LD_TRACE_LOADED_OBJECTS_PROGNAME . +Typically used to print both the names of programs and shared libraries +being inspected using +.Xr ldd 1 . +.It Li %o +The library name. +.It Li %p +The full pathname as determined by +.Nm rtld Ns 's +library search rules. +.It Li %x +The library's load address. +.El +.Pp +Additionally, +.Ql \en +and +.Ql \et +are recognized and have their usual meaning. +.It Ev LD_UTRACE +If set, +.Nm +will log events such as the loading and unloading of shared objects via +.Xr utrace 2 . +.It Ev LD_LOADFLTR +If set, +.Nm +will process the filtee dependencies of the loaded objects immediately, +instead of postponing it until required. +Normally, the filtees are opened at the time of the first symbol resolution +from the filter object. +.El +.Sh DIRECT EXECUTION MODE +.Nm +is typically used implicitly, loaded by the kernel as requested by the +.Dv PT_INTERP +program header of the executed binary. +.Fx +also supports a direct execution mode for the dynamic linker. +In this mode, the user explicitly executes +.Nm +and provides the path of the program to be linked and executed as +an argument. +This mode allows use of a non-standard dynamic linker for a program +activation without changing the binary or without changing +the installed dynamic linker. +Execution options may be specified. +.Pp +The syntax of the direct invocation is +.Bd -ragged -offset indent +.Pa /libexec/ld-elf.so.1 +.Op Fl f Ar fd +.Op Fl p +.Op Fl - +.Pa image_path +.Op Ar image arguments +.Ed +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl f Ar fd +File descriptor +.Ar fd +references the binary to be activated by +.Nm . +It must already be opened in the process when executing +.Nm . +If this option is specified, +.Ar image_path +is only used to provide the +.Va argv[0] +value to the program. +.It Fl p +If the +.Pa image_path +argument specifies a name which does not contain a slash +.Dq Li / +character, +.Nm +uses the search path provided by the environment variable +.Dv PATH +to find the binary to execute. +.It Fl - +Ends the +.Nm +options. +The argument following +.Fl - +is interpreted as the path of binary to execute. +.El +.Pp +To conform to user expectation to not break some naively restricted +execution environments, in the direct execution mode +.Nm +emulates verification of the binary execute permission +for current user. +The verification only uses Unix +.Dv DACs , +ignores +.Dv ACLs +and is racy by its nature. +The environments which rely on such restrictions are weak +and breakable on its own. +.Sh FILES +.Bl -tag -width ".Pa /var/run/ld-elf32.so.hints" -compact +.It Pa /var/run/ld-elf.so.hints +Hints file. +.It Pa /var/run/ld-elf32.so.hints +Hints file for 32-bit binaries on 64-bit system. +.It Pa /etc/libmap.conf +The libmap configuration file. +.It Pa /etc/libmap32.conf +The libmap configuration file for 32-bit binaries on 64-bit system. +.El +.Sh SEE ALSO +.Xr ld 1 , +.Xr ldd 1 , +.Xr capsicum 4 , +.Xr elf 5 , +.Xr libmap.conf 5 , +.Xr ldconfig 8 diff --git a/libexec/rtld-elf/rtld_printf.c b/libexec/rtld-elf/rtld_printf.c new file mode 100644 index 0000000..4c3f705 --- /dev/null +++ b/libexec/rtld-elf/rtld_printf.c @@ -0,0 +1,501 @@ +/*- + * Copyright (c) 1986, 1988, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * Copyright (c) 2011 Konstantin Belousov + * + * 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. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/rtld_printf.c 267678 2014-06-20 17:08:32Z jonathan $ + */ + +#include +#include +#include +#include +#include +#include +#include "rtld_printf.h" + +#define MAXNBUF (sizeof(intmax_t) * NBBY + 1) + +#define PRINT_METHOD_SNPRINTF 1 +#define PRINT_METHOD_WRITE 2 + +struct snprintf_arg { + int method; + char *str; + char *buf; + size_t remain; + size_t buf_total; + int fd; +}; + +static void +printf_out(struct snprintf_arg *info) +{ + + if (info->remain == info->buf_total) + return; + write(info->fd, info->buf, info->buf_total - info->remain); + info->str = info->buf; + info->remain = info->buf_total; +} + +static void +snprintf_func(int ch, struct snprintf_arg *const info) +{ + + switch (info->method) { + case PRINT_METHOD_SNPRINTF: + if (info->remain >= 2) { + *info->str++ = ch; + info->remain--; + } + break; + case PRINT_METHOD_WRITE: + if (info->remain > 0) { + *info->str++ = ch; + info->remain--; + } else + printf_out(info); + break; + } +} + +static char const hex2ascii_lower[] = "0123456789abcdefghijklmnopqrstuvwxyz"; +static char const hex2ascii_upper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#define hex2ascii(hex) (hex2ascii_lower[hex]) +#define hex2ascii_upper(hex) (hex2ascii_upper[hex]) + +static __inline int +imax(int a, int b) +{ + + return (a > b ? a : b); +} + +static char * +ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) +{ + char *p, c; + + p = nbuf; + *p = '\0'; + do { + c = upper ? hex2ascii_upper(num % base) : + hex2ascii(num % base); + *++p = c; + } while (num /= base); + if (lenp) + *lenp = p - nbuf; + return (p); +} + +static int +kvprintf(char const *fmt, struct snprintf_arg *arg, int radix, va_list ap) +{ +#define PCHAR(c) snprintf_func((c), arg) + char nbuf[MAXNBUF]; + const char *p, *percent, *q; + u_char *up; + int ch, n; + uintmax_t num; + int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; + int cflag, hflag, jflag, tflag, zflag; + int dwidth, upper; + char padc; + int stop = 0, retval = 0; + + num = 0; + + if (fmt == NULL) + fmt = "(fmt null)\n"; + + if (radix < 2 || radix > 36) + radix = 10; + + for (;;) { + padc = ' '; + width = 0; + while ((ch = (u_char)*fmt++) != '%' || stop) { + if (ch == '\0') + return (retval); + PCHAR(ch); + } + percent = fmt - 1; + qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; + sign = 0; dot = 0; dwidth = 0; upper = 0; + cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; +reswitch: switch (ch = (u_char)*fmt++) { + case '.': + dot = 1; + goto reswitch; + case '#': + sharpflag = 1; + goto reswitch; + case '+': + sign = 1; + goto reswitch; + case '-': + ladjust = 1; + goto reswitch; + case '%': + PCHAR(ch); + break; + case '*': + if (!dot) { + width = va_arg(ap, int); + if (width < 0) { + ladjust = !ladjust; + width = -width; + } + } else { + dwidth = va_arg(ap, int); + } + goto reswitch; + case '0': + if (!dot) { + padc = '0'; + goto reswitch; + } + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + for (n = 0;; ++fmt) { + n = n * 10 + ch - '0'; + ch = *fmt; + if (ch < '0' || ch > '9') + break; + } + if (dot) + dwidth = n; + else + width = n; + goto reswitch; + case 'b': + num = (u_int)va_arg(ap, int); + p = va_arg(ap, char *); + for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) + PCHAR(*q--); + + if (num == 0) + break; + + for (tmp = 0; *p;) { + n = *p++; + if (num & (1 << (n - 1))) { + PCHAR(tmp ? ',' : '<'); + for (; (n = *p) > ' '; ++p) + PCHAR(n); + tmp = 1; + } else + for (; *p > ' '; ++p) + continue; + } + if (tmp) + PCHAR('>'); + break; + case 'c': + PCHAR(va_arg(ap, int)); + break; + case 'D': + up = va_arg(ap, u_char *); + p = va_arg(ap, char *); + if (!width) + width = 16; + while(width--) { + PCHAR(hex2ascii(*up >> 4)); + PCHAR(hex2ascii(*up & 0x0f)); + up++; + if (width) + for (q=p;*q;q++) + PCHAR(*q); + } + break; + case 'd': + case 'i': + base = 10; + sign = 1; + goto handle_sign; + case 'h': + if (hflag) { + hflag = 0; + cflag = 1; + } else + hflag = 1; + goto reswitch; + case 'j': + jflag = 1; + goto reswitch; + case 'l': + if (lflag) { + lflag = 0; + qflag = 1; + } else + lflag = 1; + goto reswitch; + case 'n': + if (jflag) + *(va_arg(ap, intmax_t *)) = retval; + else if (qflag) + *(va_arg(ap, quad_t *)) = retval; + else if (lflag) + *(va_arg(ap, long *)) = retval; + else if (zflag) + *(va_arg(ap, size_t *)) = retval; + else if (hflag) + *(va_arg(ap, short *)) = retval; + else if (cflag) + *(va_arg(ap, char *)) = retval; + else + *(va_arg(ap, int *)) = retval; + break; + case 'o': + base = 8; + goto handle_nosign; + case 'p': + base = 16; + sharpflag = (width == 0); + sign = 0; + num = (uintptr_t)va_arg(ap, void *); + goto number; + case 'q': + qflag = 1; + goto reswitch; + case 'r': + base = radix; + if (sign) + goto handle_sign; + goto handle_nosign; + case 's': + p = va_arg(ap, char *); + if (p == NULL) + p = "(null)"; + if (!dot) + n = strlen (p); + else + for (n = 0; n < dwidth && p[n]; n++) + continue; + + width -= n; + + if (!ladjust && width > 0) + while (width--) + PCHAR(padc); + while (n--) + PCHAR(*p++); + if (ladjust && width > 0) + while (width--) + PCHAR(padc); + break; + case 't': + tflag = 1; + goto reswitch; + case 'u': + base = 10; + goto handle_nosign; + case 'X': + upper = 1; + case 'x': + base = 16; + goto handle_nosign; + case 'y': + base = 16; + sign = 1; + goto handle_sign; + case 'z': + zflag = 1; + goto reswitch; +handle_nosign: + sign = 0; + if (jflag) + num = va_arg(ap, uintmax_t); + else if (qflag) + num = va_arg(ap, u_quad_t); + else if (tflag) + num = va_arg(ap, ptrdiff_t); + else if (lflag) + num = va_arg(ap, u_long); + else if (zflag) + num = va_arg(ap, size_t); + else if (hflag) + num = (u_short)va_arg(ap, int); + else if (cflag) + num = (u_char)va_arg(ap, int); + else + num = va_arg(ap, u_int); + goto number; +handle_sign: + if (jflag) + num = va_arg(ap, intmax_t); + else if (qflag) + num = va_arg(ap, quad_t); + else if (tflag) + num = va_arg(ap, ptrdiff_t); + else if (lflag) + num = va_arg(ap, long); + else if (zflag) + num = va_arg(ap, ssize_t); + else if (hflag) + num = (short)va_arg(ap, int); + else if (cflag) + num = (char)va_arg(ap, int); + else + num = va_arg(ap, int); +number: + if (sign && (intmax_t)num < 0) { + neg = 1; + num = -(intmax_t)num; + } + p = ksprintn(nbuf, num, base, &n, upper); + tmp = 0; + if (sharpflag && num != 0) { + if (base == 8) + tmp++; + else if (base == 16) + tmp += 2; + } + if (neg) + tmp++; + + if (!ladjust && padc == '0') + dwidth = width - tmp; + width -= tmp + imax(dwidth, n); + dwidth -= n; + if (!ladjust) + while (width-- > 0) + PCHAR(' '); + if (neg) + PCHAR('-'); + if (sharpflag && num != 0) { + if (base == 8) { + PCHAR('0'); + } else if (base == 16) { + PCHAR('0'); + PCHAR('x'); + } + } + while (dwidth-- > 0) + PCHAR('0'); + + while (*p) + PCHAR(*p--); + + if (ladjust) + while (width-- > 0) + PCHAR(' '); + + break; + default: + while (percent < fmt) + PCHAR(*percent++); + /* + * Since we ignore an formatting argument it is no + * longer safe to obey the remaining formatting + * arguments as the arguments will no longer match + * the format specs. + */ + stop = 1; + break; + } + } +#undef PCHAR +} + +int +rtld_snprintf(char *buf, size_t bufsize, const char *fmt, ...) +{ + va_list ap; + int retval; + + va_start(ap, fmt); + retval = rtld_vsnprintf(buf, bufsize, fmt, ap); + va_end(ap); + return (retval); +} + +int +rtld_vsnprintf(char *buf, size_t bufsize, const char *fmt, va_list ap) +{ + struct snprintf_arg info; + int retval; + + info.method = PRINT_METHOD_SNPRINTF; + info.buf = info.str = buf; + info.buf_total = info.remain = bufsize; + info.fd = -1; + retval = kvprintf(fmt, &info, 10, ap); + if (info.remain >= 1) + *info.str++ = '\0'; + return (retval); +} + +int +rtld_vfdprintf(int fd, const char *fmt, va_list ap) +{ + char buf[512]; + struct snprintf_arg info; + int retval; + + info.method = PRINT_METHOD_WRITE; + info.buf = info.str = buf; + info.buf_total = info.remain = sizeof(buf); + info.fd = fd; + retval = kvprintf(fmt, &info, 10, ap); + printf_out(&info); + return (retval); +} + +int +rtld_fdprintf(int fd, const char *fmt, ...) +{ + va_list ap; + int retval; + + va_start(ap, fmt); + retval = rtld_vfdprintf(fd, fmt, ap); + va_end(ap); + return (retval); +} + +void +rtld_fdputstr(int fd, const char *str) +{ + + write(fd, str, strlen(str)); +} + +void +rtld_fdputchar(int fd, int c) +{ + char c1; + + c1 = c; + write(fd, &c1, 1); +} diff --git a/libexec/rtld-elf/rtld_utrace.h b/libexec/rtld-elf/rtld_utrace.h new file mode 100644 index 0000000..58d4da1 --- /dev/null +++ b/libexec/rtld-elf/rtld_utrace.h @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2007 John Baldwin + * + * 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. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/rtld_utrace.h 304453 2016-08-19 08:00:48Z kib $ + */ + +#ifndef RTLD_UTRACE_H +#define RTLD_UTRACE_H + +#include + +#define UTRACE_DLOPEN_START 1 +#define UTRACE_DLOPEN_STOP 2 +#define UTRACE_DLCLOSE_START 3 +#define UTRACE_DLCLOSE_STOP 4 +#define UTRACE_LOAD_OBJECT 5 +#define UTRACE_UNLOAD_OBJECT 6 +#define UTRACE_ADD_RUNDEP 7 +#define UTRACE_PRELOAD_FINISHED 8 +#define UTRACE_INIT_CALL 9 +#define UTRACE_FINI_CALL 10 +#define UTRACE_DLSYM_START 11 +#define UTRACE_DLSYM_STOP 12 + +#define RTLD_UTRACE_SIG_SZ 4 +#define RTLD_UTRACE_SIG "RTLD" + +struct utrace_rtld { + char sig[RTLD_UTRACE_SIG_SZ]; + int event; + void *handle; + void *mapbase; /* Used for 'parent' and 'init/fini' */ + size_t mapsize; + int refcnt; /* Used for 'mode' */ + char name[MAXPATHLEN]; +}; + +#endif diff --git a/libexec/rtld-elf/sparc64/Makefile.inc b/libexec/rtld-elf/sparc64/Makefile.inc new file mode 100644 index 0000000..60d9bbb --- /dev/null +++ b/libexec/rtld-elf/sparc64/Makefile.inc @@ -0,0 +1 @@ +# $FreeBSD: releng/11.1/libexec/rtld-elf/sparc64/Makefile.inc 92195 2002-03-13 02:40:39Z jake $ diff --git a/libexec/rtld-elf/sparc64/reloc.c b/libexec/rtld-elf/sparc64/reloc.c new file mode 100644 index 0000000..1efaa11 --- /dev/null +++ b/libexec/rtld-elf/sparc64/reloc.c @@ -0,0 +1,862 @@ +/* $NetBSD: mdreloc.c,v 1.42 2008/04/28 20:23:04 martin Exp $ */ + +/*- + * 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. + * + * 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. + */ + +#include +__FBSDID("$FreeBSD: releng/11.1/libexec/rtld-elf/sparc64/reloc.c 316135 2017-03-29 11:03:08Z kib $"); + +#include +#include + +#include +#include +#include +#include +#include + +#include "debug.h" +#include "rtld.h" + +/* + * 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_X 0x02000000 /* Bare symbols, needs proc */ +#define _RF_D 0x01000000 /* Use dynamic TLS offset */ +#define _RF_O 0x00800000 /* Use static TLS offset */ +#define _RF_I 0x00400000 /* Use TLS object ID */ +#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */ +#define _RF_RS(s) ( (s) & 0xff) /* right shift */ +static const int reloc_target_flags[] = { + 0, /* NONE */ + _RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0), /* 8 */ + _RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0), /* 16 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 32 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(8) | _RF_RS(0), /* DISP_8 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(16) | _RF_RS(0), /* DISP_16 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* DISP_32 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_30 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_22 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(10), /* HI22 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 22 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 13 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* LO10 */ + _RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT10 */ + _RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT13 */ + _RF_G| _RF_SZ(32) | _RF_RS(10), /* GOT22 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PC10 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PC22 */ + _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WPLT30 */ + _RF_SZ(32) | _RF_RS(0), /* COPY */ + _RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* GLOB_DAT */ + _RF_SZ(32) | _RF_RS(0), /* JMP_SLOT */ + _RF_A| _RF_B| _RF_SZ(64) | _RF_RS(0), /* RELATIVE */ + _RF_S|_RF_A| _RF_U| _RF_SZ(32) | _RF_RS(0), /* UA_32 */ + + _RF_A| _RF_SZ(32) | _RF_RS(0), /* PLT32 */ + _RF_A| _RF_SZ(32) | _RF_RS(10), /* HIPLT22 */ + _RF_A| _RF_SZ(32) | _RF_RS(0), /* LOPLT10 */ + _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PCPLT32 */ + _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PCPLT22 */ + _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PCPLT10 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 10 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 11 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(64) | _RF_RS(0), /* 64 */ + _RF_S|_RF_A|/*extra*/ _RF_SZ(32) | _RF_RS(0), /* OLO10 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(42), /* HH22 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(32), /* HM10 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(10), /* LM22 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(42), /* PC_HH22 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(32), /* PC_HM10 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PC_LM22 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP16 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP19 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GLOB_JMP */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 7 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 5 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 6 */ + _RF_S|_RF_A|_RF_P| _RF_SZ(64) | _RF_RS(0), /* DISP64 */ + _RF_A| _RF_SZ(64) | _RF_RS(0), /* PLT64 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(10), /* HIX22 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* LOX10 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(22), /* H44 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(12), /* M44 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* L44 */ + _RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* REGISTER */ + _RF_S|_RF_A| _RF_U| _RF_SZ(64) | _RF_RS(0), /* UA64 */ + _RF_S|_RF_A| _RF_U| _RF_SZ(16) | _RF_RS(0), /* UA16 */ + + /* TLS */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* GD_HI22 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GD_LO10 */ + 0, /* GD_ADD */ + _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* GD_CALL */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* LDM_HI22 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LDM_LO10 */ + 0, /* LDM_ADD */ + _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* LDM_CALL */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* LDO_HIX22 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LDO_LOX10 */ + 0, /* LDO_ADD */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* IE_HI22 */ + _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* IE_LO10 */ + 0, /* IE_LD */ + 0, /* IE_LDX */ + 0, /* IE_ADD */ + _RF_S|_RF_A| _RF_O| _RF_SZ(32) | _RF_RS(10), /* LE_HIX22 */ + _RF_S|_RF_A| _RF_O| _RF_SZ(32) | _RF_RS(0), /* LE_LOX10 */ + _RF_S| _RF_I| _RF_SZ(32) | _RF_RS(0), /* DTPMOD32 */ + _RF_S| _RF_I| _RF_SZ(64) | _RF_RS(0), /* DTPMOD64 */ + _RF_S|_RF_A| _RF_D| _RF_SZ(32) | _RF_RS(0), /* DTPOFF32 */ + _RF_S|_RF_A| _RF_D| _RF_SZ(64) | _RF_RS(0), /* DTPOFF64 */ + _RF_S|_RF_A| _RF_O| _RF_SZ(32) | _RF_RS(0), /* TPOFF32 */ + _RF_S|_RF_A| _RF_O| _RF_SZ(64) | _RF_RS(0) /* TPOFF64 */ +}; + +#if 0 +static const char *const reloc_names[] = { + "NONE", "8", "16", "32", "DISP_8", "DISP_16", "DISP_32", "WDISP_30", + "WDISP_22", "HI22", "22", "13", "LO10", "GOT10", "GOT13", "GOT22", + "PC10", "PC22", "WPLT30", "COPY", "GLOB_DAT", "JMP_SLOT", "RELATIVE", + "UA_32", "PLT32", "HIPLT22", "LOPLT10", "LOPLT10", "PCPLT22", + "PCPLT32", "10", "11", "64", "OLO10", "HH22", "HM10", "LM22", + "PC_HH22", "PC_HM10", "PC_LM22", "WDISP16", "WDISP19", "GLOB_JMP", + "7", "5", "6", "DISP64", "PLT64", "HIX22", "LOX10", "H44", "M44", + "L44", "REGISTER", "UA64", "UA16", "GD_HI22", "GD_LO10", "GD_ADD", + "GD_CALL", "LDM_HI22", "LDMO10", "LDM_ADD", "LDM_CALL", "LDO_HIX22", + "LDO_LOX10", "LDO_ADD", "IE_HI22", "IE_LO10", "IE_LD", "IE_LDX", + "IE_ADD", "LE_HIX22", "LE_LOX10", "DTPMOD32", "DTPMOD64", "DTPOFF32", + "DTPOFF64", "TPOFF32", "TPOFF64" +}; +#endif + +#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_BARE_SYMBOL(t) ((reloc_target_flags[t] & _RF_X) != 0) +#define RELOC_USE_TLS_DOFF(t) ((reloc_target_flags[t] & _RF_D) != 0) +#define RELOC_USE_TLS_OFF(t) ((reloc_target_flags[t] & _RF_O) != 0) +#define RELOC_USE_TLS_ID(t) ((reloc_target_flags[t] & _RF_I) != 0) +#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff) +#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff) + +static const long reloc_target_bitmask[] = { +#define _BM(x) (~(-(1ULL << (x)))) + 0, /* NONE */ + _BM(8), _BM(16), _BM(32), /* 8, 16, 32 */ + _BM(8), _BM(16), _BM(32), /* DISP8, DISP16, DISP32 */ + _BM(30), _BM(22), /* WDISP30, WDISP22 */ + _BM(22), _BM(22), /* HI22, 22 */ + _BM(13), _BM(10), /* 13, LO10 */ + _BM(10), _BM(13), _BM(22), /* GOT10, GOT13, GOT22 */ + _BM(10), _BM(22), /* PC10, PC22 */ + _BM(30), 0, /* WPLT30, COPY */ + _BM(32), _BM(32), _BM(32), /* GLOB_DAT, JMP_SLOT, RELATIVE */ + _BM(32), _BM(32), /* UA32, PLT32 */ + _BM(22), _BM(10), /* HIPLT22, LOPLT10 */ + _BM(32), _BM(22), _BM(10), /* PCPLT32, PCPLT22, PCPLT10 */ + _BM(10), _BM(11), -1, /* 10, 11, 64 */ + _BM(13), _BM(22), /* OLO10, HH22 */ + _BM(10), _BM(22), /* HM10, LM22 */ + _BM(22), _BM(10), _BM(22), /* PC_HH22, PC_HM10, PC_LM22 */ + _BM(16), _BM(19), /* WDISP16, WDISP19 */ + -1, /* GLOB_JMP */ + _BM(7), _BM(5), _BM(6), /* 7, 5, 6 */ + -1, -1, /* DISP64, PLT64 */ + _BM(22), _BM(13), /* HIX22, LOX10 */ + _BM(22), _BM(10), _BM(13), /* H44, M44, L44 */ + -1, -1, _BM(16), /* REGISTER, UA64, UA16 */ + _BM(22), _BM(10), 0, _BM(30), /* GD_HI22, GD_LO10, GD_ADD, GD_CALL */ + _BM(22), _BM(10), 0, /* LDM_HI22, LDMO10, LDM_ADD */ + _BM(30), /* LDM_CALL */ + _BM(22), _BM(10), 0, /* LDO_HIX22, LDO_LOX10, LDO_ADD */ + _BM(22), _BM(10), 0, 0, /* IE_HI22, IE_LO10, IE_LD, IE_LDX */ + 0, /* IE_ADD */ + _BM(22), _BM(13), /* LE_HIX22, LE_LOX10 */ + _BM(32), -1, /* DTPMOD32, DTPMOD64 */ + _BM(32), -1, /* DTPOFF32, DTPOFF64 */ + _BM(32), -1 /* TPOFF32, TPOFF64 */ +#undef _BM +}; +#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t]) + +#undef flush +#define flush(va, offs) \ + __asm __volatile("flush %0 + %1" : : "r" (va), "I" (offs)); + +static int reloc_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela, + SymCache *cache, int flags, RtldLockState *lockstate); +static void install_plt(Elf_Word *pltgot, Elf_Addr proc); + +extern char _rtld_bind_start_0[]; +extern char _rtld_bind_start_1[]; + +int +do_copy_relocations(Obj_Entry *dstobj) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + const Elf_Sym *dstsym; + const Elf_Sym *srcsym; + void *dstaddr; + const void *srcaddr; + const Obj_Entry *srcobj, *defobj; + SymLook req; + const char *name; + size_t size; + int res; + + assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */ + + relalim = (const Elf_Rela *)((caddr_t)dstobj->rela + dstobj->relasize); + for (rela = dstobj->rela; rela < relalim; rela++) { + if (ELF_R_TYPE(rela->r_info) == R_SPARC_COPY) { + dstaddr = (void *)(dstobj->relocbase + rela->r_offset); + dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); + name = dstobj->strtab + dstsym->st_name; + size = dstsym->st_size; + symlook_init(&req, name); + req.ventry = fetch_ventry(dstobj, + ELF_R_SYM(rela->r_info)); + req.flags = SYMLOOK_EARLY; + + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { + res = symlook_obj(&req, srcobj); + if (res == 0) { + srcsym = req.sym_out; + defobj = req.defobj_out; + break; + } + } + if (srcobj == NULL) { + _rtld_error("Undefined symbol \"%s\"" + "referenced from COPY relocation" + "in %s", name, dstobj->path); + return (-1); + } + + srcaddr = (const void *)(defobj->relocbase + + srcsym->st_value); + memcpy(dstaddr, srcaddr, size); + } + } + + return (0); +} + +int +reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, + RtldLockState *lockstate) +{ + const Elf_Rela *relalim; + const Elf_Rela *rela; + SymCache *cache; + int r = -1; + + if ((flags & SYMLOOK_IFUNC) != 0) + /* XXX not implemented */ + return (0); + + /* + * The dynamic loader may be called from a thread, we have + * limited amounts of stack available so we cannot use alloca(). + */ + if (obj != obj_rtld) { + cache = calloc(obj->dynsymcount, sizeof(SymCache)); + /* No need to check for NULL here */ + } else + cache = NULL; + + relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize); + for (rela = obj->rela; rela < relalim; rela++) { + if (reloc_nonplt_object(obj, rela, cache, flags, lockstate) < 0) + goto done; + } + r = 0; +done: + if (cache != NULL) + free(cache); + return (r); +} + +static int +reloc_nonplt_object(Obj_Entry *obj, const Elf_Rela *rela, SymCache *cache, + int flags, RtldLockState *lockstate) +{ + const Obj_Entry *defobj; + const Elf_Sym *def; + Elf_Addr *where; + Elf_Word *where32; + Elf_Word type; + Elf_Addr value; + Elf_Addr mask; + + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + where32 = (Elf_Word *)where; + defobj = NULL; + def = NULL; + + type = ELF64_R_TYPE_ID(rela->r_info); + if (type == R_SPARC_NONE) + return (0); + + /* We do JMP_SLOTs below. */ + if (type == R_SPARC_JMP_SLOT) + return (0); + + /* COPY relocs are also handled elsewhere. */ + if (type == R_SPARC_COPY) + return (0); + + /* Ignore ADD and CALL relocations for dynamic TLS references. */ + if (type == R_SPARC_TLS_GD_ADD || type == R_SPARC_TLS_GD_CALL || + type == R_SPARC_TLS_LDM_ADD || type == R_SPARC_TLS_LDM_CALL || + type == R_SPARC_TLS_LDO_ADD) + return (0); + + /* + * Note: R_SPARC_TLS_TPOFF64 must be the numerically largest + * relocation type. + */ + if (type >= sizeof(reloc_target_bitmask) / + sizeof(*reloc_target_bitmask)) { + _rtld_error("%s: Unsupported relocation type %d in non-PLT " + "object\n", obj->path, type); + return (-1); + } + + value = rela->r_addend; + + /* + * Handle relative relocs here, because we might not be able to access + * globals yet. + */ + if (type == R_SPARC_RELATIVE) { + /* XXXX -- apparently we ignore the preexisting value. */ + *where = (Elf_Addr)(obj->relocbase + value); + return (0); + } + + /* + * If we get here while relocating rtld itself, we will crash because + * a non-local variable is accessed. + */ + if (RELOC_RESOLVE_SYMBOL(type)) { + /* Find the symbol. */ + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, + flags, cache, lockstate); + if (def == NULL) + return (-1); + + if (RELOC_USE_TLS_ID(type)) + value = (Elf_Addr)defobj->tlsindex; + else if (RELOC_USE_TLS_DOFF(type)) + value += (Elf_Addr)def->st_value; + else if (RELOC_USE_TLS_OFF(type)) { + /* + * We lazily allocate offsets for static TLS as we + * see the first relocation that references the TLS + * block. This allows us to support (small amounts + * of) static TLS in dynamically loaded modules. If + * we run out of space, we generate an error. + */ + if (!defobj->tls_done && + !allocate_tls_offset((Obj_Entry*)defobj)) { + _rtld_error("%s: No space available for " + "static Thread Local Storage", obj->path); + return (-1); + } + value += (Elf_Addr)(def->st_value - + defobj->tlsoffset); + } else { + /* Add in the symbol's absolute address. */ + value += (Elf_Addr)(def->st_value + + defobj->relocbase); + } + } + + if (type == R_SPARC_OLO10) + value = (value & 0x3ff) + ELF64_R_TYPE_DATA(rela->r_info); + + if (type == R_SPARC_HIX22 || type == R_SPARC_TLS_LE_HIX22) + value ^= 0xffffffffffffffff; + + if (RELOC_PC_RELATIVE(type)) + value -= (Elf_Addr)where; + + if (RELOC_BASE_RELATIVE(type)) { + /* + * Note that even though sparcs use `Elf_rela' exclusively + * we still need the implicit memory addend in relocations + * referring to GOT entries. Undoubtedly, someone f*cked + * this up in the distant past, and now we're stuck with + * it in the name of compatibility for all eternity ... + * + * In any case, the implicit and explicit should be mutually + * exclusive. We provide a check for that here. + */ + /* XXXX -- apparently we ignore the preexisting value */ + value += (Elf_Addr)(obj->relocbase); + } + + mask = RELOC_VALUE_BITMASK(type); + value >>= RELOC_VALUE_RIGHTSHIFT(type); + value &= mask; + + if (type == R_SPARC_LOX10 || type == R_SPARC_TLS_LE_LOX10) + value |= 0x1c00; + + if (RELOC_UNALIGNED(type)) { + /* Handle unaligned relocations. */ + Elf_Addr tmp; + char *ptr; + int size; + int i; + + size = RELOC_TARGET_SIZE(type) / 8; + ptr = (char *)where; + tmp = 0; + + /* 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 >> ((size - i - 1) * 8)) & 0xff); + } else if (RELOC_TARGET_SIZE(type) > 32) { + *where &= ~mask; + *where |= value; + } else { + *where32 &= ~mask; + *where32 |= value; + } + + return (0); +} + +int +reloc_plt(Obj_Entry *obj) +{ +#if 0 + const Obj_Entry *defobj; + const Elf_Rela *relalim; + const Elf_Rela *rela; + const Elf_Sym *def; + Elf_Addr *where; + Elf_Addr value; + + relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); + for (rela = obj->pltrela; rela < relalim; rela++) { + if (rela->r_addend == 0) + continue; + assert(ELF64_R_TYPE_ID(rela->r_info) == R_SPARC_JMP_SLOT); + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, + SYMLOOK_IN_PLT, NULL, lockstate); + value = (Elf_Addr)(defobj->relocbase + def->st_value); + *where = value; + } +#endif + return (0); +} + +/* + * Instruction templates: + */ +#define BAA 0x10400000 /* ba,a %xcc, 0 */ +#define SETHI 0x03000000 /* sethi %hi(0), %g1 */ +#define JMP 0x81c06000 /* jmpl %g1+%lo(0), %g0 */ +#define NOP 0x01000000 /* sethi %hi(0), %g0 */ +#define OR 0x82806000 /* or %g1, 0, %g1 */ +#define XOR 0x82c06000 /* xor %g1, 0, %g1 */ +#define MOV71 0x8283a000 /* or %o7, 0, %g1 */ +#define MOV17 0x9c806000 /* or %g1, 0, %o7 */ +#define CALL 0x40000000 /* call 0 */ +#define SLLX 0x8b407000 /* sllx %g1, 0, %g1 */ +#define SETHIG5 0x0b000000 /* sethi %hi(0), %g5 */ +#define ORG5 0x82804005 /* or %g1, %g5, %g1 */ + +/* %hi(v) with variable shift */ +#define HIVAL(v, s) (((v) >> (s)) & 0x003fffff) +#define LOVAL(v) ((v) & 0x000003ff) + +int +reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) +{ + const Obj_Entry *defobj; + const Elf_Rela *relalim; + const Elf_Rela *rela; + const Elf_Sym *def; + Elf_Addr *where; + Elf_Addr target; + + relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); + for (rela = obj->pltrela; rela < relalim; rela++) { + assert(ELF64_R_TYPE_ID(rela->r_info) == R_SPARC_JMP_SLOT); + where = (Elf_Addr *)(obj->relocbase + rela->r_offset); + def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, + SYMLOOK_IN_PLT | flags, NULL, lockstate); + if (def == NULL) + return -1; + target = (Elf_Addr)(defobj->relocbase + def->st_value); + reloc_jmpslot(where, target, defobj, obj, (Elf_Rel *)rela); + } + obj->jmpslots_done = true; + return (0); +} + +int +reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +int +reloc_gnu_ifunc(Obj_Entry *obj, int flags, + struct Struct_RtldLockState *lockstate) +{ + + /* XXX not implemented */ + return (0); +} + +Elf_Addr +reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *obj, + const Obj_Entry *refobj, const Elf_Rel *rel) +{ + const Elf_Rela *rela = (const Elf_Rela *)rel; + Elf_Addr offset; + Elf_Word *where; + + if (ld_bind_not) { + /* Skip any PLT modifications */ + } else if (rela - refobj->pltrela < 32764) { + /* + * At the PLT entry pointed at by `where', we now construct + * a direct transfer to the now fully resolved function + * address. + * + * A PLT entry is supposed to start by looking like this: + * + * sethi (. - .PLT0), %g1 + * ba,a %xcc, .PLT1 + * nop + * nop + * nop + * nop + * nop + * nop + * + * When we replace these entries we start from the second + * entry and do it in reverse order so the last thing we + * do is replace the branch. That allows us to change this + * atomically. + * + * We now need to find out how far we need to jump. We + * have a choice of several different relocation techniques + * which are increasingly expensive. + */ + where = (Elf_Word *)wherep; + offset = ((Elf_Addr)where) - target; + if (offset <= (1L<<20) && offset >= -(1L<<20)) { + /* + * We're within 1MB -- we can use a direct branch + * instruction. + * + * We can generate this pattern: + * + * sethi %hi(. - .PLT0), %g1 + * ba,a %xcc, addr + * nop + * nop + * nop + * nop + * nop + * nop + * + */ + where[1] = BAA | ((offset >> 2) &0x3fffff); + flush(where, 4); + } else if (target >= 0 && target < (1L<<32)) { + /* + * We're within 32-bits of address zero. + * + * The resulting code in the jump slot is: + * + * sethi %hi(. - .PLT0), %g1 + * sethi %hi(addr), %g1 + * jmp %g1+%lo(addr) + * nop + * nop + * nop + * nop + * nop + * + */ + where[2] = JMP | LOVAL(target); + flush(where, 8); + where[1] = SETHI | HIVAL(target, 10); + flush(where, 4); + } else if (target <= 0 && target > -(1L<<32)) { + /* + * We're within 32-bits of address -1. + * + * The resulting code in the jump slot is: + * + * sethi %hi(. - .PLT0), %g1 + * sethi %hix(addr), %g1 + * xor %g1, %lox(addr), %g1 + * jmp %g1 + * nop + * nop + * nop + * nop + * + */ + where[3] = JMP; + flush(where, 12); + where[2] = XOR | ((~target) & 0x00001fff); + flush(where, 8); + where[1] = SETHI | HIVAL(~target, 10); + flush(where, 4); + } else if (offset <= (1L<<32) && offset >= -((1L<<32) - 4)) { + /* + * We're within 32-bits -- we can use a direct call + * insn + * + * The resulting code in the jump slot is: + * + * sethi %hi(. - .PLT0), %g1 + * mov %o7, %g1 + * call (.+offset) + * mov %g1, %o7 + * nop + * nop + * nop + * nop + * + */ + where[3] = MOV17; + flush(where, 12); + where[2] = CALL | ((offset >> 4) & 0x3fffffff); + flush(where, 8); + where[1] = MOV71; + flush(where, 4); + } else if (offset >= 0 && offset < (1L<<44)) { + /* + * We're within 44 bits. We can generate this + * pattern: + * + * The resulting code in the jump slot is: + * + * sethi %hi(. - .PLT0), %g1 + * sethi %h44(addr), %g1 + * or %g1, %m44(addr), %g1 + * sllx %g1, 12, %g1 + * jmp %g1+%l44(addr) + * nop + * nop + * nop + * + */ + where[4] = JMP | LOVAL(offset); + flush(where, 16); + where[3] = SLLX | 12; + flush(where, 12); + where[2] = OR | (((offset) >> 12) & 0x00001fff); + flush(where, 8); + where[1] = SETHI | HIVAL(offset, 22); + flush(where, 4); + } else if (offset < 0 && offset > -(1L<<44)) { + /* + * We're within 44 bits. We can generate this + * pattern: + * + * The resulting code in the jump slot is: + * + * sethi %hi(. - .PLT0), %g1 + * sethi %h44(-addr), %g1 + * xor %g1, %m44(-addr), %g1 + * sllx %g1, 12, %g1 + * jmp %g1+%l44(addr) + * nop + * nop + * nop + * + */ + where[4] = JMP | LOVAL(offset); + flush(where, 16); + where[3] = SLLX | 12; + flush(where, 12); + where[2] = XOR | (((~offset) >> 12) & 0x00001fff); + flush(where, 8); + where[1] = SETHI | HIVAL(~offset, 22); + flush(where, 4); + } else { + /* + * We need to load all 64-bits + * + * The resulting code in the jump slot is: + * + * sethi %hi(. - .PLT0), %g1 + * sethi %hh(addr), %g1 + * sethi %lm(addr), %g5 + * or %g1, %hm(addr), %g1 + * sllx %g1, 32, %g1 + * or %g1, %g5, %g1 + * jmp %g1+%lo(addr) + * nop + * + */ + where[6] = JMP | LOVAL(target); + flush(where, 24); + where[5] = ORG5; + flush(where, 20); + where[4] = SLLX | 32; + flush(where, 16); + where[3] = OR | LOVAL((target) >> 32); + flush(where, 12); + where[2] = SETHIG5 | HIVAL(target, 10); + flush(where, 8); + where[1] = SETHI | HIVAL(target, 42); + flush(where, 4); + } + } else { + /* + * This is a high PLT slot; the relocation offset specifies a + * pointer that needs to be frobbed; no actual code needs to + * be modified. The pointer to be calculated needs the addend + * added and the reference object relocation base subtraced. + */ + *wherep = target + rela->r_addend - + (Elf_Addr)refobj->relocbase; + } + + return (target); +} + +void +ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) +{ +} + +/* + * Install rtld function call into this PLT slot. + */ +#define SAVE 0x9de3bf50 +#define SETHI_l0 0x21000000 +#define SETHI_l1 0x23000000 +#define OR_l0_l0 0xa0142000 +#define SLLX_l0_32_l0 0xa12c3020 +#define OR_l0_l1_l0 0xa0140011 +#define JMPL_l0_o1 0x93c42000 +#define MOV_g1_o0 0x90100001 + +void +init_pltgot(Obj_Entry *obj) +{ + Elf_Word *entry; + + if (obj->pltgot != NULL) { + entry = (Elf_Word *)obj->pltgot; + install_plt(&entry[0], (Elf_Addr)_rtld_bind_start_0); + install_plt(&entry[8], (Elf_Addr)_rtld_bind_start_1); + obj->pltgot[8] = (Elf_Addr)obj; + } +} + +static void +install_plt(Elf_Word *pltgot, Elf_Addr proc) +{ + pltgot[0] = SAVE; + flush(pltgot, 0); + pltgot[1] = SETHI_l0 | HIVAL(proc, 42); + flush(pltgot, 4); + pltgot[2] = SETHI_l1 | HIVAL(proc, 10); + flush(pltgot, 8); + pltgot[3] = OR_l0_l0 | LOVAL((proc) >> 32); + flush(pltgot, 12); + pltgot[4] = SLLX_l0_32_l0; + flush(pltgot, 16); + pltgot[5] = OR_l0_l1_l0; + flush(pltgot, 20); + pltgot[6] = JMPL_l0_o1 | LOVAL(proc); + flush(pltgot, 24); + pltgot[7] = MOV_g1_o0; + flush(pltgot, 28); +} + +void +allocate_initial_tls(Obj_Entry *objs) +{ + Elf_Addr* tpval; + + /* + * Fix the size of the static TLS block by using the maximum offset + * allocated so far and adding a bit for dynamic modules to use. + */ + tls_static_space = tls_last_offset + RTLD_STATIC_TLS_EXTRA; + tpval = allocate_tls(objs, NULL, 3 * sizeof(Elf_Addr), + sizeof(Elf_Addr)); + __asm __volatile("mov %0, %%g7" : : "r" (tpval)); +} + +void *__tls_get_addr(tls_index *ti) +{ + register Elf_Addr** tp __asm__("%g7"); + + return (tls_get_addr_common(tp, ti->ti_module, ti->ti_offset)); +} diff --git a/libexec/rtld-elf/sparc64/rtld_machdep.h b/libexec/rtld-elf/sparc64/rtld_machdep.h new file mode 100644 index 0000000..140a0a2 --- /dev/null +++ b/libexec/rtld-elf/sparc64/rtld_machdep.h @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 1999, 2000 John D. Polstra. + * 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 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 AUTHOR 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/sparc64/rtld_machdep.h 316135 2017-03-29 11:03:08Z kib $ + */ + +#ifndef RTLD_MACHDEP_H +#define RTLD_MACHDEP_H 1 + +#include +#include + +struct Struct_Obj_Entry; + +/* Return the address of the .dynamic section in the dynamic linker. */ +Elf_Dyn *rtld_dynamic_addr(void); +#define rtld_dynamic(obj) rtld_dynamic_addr() + +Elf_Addr reloc_jmpslot(Elf_Addr *, Elf_Addr, + const struct Struct_Obj_Entry *, const struct Struct_Obj_Entry *, + const Elf_Rel *); + +#define make_function_pointer(def, defobj) \ + ((defobj)->relocbase + (def)->st_value) + +#define call_initfini_pointer(obj, target) \ + (((InitFunc)(target))()) + +#define call_init_pointer(obj, target) \ + (((InitArrFunc)(target))(main_argc, main_argv, environ)) + +#define call_ifunc_resolver(ptr) \ + (((Elf_Addr (*)(void))ptr)()) + +#define round(size, align) \ + (((size) + (align) - 1) & ~((align) - 1)) +#define calculate_first_tls_offset(size, align) \ + round(size, align) +#define calculate_tls_offset(prev_offset, prev_size, size, align) \ + round((prev_offset) + (size), align) +#define calculate_tls_end(off, size) ((off) + (size)) + +typedef struct { + unsigned long ti_module; + unsigned long ti_offset; +} tls_index; + +extern void *__tls_get_addr(tls_index *ti); + +#define RTLD_DEFAULT_STACK_PF_EXEC 0 +#define RTLD_DEFAULT_STACK_EXEC 0 + +#define md_abi_variant_hook(x) + +#endif diff --git a/libexec/rtld-elf/sparc64/rtld_start.S b/libexec/rtld-elf/sparc64/rtld_start.S new file mode 100644 index 0000000..48871ae --- /dev/null +++ b/libexec/rtld-elf/sparc64/rtld_start.S @@ -0,0 +1,170 @@ +/* $NetBSD: rtld_start.S,v 1.5 2001/08/14 22:17:48 eeh Exp $ */ + +/*- + * Copyright (c) 2001 Jake Burkholder. + * 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 Christos Zoulas and 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/sparc64/rtld_start.S 130661 2004-06-18 02:01:37Z tmm $ + */ + +#include + +/* + * ELF: + * On startup the stack should contain 16 extended word register save + * area, followed by the arg count, etc. + */ + +ENTRY(.rtld_start) + clr %fp + mov %o0, %l0 + mov %o3, %l1 + + sub %sp, 16, %sp + add %sp, SPOFF + CCFSZ + 0x0, %o1 + call _rtld + add %sp, SPOFF + CCFSZ + 0x8, %o2 + + ldx [%sp + SPOFF + CCFSZ + 0x0], %o1 + ldx [%sp + SPOFF + CCFSZ + 0x8], %o2 + add %sp, 16, %sp + + mov %l1, %o3 + jmp %o0 + mov %l0, %o0 +END(.rtld_start) + +/* + * Find the address of _DYNAMIC by disassembling a call instruction to it. + * Binutils may not fill in the GOT as expected on other architectures. + */ +.weak _DYNAMIC + +ENTRY(rtld_dynamic_addr) + save %sp, -CCFSZ, %sp + call 1f + nop + call _DYNAMIC + 8 +1: lduw [%o7 + 8], %o0 + sll %o0, 2, %o0 + sra %o0, 0, %o0 + ret + restore %o0, %o7, %o0 +END(rtld_dynamic_addr) + + /* + * 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 + * PLT entries above 32768. + * + * _rtld_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: + * + * n = x >> 15; + * + * and _rtld_bind_start_0(x, y) should do, according to the SCD: + * + * i = x - y - 1048596; + * n = 32768 + (i/5120)*160 + (i%5120)/24; + * + * Note that the number of 1048596 from above is incorrect; rather, + * we need to use HIPLTOFFS as defined below. + * + * Neither routine needs to issue a save since it's already been + * done in the PLT entry. + */ + +#define NPLTLOSLOTS 32768 +#define PLTSLOTSZ 32 +/* + * - 16 to compensate for the difference of the positions of the jumps that + * generate the arguments in .PLT0 and the high plt entry. + */ +#define HIPLTOFFS (NPLTLOSLOTS * PLTSLOTSZ - 16) + +ENTRY(_rtld_bind_start_0) + sethi %hi(HIPLTOFFS), %l1 + or %l1, %lo(HIPLTOFFS), %l1 + sub %o0, %o1, %l0 /* x - y */ + sub %l0, %l1, %l0 /* i = x - y - HIPLTOFFS */ + sethi %hi(5120), %l7 + sdivx %l0, %l7, %l1 /* Calculate i / 5120 */ + mulx %l1, %l7, %l3 + sub %l0, %l3, %l2 /* And i % 5120 */ + mulx %l1, 160, %l5 /* (i / 5120) * 160 */ + sdivx %l2, 24, %l4 /* (i % 5120) / 24 */ + sethi %hi(NPLTLOSLOTS), %l6 + add %l4, %l5, %l4 /* (i / 5120) * 160 + (i % 5120) / 24 */ + add %l4, %l6, %l4 /* + NPLTLOSLOTS */ + sub %l4, 4, %l4 /* XXX: 4 entries are reserved */ + + sllx %l4, 1, %l5 /* Each element is an Elf_Rela which */ + add %l5, %l4, %l4 /* is 3 longwords or 24 bytes. */ + sllx %l4, 3, %l4 /* So multiply by 24. */ + + ldx [%o1 + (10*4)], %o0 /* Load object pointer from PLT2 */ + + call _rtld_bind /* Call _rtld_bind(obj, offset) */ + mov %l4, %o1 + + jmp %o0 /* return value == function address */ + restore /* Dump our stack frame */ +END(_rtld_bind_start_0) + +ENTRY(_rtld_bind_start_1) + srax %o0, 15, %o2 /* %o0 is the index to our PLT slot */ + sub %o2, 4, %o2 /* XXX: 4 entries are reserved */ + + sllx %o2, 1, %o3 /* Each element is an Elf_Rela which */ + add %o3, %o2, %o2 /* is 3 longwords or 24 bytes. */ + sllx %o2, 3, %o2 /* So multiply by 24. */ + + ldx [%o1 + 8], %o0 /* The object pointer is at [%o1 + 8] */ + + call _rtld_bind /* Call _rtld_bind(obj, offset) */ + mov %o2, %o1 + + jmp %o0 /* return value == function address */ + restore /* Dump our stack frame */ +END(_rtld_bind_start_1) diff --git a/libexec/rtld-elf/tests/Makefile b/libexec/rtld-elf/tests/Makefile new file mode 100644 index 0000000..29f3b6c --- /dev/null +++ b/libexec/rtld-elf/tests/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD: releng/11.1/libexec/rtld-elf/tests/Makefile 316388 2017-04-02 02:16:01Z asomers $ + +SUBDIR+= libpythagoras target + +SUBDIR_DEPEND_target= libpythagoras +ATF_TESTS_C= ld_library_pathfds +WARNS?= 3 + +.include diff --git a/libexec/rtld-elf/tests/Makefile.depend b/libexec/rtld-elf/tests/Makefile.depend new file mode 100644 index 0000000..e30c64b --- /dev/null +++ b/libexec/rtld-elf/tests/Makefile.depend @@ -0,0 +1,19 @@ +# $FreeBSD: releng/11.1/libexec/rtld-elf/tests/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + gnu/lib/csu \ + gnu/lib/libgcc \ + include \ + include/xlocale \ + lib/${CSU_DIR} \ + lib/atf/libatf-c \ + lib/libc \ + lib/libcompiler_rt \ + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/libexec/rtld-elf/tests/ld_library_pathfds.c b/libexec/rtld-elf/tests/ld_library_pathfds.c new file mode 100644 index 0000000..38cf8a2 --- /dev/null +++ b/libexec/rtld-elf/tests/ld_library_pathfds.c @@ -0,0 +1,221 @@ +/*- + * Copyright 2014 Jonathan Anderson. + * 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/tests/ld_library_pathfds.c 269504 2014-08-04 05:46:10Z ngie $ + */ + +#include +#include +#include + + +struct descriptors { + int binary; + int testdir; + int root; + int etc; + int usr; +}; + +static void setup(struct descriptors *, const atf_tc_t *); +static void expect_success(int binary, char *pathfds); +static void expect_missing_library(int binary, char *pathfds); + +static void try_to_run(int binary, int expected_exit_status, + char * const *env, const char *expected_out, const char *expected_err); +static int opendir(const char *name); +static int opendirat(int parent, const char *name); + + +ATF_TC_WITHOUT_HEAD(missing_library); +ATF_TC_BODY(missing_library, tc) +{ + struct descriptors files; + + setup(&files, tc); + expect_missing_library(files.binary, NULL); +} + + +ATF_TC_WITHOUT_HEAD(wrong_library_directories); +ATF_TC_BODY(wrong_library_directories, tc) +{ + struct descriptors files; + char *pathfds; + + setup(&files, tc); + ATF_REQUIRE( + asprintf(&pathfds, "LD_LIBRARY_PATH_FDS=%d", files.etc) > 0); + + expect_missing_library(files.binary, pathfds); +} + + +ATF_TC_WITHOUT_HEAD(bad_library_directories); +ATF_TC_BODY(bad_library_directories, tc) +{ + struct descriptors files; + char *pathfds; + + setup(&files, tc); + ATF_REQUIRE(asprintf(&pathfds, "LD_LIBRARY_PATH_FDS=::") > 0); + + expect_missing_library(files.binary, pathfds); +} + + +ATF_TC_WITHOUT_HEAD(single_library_directory); +ATF_TC_BODY(single_library_directory, tc) +{ + struct descriptors files; + char *pathfds; + + setup(&files, tc); + ATF_REQUIRE( + asprintf(&pathfds, "LD_LIBRARY_PATH_FDS=%d", files.testdir) > 0); + + expect_success(files.binary, pathfds); +} + + +ATF_TC_WITHOUT_HEAD(first_library_directory); +ATF_TC_BODY(first_library_directory, tc) +{ + struct descriptors files; + char *pathfds; + + setup(&files, tc); + ATF_REQUIRE( + asprintf(&pathfds, "LD_LIBRARY_PATH_FDS=%d:%d", + files.testdir, files.etc) > 0); + + expect_success(files.binary, pathfds); +} + + +ATF_TC_WITHOUT_HEAD(middle_library_directory); +ATF_TC_BODY(middle_library_directory, tc) +{ + struct descriptors files; + char *pathfds; + + setup(&files, tc); + ATF_REQUIRE( + asprintf(&pathfds, "LD_LIBRARY_PATH_FDS=%d:%d:%d", + files.root, files.testdir, files.usr) > 0); + + expect_success(files.binary, pathfds); +} + + +ATF_TC_WITHOUT_HEAD(last_library_directory); +ATF_TC_BODY(last_library_directory, tc) +{ + struct descriptors files; + char *pathfds; + + setup(&files, tc); + ATF_REQUIRE( + asprintf(&pathfds, "LD_LIBRARY_PATH_FDS=%d:%d", + files.root, files.testdir) > 0); + + expect_success(files.binary, pathfds); +} + + + +/* Register test cases with ATF. */ +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, missing_library); + ATF_TP_ADD_TC(tp, wrong_library_directories); + ATF_TP_ADD_TC(tp, bad_library_directories); + ATF_TP_ADD_TC(tp, single_library_directory); + ATF_TP_ADD_TC(tp, first_library_directory); + ATF_TP_ADD_TC(tp, middle_library_directory); + ATF_TP_ADD_TC(tp, last_library_directory); + + return atf_no_error(); +} + + +static void +setup(struct descriptors *dp, const atf_tc_t *tc) +{ + + dp->testdir = opendir(atf_tc_get_config_var(tc, "srcdir")); + ATF_REQUIRE(dp->testdir >= 0); + ATF_REQUIRE( + (dp->binary = openat(dp->testdir, "target", O_RDONLY)) >= 0); + + ATF_REQUIRE((dp->root = opendir("/")) >= 0); + ATF_REQUIRE((dp->etc = opendirat(dp->root, "etc")) >= 0); + ATF_REQUIRE((dp->usr = opendirat(dp->root, "usr")) >= 0); +} + +static void +expect_success(int binary, char *pathfds) +{ + char * const env[] = { pathfds, NULL }; + try_to_run(binary, 0, env, "the hypotenuse of 3 and 4 is 5\n", ""); +} + +static void +expect_missing_library(int binary, char *pathfds) +{ + char * const env[] = { pathfds, NULL }; + try_to_run(binary, 1, env, "", + "Shared object \"libpythagoras.so.0\" not found," + " required by \"target\"\n"); +} + + +static void +try_to_run(int binary, int exit_status, char * const *env, + const char *expected_out, const char *expected_err) +{ + pid_t child = atf_utils_fork(); + + if (child == 0) { + char * const args[] = { "target", NULL }; + + fexecve(binary, args, env); + atf_tc_fail("fexecve() failed"); + } + + atf_utils_wait(child, exit_status, expected_out, expected_err); +} + + +static int +opendir(const char *name) +{ + return open(name, O_RDONLY | O_DIRECTORY); +} + +static int +opendirat(int parent, const char *name) +{ + return openat(parent, name, O_RDONLY | O_DIRECTORY); +} diff --git a/libexec/rtld-elf/tests/libpythagoras/Makefile b/libexec/rtld-elf/tests/libpythagoras/Makefile new file mode 100644 index 0000000..5995add --- /dev/null +++ b/libexec/rtld-elf/tests/libpythagoras/Makefile @@ -0,0 +1,16 @@ +# $FreeBSD: releng/11.1/libexec/rtld-elf/tests/libpythagoras/Makefile 316388 2017-04-02 02:16:01Z asomers $ + +.include + +LIB= pythagoras +SHLIB_MAJOR= 0 + +LIBDIR= ${TESTSBASE}/libexec/rtld-elf +SHLIBDIR= ${TESTSBASE}/libexec/rtld-elf + +SRCS= pythagoras.c + +WARNS?= 6 +LIBADD= m + +.include diff --git a/libexec/rtld-elf/tests/libpythagoras/Makefile.depend b/libexec/rtld-elf/tests/libpythagoras/Makefile.depend new file mode 100644 index 0000000..fb50b4b --- /dev/null +++ b/libexec/rtld-elf/tests/libpythagoras/Makefile.depend @@ -0,0 +1,18 @@ +# $FreeBSD: releng/11.1/libexec/rtld-elf/tests/libpythagoras/Makefile.depend 311183 2017-01-03 22:51:40Z bdrewery $ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + gnu/lib/csu \ + gnu/lib/libgcc \ + include \ + lib/${CSU_DIR} \ + lib/libc \ + lib/libcompiler_rt \ + lib/msun \ + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/libexec/rtld-elf/tests/libpythagoras/pythagoras.c b/libexec/rtld-elf/tests/libpythagoras/pythagoras.c new file mode 100644 index 0000000..0df422f --- /dev/null +++ b/libexec/rtld-elf/tests/libpythagoras/pythagoras.c @@ -0,0 +1,42 @@ +/*- + * Copyright 2014 Jonathan Anderson. + * 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/tests/libpythagoras/pythagoras.c 267679 2014-06-20 17:14:59Z jonathan $ + */ + +#include +#include + +#include "pythagoras.h" + +double +pythagorean_theorem(double a, double b) +{ + + if (a <= 0 || b <= 0) { + errno = ERANGE; + return (-1.0); + } + return (sqrt(pow(a, 2) + pow(b, 2))); +} diff --git a/libexec/rtld-elf/tests/libpythagoras/pythagoras.h b/libexec/rtld-elf/tests/libpythagoras/pythagoras.h new file mode 100644 index 0000000..e0487c4 --- /dev/null +++ b/libexec/rtld-elf/tests/libpythagoras/pythagoras.h @@ -0,0 +1,28 @@ +/*- + * Copyright 2014 Jonathan Anderson. + * 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/tests/libpythagoras/pythagoras.h 267679 2014-06-20 17:14:59Z jonathan $ + */ + +double pythagorean_theorem(double, double); diff --git a/libexec/rtld-elf/tests/target/Makefile b/libexec/rtld-elf/tests/target/Makefile new file mode 100644 index 0000000..6af3acb --- /dev/null +++ b/libexec/rtld-elf/tests/target/Makefile @@ -0,0 +1,17 @@ +# $FreeBSD: releng/11.1/libexec/rtld-elf/tests/target/Makefile 316388 2017-04-02 02:16:01Z asomers $ + +.include + +PROG= target +BINDIR= ${TESTSBASE}/libexec/rtld-elf + +WARNS?= 3 +CFLAGS+= -I${.CURDIR}/../libpythagoras + +LDFLAGS+= -L${.OBJDIR}/../libpythagoras +DPADD+= ${.OBJDIR}/../libpythagoras/libpythagoras.a +LDADD= -lpythagoras + +MAN= + +.include diff --git a/libexec/rtld-elf/tests/target/Makefile.depend b/libexec/rtld-elf/tests/target/Makefile.depend new file mode 100644 index 0000000..119e47a --- /dev/null +++ b/libexec/rtld-elf/tests/target/Makefile.depend @@ -0,0 +1,18 @@ +# $FreeBSD: releng/11.1/libexec/rtld-elf/tests/target/Makefile.depend 311183 2017-01-03 22:51:40Z bdrewery $ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + gnu/lib/csu \ + gnu/lib/libgcc \ + include \ + lib/${CSU_DIR} \ + lib/libc \ + lib/libcompiler_rt \ + libexec/rtld-elf/tests/libpythagoras \ + + +.include + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/libexec/rtld-elf/tests/target/target.c b/libexec/rtld-elf/tests/target/target.c new file mode 100644 index 0000000..af883e9 --- /dev/null +++ b/libexec/rtld-elf/tests/target/target.c @@ -0,0 +1,39 @@ +/*- + * Copyright 2014 Jonathan Anderson. + * 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. + * + * $FreeBSD: releng/11.1/libexec/rtld-elf/tests/target/target.c 267679 2014-06-20 17:14:59Z jonathan $ + */ + +#include "pythagoras.h" + +#include + +int +main(int argc, char *argv[]) +{ + float hypotenuse = pythagorean_theorem(3, 4); + printf("the hypotenuse of 3 and 4 is %d\n", (int) hypotenuse); + + return 0; +}