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