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