Merging upstream version 5.01+dfsg.
[syslinux-debian/hramrach.git] / com32 / lib / sys / module / common.c
blob8547036b5b82249799b2500578d676755f2f7953
1 /*
2 * common.c
4 * Created on: Aug 11, 2008
5 * Author: Stefan Bucur <stefanb@zytor.com>
6 */
8 #include <stdio.h>
9 #include <elf.h>
10 #include <string.h>
11 #include <fs.h>
13 #include <linux/list.h>
14 #include <sys/module.h>
16 #include "elfutils.h"
17 #include "common.h"
19 /**
20 * The one and only list of loaded modules
22 LIST_HEAD(modules_head);
24 // User-space debugging routines
25 #ifdef ELF_DEBUG
26 void print_elf_ehdr(Elf32_Ehdr *ehdr) {
27 int i;
29 fprintf(stderr, "Identification:\t");
30 for (i=0; i < EI_NIDENT; i++) {
31 printf("%d ", ehdr->e_ident[i]);
33 fprintf(stderr, "\n");
34 fprintf(stderr, "Type:\t\t%u\n", ehdr->e_type);
35 fprintf(stderr, "Machine:\t%u\n", ehdr->e_machine);
36 fprintf(stderr, "Version:\t%u\n", ehdr->e_version);
37 fprintf(stderr, "Entry:\t\t0x%08x\n", ehdr->e_entry);
38 fprintf(stderr, "PHT Offset:\t0x%08x\n", ehdr->e_phoff);
39 fprintf(stderr, "SHT Offset:\t0x%08x\n", ehdr->e_shoff);
40 //fprintf(stderr, "Flags:\t\t%u\n", ehdr->e_flags);
41 //fprintf(stderr, "Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize,sizeof(Elf32_Ehdr));
42 fprintf(stderr, "phnum: %d shnum: %d\n", ehdr->e_phnum,
43 ehdr->e_shnum);
46 void print_elf_symbols(struct elf_module *module) {
47 unsigned int i;
48 Elf32_Sym *crt_sym;
50 for (i = 1; i < module->symtable_size/module->syment_size; i++)
52 crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size);
54 fprintf(stderr,"%s %d\n", module->str_table + crt_sym->st_name, crt_sym->st_value);
58 #endif //ELF_DEBUG
60 FILE *findpath(char *name)
62 char path[FILENAME_MAX];
63 FILE *f;
64 char *p, *n;
65 int i;
67 f = fopen(name, "rb"); /* for full path */
68 if (f)
69 return f;
71 p = PATH;
72 again:
73 i = 0;
74 while (*p && *p != ':' && i < FILENAME_MAX - 1) {
75 path[i++] = *p++;
78 if (*p == ':')
79 p++;
81 /* Ensure we have a '/' separator */
82 if (path[i] != '/' && i < FILENAME_MAX - 1)
83 path[i++] = '/';
85 n = name;
86 while (*n && i < FILENAME_MAX - 1)
87 path[i++] = *n++;
88 path[i] = '\0';
90 f = fopen(path, "rb");
91 if (f)
92 return f;
94 if (p >= PATH && p < PATH + strlen(PATH))
95 goto again;
97 return NULL;
101 * Image files manipulation routines
104 int image_load(struct elf_module *module)
106 module->u.l._file = findpath(module->name);
108 if (module->u.l._file == NULL) {
109 DBG_PRINT("Could not open object file '%s'\n", module->name);
110 goto error;
113 module->u.l._cr_offset = 0;
115 return 0;
117 error:
118 if (module->u.l._file != NULL) {
119 fclose(module->u.l._file);
120 module->u.l._file = NULL;
123 return -1;
127 int image_unload(struct elf_module *module) {
128 if (module->u.l._file != NULL) {
129 fclose(module->u.l._file);
130 module->u.l._file = NULL;
133 module->u.l._cr_offset = 0;
135 return 0;
138 int image_read(void *buff, size_t size, struct elf_module *module) {
139 size_t result = fread(buff, size, 1, module->u.l._file);
141 if (result < 1)
142 return -1;
144 module->u.l._cr_offset += size;
145 return 0;
148 int image_skip(size_t size, struct elf_module *module) {
149 void *skip_buff = NULL;
150 size_t result;
152 if (size == 0)
153 return 0;
155 skip_buff = malloc(size);
156 result = fread(skip_buff, size, 1, module->u.l._file);
157 free(skip_buff);
159 if (result < 1)
160 return -1;
162 module->u.l._cr_offset += size;
163 return 0;
166 int image_seek(Elf32_Off offset, struct elf_module *module) {
167 if (offset < module->u.l._cr_offset) // Cannot seek backwards
168 return -1;
170 return image_skip(offset - module->u.l._cr_offset, module);
174 // Initialization of the module subsystem
175 int modules_init(void) {
176 return 0;
179 // Termination of the module subsystem
180 void modules_term(void) {
184 // Allocates the structure for a new module
185 struct elf_module *module_alloc(const char *name) {
186 struct elf_module *result = malloc(sizeof(struct elf_module));
188 if (!result) {
189 dprintf("module: Failed to alloc elf_module\n");
190 return NULL;
193 memset(result, 0, sizeof(struct elf_module));
195 INIT_LIST_HEAD(&result->list);
196 INIT_LIST_HEAD(&result->required);
197 INIT_LIST_HEAD(&result->dependants);
199 strncpy(result->name, name, MODULE_NAME_SIZE);
201 return result;
204 struct module_dep *module_dep_alloc(struct elf_module *module) {
205 struct module_dep *result = malloc(sizeof(struct module_dep));
207 INIT_LIST_HEAD (&result->list);
209 result->module = module;
211 return result;
214 struct elf_module *module_find(const char *name) {
215 struct elf_module *cr_module;
217 for_each_module(cr_module) {
218 if (strcmp(cr_module->name, name) == 0)
219 return cr_module;
222 return NULL;
226 // Performs verifications on ELF header to assure that the open file is a
227 // valid SYSLINUX ELF module.
228 int check_header_common(Elf32_Ehdr *elf_hdr) {
229 // Check the header magic
230 if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 ||
231 elf_hdr->e_ident[EI_MAG1] != ELFMAG1 ||
232 elf_hdr->e_ident[EI_MAG2] != ELFMAG2 ||
233 elf_hdr->e_ident[EI_MAG3] != ELFMAG3) {
235 DBG_PRINT("The file is not an ELF object\n");
236 return -1;
239 if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) {
240 DBG_PRINT("Invalid ELF class code\n");
241 return -1;
244 if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) {
245 DBG_PRINT("Invalid ELF data encoding\n");
246 return -1;
249 if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION ||
250 elf_hdr->e_version != MODULE_ELF_VERSION) {
251 DBG_PRINT("Invalid ELF file version\n");
252 return -1;
255 if (elf_hdr->e_machine != MODULE_ELF_MACHINE) {
256 DBG_PRINT("Invalid ELF architecture\n");
257 return -1;
260 return 0;
264 int enforce_dependency(struct elf_module *req, struct elf_module *dep) {
265 struct module_dep *crt_dep;
266 struct module_dep *new_dep;
268 list_for_each_entry(crt_dep, &req->dependants, list) {
269 if (crt_dep->module == dep) {
270 // The dependency is already enforced
271 return 0;
275 new_dep = module_dep_alloc(req);
276 list_add(&new_dep->list, &dep->required);
278 new_dep = module_dep_alloc(dep);
279 list_add(&new_dep->list, &req->dependants);
281 return 0;
284 int clear_dependency(struct elf_module *req, struct elf_module *dep) {
285 struct module_dep *crt_dep = NULL;
286 int found = 0;
288 list_for_each_entry(crt_dep, &req->dependants, list) {
289 if (crt_dep->module == dep) {
290 found = 1;
291 break;
295 if (found) {
296 list_del(&crt_dep->list);
297 free(crt_dep);
300 found = 0;
302 list_for_each_entry(crt_dep, &dep->required, list) {
303 if (crt_dep->module == req) {
304 found = 1;
305 break;
309 if (found) {
310 list_del(&crt_dep->list);
311 free(crt_dep);
314 return 0;
317 int check_symbols(struct elf_module *module)
319 unsigned int i;
320 Elf32_Sym *crt_sym = NULL, *ref_sym = NULL;
321 char *crt_name;
322 struct elf_module *crt_module;
324 int strong_count;
325 int weak_count;
327 for (i = 1; i < module->symtable_size/module->syment_size; i++)
329 crt_sym = symbol_get_entry(module, i);
330 crt_name = module->str_table + crt_sym->st_name;
332 strong_count = 0;
333 weak_count = (ELF32_ST_BIND(crt_sym->st_info) == STB_WEAK);
335 for_each_module(crt_module)
337 ref_sym = module_find_symbol(crt_name, crt_module);
339 // If we found a definition for our symbol...
340 if (ref_sym != NULL && ref_sym->st_shndx != SHN_UNDEF)
342 switch (ELF32_ST_BIND(ref_sym->st_info))
344 case STB_GLOBAL:
345 strong_count++;
346 break;
347 case STB_WEAK:
348 weak_count++;
349 break;
354 if (crt_sym->st_shndx == SHN_UNDEF)
356 // We have an undefined symbol
358 // We use the weak_count to differentiate
359 // between Syslinux-derivative-specific
360 // functions. For example, unload_pxe() is
361 // only provided by PXELINUX, so we mark it as
362 // __weak and replace it with a reference to
363 // undefined_symbol() on SYSLINUX, EXTLINUX,
364 // and ISOLINUX. See perform_relocations().
365 if (strong_count == 0 && weak_count == 0)
367 DBG_PRINT("Symbol %s is undefined\n", crt_name);
368 printf("Undef symbol FAIL: %s\n",crt_name);
369 return -1;
372 else
374 if (strong_count > 0 && ELF32_ST_BIND(ref_sym->st_info) == STB_GLOBAL)
376 // It's not an error - at relocation, the most recent symbol
377 // will be considered
378 DBG_PRINT("Info: Symbol %s is defined more than once\n", crt_name);
381 //printf("symbol %s laoded from %d\n",crt_name,crt_sym->st_value);
384 return 0;
387 int module_unloadable(struct elf_module *module) {
388 if (!list_empty(&module->dependants))
389 return 0;
391 return 1;
395 // Unloads the module from the system and releases all the associated memory
396 int _module_unload(struct elf_module *module) {
397 struct module_dep *crt_dep, *tmp;
398 // Make sure nobody needs us
399 if (!module_unloadable(module)) {
400 DBG_PRINT("Module is required by other modules.\n");
401 return -1;
404 // Remove any dependency information
405 list_for_each_entry_safe(crt_dep, tmp, &module->required, list) {
406 clear_dependency(crt_dep->module, module);
409 // Remove the module from the module list
410 list_del_init(&module->list);
412 // Release the loaded segments or sections
413 if (module->module_addr != NULL) {
414 elf_free(module->module_addr);
416 DBG_PRINT("%s MODULE %s UNLOADED\n", module->shallow ? "SHALLOW" : "",
417 module->name);
419 // Release the module structure
420 free(module);
422 return 0;
425 int module_unload(struct elf_module *module) {
426 module_ctor_t *dtor;
428 for (dtor = module->dtors; dtor && *dtor; dtor++)
429 (*dtor) ();
431 return _module_unload(module);
434 struct elf_module *unload_modules_since(const char *name) {
435 struct elf_module *m, *mod, *begin = NULL;
437 for_each_module(mod) {
438 if (!strcmp(mod->name, name)) {
439 begin = mod;
440 break;
444 if (!begin)
445 return begin;
447 for_each_module_safe(mod, m) {
448 if (mod == begin)
449 break;
451 if (mod != begin)
452 module_unload(mod);
455 return begin;
458 static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
459 unsigned long h = elf_hash((const unsigned char*)name);
460 Elf32_Word *cr_word = module->hash_table;
462 Elf32_Word nbucket = *cr_word++;
463 cr_word++; // Skip nchain
465 Elf32_Word *bkt = cr_word;
466 Elf32_Word *chn = cr_word + nbucket;
468 Elf32_Word crt_index = bkt[h % module->hash_table[0]];
469 Elf32_Sym *crt_sym;
472 while (crt_index != STN_UNDEF) {
473 crt_sym = symbol_get_entry(module, crt_index);
475 if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
476 return crt_sym;
478 crt_index = chn[crt_index];
481 return NULL;
484 static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) {
485 unsigned long h = elf_gnu_hash((const unsigned char*)name);
487 // Setup code (TODO: Optimize this by computing only once)
488 Elf32_Word *cr_word = module->ghash_table;
489 Elf32_Word nbucket = *cr_word++;
490 Elf32_Word symbias = *cr_word++;
491 Elf32_Word bitmask_nwords = *cr_word++;
493 if ((bitmask_nwords & (bitmask_nwords - 1)) != 0) {
494 DBG_PRINT("Invalid GNU Hash structure\n");
495 return NULL;
498 Elf32_Word gnu_shift = *cr_word++;
500 Elf32_Addr *gnu_bitmask = (Elf32_Addr*)cr_word;
501 cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords;
503 Elf32_Word *gnu_buckets = cr_word;
504 cr_word += nbucket;
506 Elf32_Word *gnu_chain_zero = cr_word - symbias;
508 // Computations
509 Elf32_Word bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
510 (bitmask_nwords - 1)];
512 unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1);
513 unsigned int hashbit2 = (h >> gnu_shift) & (MODULE_ELF_CLASS_SIZE - 1);
515 if ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1) {
516 unsigned long rem;
517 Elf32_Word bucket;
519 rem = h % nbucket;
521 bucket = gnu_buckets[rem];
523 if (bucket != 0) {
524 const Elf32_Word* hasharr = &gnu_chain_zero[bucket];
526 do {
527 if (((*hasharr ^ h ) >> 1) == 0) {
528 Elf32_Sym *crt_sym = symbol_get_entry(module, (hasharr - gnu_chain_zero));
530 if (strcmp(name, module->str_table + crt_sym->st_name) == 0) {
531 return crt_sym;
534 } while ((*hasharr++ & 1u) == 0);
538 return NULL;
541 static Elf32_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module)
544 unsigned int i;
545 Elf32_Sym *crt_sym;
547 for (i = 1; i < module->symtable_size/module->syment_size; i++)
549 crt_sym = symbol_get_entry(module, i);
550 if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
552 return crt_sym;
556 return NULL;
559 Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) {
560 Elf32_Sym *result = NULL;
562 if (module->ghash_table != NULL)
563 result = module_find_symbol_gnu(name, module);
565 if (result == NULL)
567 if (module->hash_table != NULL)
569 //printf("Attempting SYSV Symbol search\n");
570 result = module_find_symbol_sysv(name, module);
572 else
574 //printf("Attempting Iterative Symbol search\n");
575 result = module_find_symbol_iterate(name, module);
579 return result;
582 Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module) {
583 struct elf_module *crt_module;
584 Elf32_Sym *crt_sym = NULL;
585 Elf32_Sym *result = NULL;
587 for_each_module(crt_module) {
588 crt_sym = module_find_symbol(name, crt_module);
590 if (crt_sym != NULL && crt_sym->st_shndx != SHN_UNDEF) {
591 switch (ELF32_ST_BIND(crt_sym->st_info)) {
592 case STB_GLOBAL:
593 if (module != NULL) {
594 *module = crt_module;
596 return crt_sym;
597 case STB_WEAK:
598 // Consider only the first weak symbol
599 if (result == NULL) {
600 if (module != NULL) {
601 *module = crt_module;
603 result = crt_sym;
605 break;
610 return result;