1/** 2 * \file 3 * \brief Rudimentary ELF64 loader and handling routines. 4 * 5 * Note that on 32-bit platforms, this loader is only able to load 6 * ELF64 files that it can address (ie. those that are not bigger than 7 * what fits into a 32-bit address space). 8 */ 9 10/* 11 * Copyright (c) 2007, 2008, 2009, 2010, 2012, ETH Zurich. 12 * All rights reserved. 13 * 14 * This file is distributed under the terms in the attached LICENSE file. 15 * If you do not find this file, copies can be found by writing to: 16 * ETH Zurich D-INFK, CAB F.78, Universitaetstrasse 6, CH-8092 Zurich, 17 * Attn: Systems Group. 18 */ 19 20/* Restricted includes, because this file is used in three environments: 21 * in the preboot loader tool "elver", in 32-bit mode 22 * in-kernel, 64-bit mode 23 * userspace, 64-bit mode 24 */ 25#include <assert.h> 26#include <stdio.h> 27#include <stdint.h> 28#include <stddef.h> 29#include <string.h> 30#include <barrelfish_kpi/paging_arch.h> 31#include <barrelfish_kpi/types.h> 32#include <errors/errno.h> 33#include <elf/elf.h> 34 35#define XEON_PHI_SBOX_BASE 0x08007D0000ULL /* PCIE Box Registers */ 36union status 37{ 38 uint32_t raw; 39 char vals[4]; 40}; 41 42static void 43print_status(char a, 44 char b) 45{ 46 47 volatile uint32_t *p = (volatile uint32_t *) ((XEON_PHI_SBOX_BASE) + 0x0000AB40); 48 volatile uint32_t *p2 = (volatile uint32_t *) ((XEON_PHI_SBOX_BASE) + 0x0000AB5C); 49 50 union status s; 51 52 s.vals[3] = 0x0a; 53 s.vals[2] = b; 54 s.vals[1] = a; 55 s.vals[0] = '>'; 56 57 while ((*p)) 58 ; 59 60 *p2 = s.raw; 61 *p = 0x7A7A7A7A; 62} 63 64static inline void 65eabort(char a, 66 char b) 67{ 68 print_status(a, b); 69 while (1) 70 ; 71} 72 73 74 75/** 76 * \brief Calculates the base of the loadable portion of the elf image in 77 * virtual memory. 78 */ 79genvaddr_t elf_virtual_base64(struct Elf64_Ehdr *ehead) 80{ 81 struct Elf64_Phdr *phead = 82 (struct Elf64_Phdr *)((uintptr_t)ehead + (uintptr_t)ehead->e_phoff); 83 84 genvaddr_t retval = 0; 85 int i; 86 87 for (i = 0; i < ehead->e_phnum; i++) { 88 struct Elf64_Phdr *p = &phead[i]; 89 if (p->p_type == PT_LOAD) { 90 if(retval == 0) { 91 retval = p->p_vaddr; 92 } 93 retval = p->p_vaddr < retval ? p->p_vaddr : retval; 94 } 95 } 96 97 return retval; 98} 99 100/** 101 * \brief Return pointer to relocation section ELF header. 102 * 103 * This function finds and returns a pointer to the first ELF section 104 * header of type 'type'. 105 * 106 * \param shdr Pointer to head of ELF section header table. 107 * \param entries Number of entries in the ELF section header table. 108 * \param type ELF section header type to look for. 109 * 110 * \return Pointer to first ELF section header of type 'type', or NULL. 111 */ 112struct Elf64_Shdr * 113elf64_find_section_header_type(struct Elf64_Shdr * shdr, 114 uint32_t entries, uint32_t type) 115{ 116 int i; 117 118 for(i = 0; i < entries; i++) { 119 struct Elf64_Shdr *s = &shdr[i]; 120 121 if(s->sh_type == type) { 122 return s; 123 } 124 } 125 126 return NULL; 127} 128 129/** 130 * \brief Return pointer to section header with given name. 131 * 132 * @param elf_base Address of ELF header 133 * @param elf_bytes Size of ELF file. 134 * @param section_name Named section to look for. 135 * 136 * @return Pointer to ELF section header with name, or NULL. 137 */ 138struct Elf64_Shdr * 139elf64_find_section_header_name(genvaddr_t elf_base, 140 size_t elf_bytes, 141 const char* section_name) 142{ 143 lvaddr_t elf_lbase = (lvaddr_t)elf_base; 144 struct Elf64_Ehdr *head = (struct Elf64_Ehdr *)elf_lbase; 145 146 if (elf_bytes < sizeof(struct Elf64_Ehdr) || !IS_ELF(*head) || 147 head->e_ident[EI_CLASS] != ELFCLASS64) { 148 return NULL; 149 } 150 151 struct Elf64_Shdr *shead = 152 (struct Elf64_Shdr *)(elf_lbase + (uintptr_t)head->e_shoff); 153 154 struct Elf64_Shdr *strtab = 155 elf64_find_section_header_type(shead, head->e_shnum, SHT_STRTAB); 156 157 if (strtab == NULL) 158 { 159 return NULL; 160 } 161 162 for (uint32_t i = 0; i < head->e_shnum; i++) 163 { 164 const char* strings = (const char*)(elf_lbase + 165 (size_t)strtab->sh_offset); 166 if (!strcmp(section_name, strings + shead[i].sh_name)) { 167 return &shead[i]; 168 } 169 } 170 return NULL; 171} 172 173/** 174 * \brief Return pointer to relocation section ELF header. 175 * 176 * This function finds and returns a pointer to the first ELF section 177 * header at virtual address 'addr'. 178 * 179 * \param shdr Pointer to head of ELF section header table. 180 * \param entries Number of entries in the ELF section header table. 181 * \param addr Virtual address to look for 182 * 183 * \return Pointer to first ELF section header loaded at 'addr', or NULL. 184 */ 185static struct Elf64_Shdr * 186elf64_find_section_header_vaddr(struct Elf64_Shdr * shdr, 187 uint32_t entries, genvaddr_t addr) 188{ 189 int i; 190 191 for(i = 0; i < entries; i++) { 192 struct Elf64_Shdr *s = &shdr[i]; 193 194 if(s->sh_addr == addr) { 195 return s; 196 } 197 } 198 199 return NULL; 200} 201 202/** 203 * \brief Relocates the ELF image from src to dst. 204 * 205 * This function processes the ELF relocation section 'rela' of size 'size' of 206 * the ELF image, formerly located at 'src', to the new location 'dst'. 207 * Relocation is necessary for certain variables that cannot be coded as 208 * position-independent code. 209 * 210 * \param dst Address to relocate to. 211 * \param src Former base address of the ELF image. 212 * \param rela Pointer to relocation section of the ELF image. 213 * \param size Size in bytes of the ELF relocation section. 214 * \param symtab Pointer to ELF symbol table. 215 * \param symsize Size in bytes of the ELF symbol table. 216 * \param start Original base address of the ELF image (needed for 217 * symbol-table-based relocations -- we don't touch the symbol table). 218 * \param vbase Pointer to ELF image in virtual memory. 219 */ 220void elf64_relocate(genvaddr_t dst, genvaddr_t src, 221 struct Elf64_Rela * rela, size_t size, 222 struct Elf64_Sym * symtab, size_t symsize, 223 genvaddr_t start, void *vbase) 224{ 225 genvaddr_t base = dst - src, abase = dst - start; 226 227 for(int i = 0; i < size / sizeof(struct Elf64_Rela); i++) { 228 struct Elf64_Rela *r = &rela[i]; 229 uint32_t type = ELF64_R_TYPE(r->r_info); 230 uint64_t *addr = (uint64_t *)((char *)vbase + r->r_offset - start); 231 232 switch(type) { 233 case R_X86_64_NONE: 234 // Do nothing 235 break; 236 237 case R_X86_64_64:{ 238 uint32_t sym = ELF64_R_SYM(r->r_info); 239 assert(sym < symsize / sizeof(struct Elf64_Sym)); 240#if 0 // XXX: symbols should be 0 but this fires sometimes 241 assert(symtab[sym].st_value != 0); 242#endif 243 *addr = abase + symtab[sym].st_value + r->r_addend; 244 break;} 245 246 case R_X86_64_RELATIVE: 247 // FIXME: why doesn't the following work? -AB 248 // I don't think this makes sense. It is a relative 249 // relocation from the old position. Thus, base and not 250 // abase should be used. Further, since r->r_addend is not 251 // updated between relocations, this will fail as soon as 252 // a binary is relocated more than once. -SP 253 //*addr = abase + r->r_addend; 254 *addr += base; 255 break; 256 257 default: 258 eabort('E','x'); 259 printf("elf_relocate: relocation %d type %"PRIu32"\n", i, type); 260 assert(!"Unimplemented: Cannot handle relocation type"); 261 break; 262 } 263 } 264} 265 266/** 267 * \brief Load ELF64 binary image into memory 268 * 269 * This function loads an ELF64 binary image, based at 'base' and of size 270 * 'size' into the memory provided by 'allocate' 271 * 272 * \param em_machine ELF machine type. 273 * \param allocate Memory allocation function. 274 * \param state Pointer to state for allocation function. 275 * \param base Base address of ELF64 binary image in memory. 276 * \param size Size of ELF64 binary image in bytes. 277 * \param retentry Used to return entry point address 278 * \param ret_tlsbase Used to return TLS block base address 279 * \param ret_tlsinitlen Used to return length of initialised TLS data block 280 * \param ret_tlstotallen Used to return total length of TLS data 281 */ 282errval_t elf64_load(uint16_t em_machine, elf_allocator_fn allocate_func, 283 void *state, lvaddr_t base, size_t size, 284 genvaddr_t *retentry, 285 genvaddr_t *ret_tlsbase, size_t *ret_tlsinitlen, 286 size_t *ret_tlstotallen) 287{ 288 struct Elf64_Ehdr *head = (struct Elf64_Ehdr *)base; 289 errval_t err; 290 int i; 291 292 // Check for valid file size 293 if (size < sizeof(struct Elf64_Ehdr)) { 294 return ELF_ERR_FILESZ; 295 } 296 297 // Check for compatible ELF64 header 298 if (!IS_ELF(*head) 299 || head->e_ident[EI_CLASS] != ELFCLASS64 300 || head->e_ident[EI_DATA] != ELFDATA2LSB 301 || head->e_ident[EI_VERSION] != EV_CURRENT 302 || head->e_ident[EI_OSABI] != ELFOSABI_SYSV 303 || head->e_ident[EI_ABIVERSION] != 0 304 || (head->e_type != ET_EXEC && head->e_type != ET_DYN) 305 || head->e_machine != em_machine 306 || head->e_version != EV_CURRENT) { 307 return ELF_ERR_HEADER; 308 } 309 310 // More sanity checks 311 if (head->e_phoff + head->e_phentsize * head->e_phnum > size 312 || head->e_phentsize != sizeof(struct Elf64_Phdr)) { 313 return ELF_ERR_PROGHDR; 314 } 315 316 struct Elf64_Shdr *shead = 317 (struct Elf64_Shdr *)(base + (uintptr_t)head->e_shoff); 318 struct Elf64_Shdr *rela = 319 elf64_find_section_header_type(shead, head->e_shnum, SHT_RELA); 320 struct Elf64_Shdr *symtab = 321 elf64_find_section_header_type(shead, head->e_shnum, SHT_SYMTAB); 322 323 size_t rela_size = rela ? rela->sh_size : 0, new_rela_size = 0; 324 struct Elf64_Shdr *new_rela = NULL; 325 326 // Find dynamic program header, if any 327 struct Elf64_Phdr *phead = 328 (struct Elf64_Phdr *)(base + (uintptr_t)head->e_phoff); 329 for (i = 0; i < head->e_phnum; i++) { 330 struct Elf64_Phdr *p = &phead[i]; 331 332 if (p->p_type == PT_DYNAMIC) { 333 struct Elf64_Dyn *dynamic = (void *)(base + (uintptr_t)p->p_offset); 334 int n_dynamic = p->p_filesz / sizeof(struct Elf64_Dyn); 335 for (int j = 0; j < n_dynamic; j++) { 336 switch (dynamic[j].d_tag) { 337 case DT_RELA: 338 // virtual address of relocations, look for matching section 339 new_rela = 340 elf64_find_section_header_vaddr(shead, head->e_shnum, 341 dynamic[j].d_un.d_val); 342 break; 343 344 case DT_RELASZ: 345 // store size of relocations, as they may cover more than 346 // one section 347 new_rela_size = dynamic[j].d_un.d_val; 348 break; 349 350 case DT_SYMTAB: 351 // virtual address of symtab, look for matching section 352 symtab = 353 elf64_find_section_header_vaddr(shead, head->e_shnum, 354 dynamic[j].d_un.d_val); 355 break; 356 357 case DT_SYMENT: 358 assert(dynamic[j].d_un.d_val == sizeof(struct Elf64_Sym)); 359 break; 360 } 361 } 362 363 if (new_rela != NULL) { 364 assert(new_rela_size != 0); 365 rela = new_rela; 366 rela_size = new_rela_size; 367 } 368 break; 369 } 370 } 371 372 373 genvaddr_t tls_base = 0; 374 size_t tls_init_len = 0, tls_total_len = 0; 375 376 // Process program headers to load file 377 for (i = 0; i < head->e_phnum; i++) { 378 struct Elf64_Phdr *p = &phead[i]; 379 if (p->p_type == PT_LOAD) { 380 381 // Map segment in user-space memory 382 void *dest = NULL; 383 err = allocate_func(state, p->p_vaddr, p->p_memsz, p->p_flags, &dest); 384 385 if (err_is_fail(err)) { 386 return err_push(err, ELF_ERR_ALLOCATE); 387 } 388 assert(dest != NULL); 389 // Copy file segment into memory 390 memcpy(dest, (void *)(base + (uintptr_t)p->p_offset), p->p_filesz); 391 392 // Initialize rest of memory segment (ie. BSS) with all zeroes 393 memset((char *)dest + p->p_filesz, 0, p->p_memsz - p->p_filesz); 394 395 // Apply relocations 396 if (rela != NULL && symtab != NULL) { 397 elf64_relocate(p->p_vaddr, p->p_vaddr, 398 (struct Elf64_Rela *) 399 (base + (uintptr_t)rela->sh_offset), 400 rela_size, 401 (struct Elf64_Sym *) 402 (base + (uintptr_t)symtab->sh_offset), 403 symtab->sh_size, p->p_vaddr, dest); 404 } 405 } else if (p->p_type == PT_TLS) { 406 assert(p->p_vaddr != 0); 407 assert(tls_base == 0); // if not we have multiple TLS sections! 408 tls_base = p->p_vaddr; 409 tls_init_len = p->p_filesz; 410 tls_total_len = p->p_memsz; 411 } 412 } 413 414 if (retentry != NULL) { 415 *retentry = head->e_entry; 416 } 417 418 if (ret_tlsbase != NULL) { 419 *ret_tlsbase = tls_base; 420 } 421 422 if (ret_tlsinitlen != NULL) { 423 *ret_tlsinitlen = tls_init_len; 424 } 425 426 if (ret_tlstotallen != NULL) { 427 *ret_tlstotallen = tls_total_len; 428 } 429 430 return SYS_ERR_OK; 431} 432