• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * elf_module.c
3  *
4  *  Created on: Aug 11, 2008
5  *      Author: Stefan Bucur <stefanb@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 
check_header(Elf_Ehdr * elf_hdr)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 
prepare_dynlinking(struct elf_module * module)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 
undefined_symbol(void)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 
extract_operations(struct elf_module * module)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
module_load(struct elf_module * module)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