riscv64 ld.so
authordrahn <drahn@openbsd.org>
Wed, 28 Apr 2021 15:16:26 +0000 (15:16 +0000)
committerdrahn <drahn@openbsd.org>
Wed, 28 Apr 2021 15:16:26 +0000 (15:16 +0000)
derived from arm64
go ahead deraadt@

libexec/ld.so/riscv64/Makefile.inc [new file with mode: 0644]
libexec/ld.so/riscv64/SYS.h [new file with mode: 0644]
libexec/ld.so/riscv64/archdep.h [new file with mode: 0644]
libexec/ld.so/riscv64/ld.script [new file with mode: 0644]
libexec/ld.so/riscv64/ldasm.S [new file with mode: 0644]
libexec/ld.so/riscv64/rtld_machine.c [new file with mode: 0644]
libexec/ld.so/riscv64/syscall.h [new file with mode: 0644]

diff --git a/libexec/ld.so/riscv64/Makefile.inc b/libexec/ld.so/riscv64/Makefile.inc
new file mode 100644 (file)
index 0000000..c8ecff0
--- /dev/null
@@ -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 (file)
index 0000000..2e7882f
--- /dev/null
@@ -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 (file)
index 0000000..2c191e9
--- /dev/null
@@ -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 (file)
index 0000000..d023125
--- /dev/null
@@ -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 (file)
index 0000000..d620c6c
--- /dev/null
@@ -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 (file)
index 0000000..ff37e57
--- /dev/null
@@ -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 (file)
index 0000000..08a6551
--- /dev/null
@@ -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__*/