176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * elf_module.c 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Created on: Aug 11, 2008 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Author: Stefan Bucur <stefanb@zytor.com> 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <errno.h> 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdlib.h> 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h> 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h> 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <elf.h> 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <dprintf.h> 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <core.h> 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <linux/list.h> 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <sys/module.h> 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <sys/exec.h> 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "elfutils.h" 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "../common.h" 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The implementation assumes that the loadable segments are present 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * in the PHT sorted by their offsets, so that only forward seeks would 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * be necessary. 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint load_segments(struct elf_module *module, Elf_Ehdr *elf_hdr) { 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int res = 0; 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman char *pht = NULL; 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman char *sht = NULL; 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Phdr *cr_pht; 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Shdr *cr_sht; 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Addr min_addr = 0x0000000000000000; // Min. ELF vaddr 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Addr max_addr = 0x0000000000000000; // Max. ELF vaddr 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Word max_align = sizeof(void*); // Min. align of posix_memalign() 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Addr min_alloc, max_alloc; // Min. and max. aligned allocables 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Addr dyn_addr = 0x0000000000000000; 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Get to the PHT 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman image_seek(elf_hdr->e_phoff, module); 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Load the PHT 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pht = malloc(elf_hdr->e_phnum * elf_hdr->e_phentsize); 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!pht) 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -1; 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman image_read(pht, elf_hdr->e_phnum * elf_hdr->e_phentsize, module); 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Compute the memory needings of the module 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i=0; i < elf_hdr->e_phnum; i++) { 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cr_pht = (Elf64_Phdr*)(pht + i * elf_hdr->e_phentsize); 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (cr_pht->p_type) { 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PT_LOAD: 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (i == 0) { 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman min_addr = cr_pht->p_vaddr; 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman min_addr = MIN(min_addr, cr_pht->p_vaddr); 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman max_addr = MAX(max_addr, cr_pht->p_vaddr + cr_pht->p_memsz); 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman max_align = MAX(max_align, cr_pht->p_align); 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PT_DYNAMIC: 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dyn_addr = cr_pht->p_vaddr; 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Unsupported - ignore 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (max_addr - min_addr == 0) { 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // No loadable segments 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG_PRINT("No loadable segments found\n"); 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (dyn_addr == 0) { 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG_PRINT("No dynamic information segment found\n"); 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // The minimum address that should be allocated 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman min_alloc = min_addr - (min_addr % max_align); 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // The maximum address that should be allocated 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman max_alloc = max_addr - (max_addr % max_align); 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (max_addr % max_align > 0) 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman max_alloc += max_align; 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (elf_malloc(&module->module_addr, 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman max_align, 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman max_alloc-min_alloc) != 0) { 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG_PRINT("Could not allocate segments\n"); 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman module->base_addr = (Elf64_Addr)(module->module_addr) - min_alloc; 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman module->module_size = max_alloc - min_alloc; 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Zero-initialize the memory 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memset(module->module_addr, 0, module->module_size); 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < elf_hdr->e_phnum; i++) { 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cr_pht = (Elf64_Phdr*)(pht + i * elf_hdr->e_phentsize); 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (cr_pht->p_type == PT_LOAD) { 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Copy the segment at its destination 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (cr_pht->p_offset < module->u.l._cr_offset) { 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // The segment contains data before the current offset 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // It can be discarded without worry - it would contain only 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // headers 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset; 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (image_read((char *)module_get_absolute(cr_pht->p_vaddr, module) + aux_off, 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cr_pht->p_filesz - aux_off, module) < 0) { 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman res = -1; 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (image_seek(cr_pht->p_offset, module) < 0) { 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman res = -1; 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (image_read(module_get_absolute(cr_pht->p_vaddr, module), 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cr_pht->p_filesz, module) < 0) { 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman res = -1; 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG_PRINT("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n", 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cr_pht->p_filesz, 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cr_pht->p_vaddr, 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (Elf64_Addr)module_get_absolute(cr_pht->p_vaddr, module)); 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Get to the SHT 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman image_seek(elf_hdr->e_shoff, module); 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Load the SHT 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize); 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!sht) { 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman res = -1; 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module); 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Setup the symtable size 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < elf_hdr->e_shnum; i++) { 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cr_sht = (Elf64_Shdr*)(sht + i * elf_hdr->e_shentsize); 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (cr_sht->sh_type == SHT_DYNSYM) { 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman module->symtable_size = cr_sht->sh_size; 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(sht); 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Setup dynamic segment location 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman module->dyn_table = module_get_absolute(dyn_addr, module); 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG_PRINT("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr, 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman max_align); 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG_PRINT("Module size: 0x%08x\n", module->module_size); 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanout: 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Free up allocated memory 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (pht != NULL) 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(pht); 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return res; 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint perform_relocation(struct elf_module *module, Elf_Rel *rel) { 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Xword *dest = module_get_absolute(rel->r_offset, module); 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // The symbol reference index 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Word sym = ELF64_R_SYM(rel->r_info); 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned char type = ELF64_R_TYPE(rel->r_info); 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // The symbol definition (if applicable) 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Sym *sym_def = NULL; 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct elf_module *sym_module = NULL; 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Addr sym_addr = 0x0; 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (sym > 0) { 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Find out details about the symbol 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // The symbol reference 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Sym *sym_ref = symbol_get_entry(module, sym); 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // The symbol definition 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sym_def = 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman global_find_symbol(module->str_table + sym_ref->st_name, 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &sym_module); 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (sym_def == NULL) { 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG_PRINT("Cannot perform relocation for symbol %s\n", 21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman module->str_table + sym_ref->st_name); 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ELF64_ST_BIND(sym_ref->st_info) != STB_WEAK) 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -1; 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // This must be a derivative-specific 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // function. We're OK as long as we never 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // execute the function. 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sym_def = global_find_symbol("undefined_symbol", &sym_module); 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Compute the absolute symbol virtual address 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sym_addr = (Elf64_Addr)module_get_absolute(sym_def->st_value, sym_module); 22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (sym_module != module) { 23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Create a dependency 23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman enforce_dependency(sym_module, module); 23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (type) { 23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case R_X86_64_NONE: 23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Do nothing 23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case R_X86_64_64: 24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *dest += sym_addr; 24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case R_X86_64_PC32: 24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *dest += sym_addr - (Elf32_Addr)dest; 24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case R_X86_64_COPY: 24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (sym_addr > 0) { 24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memcpy((void*)dest, (void*)sym_addr, sym_def->st_size); 24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case R_X86_64_GLOB_DAT: 25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case R_X86_64_JUMP_SLOT: 25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman //Maybe TODO: Keep track of the GOT entries allocations 25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *dest = sym_addr; 25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case R_X86_64_RELATIVE: 25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *dest += module->base_addr; 25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG_PRINT("Relocation type %d not supported\n", type); 26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -1; 26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint resolve_symbols(struct elf_module *module) { 26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Dyn *dyn_entry = module->dyn_table; 26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int i; 27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int res; 27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Word plt_rel_size = 0; 27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman void *plt_rel = NULL; 27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman void *rel = NULL; 27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Word rel_size = 0; 27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Word rel_entry = 0; 27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Xword rela_size = 0; 27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Xword rela_entry = 0; 28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Xword sym_ent = 0; 28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // The current relocation 28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman Elf64_Rel *crt_rel; 28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (dyn_entry->d_tag != DT_NULL) { 28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch(dyn_entry->d_tag) { 28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // PLT relocation information 28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case DT_PLTRELSZ: 29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman plt_rel_size = dyn_entry->d_un.d_val; 29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case DT_PLTREL: 29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (dyn_entry->d_un.d_val != DT_REL && dyn_entry->d_un.d_val != DT_RELA) { 29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG_PRINT("Unsupported PLT relocation\n"); 29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -1; 29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman //break; 29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case DT_JMPREL: 29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman plt_rel = module_get_absolute(dyn_entry->d_un.d_ptr, module); 30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Standard relocation information 30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case DT_REL: 30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rel = module_get_absolute(dyn_entry->d_un.d_ptr, module); 30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case DT_RELA: 30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rel = module_get_absolute(dyn_entry->d_un.d_ptr, module); 30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case DT_RELSZ: 31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rel_size = dyn_entry->d_un.d_val; 31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case DT_RELASZ: 31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rela_size = dyn_entry->d_un.d_val; 31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case DT_RELENT: 31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rel_entry = dyn_entry->d_un.d_val; 31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case DT_RELAENT: 31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rela_entry = dyn_entry->d_un.d_val; 32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* FIXME: We may need to rely upon SYMENT if DT_RELAENT is missing in the object file */ 32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case DT_SYMENT: 32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sym_ent = dyn_entry->d_un.d_val; 32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Module initialization and termination 32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case DT_INIT: 32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // TODO Implement initialization functions 32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case DT_FINI: 33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // TODO Implement finalization functions 33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dyn_entry++; 33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (rel_size > 0) { 33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Process standard relocations 34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < rel_size/rel_entry; i++) { 34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman crt_rel = (Elf64_Rel*)(rel + i*rel_entry); 34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman res = perform_relocation(module, crt_rel); 34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (res < 0) 34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return res; 34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (rela_size > 0) { 35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Process standard relocations 35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < rela_size/rela_entry; i++) { 35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman crt_rel = (Elf64_Rel*)(rel + i*rela_entry); 35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman res = perform_relocation(module, crt_rel); 35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (res < 0) 35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return res; 36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (plt_rel_size > 0) { 36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // TODO: Permit this lazily 36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman // Process PLT relocations 36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* some modules do not have DT_SYMENT, set it sym_ent in such cases */ 36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!rela_entry) rela_entry = sym_ent; 36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman //for (i = 0; i < plt_rel_size/sizeof(Elf64_Rel); i++) { 36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < plt_rel_size/rela_entry; i++) { 36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman //crt_rel = (Elf64_Rel*)(plt_rel + i*sizeof(Elf64_Rel)); 37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman crt_rel = (Elf64_Rel*)(plt_rel + i*rela_entry); 37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman res = perform_relocation(module, crt_rel); 37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (res < 0) 37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return res; 37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 381