|
|
1.1 ! root 1: /****************************************************************************** ! 2: * Copyright (c) 2004, 2011 IBM Corporation ! 3: * All rights reserved. ! 4: * This program and the accompanying materials ! 5: * are made available under the terms of the BSD License ! 6: * which accompanies this distribution, and is available at ! 7: * http://www.opensource.org/licenses/bsd-license.php ! 8: * ! 9: * Contributors: ! 10: * IBM Corporation - initial implementation ! 11: *****************************************************************************/ ! 12: ! 13: /* ! 14: * 64-bit ELF loader for PowerPC. ! 15: * See the "64-bit PowerPC ELF Application Binary Interface Supplement" and ! 16: * the "ELF-64 Object File Format" documentation for details. ! 17: */ ! 18: ! 19: #include <string.h> ! 20: #include <stdio.h> ! 21: #include <libelf.h> ! 22: ! 23: struct ehdr64 ! 24: { ! 25: uint32_t ei_ident; ! 26: uint8_t ei_class; ! 27: uint8_t ei_data; ! 28: uint8_t ei_version; ! 29: uint8_t ei_pad[9]; ! 30: uint16_t e_type; ! 31: uint16_t e_machine; ! 32: uint32_t e_version; ! 33: uint64_t e_entry; ! 34: uint64_t e_phoff; ! 35: uint64_t e_shoff; ! 36: uint32_t e_flags; ! 37: uint16_t e_ehsize; ! 38: uint16_t e_phentsize; ! 39: uint16_t e_phnum; ! 40: uint16_t e_shentsize; ! 41: uint16_t e_shnum; ! 42: uint16_t e_shstrndx; ! 43: }; ! 44: ! 45: struct phdr64 ! 46: { ! 47: uint32_t p_type; ! 48: uint32_t p_flags; ! 49: uint64_t p_offset; ! 50: uint64_t p_vaddr; ! 51: uint64_t p_paddr; ! 52: uint64_t p_filesz; ! 53: uint64_t p_memsz; ! 54: uint64_t p_align; ! 55: }; ! 56: ! 57: struct shdr64 ! 58: { ! 59: uint32_t sh_name; /* Section name */ ! 60: uint32_t sh_type; /* Section type */ ! 61: uint64_t sh_flags; /* Section attributes */ ! 62: uint64_t sh_addr; /* Virtual address in memory */ ! 63: uint64_t sh_offset; /* Offset in file */ ! 64: uint64_t sh_size; /* Size of section */ ! 65: uint32_t sh_link; /* Link to other section */ ! 66: uint32_t sh_info; /* Miscellaneous information */ ! 67: uint64_t sh_addralign; /* Address alignment boundary */ ! 68: uint64_t sh_entsize; /* Size of entries, if section has table */ ! 69: }; ! 70: ! 71: struct rela /* RelA relocation table entry */ ! 72: { ! 73: uint64_t r_offset; /* Address of reference */ ! 74: uint64_t r_info; /* Symbol index and type of relocation */ ! 75: int64_t r_addend; /* Constant part of expression */ ! 76: }; ! 77: ! 78: struct sym64 ! 79: { ! 80: uint32_t st_name; /* Symbol name */ ! 81: uint8_t st_info; /* Type and Binding attributes */ ! 82: uint8_t st_other; /* Reserved */ ! 83: uint16_t st_shndx; /* Section table index */ ! 84: uint64_t st_value; /* Symbol value */ ! 85: uint64_t st_size; /* Size of object (e.g., common) */ ! 86: }; ! 87: ! 88: ! 89: /* For relocations */ ! 90: #define ELF_R_SYM(i) ((i)>>32) ! 91: #define ELF_R_TYPE(i) ((uint32_t)(i) & 0xFFFFFFFF) ! 92: #define ELF_R_INFO(s,t) ((((uint64_t) (s)) << 32) + (t)) ! 93: ! 94: /* ! 95: * Relocation types for PowerPC64. ! 96: */ ! 97: #define R_PPC64_NONE 0 ! 98: #define R_PPC64_ADDR32 1 ! 99: #define R_PPC64_ADDR24 2 ! 100: #define R_PPC64_ADDR16 3 ! 101: #define R_PPC64_ADDR16_LO 4 ! 102: #define R_PPC64_ADDR16_HI 5 ! 103: #define R_PPC64_ADDR16_HA 6 ! 104: #define R_PPC64_ADDR14 7 ! 105: #define R_PPC64_ADDR14_BRTAKEN 8 ! 106: #define R_PPC64_ADDR14_BRNTAKEN 9 ! 107: #define R_PPC64_REL24 10 ! 108: #define R_PPC64_REL14 11 ! 109: #define R_PPC64_REL14_BRTAKEN 12 ! 110: #define R_PPC64_REL14_BRNTAKEN 13 ! 111: #define R_PPC64_GOT16 14 ! 112: #define R_PPC64_GOT16_LO 15 ! 113: #define R_PPC64_GOT16_HI 16 ! 114: #define R_PPC64_GOT16_HA 17 ! 115: #define R_PPC64_COPY 19 ! 116: #define R_PPC64_GLOB_DAT 20 ! 117: #define R_PPC64_JMP_SLOT 21 ! 118: #define R_PPC64_RELATIVE 22 ! 119: #define R_PPC64_UADDR32 24 ! 120: #define R_PPC64_UADDR16 25 ! 121: #define R_PPC64_REL32 26 ! 122: #define R_PPC64_PLT32 27 ! 123: #define R_PPC64_PLTREL32 28 ! 124: #define R_PPC64_PLT16_LO 29 ! 125: #define R_PPC64_PLT16_HI 30 ! 126: #define R_PPC64_PLT16_HA 31 ! 127: #define R_PPC64_SECTOFF 33 ! 128: #define R_PPC64_SECTOFF_LO 34 ! 129: #define R_PPC64_SECTOFF_HI 35 ! 130: #define R_PPC64_SECTOFF_HA 36 ! 131: #define R_PPC64_ADDR30 37 ! 132: #define R_PPC64_ADDR64 38 ! 133: #define R_PPC64_ADDR16_HIGHER 39 ! 134: #define R_PPC64_ADDR16_HIGHERA 40 ! 135: #define R_PPC64_ADDR16_HIGHEST 41 ! 136: #define R_PPC64_ADDR16_HIGHESTA 42 ! 137: #define R_PPC64_UADDR64 43 ! 138: #define R_PPC64_REL64 44 ! 139: #define R_PPC64_PLT64 45 ! 140: #define R_PPC64_PLTREL64 46 ! 141: #define R_PPC64_TOC16 47 ! 142: #define R_PPC64_TOC16_LO 48 ! 143: #define R_PPC64_TOC16_HI 49 ! 144: #define R_PPC64_TOC16_HA 50 ! 145: #define R_PPC64_TOC 51 ! 146: #define R_PPC64_PLTGOT16 52 ! 147: #define R_PPC64_PLTGOT16_LO 53 ! 148: #define R_PPC64_PLTGOT16_HI 54 ! 149: #define R_PPC64_PLTGOT16_HA 55 ! 150: #define R_PPC64_ADDR16_DS 56 ! 151: #define R_PPC64_ADDR16_LO_DS 57 ! 152: #define R_PPC64_GOT16_DS 58 ! 153: #define R_PPC64_GOT16_LO_DS 59 ! 154: #define R_PPC64_PLT16_LO_DS 60 ! 155: #define R_PPC64_SECTOFF_DS 61 ! 156: #define R_PPC64_SECTOFF_LO_DS 62 ! 157: #define R_PPC64_TOC16_DS 63 ! 158: #define R_PPC64_TOC16_LO_DS 64 ! 159: #define R_PPC64_PLTGOT16_DS 65 ! 160: #define R_PPC64_PLTGOT16_LO_DS 66 ! 161: #define R_PPC64_TLS 67 ! 162: #define R_PPC64_DTPMOD64 68 ! 163: #define R_PPC64_TPREL16 69 ! 164: #define R_PPC64_TPREL16_LO 60 ! 165: #define R_PPC64_TPREL16_HI 71 ! 166: #define R_PPC64_TPREL16_HA 72 ! 167: #define R_PPC64_TPREL64 73 ! 168: #define R_PPC64_DTPREL16 74 ! 169: #define R_PPC64_DTPREL16_LO 75 ! 170: #define R_PPC64_DTPREL16_HI 76 ! 171: #define R_PPC64_DTPREL16_HA 77 ! 172: #define R_PPC64_DTPREL64 78 ! 173: #define R_PPC64_GOT_TLSGD16 79 ! 174: #define R_PPC64_GOT_TLSGD16_LO 80 ! 175: #define R_PPC64_GOT_TLSGD16_HI 81 ! 176: #define R_PPC64_GOT_TLSGD16_HA 82 ! 177: #define R_PPC64_GOT_TLSLD16 83 ! 178: #define R_PPC64_GOT_TLSLD16_LO 84 ! 179: #define R_PPC64_GOT_TLSLD16_HI 85 ! 180: #define R_PPC64_GOT_TLSLD16_HA 86 ! 181: #define R_PPC64_GOT_TPREL16_DS 87 ! 182: #define R_PPC64_GOT_TPREL16_LO_ DS 88 ! 183: #define R_PPC64_GOT_TPREL16_HI 89 ! 184: #define R_PPC64_GOT_TPREL16_HA 90 ! 185: #define R_PPC64_GOT_DTPREL16_DS 91 ! 186: #define R_PPC64_GOT_DTPREL16_LO_DS 92 ! 187: #define R_PPC64_GOT_DTPREL16_HI 93 ! 188: #define R_PPC64_GOT_DTPREL16_HA 94 ! 189: #define R_PPC64_TPREL16_DS 95 ! 190: #define R_PPC64_TPREL16_LO_DS 96 ! 191: #define R_PPC64_TPREL16_HIGHER 97 ! 192: #define R_PPC64_TPREL16_HIGHERA 98 ! 193: #define R_PPC64_TPREL16_HIGHEST 99 ! 194: #define R_PPC64_TPREL16_HIGHESTA 100 ! 195: #define R_PPC64_DTPREL16_DS 101 ! 196: #define R_PPC64_DTPREL16_LO_DS 102 ! 197: #define R_PPC64_DTPREL16_HIGHER 103 ! 198: #define R_PPC64_DTPREL16_HIGHERA 104 ! 199: #define R_PPC64_DTPREL16_HIGHEST 105 ! 200: #define R_PPC64_DTPREL16_HIGHESTA 106 ! 201: ! 202: ! 203: static struct phdr64* ! 204: get_phdr64(unsigned long *file_addr) ! 205: { ! 206: return (struct phdr64 *) (((unsigned char *) file_addr) ! 207: + ((struct ehdr64 *)file_addr)->e_phoff); ! 208: } ! 209: ! 210: static void ! 211: load_segment64(unsigned long *file_addr, struct phdr64 *phdr, signed long offset, ! 212: int (*pre_load)(void*, long), ! 213: void (*post_load)(void*, long)) ! 214: { ! 215: unsigned long src = phdr->p_offset + (unsigned long) file_addr; ! 216: unsigned long destaddr; ! 217: ! 218: destaddr = phdr->p_paddr + offset; ! 219: ! 220: /* check if we're allowed to copy */ ! 221: if (pre_load != NULL) { ! 222: if (pre_load((void*)destaddr, phdr->p_memsz) != 0) ! 223: return; ! 224: } ! 225: ! 226: /* copy into storage */ ! 227: memmove((void*)destaddr, (void*)src, phdr->p_filesz); ! 228: ! 229: /* clear bss */ ! 230: memset((void*)(destaddr + phdr->p_filesz), 0, ! 231: phdr->p_memsz - phdr->p_filesz); ! 232: ! 233: if (phdr->p_memsz && post_load != NULL) { ! 234: post_load((void*)destaddr, phdr->p_memsz); ! 235: } ! 236: } ! 237: ! 238: unsigned long ! 239: elf_load_segments64(void *file_addr, signed long offset, ! 240: int (*pre_load)(void*, long), ! 241: void (*post_load)(void*, long)) ! 242: { ! 243: struct ehdr64 *ehdr = (struct ehdr64 *) file_addr; ! 244: /* Calculate program header address */ ! 245: struct phdr64 *phdr = get_phdr64(file_addr); ! 246: int i; ! 247: signed long virt2phys = 0; /* Offset between virtual and physical */ ! 248: ! 249: /* loop e_phnum times */ ! 250: for (i = 0; i <= ehdr->e_phnum; i++) { ! 251: /* PT_LOAD ? */ ! 252: if (phdr->p_type == PT_LOAD) { ! 253: if (!virt2phys) { ! 254: virt2phys = phdr->p_paddr - phdr->p_vaddr; ! 255: } ! 256: /* copy segment */ ! 257: load_segment64(file_addr, phdr, offset, pre_load, post_load); ! 258: } ! 259: /* step to next header */ ! 260: phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize); ! 261: } ! 262: ! 263: /* Entry point is always a virtual address, so translate it ! 264: * to physical before returning it */ ! 265: return ehdr->e_entry + virt2phys; ! 266: } ! 267: ! 268: /** ! 269: * Return the base address for loading (i.e. the address of the first PT_LOAD ! 270: * segment) ! 271: * @param file_addr pointer to the ELF file in memory ! 272: * @return the base address ! 273: */ ! 274: long ! 275: elf_get_base_addr64(void *file_addr) ! 276: { ! 277: struct ehdr64 *ehdr = (struct ehdr64 *) file_addr; ! 278: /* Calculate program header address */ ! 279: struct phdr64 *phdr = get_phdr64(file_addr); ! 280: int i; ! 281: ! 282: /* loop e_phnum times */ ! 283: for (i = 0; i <= ehdr->e_phnum; i++) { ! 284: /* PT_LOAD ? */ ! 285: if (phdr->p_type == PT_LOAD) { ! 286: /* Return base address */ ! 287: return phdr->p_paddr; ! 288: } ! 289: /* step to next header */ ! 290: phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize); ! 291: } ! 292: ! 293: return 0; ! 294: } ! 295: ! 296: ! 297: /** ! 298: * Apply one relocation entry. ! 299: */ ! 300: static void ! 301: elf_apply_rela64(void *file_addr, signed long offset, struct rela *relaentry, ! 302: struct sym64 *symtabentry) ! 303: { ! 304: void *addr; ! 305: unsigned long s_a; ! 306: unsigned long base_addr; ! 307: ! 308: base_addr = elf_get_base_addr64(file_addr); ! 309: ! 310: /* Sanity check */ ! 311: if (relaentry->r_offset < base_addr) { ! 312: printf("\nELF relocation out of bounds!\n"); ! 313: return; ! 314: } ! 315: ! 316: base_addr += offset; ! 317: ! 318: /* Actual address where the relocation will be applied at. */ ! 319: addr = (void*)(relaentry->r_offset + offset); ! 320: ! 321: /* Symbol value (S) + Addend (A) */ ! 322: s_a = symtabentry->st_value + offset + relaentry->r_addend; ! 323: ! 324: switch (ELF_R_TYPE(relaentry->r_info)) { ! 325: case R_PPC64_ADDR32: /* S + A */ ! 326: *(uint32_t *)addr = (uint32_t) s_a; ! 327: break; ! 328: case R_PPC64_ADDR64: /* S + A */ ! 329: *(uint64_t *)addr = (uint64_t) s_a; ! 330: break; ! 331: case R_PPC64_TOC: /* .TOC */ ! 332: *(uint64_t *)addr += offset; ! 333: break; ! 334: case R_PPC64_ADDR16_HIGHEST: /* #highest(S + A) */ ! 335: *(uint16_t *)addr = ((s_a >> 48) & 0xffff); ! 336: break; ! 337: case R_PPC64_ADDR16_HIGHER: /* #higher(S + A) */ ! 338: *(uint16_t *)addr = ((s_a >> 32) & 0xffff); ! 339: break; ! 340: case R_PPC64_ADDR16_HI: /* #hi(S + A) */ ! 341: *(uint16_t *)addr = ((s_a >> 16) & 0xffff); ! 342: break; ! 343: case R_PPC64_ADDR16_LO: /* #lo(S + A) */ ! 344: *(uint16_t *)addr = s_a & 0xffff; ! 345: break; ! 346: case R_PPC64_ADDR16_LO_DS: ! 347: *(uint16_t *)addr = (s_a & 0xfffc); ! 348: break; ! 349: case R_PPC64_ADDR16_HA: /* #ha(S + A) */ ! 350: *(uint16_t *)addr = (((s_a >> 16) + ((s_a & 0x8000) ? 1 : 0)) ! 351: & 0xffff); ! 352: break; ! 353: ! 354: case R_PPC64_TOC16: /* half16* S + A - .TOC. */ ! 355: case R_PPC64_TOC16_LO_DS: ! 356: case R_PPC64_TOC16_LO: /* #lo(S + A - .TOC.) */ ! 357: case R_PPC64_TOC16_HI: /* #hi(S + A - .TOC.) */ ! 358: case R_PPC64_TOC16_HA: ! 359: case R_PPC64_TOC16_DS: /* (S + A - .TOC) >> 2 */ ! 360: case R_PPC64_REL14: ! 361: case R_PPC64_REL24: /* (S + A - P) >> 2 */ ! 362: case R_PPC64_REL64: /* S + A - P */ ! 363: case R_PPC64_GOT16_DS: ! 364: case R_PPC64_GOT16_LO_DS: ! 365: // printf("\t\tignoring relocation type %i\n", ! 366: // ELF_R_TYPE(relaentry->r_info)); ! 367: break; ! 368: default: ! 369: printf("ERROR: Unhandled relocation (A) type %i\n", ! 370: ELF_R_TYPE(relaentry->r_info)); ! 371: } ! 372: } ! 373: ! 374: ! 375: /** ! 376: * Step through all relocation entries and apply them one by one. ! 377: */ ! 378: static void ! 379: elf_apply_all_rela64(void *file_addr, signed long offset, struct shdr64 *shdrs, int idx) ! 380: { ! 381: struct shdr64 *rela_shdr = &shdrs[idx]; ! 382: struct shdr64 *dst_shdr = &shdrs[rela_shdr->sh_info]; ! 383: struct shdr64 *sym_shdr = &shdrs[rela_shdr->sh_link]; ! 384: struct rela *relaentry; ! 385: struct sym64 *symtabentry; ! 386: uint32_t symbolidx; ! 387: int i; ! 388: ! 389: /* If the referenced section has not been allocated, then it has ! 390: * not been loaded and thus does not need to be relocated. */ ! 391: if ((dst_shdr->sh_flags & SHF_ALLOC) != SHF_ALLOC) ! 392: return; ! 393: ! 394: for (i = 0; i < rela_shdr->sh_size; i += rela_shdr->sh_entsize) { ! 395: relaentry = (struct rela *)(file_addr + rela_shdr->sh_offset + i); ! 396: ! 397: symbolidx = ELF_R_SYM(relaentry->r_info); ! 398: symtabentry = (struct sym64*)(file_addr + sym_shdr->sh_offset) + symbolidx; ! 399: ! 400: elf_apply_rela64(file_addr, offset, relaentry, symtabentry); ! 401: } ! 402: } ! 403: ! 404: ! 405: /** ! 406: * Apply ELF relocations ! 407: */ ! 408: void ! 409: elf_relocate64(void *file_addr, signed long offset) ! 410: { ! 411: struct ehdr64 *ehdr = (struct ehdr64 *) file_addr; ! 412: /* Calculate section header address */ ! 413: struct shdr64 *shdrs = (struct shdr64 *) ! 414: (((unsigned char *) file_addr) + ehdr->e_shoff); ! 415: int i; ! 416: ! 417: /* loop over all segments */ ! 418: for (i = 0; i <= ehdr->e_shnum; i++) { ! 419: /* Skip if it is not a relocation segment */ ! 420: if (shdrs[i].sh_type == SHT_RELA) { ! 421: elf_apply_all_rela64(file_addr, offset, shdrs, i); ! 422: } ! 423: } ! 424: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.