1/** 2 * \file 3 * \brief Rudimentary ELF loader and handling routines. 4 */ 5 6/* 7 * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15/* Restricted includes, because this file is used in three environments: 16 * in the preboot loader tool "elver", in 32-bit mode 17 * in-kernel, 64-bit mode 18 * userspace, 64-bit mode 19 */ 20#include <stddef.h> 21#include <stdint.h> 22#include <barrelfish_kpi/paging_arch.h> 23#include <barrelfish_kpi/types.h> 24#include <errors/errno.h> 25#include <elf/elf.h> 26 27/** 28 * \brief Load ELF binary image into memory 29 * 30 * This function loads an ELF binary image, based at 'base' and of size 31 * 'size' into the memory provided by 'allocate' 32 * 33 * \param em_machine ELF machine type. 34 * \param allocate Memory allocation function. 35 * \param state Pointer to state for allocation function. 36 * \param base Base address of ELF binary image in memory. 37 * \param size Size of ELF binary image in bytes. 38 * \param retentry Used to return entry point address 39 * \param ret_tlsbase Used to return TLS block base address 40 * \param ret_tlssize Used to return TLS block size 41 */ 42errval_t elf_load_tls(uint16_t em_machine, elf_allocator_fn allocate_func, 43 void *state, lvaddr_t base, 44 size_t size, genvaddr_t *retentry, 45 genvaddr_t *ret_tlsbase, size_t *ret_tlsinitlen, 46 size_t *ret_tlstotallen) 47{ 48 struct Elf64_Ehdr *head = (struct Elf64_Ehdr *)base; 49 50 if(!IS_ELF(*head)) { 51 return ELF_ERR_HEADER; 52 } 53 54 switch(head->e_ident[EI_CLASS]) { 55 case ELFCLASS32: 56 return elf32_load(em_machine, allocate_func, state, base, size, 57 retentry, ret_tlsbase, ret_tlsinitlen, ret_tlstotallen); 58 59 case ELFCLASS64: 60 return elf64_load(em_machine, allocate_func, state, base, size, 61 retentry, ret_tlsbase, ret_tlsinitlen, ret_tlstotallen); 62 } 63 64 return ELF_ERR_HEADER; 65} 66 67errval_t elf_load(uint16_t em_machine, elf_allocator_fn allocate_func, 68 void *state, lvaddr_t base, 69 size_t size, genvaddr_t *retentry) 70{ 71 return elf_load_tls(em_machine, allocate_func, state, base, size, 72 retentry, NULL, NULL, NULL); 73} 74 75static size_t elf_virtual_size64(struct Elf64_Ehdr *ehead) 76{ 77 struct Elf64_Phdr *phead = 78 (struct Elf64_Phdr *)((uintptr_t)ehead + (uintptr_t)ehead->e_phoff); 79 80 size_t retval = 0; 81 int i; 82 83 for (i = 0; i < ehead->e_phnum; i++) { 84 struct Elf64_Phdr *p = &phead[i]; 85 if (p->p_type == PT_LOAD) { 86 retval = p->p_vaddr + p->p_memsz; 87 } 88 } 89 90 return retval - elf_virtual_base64(ehead); 91} 92 93static size_t elf_virtual_size32(struct Elf32_Ehdr *ehead) 94{ 95 struct Elf32_Phdr *phead = 96 (struct Elf32_Phdr *)((uintptr_t)ehead + (uintptr_t)ehead->e_phoff); 97 98 size_t retval = 0; 99 int i; 100 101 for (i = 0; i < ehead->e_phnum; i++) { 102 struct Elf32_Phdr *p = &phead[i]; 103 if (p->p_type == PT_LOAD) { 104 retval = p->p_vaddr + p->p_memsz; 105 } 106 } 107 108 return retval - elf_virtual_base32(ehead); 109} 110 111/** 112 * \brief Calculates the size of the loadable portion of the elf image in 113 * virtual memory. This is the amount of virtual memory required to load an 114 * image. 115 */ 116size_t elf_virtual_size(lvaddr_t base) 117{ 118 size_t elfsize = 0; 119 120 struct Elf64_Ehdr *ehead = (struct Elf64_Ehdr *)base; 121 if (IS_ELF(*ehead)) { 122 switch (ehead->e_ident[EI_CLASS]) { 123 case ELFCLASS64: 124 elfsize = elf_virtual_size64(ehead); 125 break; 126 127 case ELFCLASS32: 128 elfsize = elf_virtual_size32((struct Elf32_Ehdr*)ehead); 129 break; 130 } 131 } 132 133 return elfsize; 134} 135 136/** 137 * \brief Calculates the base of the loadable portion of the elf image in 138 * virtual memory. 139 */ 140genvaddr_t elf_virtual_base(lvaddr_t base) 141{ 142 genvaddr_t elfbase = 0; 143 144 struct Elf64_Ehdr *ehead = (struct Elf64_Ehdr *)base; 145 if (IS_ELF(*ehead)) { 146 switch (ehead->e_ident[EI_CLASS]) { 147 case ELFCLASS64: 148 elfbase = elf_virtual_base64(ehead); 149 break; 150 151 case ELFCLASS32: 152 elfbase = elf_virtual_base32((struct Elf32_Ehdr*)ehead); 153 break; 154 } 155 } 156 157 return elfbase; 158} 159 160static errval_t elf32_get_eh_info(lvaddr_t elfbase, size_t elfsize, 161 lvaddr_t *eh_frame, size_t *eh_frame_size, 162 lvaddr_t *eh_frame_hdr, size_t *eh_frame_hdr_size) 163{ 164 struct Elf32_Shdr *shdr; 165 166 lvaddr_t addr = 0; 167 size_t size = 0; 168 169 shdr= elf32_find_section_header_name(elfbase, elfsize, ".eh_frame"); 170 if (shdr != NULL) { 171 size = shdr->sh_size; 172 addr = shdr->sh_addr; 173 } 174 175 if (eh_frame) { 176 *eh_frame = addr; 177 } 178 if (eh_frame_size) { 179 *eh_frame_size = size; 180 } 181 182 size = 0; 183 addr = 0; 184 185 shdr= elf32_find_section_header_name(elfbase, elfsize, ".eh_frame_hdr"); 186 if (shdr != NULL) { 187 size = shdr->sh_size; 188 addr = shdr->sh_addr; 189 } 190 191 if (eh_frame_hdr) { 192 *eh_frame_hdr = addr; 193 } 194 if (eh_frame_hdr_size) { 195 *eh_frame_hdr_size = size; 196 } 197 198 return SYS_ERR_OK; 199} 200 201static errval_t elf64_get_eh_info(lvaddr_t elfbase, size_t elfsize, 202 lvaddr_t *eh_frame, size_t *eh_frame_size, 203 lvaddr_t *eh_frame_hdr, size_t *eh_frame_hdr_size) 204{ 205 struct Elf64_Shdr *shdr; 206 207 lvaddr_t addr = 0; 208 size_t size = 0; 209 210 shdr= elf64_find_section_header_name(elfbase, elfsize, ".eh_frame"); 211 if (shdr != NULL) { 212 size = shdr->sh_size; 213 addr = shdr->sh_addr; 214 } 215 216 if (eh_frame) { 217 *eh_frame = addr; 218 } 219 if (eh_frame_size) { 220 *eh_frame_size = size; 221 } 222 223 size = 0; 224 addr = 0; 225 226 shdr= elf64_find_section_header_name(elfbase, elfsize, ".eh_frame_hdr"); 227 if (shdr != NULL) { 228 size = shdr->sh_size; 229 addr = shdr->sh_addr; 230 } 231 232 if (eh_frame_hdr) { 233 *eh_frame_hdr = addr; 234 } 235 if (eh_frame_hdr_size) { 236 *eh_frame_hdr_size = size; 237 } 238 239 return SYS_ERR_OK; 240} 241 242/** 243 * \brief obtains the error handling frame information form the elf image 244 * 245 * \param elfbase virtual base address of the mapped elf 246 * \param elfsize size of the elf in bytes 247 * \param eh_frame returns the virtual address of the eh_frame 248 * \param eh_frame_size returns the size of the eh_frame 249 * \param eh_frame_hdr returns the virtual address of the eh_frame_hdr 250 * \param eh_frame_hdr_size returns the size of the eh_frame_hdr 251 * 252 * \returns SYS_ERR_OK on success 253 */ 254errval_t elf_get_eh_info(lvaddr_t elfbase, size_t elfsize, 255 lvaddr_t *eh_frame, size_t *eh_frame_size, 256 lvaddr_t *eh_frame_hdr, size_t *eh_frame_hdr_size) 257{ 258 struct Elf64_Ehdr *ehead = (struct Elf64_Ehdr *)elfbase; 259 if (IS_ELF(*ehead)) { 260 switch (ehead->e_ident[EI_CLASS]) { 261 case ELFCLASS64: 262 return elf64_get_eh_info(elfbase, elfsize, eh_frame, eh_frame_size, 263 eh_frame_hdr, eh_frame_hdr_size); 264 break; 265 case ELFCLASS32: 266 return elf32_get_eh_info(elfbase, elfsize, eh_frame, eh_frame_size, 267 eh_frame_hdr, eh_frame_hdr_size); 268 break; 269 } 270 } 271 return ELF_ERR_HEADER; 272} 273