1 /* $OpenBSD: rtld_machine.c,v 1.37 2019/11/27 01:24:35 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 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 reloff); 47 48 #define R_TYPE(x) R_ARM_ ## x 49 50 int 51 _dl_md_reloc(elf_object_t *object, int rel, int relsz) 52 { 53 long i; 54 long numrel; 55 long relrel; 56 Elf_Addr loff; 57 Elf_Addr prev_value = 0; 58 const Elf_Sym *prev_sym = NULL; 59 Elf_Rel *rels; 60 61 loff = object->obj_base; 62 numrel = object->Dyn.info[relsz] / sizeof(Elf_Rel); 63 relrel = object->relcount; 64 rels = (Elf_Rel *)(object->Dyn.info[rel]); 65 66 if (rels == NULL) 67 return 0; 68 69 if (relrel > numrel) 70 _dl_die("relcount > numrel: %ld > %ld", relrel, numrel); 71 72 /* tight loop for leading RELATIVE relocs */ 73 for (i = 0; i < relrel; i++, rels++) { 74 Elf_Addr *where; 75 76 where = (Elf_Addr *)(rels->r_offset + loff); 77 *where += loff; 78 } 79 for (; i < numrel; i++, rels++) { 80 Elf_Addr *where, value; 81 Elf_Word type; 82 const Elf_Sym *sym; 83 const char *symn; 84 85 where = (Elf_Addr *)(rels->r_offset + loff); 86 87 sym = object->dyn.symtab; 88 sym += ELF_R_SYM(rels->r_info); 89 symn = object->dyn.strtab + sym->st_name; 90 91 type = ELF_R_TYPE(rels->r_info); 92 switch (type) { 93 case R_TYPE(NONE): 94 case R_TYPE(JUMP_SLOT): /* shouldn't happen */ 95 continue; 96 97 case R_TYPE(RELATIVE): 98 *where += loff; 99 continue; 100 101 case R_TYPE(ABS32): 102 case R_TYPE(GLOB_DAT): 103 value = *where; 104 break; 105 106 case R_TYPE(COPY): 107 { 108 struct sym_res sr; 109 110 sr = _dl_find_symbol(symn, 111 SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT, 112 sym, object); 113 if (sr.sym == NULL) 114 return 1; 115 116 value = sr.obj->obj_base + sr.sym->st_value; 117 _dl_bcopy((void *)value, where, sym->st_size); 118 continue; 119 } 120 121 default: 122 _dl_die("relocation error %d", type); 123 } 124 125 126 /* Finish the ABS32 and GLOB_DAT cases */ 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 154 static int 155 _dl_md_reloc_all_plt(elf_object_t *object, const Elf_Rel *reloc, 156 const Elf_Rel *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 */ 186 int 187 _dl_md_reloc_got(elf_object_t *object, int lazy) 188 { 189 Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT]; 190 const Elf_Rel *reloc, *rend; 191 192 if (pltgot == NULL) 193 return 0; /* it is possible to have no PLT/GOT relocations */ 194 195 if (object->Dyn.info[DT_PLTREL] != DT_REL) 196 return 0; 197 198 if (object->traced) 199 lazy = 1; 200 201 reloc = (const Elf_Rel *)(object->Dyn.info[DT_JMPREL]); 202 rend = (const Elf_Rel *)((char *)reloc + object->Dyn.info[DT_PLTRELSZ]); 203 204 if (!lazy) 205 return _dl_md_reloc_all_plt(object, reloc, rend); 206 207 /* Lazy */ 208 pltgot[1] = (Elf_Addr)object; 209 pltgot[2] = (Elf_Addr)_dl_bind_start; 210 211 for (; reloc < rend; reloc++) { 212 Elf_Addr *where; 213 where = (Elf_Addr *)(reloc->r_offset + object->obj_base); 214 *where += object->obj_base; 215 } 216 217 return 0; 218 } 219 220 Elf_Addr 221 _dl_bind(elf_object_t *object, int relidx) 222 { 223 Elf_Rel *rel; 224 const Elf_Sym *sym; 225 const char *symn; 226 struct sym_res sr; 227 int64_t cookie = pcookie; 228 struct { 229 struct __kbind param; 230 Elf_Word newval; 231 } buf; 232 233 rel = ((Elf_Rel *)object->Dyn.info[DT_JMPREL]) + (relidx); 234 235 sym = object->dyn.symtab; 236 sym += ELF_R_SYM(rel->r_info); 237 symn = object->dyn.strtab + sym->st_name; 238 239 sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, 240 sym, object); 241 if (sr.sym == NULL) 242 _dl_die("lazy binding failed!"); 243 244 buf.newval = sr.obj->obj_base + sr.sym->st_value; 245 246 if (__predict_false(sr.obj->traced) && _dl_trace_plt(sr.obj, symn)) 247 return buf.newval; 248 249 buf.param.kb_addr = (Elf_Addr *)(object->obj_base + rel->r_offset); 250 buf.param.kb_size = sizeof(Elf_Word); 251 252 /* directly code the syscall, so that it's actually inline here */ 253 { 254 register long syscall_num __asm("r12") = SYS_kbind; 255 register void *arg1 __asm("r0") = &buf; 256 register long arg2 __asm("r1") = sizeof(buf); 257 register long arg3 __asm("r2") = 0xffffffff & cookie; 258 register long arg4 __asm("r3") = 0xffffffff & (cookie >> 32); 259 260 __asm volatile("swi 0" : "+r" (arg1), "+r" (arg2) 261 : "r" (syscall_num), "r" (arg3), "r" (arg4) 262 : "cc", "memory"); 263 } 264 265 return buf.newval; 266 } 267