1/* $OpenBSD: rtld_machine.c,v 1.4 2023/01/29 20:30:21 gnezdo Exp $ */ 2 3/* 4 * Copyright (c) 2004,2021 Dale Rahn <drahn@openbsd.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29#define _DYN_LOADER 30 31#include <sys/types.h> 32#include <sys/exec_elf.h> 33#include <sys/syscall.h> 34#include <sys/unistd.h> 35 36#include <machine/reloc.h> 37 38#include "util.h" 39#include "resolve.h" 40 41int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden; 42#define R_TYPE(x) R_RISCV_ ## x 43 44void _dl_bind_start(void); /* XXX */ 45Elf_Addr _dl_bind(elf_object_t *object, int index); 46#define _RF_S 0x80000000 /* Resolve symbol */ 47#define _RF_A 0x40000000 /* Use addend */ 48#define _RF_P 0x20000000 /* Location relative */ 49#define _RF_G 0x10000000 /* GOT offset */ 50#define _RF_B 0x08000000 /* Load address relative */ 51#define _RF_V 0x02000000 /* ERROR */ 52#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */ 53#define _RF_RS(s) ((s) & 0xff) /* right shift */ 54static const int reloc_target_flags[] = { 55 [ R_TYPE(NONE) ] = 0, 56 [ R_TYPE(32) ] = 57 _RF_V|_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GLOB_DAT */ 58 [ R_TYPE(64) ] = 59 _RF_V|_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* GLOB_DAT */ 60 [ R_TYPE(JUMP_SLOT) ] = 61 _RF_V|_RF_S| _RF_SZ(64) | _RF_RS(0), /* JUMP_SLOT */ 62 [ R_TYPE(RELATIVE) ] = 63 _RF_V|_RF_B|_RF_A| _RF_SZ(64) | _RF_RS(0), /* REL64 */ 64// [ R_TYPE(TLSDESC) ] = _RF_V|_RF_S, 65 [ R_TYPE(TLS_TPREL64) ] = _RF_V|_RF_S, 66 [ R_TYPE(COPY) ] = 67 _RF_V|_RF_S| _RF_SZ(32) | _RF_RS(0), /* 20 COPY */ 68 69}; 70 71#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0) 72#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0) 73#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0) 74#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0) 75#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff) 76#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff) 77 78static const Elf_Addr reloc_target_bitmask[] = { 79#define _BM(x) (~(Elf_Addr)0 >> ((8*sizeof(reloc_target_bitmask[0])) - (x))) 80 [ R_TYPE(NONE) ] = 0, 81 [ R_TYPE(32) ] = _BM(32), 82 [ R_TYPE(64) ] = _BM(64), 83 [ R_TYPE(JUMP_SLOT) ] = _BM(64), 84 [ R_TYPE(RELATIVE) ] = _BM(64), 85// [ R_TYPE(TLSDESC) ] = _BM(64), 86 [ R_TYPE(TLS_TPREL64) ] = _BM(64), 87 [ R_TYPE(COPY) ] = _BM(64), 88#undef _BM 89}; 90#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t]) 91 92 93void _dl_reloc_plt(Elf_Word *where, Elf_Addr value, Elf_RelA *rel); 94 95int 96_dl_md_reloc(elf_object_t *object, int rel, int relsz) 97{ 98 long i; 99 long numrel; 100 long relrel; 101 int fails = 0; 102 Elf_Addr loff; 103 Elf_Addr prev_value = 0; 104 const Elf_Sym *prev_sym = NULL; 105 Elf_RelA *rels; 106 107 loff = object->obj_base; 108 numrel = object->Dyn.info[relsz] / sizeof(Elf_RelA); 109 relrel = rel == DT_RELA ? object->relcount : 0; 110 rels = (Elf_RelA *)(object->Dyn.info[rel]); 111 112 if (rels == NULL) 113 return 0; 114 115 if (relrel > numrel) 116 _dl_die("relcount > numrel: %ld > %ld", relrel, numrel); 117 118 /* tight loop for leading RELATIVE relocs */ 119 for (i = 0; i < relrel; i++, rels++) { 120 Elf_Addr *where; 121 122 where = (Elf_Addr *)(rels->r_offset + loff); 123 *where += loff; 124 } 125 for (; i < numrel; i++, rels++) { 126 Elf_Addr *where, value, mask; 127 Elf_Word type; 128 const Elf_Sym *sym; 129 const char *symn; 130 131 type = ELF_R_TYPE(rels->r_info); 132 133 if (type >= nitems(reloc_target_flags) || 134 (reloc_target_flags[type] & _RF_V) == 0) 135 _dl_die("bad relocation %ld %d", i, type); 136 137 if (type == R_TYPE(NONE)) 138 continue; 139 140 if (type == R_TYPE(JUMP_SLOT) && rel != DT_JMPREL) 141 continue; 142 143 where = (Elf_Addr *)(rels->r_offset + loff); 144 145 if (RELOC_USE_ADDEND(type)) 146 value = rels->r_addend; 147 else 148 value = 0; 149 150 sym = NULL; 151 symn = NULL; 152 if (RELOC_RESOLVE_SYMBOL(type)) { 153 sym = object->dyn.symtab; 154 sym += ELF_R_SYM(rels->r_info); 155 symn = object->dyn.strtab + sym->st_name; 156 157 if (sym->st_shndx != SHN_UNDEF && 158 ELF_ST_BIND(sym->st_info) == STB_LOCAL) { 159 value += loff; 160 } else if (sym == prev_sym) { 161 value += prev_value; 162 } else { 163 struct sym_res sr; 164 165 sr = _dl_find_symbol(symn, 166 SYM_SEARCH_ALL|SYM_WARNNOTFOUND| 167 ((type == R_TYPE(JUMP_SLOT)) ? 168 SYM_PLT : SYM_NOTPLT), sym, object); 169 if (sr.sym == NULL) { 170resolve_failed: 171 if (ELF_ST_BIND(sym->st_info) != 172 STB_WEAK) 173 fails++; 174 continue; 175 } 176 prev_sym = sym; 177 prev_value = (Elf_Addr)(sr.obj->obj_base + 178 sr.sym->st_value); 179 value += prev_value; 180 } 181 } 182 183 if (type == R_TYPE(JUMP_SLOT)) { 184 /* 185 _dl_reloc_plt((Elf_Word *)where, value, rels); 186 */ 187 *where = value; 188 continue; 189 } 190 191 if (type == R_TYPE(COPY)) { 192 void *dstaddr = where; 193 const void *srcaddr; 194 const Elf_Sym *dstsym = sym; 195 struct sym_res sr; 196 197 sr = _dl_find_symbol(symn, 198 SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT, 199 dstsym, object); 200 if (sr.sym == NULL) 201 goto resolve_failed; 202 203 srcaddr = (void *)(sr.obj->obj_base + sr.sym->st_value); 204 _dl_bcopy(srcaddr, dstaddr, dstsym->st_size); 205 continue; 206 } 207 208 if (RELOC_PC_RELATIVE(type)) 209 value -= (Elf_Addr)where; 210 if (RELOC_BASE_RELATIVE(type)) 211 value += loff; 212 213 mask = RELOC_VALUE_BITMASK(type); 214 value >>= RELOC_VALUE_RIGHTSHIFT(type); 215 value &= mask; 216 217 *where &= ~mask; 218 *where |= value; 219 } 220 221 return fails; 222} 223 224/* 225 * Relocate the Global Offset Table (GOT). 226 * This is done by calling _dl_md_reloc on DT_JMPREL for DL_BIND_NOW, 227 * otherwise the lazy binding plt initialization is performed. 228 */ 229int 230_dl_md_reloc_got(elf_object_t *object, int lazy) 231{ 232 int fails = 0; 233 Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT]; 234 int i, num; 235 Elf_RelA *rel; 236 237 if (object->Dyn.info[DT_PLTREL] != DT_RELA) 238 return 0; 239 240 if (!lazy) { 241 fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); 242 } else { 243 rel = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]); 244 num = (object->Dyn.info[DT_PLTRELSZ]); 245 246 for (i = 0; i < num/sizeof(Elf_RelA); i++, rel++) { 247 Elf_Addr *where; 248 where = (Elf_Addr *)(rel->r_offset + object->obj_base); 249 *where += object->obj_base; 250 } 251 252 pltgot[0] = (Elf_Addr)_dl_bind_start; 253 pltgot[1] = (Elf_Addr)object; 254 } 255 256 return fails; 257} 258 259Elf_Addr 260_dl_bind(elf_object_t *object, int relidx) 261{ 262 Elf_RelA *rel; 263 const Elf_Sym *sym; 264 const char *symn; 265 struct sym_res sr; 266 int64_t cookie = pcookie; 267 struct { 268 struct __kbind param; 269 Elf_Addr newval; 270 } buf; 271 272 rel = ((Elf_RelA *)object->Dyn.info[DT_JMPREL]) + (relidx); 273 274 sym = object->dyn.symtab; 275 sym += ELF_R_SYM(rel->r_info); 276 symn = object->dyn.strtab + sym->st_name; 277 278 sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, 279 sym, object); 280 if (sr.sym == NULL) 281 _dl_die("lazy binding failed!"); 282 283 buf.newval = sr.obj->obj_base + sr.sym->st_value; 284 285 if (sr.obj->traced && _dl_trace_plt(sr.obj, symn)) 286 return buf.newval; 287 288 buf.param.kb_addr = (Elf_Word *)(object->obj_base + rel->r_offset); 289 buf.param.kb_size = sizeof(Elf_Addr); 290 291 /* directly code the syscall, so that it's actually inline here */ 292 { 293 register long syscall_num __asm("t0") = SYS_kbind; 294 register void *arg1 __asm("a0") = &buf; 295 register long arg2 __asm("a1") = sizeof(buf); 296 register long arg3 __asm("a2") = cookie; 297 298 __asm volatile("ecall" : "+r" (arg1), "+r" (arg2) 299 : "r" (syscall_num), "r" (arg3) 300 : "cc", "memory"); 301 } 302 303 return buf.newval; 304} 305