rtld_machine.c revision 1.1
1/* $OpenBSD: rtld_machine.c,v 1.1 2021/04/28 15:16:26 drahn 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/mman.h> 33#include <sys/syscall.h> 34#include <sys/unistd.h> 35 36#include <nlist.h> 37#include <link.h> 38 39#include "syscall.h" 40#include "archdep.h" 41#include "resolve.h" 42 43int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden; 44#define R_TYPE(x) R_RISCV_ ## x 45 46void _dl_bind_start(void); /* XXX */ 47Elf_Addr _dl_bind(elf_object_t *object, int index); 48#define _RF_S 0x80000000 /* Resolve symbol */ 49#define _RF_A 0x40000000 /* Use addend */ 50#define _RF_P 0x20000000 /* Location relative */ 51#define _RF_G 0x10000000 /* GOT offset */ 52#define _RF_B 0x08000000 /* Load address relative */ 53#define _RF_V 0x02000000 /* ERROR */ 54#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */ 55#define _RF_RS(s) ((s) & 0xff) /* right shift */ 56static const int reloc_target_flags[] = { 57 [ R_TYPE(NONE) ] = 0, 58 [ R_TYPE(32) ] = 59 _RF_V|_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GLOB_DAT */ 60 [ R_TYPE(64) ] = 61 _RF_V|_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* GLOB_DAT */ 62 [ R_TYPE(JUMP_SLOT) ] = 63 _RF_V|_RF_S| _RF_SZ(64) | _RF_RS(0), /* JUMP_SLOT */ 64 [ R_TYPE(RELATIVE) ] = 65 _RF_V|_RF_B|_RF_A| _RF_SZ(64) | _RF_RS(0), /* REL64 */ 66// [ R_TYPE(TLSDESC) ] = _RF_V|_RF_S, 67 [ R_TYPE(TLS_TPREL64) ] = _RF_V|_RF_S, 68 [ R_TYPE(COPY) ] = 69 _RF_V|_RF_S| _RF_SZ(32) | _RF_RS(0), /* 20 COPY */ 70 71}; 72 73#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0) 74#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0) 75#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0) 76#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0) 77#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff) 78#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff) 79 80static const Elf_Addr reloc_target_bitmask[] = { 81#define _BM(x) (~(Elf_Addr)0 >> ((8*sizeof(reloc_target_bitmask[0])) - (x))) 82 [ R_TYPE(NONE) ] = 0, 83 [ R_TYPE(32) ] = _BM(32), 84 [ R_TYPE(64) ] = _BM(64), 85 [ R_TYPE(JUMP_SLOT) ] = _BM(64), 86 [ R_TYPE(RELATIVE) ] = _BM(64), 87// [ R_TYPE(TLSDESC) ] = _BM(64), 88 [ R_TYPE(TLS_TPREL64) ] = _BM(64), 89 [ R_TYPE(COPY) ] = _BM(64), 90#undef _BM 91}; 92#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t]) 93 94 95void _dl_reloc_plt(Elf_Word *where, Elf_Addr value, Elf_RelA *rel); 96 97#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) 98 99int 100_dl_md_reloc(elf_object_t *object, int rel, int relsz) 101{ 102 long i; 103 long numrel; 104 long relrel; 105 int fails = 0; 106 Elf_Addr loff; 107 Elf_Addr prev_value = 0; 108 const Elf_Sym *prev_sym = NULL; 109 Elf_RelA *rels; 110 111 loff = object->obj_base; 112 numrel = object->Dyn.info[relsz] / sizeof(Elf_RelA); 113 relrel = rel == DT_RELA ? object->relcount : 0; 114 rels = (Elf_RelA *)(object->Dyn.info[rel]); 115 116 if (rels == NULL) 117 return 0; 118 119 if (relrel > numrel) 120 _dl_die("relcount > numrel: %ld > %ld", relrel, numrel); 121 122 /* tight loop for leading RELATIVE relocs */ 123 for (i = 0; i < relrel; i++, rels++) { 124 Elf_Addr *where; 125 126 where = (Elf_Addr *)(rels->r_offset + loff); 127 *where += loff; 128 } 129 for (; i < numrel; i++, rels++) { 130 Elf_Addr *where, value, mask; 131 Elf_Word type; 132 const Elf_Sym *sym; 133 const char *symn; 134 135 type = ELF_R_TYPE(rels->r_info); 136 137 if (type >= nitems(reloc_target_flags) || 138 (reloc_target_flags[type] & _RF_V) == 0) 139 _dl_die("bad relocation %ld %d", i, type); 140 141 if (type == R_TYPE(NONE)) 142 continue; 143 144 if (type == R_TYPE(JUMP_SLOT) && rel != DT_JMPREL) 145 continue; 146 147 where = (Elf_Addr *)(rels->r_offset + loff); 148 149 if (RELOC_USE_ADDEND(type)) 150 value = rels->r_addend; 151 else 152 value = 0; 153 154 sym = NULL; 155 symn = NULL; 156 if (RELOC_RESOLVE_SYMBOL(type)) { 157 sym = object->dyn.symtab; 158 sym += ELF_R_SYM(rels->r_info); 159 symn = object->dyn.strtab + sym->st_name; 160 161 if (sym->st_shndx != SHN_UNDEF && 162 ELF_ST_BIND(sym->st_info) == STB_LOCAL) { 163 value += loff; 164 } else if (sym == prev_sym) { 165 value += prev_value; 166 } else { 167 struct sym_res sr; 168 169 sr = _dl_find_symbol(symn, 170 SYM_SEARCH_ALL|SYM_WARNNOTFOUND| 171 ((type == R_TYPE(JUMP_SLOT)) ? 172 SYM_PLT : SYM_NOTPLT), sym, object); 173 if (sr.sym == NULL) { 174resolve_failed: 175 if (ELF_ST_BIND(sym->st_info) != 176 STB_WEAK) 177 fails++; 178 continue; 179 } 180 prev_sym = sym; 181 prev_value = (Elf_Addr)(sr.obj->obj_base + 182 sr.sym->st_value); 183 value += prev_value; 184 } 185 } 186 187 if (type == R_TYPE(JUMP_SLOT)) { 188 /* 189 _dl_reloc_plt((Elf_Word *)where, value, rels); 190 */ 191 *where = value; 192 continue; 193 } 194 195 if (type == R_TYPE(COPY)) { 196 void *dstaddr = where; 197 const void *srcaddr; 198 const Elf_Sym *dstsym = sym; 199 struct sym_res sr; 200 201 sr = _dl_find_symbol(symn, 202 SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT, 203 dstsym, object); 204 if (sr.sym == NULL) 205 goto resolve_failed; 206 207 srcaddr = (void *)(sr.obj->obj_base + sr.sym->st_value); 208 _dl_bcopy(srcaddr, dstaddr, dstsym->st_size); 209 continue; 210 } 211 212 if (RELOC_PC_RELATIVE(type)) 213 value -= (Elf_Addr)where; 214 if (RELOC_BASE_RELATIVE(type)) 215 value += loff; 216 217 mask = RELOC_VALUE_BITMASK(type); 218 value >>= RELOC_VALUE_RIGHTSHIFT(type); 219 value &= mask; 220 221 *where &= ~mask; 222 *where |= value; 223 } 224 225 return fails; 226} 227 228/* 229 * Relocate the Global Offset Table (GOT). 230 * This is done by calling _dl_md_reloc on DT_JMPREL for DL_BIND_NOW, 231 * otherwise the lazy binding plt initialization is performed. 232 */ 233int 234_dl_md_reloc_got(elf_object_t *object, int lazy) 235{ 236 int fails = 0; 237 Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT]; 238 int i, num; 239 Elf_RelA *rel; 240 241 if (object->Dyn.info[DT_PLTREL] != DT_RELA) 242 return 0; 243 244 // XXX - fix and enable. 245 lazy = 0; 246 247 if (!lazy) { 248 fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); 249 } else { 250 rel = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]); 251 num = (object->Dyn.info[DT_PLTRELSZ]); 252 253 for (i = 0; i < num/sizeof(Elf_RelA); i++, rel++) { 254 Elf_Addr *where; 255 where = (Elf_Addr *)(rel->r_offset + object->obj_base); 256 *where += object->obj_base; 257 } 258 259 pltgot[1] = (Elf_Addr)object; 260 pltgot[2] = (Elf_Addr)_dl_bind_start; 261 } 262 263 return fails; 264} 265 266Elf_Addr 267_dl_bind(elf_object_t *object, int relidx) 268{ 269 Elf_RelA *rel; 270 const Elf_Sym *sym; 271 const char *symn; 272 struct sym_res sr; 273 int64_t cookie = pcookie; 274 struct { 275 struct __kbind param; 276 Elf_Addr newval; 277 } buf; 278 279 rel = ((Elf_RelA *)object->Dyn.info[DT_JMPREL]) + (relidx); 280 281 sym = object->dyn.symtab; 282 sym += ELF_R_SYM(rel->r_info); 283 symn = object->dyn.strtab + sym->st_name; 284 285 sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, 286 sym, object); 287 if (sr.sym == NULL) 288 _dl_die("lazy binding failed!"); 289 290 buf.newval = sr.obj->obj_base + sr.sym->st_value; 291 292 if (sr.obj->traced && _dl_trace_plt(sr.obj, symn)) 293 return buf.newval; 294 295 buf.param.kb_addr = (Elf_Word *)(object->obj_base + rel->r_offset); 296 buf.param.kb_size = sizeof(Elf_Addr); 297 298 /* directly code the syscall, so that it's actually inline here */ 299 { 300 register long syscall_num __asm("t0") = SYS_kbind; 301 register void *arg1 __asm("a0") = &buf; 302 register long arg2 __asm("a1") = sizeof(buf); 303 register long arg3 __asm("x2") = cookie; 304 305 __asm volatile("ecall" : "+r" (arg1), "+r" (arg2) 306 : "r" (syscall_num), "r" (arg3) 307 : "cc", "memory"); 308 } 309 310 return buf.newval; 311} 312