diff options
author | Dale Rahn <drahn@cvs.openbsd.org> | 2021-04-28 15:16:27 +0000 |
---|---|---|
committer | Dale Rahn <drahn@cvs.openbsd.org> | 2021-04-28 15:16:27 +0000 |
commit | d9fb0b665e7099365d76f40348671710d4a7f8f5 (patch) | |
tree | 3fe2f7b0ebbed76438f7b0767e65e07ecf51eeda /libexec | |
parent | 8620522555fabdee069549f85fc01ce843505bd7 (diff) |
riscv64 ld.so
derived from arm64
go ahead deraadt@
Diffstat (limited to 'libexec')
-rw-r--r-- | libexec/ld.so/riscv64/Makefile.inc | 12 | ||||
-rw-r--r-- | libexec/ld.so/riscv64/SYS.h | 47 | ||||
-rw-r--r-- | libexec/ld.so/riscv64/archdep.h | 68 | ||||
-rw-r--r-- | libexec/ld.so/riscv64/ld.script | 69 | ||||
-rw-r--r-- | libexec/ld.so/riscv64/ldasm.S | 144 | ||||
-rw-r--r-- | libexec/ld.so/riscv64/rtld_machine.c | 311 | ||||
-rw-r--r-- | libexec/ld.so/riscv64/syscall.h | 70 |
7 files changed, 721 insertions, 0 deletions
diff --git a/libexec/ld.so/riscv64/Makefile.inc b/libexec/ld.so/riscv64/Makefile.inc new file mode 100644 index 00000000000..c8ecff04984 --- /dev/null +++ b/libexec/ld.so/riscv64/Makefile.inc @@ -0,0 +1,12 @@ +# $OpenBSD: Makefile.inc,v 1.1 2021/04/28 15:16:26 drahn Exp $ + +CFLAGS += -fpic +CFLAGS += -march=rv64gc # this prevents the use of float in ld.so +AFLAGS += -D_STANDALONE +CPPFLAGS += -I${.CURDIR}/../../lib/libc/arch/riscv64 +LD_SCRIPT = ${.CURDIR}/${MACHINE_CPU}/ld.script + +# Suppress DWARF2 warnings +DEBUG?= -gdwarf-4 + +RELATIVE_RELOC=R_RISCV_RELATIVE diff --git a/libexec/ld.so/riscv64/SYS.h b/libexec/ld.so/riscv64/SYS.h new file mode 100644 index 00000000000..2e7882fc04d --- /dev/null +++ b/libexec/ld.so/riscv64/SYS.h @@ -0,0 +1,47 @@ +/* $OpenBSD: SYS.h,v 1.1 2021/04/28 15:16:26 drahn Exp $ */ + +/* + * Copyright (c) 2016 Dale Rahn <drahn@openbsd.org> + * + * 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. + * + */ + +#include <machine/asm.h> +#include <sys/syscall.h> + +#define SYSTRAP(x) \ + li t0, SYS_ ## x ;\ + ecall ;\ + /* XXX fence */ + +#define DL_SYSCALL(n) \ + .global __CONCAT(_dl_,n) ;\ + .type __CONCAT(_dl_,n)%function ;\ +__CONCAT(_dl_,n): ;\ + RETGUARD_SETUP(__CONCAT(_dl_,n), x15) ;\ + SYSTRAP(n) ;\ + beqz t0, 1f ;\ + sub a0, zero, a0 /* r0 = -errno */ ;\ +1: ;\ + RETGUARD_CHECK(__CONCAT(_dl_,n), x15) ;\ + ret diff --git a/libexec/ld.so/riscv64/archdep.h b/libexec/ld.so/riscv64/archdep.h new file mode 100644 index 00000000000..2c191e9364a --- /dev/null +++ b/libexec/ld.so/riscv64/archdep.h @@ -0,0 +1,68 @@ +/* $OpenBSD: archdep.h,v 1.1 2021/04/28 15:16:26 drahn Exp $ */ + +/* + * Copyright (c) 2021 Dale Rahn <drahn@openbsd.org> + * Copyright (c) 1998 Per Fogelstrom, Opsycon AB + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef _AARCH64_ARCHDEP_H_ +#define _AARCH64_ARCHDEP_H_ + +#define RELOC_TAG DT_RELA +#define HAVE_JMPREL 1 + +#define MACHID EM_RISCV /* ELF e_machine ID value checked */ + +#include <elf.h> +#include <machine/reloc.h> +#include "syscall.h" +#include "util.h" + +static inline void +RELOC_JMPREL(Elf_RelA *r, const Elf_Sym *s, Elf_Addr *p, unsigned long v, + Elf_Addr *pltgot) +{ + if (ELF_R_TYPE(r->r_info) == R_RISCV_JUMP_SLOT) { + p[0] = v + s->st_value + r->r_addend; + } else { + _dl_exit(5); + } +} + +static inline void +RELOC_DYN(Elf_RelA *r, const Elf_Sym *s, Elf_Addr *p, unsigned long v) +{ + if (ELF_R_TYPE(r->r_info) == R_RISCV_RELATIVE) { + *p = v + r->r_addend; + } else if (ELF_R_TYPE(r->r_info) == R_RISCV_64) { + *p = v + s->st_value + r->r_addend; + } else { + _dl_exit(6); + } +} + +#define RELOC_GOT(obj, offs) + +#endif /* _AARCH64_ARCHDEP_H_ */ diff --git a/libexec/ld.so/riscv64/ld.script b/libexec/ld.so/riscv64/ld.script new file mode 100644 index 00000000000..d0231259a0b --- /dev/null +++ b/libexec/ld.so/riscv64/ld.script @@ -0,0 +1,69 @@ +PHDRS +{ + rodata PT_LOAD FILEHDR PHDRS FLAGS (4); + text PT_LOAD; + data PT_LOAD; + random PT_OPENBSD_RANDOMIZE; + relro PT_GNU_RELRO; + dynamic PT_DYNAMIC; + note PT_NOTE; +} + +SECTIONS +{ + /* RODATA */ + . = 0 + SIZEOF_HEADERS; + .dynsym : { *(.dynsym) } :rodata + .gnu.hash : { *(.gnu.hash) } :rodata + .dynstr : { *(.dynstr) } :rodata + .rodata : { *(.rodata .rodata.*) } :rodata + .eh_frame : { *(.eh_frame) } :rodata + + /* TEXT */ + . = ALIGN(0x10000); + .text : { *(.text .text.*) } :text + . = ALIGN(0x1000); + .boot.text : + { + boot_text_start = .; + *(.boot.text) + boot_text_end = .; + } :text + + /* RELRO DATA */ + . = DATA_SEGMENT_ALIGN (0x10000, 0x1000); + .openbsd.randomdata : + { + *(.openbsd.randomdata .openbsd.randomdata.*) + } :data :relro :random + .data.rel.ro : { *(.data.rel.ro.local*) *(.data.rel.ro*) } :data :relro + .dynamic : { *(.dynamic) } :data :relro :dynamic + .got : { *(.got.plt) *(.got) } :data :relro + . = DATA_SEGMENT_RELRO_END (0, .); + + /* BOOTDATA */ + . = ALIGN(0x1000); + boot_data_start = .; + .rela.dyn : + { + *(.rela.text .rela.text.*) + *(.rela.rodata .rela.rodata.*) + *(.rela.data .rela.data.*) + *(.rela.got) + *(.rela.bss .rela.bss.*) + } :data +/* XXX .rela.plt is unused but cannot delete: ld.bfd zeros DT_RELASZ then! */ + .rela.plt : { *(.rela.plt) } :data + .hash : { *(.hash) } :data + .note : { *(.note.openbsd.*) } :data :note + .boot.data : { *(.boot.data .boot.data.*) } :data + boot_data_end = .; + + /* DATA */ + . = ALIGN(0x1000); + .data : { *(.data .data.*) } :data + .bss : { *(.dynbss) *(.bss .bss.*) *(COMMON) } :data + . = DATA_SEGMENT_END (.); + + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/libexec/ld.so/riscv64/ldasm.S b/libexec/ld.so/riscv64/ldasm.S new file mode 100644 index 00000000000..d620c6cf9f2 --- /dev/null +++ b/libexec/ld.so/riscv64/ldasm.S @@ -0,0 +1,144 @@ +/* $OpenBSD: ldasm.S,v 1.1 2021/04/28 15:16:26 drahn Exp $ */ + +/* + * Copyright (c) 2016,2021 Dale Rahn <drahn@openbsd.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#define DL_DATA_SIZE (16 * 8) /* needs to be 8(16?) byte aligned */ +#include <machine/asm.h> +#include <sys/syscall.h> + + .option norelax + .section .boot.text,"ax",@progbits + _ALIGN_TEXT + .globl _dl_start + .type _dl_start,@function +_dl_start: + mv a0, sp + mv fp, sp + + addi sp, sp, -(8+8+DL_DATA_SIZE) // dl_data size + addi s10, sp, 8 // dl_data + + mv a1, s10 // dl_data + +1: auipc a2, %pcrel_hi(_DYNAMIC) /* &_DYNAMIC */ + addi a2, a2, %pcrel_lo(1b) + + call _dl_boot_bind + + ld a0, (fp) // load argc + addi a1, fp, 0x0008 // argv + slli a2, a0, 0x3 + add a2, a1, a2 + addi a2, a2, 0x0008 // compute envp into a2 + + // _dl_boot(argv, envp, loff, dl_data) + mv a0, a1 // argv + mv a1, a2 // envp + ld a2, (7*8)(s10) // loff from dl_data + mv a3, s10 // dl_data + + call _dl_boot + + mv sp, fp // move stack back + mv fp, zero // clear frame back pointer + +2: auipc a3, %got_pcrel_hi(_dl_dtors) /* cleanup */ + addi a3, a3, %pcrel_lo(2b) + + jr a0 +END(_dl_start) + +ENTRY(_dl_bind_start) + /* + * x16 is pointer to pltgot[2] + * x17 is available as scratch register + * return address and pointer to pltgot entry for this + * relocation are on the stack + */ + mv x17, sp + + /* save parameter/result registers */ + addi sp, sp, -(16*8) /* should be aligned well enough */ + sd t1, ( 2*8)(sp) + sd t2, ( 3*8)(sp) + sd a0, ( 4*8)(sp) + sd a1, ( 5*8)(sp) + sd a2, ( 6*8)(sp) + sd a3, ( 7*8)(sp) + sd a4, ( 8*8)(sp) + sd a5, ( 9*8)(sp) + sd a6, (10*8)(sp) + sd a7, (11*8)(sp) + sd t3, (12*8)(sp) + sd t4, (13*8)(sp) + sd t5, (14*8)(sp) + sd t6, (15*8)(sp) + + /* what about float registers !?! */ + /* + * no need to save v0-v9 as ld.so is compiled with + * -march=armv8-a+nofp+nosimd and therefore doesn't touch the + * SIMD and Floating-Point registers + */ + + mv a0, t0 + slli a1, t1, 1 + add a1, a1, t1 + jal _dl_bind + nop + mv t0, a0 + + // restore parameter/result registers + ld t1, ( 2*8)(sp) + ld t2, ( 3*8)(sp) + ld a0, ( 4*8)(sp) + ld a1, ( 5*8)(sp) + ld a2, ( 6*8)(sp) + ld a3, ( 7*8)(sp) + ld a4, ( 8*8)(sp) + ld a5, ( 9*8)(sp) + ld a6, (10*8)(sp) + ld a7, (11*8)(sp) + ld t3, (12*8)(sp) + ld t4, (13*8)(sp) + sd t5, (14*8)(sp) + sd t6, (15*8)(sp) + add sp, sp, (16*8) + + // restore LR saved by PLT stub + // XXX - correct? + ld ra, 16(sp) + add sp, sp, 16 + jr t0 +END(_dl_bind_start) + +ENTRY(_rtld_tlsdesc) + RETGUARD_SETUP(_rtld_tlsdesc, x15) + ld a0, 8(a0) + RETGUARD_CHECK(_rtld_tlsdesc, x15) + ret +END(_rtld_tlsdesc) diff --git a/libexec/ld.so/riscv64/rtld_machine.c b/libexec/ld.so/riscv64/rtld_machine.c new file mode 100644 index 00000000000..ff37e571b4f --- /dev/null +++ b/libexec/ld.so/riscv64/rtld_machine.c @@ -0,0 +1,311 @@ +/* $OpenBSD: rtld_machine.c,v 1.1 2021/04/28 15:16:26 drahn Exp $ */ + +/* + * Copyright (c) 2004,2021 Dale Rahn <drahn@openbsd.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#define _DYN_LOADER + +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/syscall.h> +#include <sys/unistd.h> + +#include <nlist.h> +#include <link.h> + +#include "syscall.h" +#include "archdep.h" +#include "resolve.h" + +int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden; +#define R_TYPE(x) R_RISCV_ ## x + +void _dl_bind_start(void); /* XXX */ +Elf_Addr _dl_bind(elf_object_t *object, int index); +#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_V 0x02000000 /* ERROR */ +#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */ +#define _RF_RS(s) ((s) & 0xff) /* right shift */ +static const int reloc_target_flags[] = { + [ R_TYPE(NONE) ] = 0, + [ R_TYPE(32) ] = + _RF_V|_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GLOB_DAT */ + [ R_TYPE(64) ] = + _RF_V|_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* GLOB_DAT */ + [ R_TYPE(JUMP_SLOT) ] = + _RF_V|_RF_S| _RF_SZ(64) | _RF_RS(0), /* JUMP_SLOT */ + [ R_TYPE(RELATIVE) ] = + _RF_V|_RF_B|_RF_A| _RF_SZ(64) | _RF_RS(0), /* REL64 */ +// [ R_TYPE(TLSDESC) ] = _RF_V|_RF_S, + [ R_TYPE(TLS_TPREL64) ] = _RF_V|_RF_S, + [ R_TYPE(COPY) ] = + _RF_V|_RF_S| _RF_SZ(32) | _RF_RS(0), /* 20 COPY */ + +}; + +#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_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0) +#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff) +#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff) + +static const Elf_Addr reloc_target_bitmask[] = { +#define _BM(x) (~(Elf_Addr)0 >> ((8*sizeof(reloc_target_bitmask[0])) - (x))) + [ R_TYPE(NONE) ] = 0, + [ R_TYPE(32) ] = _BM(32), + [ R_TYPE(64) ] = _BM(64), + [ R_TYPE(JUMP_SLOT) ] = _BM(64), + [ R_TYPE(RELATIVE) ] = _BM(64), +// [ R_TYPE(TLSDESC) ] = _BM(64), + [ R_TYPE(TLS_TPREL64) ] = _BM(64), + [ R_TYPE(COPY) ] = _BM(64), +#undef _BM +}; +#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t]) + + +void _dl_reloc_plt(Elf_Word *where, Elf_Addr value, Elf_RelA *rel); + +#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) + +int +_dl_md_reloc(elf_object_t *object, int rel, int relsz) +{ + long i; + long numrel; + long relrel; + int fails = 0; + Elf_Addr loff; + Elf_Addr prev_value = 0; + const Elf_Sym *prev_sym = NULL; + Elf_RelA *rels; + + loff = object->obj_base; + numrel = object->Dyn.info[relsz] / sizeof(Elf_RelA); + relrel = rel == DT_RELA ? object->relcount : 0; + rels = (Elf_RelA *)(object->Dyn.info[rel]); + + if (rels == NULL) + return 0; + + if (relrel > numrel) + _dl_die("relcount > numrel: %ld > %ld", relrel, numrel); + + /* tight loop for leading RELATIVE relocs */ + for (i = 0; i < relrel; i++, rels++) { + Elf_Addr *where; + + where = (Elf_Addr *)(rels->r_offset + loff); + *where += loff; + } + for (; i < numrel; i++, rels++) { + Elf_Addr *where, value, mask; + Elf_Word type; + const Elf_Sym *sym; + const char *symn; + + type = ELF_R_TYPE(rels->r_info); + + if (type >= nitems(reloc_target_flags) || + (reloc_target_flags[type] & _RF_V) == 0) + _dl_die("bad relocation %ld %d", i, type); + + if (type == R_TYPE(NONE)) + continue; + + if (type == R_TYPE(JUMP_SLOT) && rel != DT_JMPREL) + continue; + + where = (Elf_Addr *)(rels->r_offset + loff); + + if (RELOC_USE_ADDEND(type)) + value = rels->r_addend; + else + value = 0; + + sym = NULL; + symn = NULL; + if (RELOC_RESOLVE_SYMBOL(type)) { + sym = object->dyn.symtab; + sym += ELF_R_SYM(rels->r_info); + symn = object->dyn.strtab + sym->st_name; + + if (sym->st_shndx != SHN_UNDEF && + ELF_ST_BIND(sym->st_info) == STB_LOCAL) { + value += loff; + } else if (sym == prev_sym) { + value += prev_value; + } else { + struct sym_res sr; + + sr = _dl_find_symbol(symn, + SYM_SEARCH_ALL|SYM_WARNNOTFOUND| + ((type == R_TYPE(JUMP_SLOT)) ? + SYM_PLT : SYM_NOTPLT), sym, object); + if (sr.sym == NULL) { +resolve_failed: + if (ELF_ST_BIND(sym->st_info) != + STB_WEAK) + fails++; + continue; + } + prev_sym = sym; + prev_value = (Elf_Addr)(sr.obj->obj_base + + sr.sym->st_value); + value += prev_value; + } + } + + if (type == R_TYPE(JUMP_SLOT)) { + /* + _dl_reloc_plt((Elf_Word *)where, value, rels); + */ + *where = value; + continue; + } + + if (type == R_TYPE(COPY)) { + void *dstaddr = where; + const void *srcaddr; + const Elf_Sym *dstsym = sym; + struct sym_res sr; + + sr = _dl_find_symbol(symn, + SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT, + dstsym, object); + if (sr.sym == NULL) + goto resolve_failed; + + srcaddr = (void *)(sr.obj->obj_base + sr.sym->st_value); + _dl_bcopy(srcaddr, dstaddr, dstsym->st_size); + continue; + } + + if (RELOC_PC_RELATIVE(type)) + value -= (Elf_Addr)where; + if (RELOC_BASE_RELATIVE(type)) + value += loff; + + mask = RELOC_VALUE_BITMASK(type); + value >>= RELOC_VALUE_RIGHTSHIFT(type); + value &= mask; + + *where &= ~mask; + *where |= value; + } + + return fails; +} + +/* + * Relocate the Global Offset Table (GOT). + * This is done by calling _dl_md_reloc on DT_JMPREL for DL_BIND_NOW, + * otherwise the lazy binding plt initialization is performed. + */ +int +_dl_md_reloc_got(elf_object_t *object, int lazy) +{ + int fails = 0; + Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT]; + int i, num; + Elf_RelA *rel; + + if (object->Dyn.info[DT_PLTREL] != DT_RELA) + return 0; + + // XXX - fix and enable. + lazy = 0; + + if (!lazy) { + fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); + } else { + rel = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]); + num = (object->Dyn.info[DT_PLTRELSZ]); + + for (i = 0; i < num/sizeof(Elf_RelA); i++, rel++) { + Elf_Addr *where; + where = (Elf_Addr *)(rel->r_offset + object->obj_base); + *where += object->obj_base; + } + + pltgot[1] = (Elf_Addr)object; + pltgot[2] = (Elf_Addr)_dl_bind_start; + } + + return fails; +} + +Elf_Addr +_dl_bind(elf_object_t *object, int relidx) +{ + Elf_RelA *rel; + const Elf_Sym *sym; + const char *symn; + struct sym_res sr; + int64_t cookie = pcookie; + struct { + struct __kbind param; + Elf_Addr newval; + } buf; + + rel = ((Elf_RelA *)object->Dyn.info[DT_JMPREL]) + (relidx); + + sym = object->dyn.symtab; + sym += ELF_R_SYM(rel->r_info); + symn = object->dyn.strtab + sym->st_name; + + sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, + sym, object); + if (sr.sym == NULL) + _dl_die("lazy binding failed!"); + + buf.newval = sr.obj->obj_base + sr.sym->st_value; + + if (sr.obj->traced && _dl_trace_plt(sr.obj, symn)) + return buf.newval; + + buf.param.kb_addr = (Elf_Word *)(object->obj_base + rel->r_offset); + buf.param.kb_size = sizeof(Elf_Addr); + + /* directly code the syscall, so that it's actually inline here */ + { + register long syscall_num __asm("t0") = SYS_kbind; + register void *arg1 __asm("a0") = &buf; + register long arg2 __asm("a1") = sizeof(buf); + register long arg3 __asm("x2") = cookie; + + __asm volatile("ecall" : "+r" (arg1), "+r" (arg2) + : "r" (syscall_num), "r" (arg3) + : "cc", "memory"); + } + + return buf.newval; +} diff --git a/libexec/ld.so/riscv64/syscall.h b/libexec/ld.so/riscv64/syscall.h new file mode 100644 index 00000000000..08a655123ad --- /dev/null +++ b/libexec/ld.so/riscv64/syscall.h @@ -0,0 +1,70 @@ +/* $OpenBSD: syscall.h,v 1.1 2021/04/28 15:16:26 drahn Exp $ */ + +/* + * Copyright (c) 1998 Per Fogelstrom, Opsycon AB + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef __DL_SYSCALL_H__ +#define __DL_SYSCALL_H__ + +#include <sys/syscall.h> +#include <sys/stat.h> + +#ifndef _dl_MAX_ERRNO +#define _dl_MAX_ERRNO 512L +#endif +#define _dl_mmap_error(__res) \ + ((long)__res < 0 && (long)__res >= -_dl_MAX_ERRNO) + +int _dl_close(int); +__dead +void _dl_exit(int); +int _dl_fstat(int, struct stat *); +ssize_t _dl_getdents(int, char *, size_t); +int _dl_issetugid(void); +int _dl_getthrid(void); +int _dl_mprotect(const void *, size_t, int); +int _dl_munmap(const void *, size_t); +int _dl_open(const char *, int); +int _dl_msyscall(void *addr, size_t len); +ssize_t _dl_read(int, const char *, size_t); +int _dl_pledge(const char *, const char **); +long _dl___syscall(quad_t, ...); +int _dl_sysctl(const int *, u_int, void *, size_t *, void *, size_t); +int _dl_utrace(const char *, const void *, size_t); +int _dl_getentropy(char *, size_t); +int _dl_sendsyslog(const char *, size_t, int); +void _dl___set_tcb(void *); +__dead +void _dl_thrkill(pid_t, int, void *); + +static inline void * +_dl_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) +{ + return (void *)_dl___syscall(SYS_mmap, addr, len, prot, + flags, fd, 0, offset); +} + +#endif /*__DL_SYSCALL_H__*/ |