PATH: use a linked list internally
[syslinux.git] / com32 / lib / sys / module / common.c
blobb763704e6d20c7ff86f57fbda43657b71cff2016
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 struct path_entry *entry;
63 char path[FILENAME_MAX];
64 FILE *f;
66 f = fopen(name, "rb"); /* for full path */
67 if (f)
68 return f;
70 list_for_each_entry(entry, &PATH, list) {
71 bool slash = false;
73 /* Ensure we have a '/' separator */
74 if (entry->str[strlen(entry->str) - 1] != '/')
75 slash = true;
77 snprintf(path, sizeof(path), "%s%s%s",
78 entry->str, slash ? "/" : "", name);
80 f = fopen(path, "rb");
81 if (f)
82 return f;
85 return NULL;
89 * Image files manipulation routines
92 int image_load(struct elf_module *module)
94 module->u.l._file = findpath(module->name);
96 if (module->u.l._file == NULL) {
97 DBG_PRINT("Could not open object file '%s'\n", module->name);
98 goto error;
101 module->u.l._cr_offset = 0;
103 return 0;
105 error:
106 if (module->u.l._file != NULL) {
107 fclose(module->u.l._file);
108 module->u.l._file = NULL;
111 return -1;
115 int image_unload(struct elf_module *module) {
116 if (module->u.l._file != NULL) {
117 fclose(module->u.l._file);
118 module->u.l._file = NULL;
121 module->u.l._cr_offset = 0;
123 return 0;
126 int image_read(void *buff, size_t size, struct elf_module *module) {
127 size_t result = fread(buff, size, 1, module->u.l._file);
129 if (result < 1)
130 return -1;
132 module->u.l._cr_offset += size;
133 return 0;
136 int image_skip(size_t size, struct elf_module *module) {
137 void *skip_buff = NULL;
138 size_t result;
140 if (size == 0)
141 return 0;
143 skip_buff = malloc(size);
144 result = fread(skip_buff, size, 1, module->u.l._file);
145 free(skip_buff);
147 if (result < 1)
148 return -1;
150 module->u.l._cr_offset += size;
151 return 0;
154 int image_seek(Elf32_Off offset, struct elf_module *module) {
155 if (offset < module->u.l._cr_offset) // Cannot seek backwards
156 return -1;
158 return image_skip(offset - module->u.l._cr_offset, module);
162 // Initialization of the module subsystem
163 int modules_init(void) {
164 return 0;
167 // Termination of the module subsystem
168 void modules_term(void) {
172 // Allocates the structure for a new module
173 struct elf_module *module_alloc(const char *name) {
174 struct elf_module *result = malloc(sizeof(struct elf_module));
176 if (!result) {
177 dprintf("module: Failed to alloc elf_module\n");
178 return NULL;
181 memset(result, 0, sizeof(struct elf_module));
183 INIT_LIST_HEAD(&result->list);
184 INIT_LIST_HEAD(&result->required);
185 INIT_LIST_HEAD(&result->dependants);
187 strncpy(result->name, name, MODULE_NAME_SIZE);
189 return result;
192 struct module_dep *module_dep_alloc(struct elf_module *module) {
193 struct module_dep *result = malloc(sizeof(struct module_dep));
195 INIT_LIST_HEAD (&result->list);
197 result->module = module;
199 return result;
202 struct elf_module *module_find(const char *name) {
203 struct elf_module *cr_module;
205 for_each_module(cr_module) {
206 if (strcmp(cr_module->name, name) == 0)
207 return cr_module;
210 return NULL;
214 // Performs verifications on ELF header to assure that the open file is a
215 // valid SYSLINUX ELF module.
216 int check_header_common(Elf32_Ehdr *elf_hdr) {
217 // Check the header magic
218 if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 ||
219 elf_hdr->e_ident[EI_MAG1] != ELFMAG1 ||
220 elf_hdr->e_ident[EI_MAG2] != ELFMAG2 ||
221 elf_hdr->e_ident[EI_MAG3] != ELFMAG3) {
223 DBG_PRINT("The file is not an ELF object\n");
224 return -1;
227 if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) {
228 DBG_PRINT("Invalid ELF class code\n");
229 return -1;
232 if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) {
233 DBG_PRINT("Invalid ELF data encoding\n");
234 return -1;
237 if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION ||
238 elf_hdr->e_version != MODULE_ELF_VERSION) {
239 DBG_PRINT("Invalid ELF file version\n");
240 return -1;
243 if (elf_hdr->e_machine != MODULE_ELF_MACHINE) {
244 DBG_PRINT("Invalid ELF architecture\n");
245 return -1;
248 return 0;
252 int enforce_dependency(struct elf_module *req, struct elf_module *dep) {
253 struct module_dep *crt_dep;
254 struct module_dep *new_dep;
256 list_for_each_entry(crt_dep, &req->dependants, list) {
257 if (crt_dep->module == dep) {
258 // The dependency is already enforced
259 return 0;
263 new_dep = module_dep_alloc(req);
264 list_add(&new_dep->list, &dep->required);
266 new_dep = module_dep_alloc(dep);
267 list_add(&new_dep->list, &req->dependants);
269 return 0;
272 int clear_dependency(struct elf_module *req, struct elf_module *dep) {
273 struct module_dep *crt_dep = NULL;
274 int found = 0;
276 list_for_each_entry(crt_dep, &req->dependants, list) {
277 if (crt_dep->module == dep) {
278 found = 1;
279 break;
283 if (found) {
284 list_del(&crt_dep->list);
285 free(crt_dep);
288 found = 0;
290 list_for_each_entry(crt_dep, &dep->required, list) {
291 if (crt_dep->module == req) {
292 found = 1;
293 break;
297 if (found) {
298 list_del(&crt_dep->list);
299 free(crt_dep);
302 return 0;
305 int check_symbols(struct elf_module *module)
307 unsigned int i;
308 Elf32_Sym *crt_sym = NULL, *ref_sym = NULL;
309 char *crt_name;
310 struct elf_module *crt_module;
312 int strong_count;
313 int weak_count;
315 for (i = 1; i < module->symtable_size/module->syment_size; i++)
317 crt_sym = symbol_get_entry(module, i);
318 crt_name = module->str_table + crt_sym->st_name;
320 strong_count = 0;
321 weak_count = (ELF32_ST_BIND(crt_sym->st_info) == STB_WEAK);
323 for_each_module(crt_module)
325 ref_sym = module_find_symbol(crt_name, crt_module);
327 // If we found a definition for our symbol...
328 if (ref_sym != NULL && ref_sym->st_shndx != SHN_UNDEF)
330 switch (ELF32_ST_BIND(ref_sym->st_info))
332 case STB_GLOBAL:
333 strong_count++;
334 break;
335 case STB_WEAK:
336 weak_count++;
337 break;
342 if (crt_sym->st_shndx == SHN_UNDEF)
344 // We have an undefined symbol
346 // We use the weak_count to differentiate
347 // between Syslinux-derivative-specific
348 // functions. For example, unload_pxe() is
349 // only provided by PXELINUX, so we mark it as
350 // __weak and replace it with a reference to
351 // undefined_symbol() on SYSLINUX, EXTLINUX,
352 // and ISOLINUX. See perform_relocations().
353 if (strong_count == 0 && weak_count == 0)
355 DBG_PRINT("Symbol %s is undefined\n", crt_name);
356 printf("Undef symbol FAIL: %s\n",crt_name);
357 return -1;
360 else
362 if (strong_count > 0 && ELF32_ST_BIND(ref_sym->st_info) == STB_GLOBAL)
364 // It's not an error - at relocation, the most recent symbol
365 // will be considered
366 DBG_PRINT("Info: Symbol %s is defined more than once\n", crt_name);
369 //printf("symbol %s laoded from %d\n",crt_name,crt_sym->st_value);
372 return 0;
375 int module_unloadable(struct elf_module *module) {
376 if (!list_empty(&module->dependants))
377 return 0;
379 return 1;
383 // Unloads the module from the system and releases all the associated memory
384 int _module_unload(struct elf_module *module) {
385 struct module_dep *crt_dep, *tmp;
386 // Make sure nobody needs us
387 if (!module_unloadable(module)) {
388 DBG_PRINT("Module is required by other modules.\n");
389 return -1;
392 // Remove any dependency information
393 list_for_each_entry_safe(crt_dep, tmp, &module->required, list) {
394 clear_dependency(crt_dep->module, module);
397 // Remove the module from the module list
398 list_del_init(&module->list);
400 // Release the loaded segments or sections
401 if (module->module_addr != NULL) {
402 elf_free(module->module_addr);
404 DBG_PRINT("%s MODULE %s UNLOADED\n", module->shallow ? "SHALLOW" : "",
405 module->name);
407 // Release the module structure
408 free(module);
410 return 0;
413 int module_unload(struct elf_module *module) {
414 module_ctor_t *dtor;
416 for (dtor = module->dtors; dtor && *dtor; dtor++)
417 (*dtor) ();
419 return _module_unload(module);
422 struct elf_module *unload_modules_since(const char *name) {
423 struct elf_module *m, *mod, *begin = NULL;
425 for_each_module(mod) {
426 if (!strcmp(mod->name, name)) {
427 begin = mod;
428 break;
432 if (!begin)
433 return begin;
435 for_each_module_safe(mod, m) {
436 if (mod == begin)
437 break;
439 if (mod != begin)
440 module_unload(mod);
443 return begin;
446 static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
447 unsigned long h = elf_hash((const unsigned char*)name);
448 Elf32_Word *cr_word = module->hash_table;
450 Elf32_Word nbucket = *cr_word++;
451 cr_word++; // Skip nchain
453 Elf32_Word *bkt = cr_word;
454 Elf32_Word *chn = cr_word + nbucket;
456 Elf32_Word crt_index = bkt[h % module->hash_table[0]];
457 Elf32_Sym *crt_sym;
460 while (crt_index != STN_UNDEF) {
461 crt_sym = symbol_get_entry(module, crt_index);
463 if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
464 return crt_sym;
466 crt_index = chn[crt_index];
469 return NULL;
472 static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) {
473 unsigned long h = elf_gnu_hash((const unsigned char*)name);
475 // Setup code (TODO: Optimize this by computing only once)
476 Elf32_Word *cr_word = module->ghash_table;
477 Elf32_Word nbucket = *cr_word++;
478 Elf32_Word symbias = *cr_word++;
479 Elf32_Word bitmask_nwords = *cr_word++;
481 if ((bitmask_nwords & (bitmask_nwords - 1)) != 0) {
482 DBG_PRINT("Invalid GNU Hash structure\n");
483 return NULL;
486 Elf32_Word gnu_shift = *cr_word++;
488 Elf32_Addr *gnu_bitmask = (Elf32_Addr*)cr_word;
489 cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords;
491 Elf32_Word *gnu_buckets = cr_word;
492 cr_word += nbucket;
494 Elf32_Word *gnu_chain_zero = cr_word - symbias;
496 // Computations
497 Elf32_Word bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
498 (bitmask_nwords - 1)];
500 unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1);
501 unsigned int hashbit2 = (h >> gnu_shift) & (MODULE_ELF_CLASS_SIZE - 1);
503 if ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1) {
504 unsigned long rem;
505 Elf32_Word bucket;
507 rem = h % nbucket;
509 bucket = gnu_buckets[rem];
511 if (bucket != 0) {
512 const Elf32_Word* hasharr = &gnu_chain_zero[bucket];
514 do {
515 if (((*hasharr ^ h ) >> 1) == 0) {
516 Elf32_Sym *crt_sym = symbol_get_entry(module, (hasharr - gnu_chain_zero));
518 if (strcmp(name, module->str_table + crt_sym->st_name) == 0) {
519 return crt_sym;
522 } while ((*hasharr++ & 1u) == 0);
526 return NULL;
529 static Elf32_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module)
532 unsigned int i;
533 Elf32_Sym *crt_sym;
535 for (i = 1; i < module->symtable_size/module->syment_size; i++)
537 crt_sym = symbol_get_entry(module, i);
538 if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
540 return crt_sym;
544 return NULL;
547 Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) {
548 Elf32_Sym *result = NULL;
550 if (module->ghash_table != NULL)
551 result = module_find_symbol_gnu(name, module);
553 if (result == NULL)
555 if (module->hash_table != NULL)
557 //printf("Attempting SYSV Symbol search\n");
558 result = module_find_symbol_sysv(name, module);
560 else
562 //printf("Attempting Iterative Symbol search\n");
563 result = module_find_symbol_iterate(name, module);
567 return result;
570 Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module) {
571 struct elf_module *crt_module;
572 Elf32_Sym *crt_sym = NULL;
573 Elf32_Sym *result = NULL;
575 for_each_module(crt_module) {
576 crt_sym = module_find_symbol(name, crt_module);
578 if (crt_sym != NULL && crt_sym->st_shndx != SHN_UNDEF) {
579 switch (ELF32_ST_BIND(crt_sym->st_info)) {
580 case STB_GLOBAL:
581 if (module != NULL) {
582 *module = crt_module;
584 return crt_sym;
585 case STB_WEAK:
586 // Consider only the first weak symbol
587 if (result == NULL) {
588 if (module != NULL) {
589 *module = crt_module;
591 result = crt_sym;
593 break;
598 return result;