1 /* $OpenBSD: rtld_machine.c,v 1.7 2022/01/08 06:49:42 guenther Exp $ */ 2 3 /* 4 * Copyright (c) 1999 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/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 41 #define DT_PROC(n) ((n) - DT_LOPROC + DT_NUM) 42 43 int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden; 44 45 /* relocation bits */ 46 #define B24_VALID_RANGE(x) \ 47 ((((x) & 0xfe000000) == 0x00000000) || (((x) & 0xfe000000) == 0xfe000000)) 48 49 void _dl_bind_start(void); /* XXX */ 50 Elf_Addr _dl_bind(elf_object_t *object, int reloff); 51 52 int 53 _dl_md_reloc(elf_object_t *object, int rel, int relasz) 54 { 55 int i; 56 int numrela; 57 long relrel; 58 int fails = 0; 59 Elf_Addr loff; 60 Elf_RelA *relas; 61 /* for jmp table relocations */ 62 Elf_Addr prev_value = 0, prev_ooff = 0; 63 const Elf_Sym *prev_sym = NULL; 64 65 loff = object->obj_base; 66 numrela = object->Dyn.info[relasz] / sizeof(Elf_RelA); 67 relrel = rel == DT_RELA ? object->relacount : 0; 68 relas = (Elf_RelA *)(object->Dyn.info[rel]); 69 70 if (relas == NULL) 71 return 0; 72 73 if (relrel > numrela) 74 _dl_die("relcount > numrel: %ld > %d", relrel, numrela); 75 76 /* tight loop for leading RELATIVE relocs */ 77 for (i = 0; i < relrel; i++, relas++) { 78 Elf_Addr *r_addr; 79 80 r_addr = (Elf_Addr *)(relas->r_offset + loff); 81 *r_addr = loff + relas->r_addend; 82 } 83 for (; i < numrela; i++, relas++) { 84 Elf_Addr *r_addr = (Elf_Addr *)(relas->r_offset + loff); 85 const Elf_Sym *sym; 86 const char *symn; 87 int type; 88 89 if (ELF_R_SYM(relas->r_info) == 0xffffff) 90 continue; 91 92 type = ELF_R_TYPE(relas->r_info); 93 94 if (type == R_PPC64_JMP_SLOT && rel != DT_JMPREL) 95 continue; 96 97 sym = object->dyn.symtab; 98 sym += ELF_R_SYM(relas->r_info); 99 symn = object->dyn.strtab + sym->st_name; 100 101 if (ELF_R_SYM(relas->r_info) && 102 !(ELF_ST_BIND(sym->st_info) == STB_LOCAL && 103 ELF_ST_TYPE (sym->st_info) == STT_NOTYPE) && 104 sym != prev_sym) { 105 struct sym_res sr; 106 107 sr = _dl_find_symbol(symn, 108 SYM_SEARCH_ALL|SYM_WARNNOTFOUND| 109 ((type == R_PPC64_JMP_SLOT) ? 110 SYM_PLT:SYM_NOTPLT), sym, object); 111 112 if (sr.sym == NULL) { 113 if (ELF_ST_BIND(sym->st_info) != STB_WEAK) 114 fails++; 115 continue; 116 } 117 prev_sym = sym; 118 prev_value = sr.sym->st_value; 119 prev_ooff = sr.obj->obj_base; 120 } 121 122 switch (type) { 123 case R_PPC64_ADDR64: 124 if (ELF_ST_BIND(sym->st_info) == STB_LOCAL && 125 (ELF_ST_TYPE(sym->st_info) == STT_SECTION || 126 ELF_ST_TYPE(sym->st_info) == STT_NOTYPE) ) { 127 *r_addr = prev_ooff + relas->r_addend; 128 } else { 129 *r_addr = prev_ooff + prev_value + 130 relas->r_addend; 131 } 132 break; 133 case R_PPC64_RELATIVE: 134 if (ELF_ST_BIND(sym->st_info) == STB_LOCAL && 135 (ELF_ST_TYPE(sym->st_info) == STT_SECTION || 136 ELF_ST_TYPE(sym->st_info) == STT_NOTYPE) ) { 137 *r_addr = loff + relas->r_addend; 138 } else { 139 *r_addr = loff + prev_value + 140 relas->r_addend; 141 } 142 break; 143 /* 144 * For Secure-PLT, RELOC_JMP_SLOT simply sets PLT 145 * slots similarly to how RELOC_GLOB_DAT updates GOT 146 * slots. 147 */ 148 case R_PPC64_JMP_SLOT: 149 case R_PPC64_GLOB_DAT: 150 *r_addr = prev_ooff + prev_value + relas->r_addend; 151 break; 152 #if 0 153 /* should not be supported ??? */ 154 case RELOC_REL24: 155 { 156 Elf_Addr val = prev_ooff + prev_value + 157 relas->r_addend - (Elf_Addr)r_addr; 158 if (!B24_VALID_RANGE(val)) { 159 /* invalid offset */ 160 _dl_die("%s: invalid %s offset %llx at %p", 161 object->load_name, "REL24", val, 162 (void *)r_addr); 163 } 164 val &= ~0xfc000003; 165 val |= (*r_addr & 0xfc000003); 166 *r_addr = val; 167 168 _dl_dcbf(r_addr); 169 } 170 break; 171 #endif 172 #if 0 173 case RELOC_16_LO: 174 { 175 Elf_Addr val; 176 177 val = loff + relas->r_addend; 178 *(Elf_Half *)r_addr = val; 179 180 _dl_dcbf(r_addr); 181 } 182 break; 183 #endif 184 #if 0 185 case RELOC_16_HI: 186 { 187 Elf_Addr val; 188 189 val = loff + relas->r_addend; 190 *(Elf_Half *)r_addr = (val >> 16); 191 192 _dl_dcbf(r_addr); 193 } 194 break; 195 #endif 196 #if 0 197 case RELOC_16_HA: 198 { 199 Elf_Addr val; 200 201 val = loff + relas->r_addend; 202 *(Elf_Half *)r_addr = ((val + 0x8000) >> 16); 203 204 _dl_dcbf(r_addr); 205 } 206 break; 207 #endif 208 #if 0 209 case RELOC_REL14_TAKEN: 210 /* val |= 1 << (31-10) XXX? */ 211 case RELOC_REL14: 212 case RELOC_REL14_NTAKEN: 213 { 214 Elf_Addr val = prev_ooff + prev_value + 215 relas->r_addend - (Elf_Addr)r_addr; 216 if (((val & 0xffff8000) != 0) && 217 ((val & 0xffff8000) != 0xffff8000)) { 218 /* invalid offset */ 219 _dl_die("%s: invalid %s offset %llx at %p", 220 object->load_name, "REL14", val, 221 (void *)r_addr); 222 } 223 val &= ~0xffff0003; 224 val |= (*r_addr & 0xffff0003); 225 *r_addr = val; 226 _dl_dcbf(r_addr); 227 } 228 break; 229 #endif 230 case R_PPC64_COPY: 231 { 232 struct sym_res sr; 233 /* 234 * we need to find a symbol, that is not in the current 235 * object, start looking at the beginning of the list, 236 * searching all objects but _not_ the current object, 237 * first one found wins. 238 */ 239 sr = _dl_find_symbol(symn, 240 SYM_SEARCH_OTHER|SYM_WARNNOTFOUND| SYM_NOTPLT, 241 sym, object); 242 if (sr.sym != NULL) { 243 _dl_bcopy((void *)(sr.obj->obj_base + sr.sym->st_value), 244 r_addr, sym->st_size); 245 } else 246 fails++; 247 } 248 break; 249 case R_PPC64_NONE: 250 break; 251 252 default: 253 _dl_die("%s: unsupported relocation '%s' %lld at %p\n", 254 object->load_name, symn, 255 ELF_R_TYPE(relas->r_info), (void *)r_addr ); 256 } 257 } 258 259 return fails; 260 } 261 262 /* 263 * Relocate the Global Offset Table (GOT). 264 * This is done by calling _dl_md_reloc on DT_JMPREL for DL_BIND_NOW, 265 * otherwise the lazy binding plt initialization is performed. 266 */ 267 int 268 _dl_md_reloc_got(elf_object_t *object, int lazy) 269 { 270 int fails = 0; 271 272 if (object->Dyn.info[DT_PLTREL] != DT_RELA) 273 return 0; 274 275 if (!lazy) { 276 fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); 277 } else { 278 Elf_Addr *plt; 279 int numplt, n; 280 281 /* Relocate processor-specific tags. */ 282 object->Dyn.info[DT_PROC(DT_PPC64_GLINK)] += object->obj_base; 283 284 plt = (Elf_Addr *) 285 (Elf_RelA *)(object->Dyn.info[DT_PLTGOT]); 286 numplt = object->Dyn.info[DT_PLTRELSZ] / sizeof(Elf_RelA); 287 plt[0] = (uint64_t)_dl_bind_start; 288 plt[1] = (uint64_t)object; 289 for (n = 0; n < numplt; n++) { 290 plt[n + 2] = object->Dyn.info[DT_PROC(DT_PPC64_GLINK)] + 291 n * 4 + 32; 292 } 293 } 294 295 return fails; 296 } 297 298 Elf_Addr 299 _dl_bind(elf_object_t *object, int relidx) 300 { 301 const Elf_Sym *sym; 302 struct sym_res sr; 303 const char *symn; 304 Elf_RelA *relas; 305 Elf_Addr *plttable; 306 int64_t cookie = pcookie; 307 struct { 308 struct __kbind param; 309 Elf_Addr newval; 310 } buf; 311 312 relas = ((Elf_RelA *)object->Dyn.info[DT_JMPREL]) + relidx; 313 314 sym = object->dyn.symtab; 315 sym += ELF_R_SYM(relas->r_info); 316 symn = object->dyn.strtab + sym->st_name; 317 318 sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, 319 sym, object); 320 if (sr.sym == NULL) 321 _dl_die("lazy binding failed!"); 322 323 buf.newval = sr.obj->obj_base + sr.sym->st_value; 324 325 if (__predict_false(sr.obj->traced) && _dl_trace_plt(sr.obj, symn)) 326 return buf.newval; 327 328 plttable = (Elf_Addr *)(Elf_RelA *)(object->Dyn.info[DT_PLTGOT]); 329 buf.param.kb_addr = &plttable[relidx + 2]; 330 buf.param.kb_size = sizeof(Elf_Addr); 331 332 { 333 register long syscall_num __asm("r0") = SYS_kbind; 334 register void *arg1 __asm("r3") = &buf.param; 335 register long arg2 __asm("r4") = sizeof(struct __kbind) + 336 sizeof(Elf_Addr); 337 register long arg3 __asm("r5") = cookie; 338 339 __asm volatile("sc" : "+r" (syscall_num), "+r" (arg1), 340 "+r" (arg2) : "r" (arg3) : "cc", "memory"); 341 } 342 343 return buf.newval; 344 } 345