rtld_machine.c revision 1.14
1/* $OpenBSD: rtld_machine.c,v 1.14 2019/11/26 23:38:52 guenther 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 43int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden; 44 45void _dl_bind_start(void) __dso_hidden; 46 47#define R_TYPE(x) R_AARCH64_ ## x 48 49int 50_dl_md_reloc(elf_object_t *object, int rel, int relsz) 51{ 52 long i; 53 long numrel; 54 long relrel; 55 Elf_Addr loff; 56 Elf_Addr prev_value = 0; 57 const Elf_Sym *prev_sym = NULL; 58 Elf_RelA *rels; 59 60 loff = object->obj_base; 61 numrel = object->Dyn.info[relsz] / sizeof(Elf_RelA); 62 relrel = object->relcount; 63 rels = (Elf_RelA *)(object->Dyn.info[rel]); 64 65 if (rels == NULL) 66 return 0; 67 68 if (relrel > numrel) 69 _dl_die("relcount > numrel: %ld > %ld", relrel, numrel); 70 71 /* tight loop for leading RELATIVE relocs */ 72 for (i = 0; i < relrel; i++, rels++) { 73 Elf_Addr *where; 74 75 where = (Elf_Addr *)(rels->r_offset + loff); 76 *where += loff; 77 } 78 for (; i < numrel; i++, rels++) { 79 Elf_Addr *where, value; 80 Elf_Word type; 81 const Elf_Sym *sym; 82 const char *symn; 83 84 where = (Elf_Addr *)(rels->r_offset + loff); 85 86 sym = object->dyn.symtab; 87 sym += ELF_R_SYM(rels->r_info); 88 symn = object->dyn.strtab + sym->st_name; 89 90 type = ELF_R_TYPE(rels->r_info); 91 switch (type) { 92 case R_TYPE(NONE): 93 case R_TYPE(JUMP_SLOT): /* shouldn't happen */ 94 continue; 95 96 case R_TYPE(RELATIVE): 97 *where = loff + rels->r_addend; 98 continue; 99 100 case R_TYPE(ABS64): 101 value = rels->r_addend; 102 break; 103 104 case R_TYPE(GLOB_DAT): 105 value = 0; 106 break; 107 108 case R_TYPE(COPY): 109 { 110 struct sym_res sr; 111 112 sr = _dl_find_symbol(symn, 113 SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT, 114 sym, object); 115 if (sr.sym == NULL) 116 return 1; 117 118 value = sr.obj->obj_base + sr.sym->st_value; 119 _dl_bcopy((void *)value, where, sym->st_size); 120 continue; 121 } 122 123 default: 124 _dl_die("bad relocation %d", type); 125 } 126 127 if (sym->st_shndx != SHN_UNDEF && 128 ELF_ST_BIND(sym->st_info) == STB_LOCAL) { 129 value += loff; 130 } else if (sym == prev_sym) { 131 value += prev_value; 132 } else { 133 struct sym_res sr; 134 135 sr = _dl_find_symbol(symn, 136 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT, 137 sym, object); 138 if (sr.sym == NULL) { 139 if (ELF_ST_BIND(sym->st_info) != STB_WEAK) 140 return 1; 141 continue; 142 } 143 prev_sym = sym; 144 prev_value = sr.obj->obj_base + sr.sym->st_value; 145 value += prev_value; 146 } 147 148 *where = value; 149 } 150 151 return 0; 152} 153 154static int 155_dl_md_reloc_all_plt(elf_object_t *object, const Elf_RelA *reloc, 156 const Elf_RelA *rend) 157{ 158 for (; reloc < rend; reloc++) { 159 const Elf_Sym *sym; 160 const char *symn; 161 Elf_Addr *where; 162 struct sym_res sr; 163 164 sym = object->dyn.symtab; 165 sym += ELF_R_SYM(reloc->r_info); 166 symn = object->dyn.strtab + sym->st_name; 167 168 sr = _dl_find_symbol(symn, 169 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym, object); 170 if (sr.sym == NULL) { 171 if (ELF_ST_BIND(sym->st_info) != STB_WEAK) 172 return 1; 173 continue; 174 } 175 176 where = (Elf_Addr *)(reloc->r_offset + object->obj_base); 177 *where = sr.obj->obj_base + sr.sym->st_value; 178 } 179 180 return 0; 181} 182 183/* 184 * Relocate the Global Offset Table (GOT). 185 * This is done by calling _dl_md_reloc on DT_JMPREL for DL_BIND_NOW, 186 * otherwise the lazy binding plt initialization is performed. 187 */ 188int 189_dl_md_reloc_got(elf_object_t *object, int lazy) 190{ 191 Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT]; 192 const Elf_RelA *reloc, *rend; 193 194 if (pltgot == NULL) 195 return 0; /* it is possible to have no PLT/GOT relocations */ 196 197 if (object->Dyn.info[DT_PLTREL] != DT_RELA) 198 return 0; 199 200 if (object->traced) 201 lazy = 1; 202 203 reloc = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]); 204 rend = (Elf_RelA *)((char *)reloc + object->Dyn.info[DT_PLTRELSZ]); 205 206 if (!lazy) 207 return _dl_md_reloc_all_plt(object, reloc, rend); 208 209 /* Lazy */ 210 pltgot[1] = (Elf_Addr)object; 211 pltgot[2] = (Elf_Addr)_dl_bind_start; 212 213 for (; reloc < rend; reloc++) { 214 Elf_Addr *where; 215 where = (Elf_Addr *)(reloc->r_offset + object->obj_base); 216 *where += object->obj_base; 217 } 218 219 return 0; 220} 221 222Elf_Addr 223_dl_bind(elf_object_t *object, int relidx) 224{ 225 Elf_RelA *rel; 226 const Elf_Sym *sym; 227 const char *symn; 228 struct sym_res sr; 229 int64_t cookie = pcookie; 230 struct { 231 struct __kbind param; 232 Elf_Addr newval; 233 } buf; 234 235 rel = ((Elf_RelA *)object->Dyn.info[DT_JMPREL]) + (relidx); 236 237 sym = object->dyn.symtab; 238 sym += ELF_R_SYM(rel->r_info); 239 symn = object->dyn.strtab + sym->st_name; 240 241 sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, 242 sym, object); 243 if (sr.sym == NULL) 244 _dl_die("lazy binding failed!"); 245 246 buf.newval = sr.obj->obj_base + sr.sym->st_value; 247 248 if (sr.obj->traced && _dl_trace_plt(sr.obj, symn)) 249 return buf.newval; 250 251 buf.param.kb_addr = (Elf_Word *)(object->obj_base + rel->r_offset); 252 buf.param.kb_size = sizeof(Elf_Addr); 253 254 /* directly code the syscall, so that it's actually inline here */ 255 { 256 register long syscall_num __asm("x8") = SYS_kbind; 257 register void *arg1 __asm("x0") = &buf; 258 register long arg2 __asm("x1") = sizeof(buf); 259 register long arg3 __asm("x2") = cookie; 260 261 __asm volatile("svc 0" : "+r" (arg1), "+r" (arg2) 262 : "r" (syscall_num), "r" (arg3) 263 : "cc", "memory"); 264 } 265 266 return buf.newval; 267} 268