Home | History | Annotate | Download | only in module
      1 /*
      2  * elf_module.c
      3  *
      4  *  Created on: Aug 11, 2008
      5  *      Author: Stefan Bucur <stefanb (at) zytor.com>
      6  */
      7 
      8 #include <errno.h>
      9 #include <stdlib.h>
     10 #include <string.h>
     11 #include <stdio.h>
     12 #include <elf.h>
     13 #include <dprintf.h>
     14 #include <core.h>
     15 
     16 #include <linux/list.h>
     17 #include <sys/module.h>
     18 #include <sys/exec.h>
     19 
     20 #include "elfutils.h"
     21 #include "common.h"
     22 
     23 static int check_header(Elf_Ehdr *elf_hdr) {
     24 	int res;
     25 
     26 	res = check_header_common(elf_hdr);
     27 
     28 	if (res != 0)
     29 		return res;
     30 
     31 	if (elf_hdr->e_type != MODULE_ELF_TYPE) {
     32 		dprintf("The ELF file must be a shared object\n");
     33 		return -1;
     34 	}
     35 
     36 	if (elf_hdr->e_phoff == 0x00000000) {
     37 		dprintf("PHT missing\n");
     38 		return -1;
     39 	}
     40 
     41 	return 0;
     42 }
     43 
     44 /*
     45  *
     46  * The implementation assumes that the loadable segments are present
     47  * in the PHT sorted by their offsets, so that only forward seeks would
     48  * be necessary.
     49  */
     50 extern int load_segments(struct elf_module *module, Elf_Ehdr *elf_hdr);
     51 
     52 static int prepare_dynlinking(struct elf_module *module) {
     53 	Elf_Dyn  *dyn_entry = module->dyn_table;
     54 
     55 	while (dyn_entry->d_tag != DT_NULL) {
     56 		switch (dyn_entry->d_tag) {
     57 		case DT_NEEDED:
     58 			/*
     59 			 * It's unlikely there'll be more than
     60 			 * MAX_NR_DEPS DT_NEEDED entries but if there
     61 			 * are then inform the user that we ran out of
     62 			 * space.
     63 			 */
     64 			if (module->nr_needed < MAX_NR_DEPS)
     65 				module->needed[module->nr_needed++] = dyn_entry->d_un.d_ptr;
     66 			else {
     67 				printf("Too many dependencies!\n");
     68 				return -1;
     69 			}
     70 			break;
     71 		case DT_HASH:
     72 			module->hash_table =
     73 				(Elf_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
     74 			break;
     75 		case DT_GNU_HASH:
     76 			module->ghash_table =
     77 				(Elf_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
     78 			break;
     79 		case DT_STRTAB:
     80 			module->str_table =
     81 				(char*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
     82 			break;
     83 		case DT_SYMTAB:
     84 			module->sym_table =
     85 				module_get_absolute(dyn_entry->d_un.d_ptr, module);
     86 			break;
     87 		case DT_STRSZ:
     88 			module->strtable_size = dyn_entry->d_un.d_val;
     89 			break;
     90 		case DT_SYMENT:
     91 			module->syment_size = dyn_entry->d_un.d_val;
     92 			break;
     93 		case DT_PLTGOT: // The first entry in the GOT
     94 			module->got = module_get_absolute(dyn_entry->d_un.d_ptr, module);
     95 			break;
     96 		}
     97 
     98 		dyn_entry++;
     99 	}
    100 
    101 	return 0;
    102 }
    103 
    104 void undefined_symbol(void)
    105 {
    106 	printf("Error: An undefined symbol was referenced\n");
    107 	kaboom();
    108 }
    109 
    110 extern int perform_relocation(struct elf_module *module, Elf_Rel *rel);
    111 extern int resolve_symbols(struct elf_module *module);
    112 
    113 static int extract_operations(struct elf_module *module) {
    114 	Elf_Sym *ctors_start, *ctors_end;
    115 	Elf_Sym *dtors_start, *dtors_end;
    116 	module_ctor_t *ctors = NULL;
    117 	module_ctor_t *dtors = NULL;
    118 
    119 	ctors_start = module_find_symbol("__ctors_start", module);
    120 	ctors_end = module_find_symbol("__ctors_end", module);
    121 
    122 	if (ctors_start && ctors_end) {
    123 		module_ctor_t *start, *end;
    124 		int nr_ctors = 0;
    125 		int i, size;
    126 
    127 		start = module_get_absolute(ctors_start->st_value, module);
    128 		end = module_get_absolute(ctors_end->st_value, module);
    129 
    130 		nr_ctors = end - start;
    131 
    132 		size = nr_ctors * sizeof(module_ctor_t);
    133 		size += sizeof(module_ctor_t); /* NULL entry */
    134 
    135 		ctors = malloc(size);
    136 		if (!ctors) {
    137 			printf("Unable to alloc memory for ctors\n");
    138 			return -1;
    139 		}
    140 
    141 		memset(ctors, 0, size);
    142 		for (i = 0; i < nr_ctors; i++)
    143 			ctors[i] = start[i];
    144 
    145 		module->ctors = ctors;
    146 	}
    147 
    148 	dtors_start = module_find_symbol("__dtors_start", module);
    149 	dtors_end = module_find_symbol("__dtors_end", module);
    150 
    151 	if (dtors_start && dtors_end) {
    152 		module_ctor_t *start, *end;
    153 		int nr_dtors = 0;
    154 		int i, size;
    155 
    156 		start = module_get_absolute(dtors_start->st_value, module);
    157 		end = module_get_absolute(dtors_end->st_value, module);
    158 
    159 		nr_dtors = end - start;
    160 
    161 		size = nr_dtors * sizeof(module_ctor_t);
    162 		size += sizeof(module_ctor_t); /* NULL entry */
    163 
    164 		dtors = malloc(size);
    165 		if (!dtors) {
    166 			printf("Unable to alloc memory for dtors\n");
    167 			free(ctors);
    168 			return -1;
    169 		}
    170 
    171 		memset(dtors, 0, size);
    172 		for (i = 0; i < nr_dtors; i++)
    173 			dtors[i] = start[i];
    174 
    175 		module->dtors = dtors;
    176 	}
    177 
    178 	return 0;
    179 }
    180 
    181 // Loads the module into the system
    182 int module_load(struct elf_module *module) {
    183 	int res;
    184 	Elf_Sym *main_sym;
    185 	Elf_Ehdr elf_hdr;
    186 	module_ctor_t *ctor;
    187 	struct elf_module *head = NULL;
    188 
    189 	// Do not allow duplicate modules
    190 	if (module_find(module->name) != NULL) {
    191 		dprintf("Module %s is already loaded.\n", module->name);
    192 		return EEXIST;
    193 	}
    194 
    195 	// Get a mapping/copy of the ELF file in memory
    196 	res = image_load(module);
    197 
    198 	if (res < 0) {
    199 		dprintf("Image load failed for %s\n", module->name);
    200 		return res;
    201 	}
    202 
    203 	// The module is a fully featured dynamic library
    204 	module->shallow = 0;
    205 
    206 	CHECKED(res, image_read(&elf_hdr, sizeof(Elf_Ehdr), module), error);
    207 	//printf("check... 1\n");
    208 
    209 	//print_elf_ehdr(&elf_hdr);
    210 
    211 	// Checking the header signature and members
    212 	CHECKED(res, check_header(&elf_hdr), error);
    213 	//printf("check... 2\n");
    214 
    215 	// Load the segments in the memory
    216 	CHECKED(res, load_segments(module, &elf_hdr), error);
    217 	//printf("bleah... 3\n");
    218 	// Obtain dynamic linking information
    219 	CHECKED(res, prepare_dynlinking(module), error);
    220 	//printf("check... 4\n");
    221 
    222 	head = module_current();
    223 
    224 	/* Find modules we need to load as dependencies */
    225 	if (module->str_table) {
    226 		int i;
    227 
    228 		/*
    229 		 * Note that we have to load the dependencies in
    230 		 * reverse order.
    231 		 */
    232 		for (i = module->nr_needed - 1; i >= 0; i--) {
    233 			char *dep, *p;
    234 			char *argv[2] = { NULL, NULL };
    235 
    236 			dep = module->str_table + module->needed[i];
    237 
    238 			/* strip everything but the last component */
    239 			if (!strlen(dep))
    240 				continue;
    241 
    242 			if (strchr(dep, '/')) {
    243 				p = strrchr(dep, '/');
    244 				p++;
    245 			} else
    246 				p = dep;
    247 
    248 			argv[0] = p;
    249 			res = spawn_load(p, 1, argv);
    250 			if (res < 0) {
    251 				printf("Failed to load %s\n", p);
    252 				goto error;
    253 			}
    254 		}
    255 	}
    256 
    257 	// Check the symbols for duplicates / missing definitions
    258 	CHECKED(res, check_symbols(module), error);
    259 	//printf("check... 5\n");
    260 
    261 	main_sym = module_find_symbol("main", module);
    262 	if (main_sym)
    263 		module->main_func =
    264 			module_get_absolute(main_sym->st_value, module);
    265 
    266 	//printf("check... 6\n");
    267 
    268 	// Add the module at the beginning of the module list
    269 	list_add(&module->list, &modules_head);
    270 
    271 	// Perform the relocations
    272 	resolve_symbols(module);
    273 
    274 	// Obtain constructors and destructors
    275 	CHECKED(res, extract_operations(module), error);
    276 
    277 	//dprintf("module->symtable_size = %d\n", module->symtable_size);
    278 
    279 	//print_elf_symbols(module);
    280 
    281 	// The file image is no longer needed
    282 	image_unload(module);
    283 
    284 	/*
    285 	dprintf("MODULE %s LOADED SUCCESSFULLY (main@%p, init@%p, exit@%p)\n",
    286 			module->name,
    287 			(module->main_func == NULL) ? NULL : *(module->main_func),
    288 			(module->init_func == NULL) ? NULL : *(module->init_func),
    289 			(module->exit_func == NULL) ? NULL : *(module->exit_func));
    290 	*/
    291 
    292 	for (ctor = module->ctors; ctor && *ctor; ctor++)
    293 		(*ctor) ();
    294 
    295 	return 0;
    296 
    297 error:
    298 	if (head)
    299 		unload_modules_since(head->name);
    300 
    301 	// Remove the module from the module list (if applicable)
    302 	list_del_init(&module->list);
    303 
    304 	if (module->module_addr != NULL) {
    305 		elf_free(module->module_addr);
    306 		module->module_addr = NULL;
    307 	}
    308 
    309 	image_unload(module);
    310 
    311 	// Clear the execution part of the module buffer
    312 	memset(&module->u, 0, sizeof module->u);
    313 
    314 	return res;
    315 }
    316 
    317