rtld_machine.c revision 1.5
1/* $OpenBSD: rtld_machine.c,v 1.5 2002/11/23 06:04:13 drahn Exp $ */ 2 3/* 4 * Copyright (c) 2002 Dale Rahn 5 * Copyright (c) 2001 Niklas Hallqvist 6 * Copyright (c) 2001 Artur Grabowski 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed under OpenBSD by 19 * Dale Rahn. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 24 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 27 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35/*- 36 * Copyright (c) 2000 Eduardo Horvath. 37 * Copyright (c) 1999 The NetBSD Foundation, Inc. 38 * All rights reserved. 39 * 40 * This code is derived from software contributed to The NetBSD Foundation 41 * by Paul Kranenburg. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by the NetBSD 54 * Foundation, Inc. and its contributors. 55 * 4. Neither the name of The NetBSD Foundation nor the names of its 56 * contributors may be used to endorse or promote products derived 57 * from this software without specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 60 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 61 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 62 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 63 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 64 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 65 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 66 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 67 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 68 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 69 * POSSIBILITY OF SUCH DAMAGE. 70 */ 71 72#define _DYN_LOADER 73 74#include <sys/types.h> 75#include <sys/cdefs.h> 76#include <sys/mman.h> 77 78#include <nlist.h> 79#include <link.h> 80 81#include "syscall.h" 82#include "archdep.h" 83#include "resolve.h" 84 85void 86_dl_bcopy(const void *src, void *dest, int size) 87{ 88 const unsigned char *psrc = src; 89 unsigned char *pdest = dest; 90 int i; 91 92 for (i = 0; i < size; i++) 93 pdest[i] = psrc[i]; 94} 95 96/* 97 * The following table holds for each relocation type: 98 * - the width in bits of the memory location the relocation 99 * applies to (not currently used) 100 * - the number of bits the relocation value must be shifted to the 101 * right (i.e. discard least significant bits) to fit into 102 * the appropriate field in the instruction word. 103 * - flags indicating whether 104 * * the relocation involves a symbol 105 * * the relocation is relative to the current position 106 * * the relocation is for a GOT entry 107 * * the relocation is relative to the load address 108 * 109 */ 110#define _RF_S 0x80000000 /* Resolve symbol */ 111#define _RF_A 0x40000000 /* Use addend */ 112#define _RF_P 0x20000000 /* Location relative */ 113#define _RF_G 0x10000000 /* GOT offset */ 114#define _RF_B 0x08000000 /* Load address relative */ 115#define _RF_U 0x04000000 /* Unaligned */ 116#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */ 117#define _RF_RS(s) ((s) & 0xff) /* right shift */ 118static int reloc_target_flags[] = { 119 0, /* NONE */ 120 _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* RELOC_32*/ 121 _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PC32 */ 122 _RF_G| _RF_SZ(32) | _RF_RS(00), /* GOT32 */ 123 _RF_A| _RF_SZ(32) | _RF_RS(0), /* PLT32 */ 124 _RF_S| _RF_SZ(32) | _RF_RS(0), /* COPY */ 125 _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GLOB_DAT */ 126 _RF_S| _RF_SZ(32) | _RF_RS(0), /* JUMP_SLOT */ 127 _RF_A| _RF_B| _RF_SZ(32) | _RF_RS(0), /* RELATIVE */ 128 0, /* GOTOFF XXX */ 129 0, /* GOTPC XXX */ 130 0, /* DUMMY 11 */ 131 0, /* DUMMY 12 */ 132 0, /* DUMMY 13 */ 133 0, /* DUMMY 14 */ 134 0, /* DUMMY 15 */ 135 0, /* DUMMY 16 */ 136 0, /* DUMMY 17 */ 137 0, /* DUMMY 18 */ 138 0, /* DUMMY 19 */ 139 _RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0), /* RELOC_16 */ 140 _RF_S|_RF_A|_RF_P| _RF_SZ(16) | _RF_RS(0), /* PC_16 */ 141 _RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0), /* RELOC_8 */ 142 _RF_S|_RF_A|_RF_P| _RF_SZ(8) | _RF_RS(0), /* RELOC_PC8 */ 143}; 144 145#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0) 146#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0) 147#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0) 148#define RELOC_UNALIGNED(t) ((reloc_target_flags[t] & _RF_U) != 0) 149#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0) 150#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff) 151#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff) 152 153static long reloc_target_bitmask[] = { 154#define _BM(x) (~(-(1ULL << (x)))) 155 0, /* NONE */ 156 _BM(32), /* RELOC_32*/ 157 _BM(32), /* PC32 */ 158 _BM(32), /* GOT32 */ 159 _BM(32), /* PLT32 */ 160 0, /* COPY */ 161 _BM(32), /* GLOB_DAT */ 162 _BM(32), /* JUMP_SLOT */ 163 _BM(32), /* RELATIVE */ 164 0, /* GOTOFF XXX */ 165 0, /* GOTPC XXX */ 166 0, /* DUMMY 11 */ 167 0, /* DUMMY 12 */ 168 0, /* DUMMY 13 */ 169 0, /* DUMMY 14 */ 170 0, /* DUMMY 15 */ 171 0, /* DUMMY 16 */ 172 0, /* DUMMY 17 */ 173 0, /* DUMMY 18 */ 174 0, /* DUMMY 19 */ 175 _BM(16), /* RELOC_16 */ 176 _BM(8), /* PC_16 */ 177 _BM(8), /* RELOC_8 */ 178 _BM(8), /* RELOC_PC8 */ 179#undef _BM 180}; 181#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t]) 182 183void _dl_reloc_plt(Elf_Addr *where, Elf_Addr value); 184 185int 186_dl_md_reloc(elf_object_t *object, int rel, int relsz) 187{ 188 long i; 189 long numrel; 190 long fails = 0; 191 Elf_Addr loff; 192 Elf_Rel *rels; 193 struct load_list *llist; 194 195 loff = object->load_offs; 196 numrel = object->Dyn.info[relsz] / sizeof(Elf32_Rel); 197 rels = (Elf32_Rel *)(object->Dyn.info[rel]); 198 if (rels == NULL) 199 return(0); 200 201 /* 202 * unprotect some segments if we need it. 203 */ 204 if ((rel == DT_REL || rel == DT_RELA)) { 205 for (llist = object->load_list; llist != NULL; llist = llist->next) { 206 if (!(llist->prot & PROT_WRITE)) 207 _dl_mprotect(llist->start, llist->size, 208 llist->prot|PROT_WRITE); 209 } 210 } 211 212 for (i = 0; i < numrel; i++, rels++) { 213 Elf_Addr *where, value, ooff, mask; 214 Elf_Word type; 215 const Elf_Sym *sym, *this; 216 const char *symn; 217 218 type = ELF_R_TYPE(rels->r_info); 219 220 if (type == R_TYPE(NONE)) 221 continue; 222 223 if (type == R_TYPE(JUMP_SLOT) && rel != DT_JMPREL) 224 continue; 225 226 where = (Elf_Addr *)(rels->r_offset + loff); 227 228 if (RELOC_USE_ADDEND(type)) 229 value = *where & RELOC_VALUE_BITMASK(type); 230 else 231 value = 0; 232 233 sym = NULL; 234 symn = NULL; 235 if (RELOC_RESOLVE_SYMBOL(type)) { 236 sym = object->dyn.symtab; 237 sym += ELF_R_SYM(rels->r_info); 238 symn = object->dyn.strtab + sym->st_name; 239 240 if (sym->st_shndx != SHN_UNDEF && 241 ELF_ST_BIND(sym->st_info) == STB_LOCAL) { 242 value += loff; 243 } else { 244 this = NULL; 245 ooff = _dl_find_symbol(symn, _dl_objects, 246 &this, SYM_SEARCH_ALL|SYM_WARNNOTFOUND| 247 ((type == R_TYPE(JUMP_SLOT))? 248 SYM_PLT:SYM_NOTPLT), 249 sym->st_size, object->load_name); 250 if (this == NULL) { 251resolve_failed: 252 _dl_printf("%s: %s: can't resolve " 253 "reference '%s'\n", 254 _dl_progname, object->load_name, 255 symn); 256 fails++; 257 continue; 258 } 259 value += (Elf_Addr)(ooff + this->st_value); 260 } 261 } 262 263 if (type == R_TYPE(JUMP_SLOT)) { 264 _dl_reloc_plt((Elf_Word *)where, value); 265 continue; 266 } 267 268 if (type == R_TYPE(COPY)) { 269 void *dstaddr = where; 270 const void *srcaddr; 271 const Elf_Sym *dstsym = sym, *srcsym = NULL; 272 size_t size = dstsym->st_size; 273 Elf_Addr soff; 274 275 soff = _dl_find_symbol(symn, object->next, &srcsym, 276 SYM_SEARCH_ALL|SYM_WARNNOTFOUND| 277 ((type == R_TYPE(JUMP_SLOT)) ? SYM_PLT:SYM_NOTPLT), 278 size, object->load_name); 279 if (srcsym == NULL) 280 goto resolve_failed; 281 282 srcaddr = (void *)(soff + srcsym->st_value); 283 _dl_bcopy(srcaddr, dstaddr, size); 284 continue; 285 } 286 287 if (RELOC_PC_RELATIVE(type)) 288 value -= (Elf_Addr)where; 289 if (RELOC_BASE_RELATIVE(type)) 290 value += loff; 291 292 mask = RELOC_VALUE_BITMASK(type); 293 value >>= RELOC_VALUE_RIGHTSHIFT(type); 294 value &= mask; 295 296 if (RELOC_UNALIGNED(type)) { 297 /* Handle unaligned relocations. */ 298 Elf_Addr tmp = 0; 299 char *ptr = (char *)where; 300 int i, size = RELOC_TARGET_SIZE(type)/8; 301 302 /* Read it in one byte at a time. */ 303 for (i=0; i<size; i++) 304 tmp = (tmp << 8) | ptr[i]; 305 306 tmp &= ~mask; 307 tmp |= value; 308 309 /* Write it back out. */ 310 for (i=0; i<size; i++) 311 ptr[i] = ((tmp >> (8*i)) & 0xff); 312 } else if (RELOC_TARGET_SIZE(type) > 32) { 313 *where &= ~mask; 314 *where |= value; 315 } else { 316 Elf32_Addr *where32 = (Elf32_Addr *)where; 317 318 *where32 &= ~mask; 319 *where32 |= value; 320 } 321 } 322 323 /* reprotect the unprotected segments */ 324 if ((rel == DT_REL || rel == DT_RELA)) { 325 for (llist = object->load_list; llist != NULL; llist = llist->next) { 326 if (!(llist->prot & PROT_WRITE)) 327 _dl_mprotect(llist->start, llist->size, 328 llist->prot); 329 } 330 } 331 332 return (fails); 333} 334 335struct jmpslot { 336 u_short opcode; 337 u_short addr[2]; 338 u_short reloc_index; 339#define JMPSLOT_RELOC_MASK 0xffff 340}; 341#define JUMP 0xe990 /* NOP + JMP opcode */ 342 343void 344_dl_reloc_plt(Elf_Addr *where, Elf_Addr value) 345{ 346 *where = value; 347} 348 349/* 350 * Resolve a symbol at run-time. 351 */ 352Elf_Addr 353_dl_bind(elf_object_t *object, int index) 354{ 355 Elf_Rel *rel; 356 Elf_Word *addr; 357 const Elf_Sym *sym, *this; 358 const char *symn; 359 Elf_Addr ooff; 360 361 rel = (Elf_Rel *)(object->Dyn.info[DT_JMPREL]); 362 363 rel += index/sizeof(Elf_Rel); 364 365 sym = object->dyn.symtab; 366 sym += ELF_R_SYM(rel->r_info); 367 symn = object->dyn.strtab + sym->st_name; 368 369 addr = (Elf_Word *)(object->load_offs + rel->r_offset); 370 this = NULL; 371 ooff = _dl_find_symbol(symn, _dl_objects, &this, 372 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, 0, object->load_name); 373 if (this == NULL) { 374 _dl_printf("lazy binding failed!\n"); 375 *((int *)0) = 0; /* XXX */ 376 } 377 378 _dl_reloc_plt(addr, ooff + this->st_value); 379 380 return((Elf_Addr)ooff + this->st_value); 381} 382 383void 384_dl_md_reloc_got(elf_object_t *object, int lazy) 385{ 386 extern void _dl_bind_start(void); /* XXX */ 387 Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT]; 388 int i, num; 389 Elf_Rel *rel; 390 struct load_list *llist; 391 392 if (pltgot == NULL) 393 return; /* it is possible to have no PLT/GOT relocations */ 394 395 pltgot[1] = (Elf_Addr)object; 396 pltgot[2] = (Elf_Addr)&_dl_bind_start; 397 398 if (object->Dyn.info[DT_PLTREL] != DT_REL) 399 return; 400 401 if (!lazy) { 402 _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); 403 return; 404 } 405 406 rel = (Elf_Rel *)(object->Dyn.info[DT_JMPREL]); 407 num = (object->Dyn.info[DT_PLTRELSZ]); 408 for (llist = object->load_list; llist != NULL; llist = llist->next) { 409 if (!(llist->prot & PROT_WRITE)) 410 _dl_mprotect(llist->start, llist->size, 411 llist->prot|PROT_WRITE); 412 } 413 for (i = 0; i < num/sizeof(Elf_Rel); i++, rel++) { 414 Elf_Addr *where; 415 where = (Elf_Addr *)(rel->r_offset + object->load_offs); 416 *where += object->load_offs; 417 } 418 for (llist = object->load_list; llist != NULL; llist = llist->next) { 419 if (!(llist->prot & PROT_WRITE)) 420 _dl_mprotect(llist->start, llist->size, 421 llist->prot); 422 } 423} 424