source: bootcd/isolinux/syslinux-6.03/com32/lib/sys/module/common.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 13.1 KB
Line 
1/*
2 * common.c
3 *
4 *  Created on: Aug 11, 2008
5 *      Author: Stefan Bucur <stefanb@zytor.com>
6 */
7
8#include <stdio.h>
9#include <elf.h>
10#include <string.h>
11#include <fs.h>
12
13#include <linux/list.h>
14#include <sys/module.h>
15
16#include "elfutils.h"
17#include "common.h"
18
19/**
20 * The one and only list of loaded modules
21 */
22LIST_HEAD(modules_head);
23
24// User-space debugging routines
25#ifdef ELF_DEBUG
26void print_elf_ehdr(Elf_Ehdr *ehdr) {
27        int i;
28
29        fprintf(stderr, "Identification:\t");
30        for (i=0; i < EI_NIDENT; i++) {
31                printf("%d ", ehdr->e_ident[i]);
32        }
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(Elf_Ehdr));
42        fprintf(stderr, "phnum: %d shnum: %d\n", ehdr->e_phnum,
43                ehdr->e_shnum);
44}
45
46void print_elf_symbols(struct elf_module *module) {
47        unsigned int i;
48        Elf_Sym *crt_sym;
49
50        for (i = 1; i < module->symtable_size/module->syment_size; i++)
51        {
52                crt_sym = (Elf_Sym*)(module->sym_table + i*module->syment_size);
53
54                fprintf(stderr,"%s %d\n", module->str_table + crt_sym->st_name, crt_sym->st_value);
55
56        }
57}
58#endif //ELF_DEBUG
59
60FILE *findpath(char *name)
61{
62        struct path_entry *entry;
63        char path[FILENAME_MAX];
64        FILE *f;
65
66        f = fopen(name, "rb"); /* for full path */
67        if (f)
68                return f;
69
70        list_for_each_entry(entry, &PATH, list) {
71                bool slash = false;
72
73                /* Ensure we have a '/' separator */
74                if (entry->str[strlen(entry->str) - 1] != '/')
75                        slash = true;
76
77                snprintf(path, sizeof(path), "%s%s%s",
78                         entry->str, slash ? "/" : "", name);
79
80                dprintf("findpath: trying \"%s\"\n", path);
81                f = fopen(path, "rb");
82                if (f)
83                        return f;
84        }
85
86        return NULL;
87}
88
89/*
90 * Image files manipulation routines
91 */
92
93int image_load(struct elf_module *module)
94{
95        module->u.l._file = findpath(module->name);
96
97        if (module->u.l._file == NULL) {
98                dprintf("Could not open object file '%s'\n", module->name);
99                goto error;
100        }
101
102        module->u.l._cr_offset = 0;
103
104        return 0;
105
106error:
107        if (module->u.l._file != NULL) {
108                fclose(module->u.l._file);
109                module->u.l._file = NULL;
110        }
111
112        return -1;
113}
114
115
116int image_unload(struct elf_module *module) {
117        if (module->u.l._file != NULL) {
118                fclose(module->u.l._file);
119                module->u.l._file = NULL;
120
121        }
122        module->u.l._cr_offset = 0;
123
124        return 0;
125}
126
127int image_read(void *buff, size_t size, struct elf_module *module) {
128        size_t result = fread(buff, size, 1, module->u.l._file);
129
130        if (result < 1)
131                return -1;
132
133        module->u.l._cr_offset += size;
134        return 0;
135}
136
137int image_skip(size_t size, struct elf_module *module) {
138        void *skip_buff = NULL;
139        size_t result;
140
141        if (size == 0)
142                return 0;
143
144        skip_buff = malloc(size);
145        result = fread(skip_buff, size, 1, module->u.l._file);
146        free(skip_buff);
147
148        if (result < 1)
149                return -1;
150
151        module->u.l._cr_offset += size;
152        return 0;
153}
154
155int image_seek(Elf_Off offset, struct elf_module *module) {
156        if (offset < module->u.l._cr_offset) // Cannot seek backwards
157                return -1;
158
159        return image_skip(offset - module->u.l._cr_offset, module);
160}
161
162
163// Initialization of the module subsystem
164int modules_init(void) {
165        return 0;
166}
167
168// Termination of the module subsystem
169void modules_term(void) {
170
171}
172
173// Allocates the structure for a new module
174struct elf_module *module_alloc(const char *name) {
175        struct elf_module *result = malloc(sizeof(struct elf_module));
176
177        if (!result) {
178            dprintf("module: Failed to alloc elf_module\n");
179            return NULL;
180        }
181
182        memset(result, 0, sizeof(struct elf_module));
183
184        INIT_LIST_HEAD(&result->list);
185        INIT_LIST_HEAD(&result->required);
186        INIT_LIST_HEAD(&result->dependants);
187
188        strncpy(result->name, name, MODULE_NAME_SIZE);
189
190        return result;
191}
192
193struct module_dep *module_dep_alloc(struct elf_module *module) {
194        struct module_dep *result = malloc(sizeof(struct module_dep));
195
196        INIT_LIST_HEAD (&result->list);
197
198        result->module = module;
199
200        return result;
201}
202
203struct elf_module *module_find(const char *name) {
204        struct elf_module *cr_module;
205
206        for_each_module(cr_module) {
207                if (strcmp(cr_module->name, name) == 0)
208                        return cr_module;
209        }
210
211        return NULL;
212}
213
214
215// Mouli: This is checking the header for 32bit machine
216// Support 64bit architecture as well.
217// Parts of the ELF header checked are common to both ELF32 and ELF64
218// Adding simple checks for both 32bit and 64bit should work (hopefully)
219//
220// Performs verifications on ELF header to assure that the open file is a
221// valid SYSLINUX ELF module.
222int check_header_common(Elf_Ehdr *elf_hdr) {
223        // Check the header magic
224        if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 ||
225                elf_hdr->e_ident[EI_MAG1] != ELFMAG1 ||
226                elf_hdr->e_ident[EI_MAG2] != ELFMAG2 ||
227                elf_hdr->e_ident[EI_MAG3] != ELFMAG3) {
228
229                dprintf("The file is not an ELF object\n");
230                return -1;
231        }
232
233        if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32 &&
234            elf_hdr->e_ident[EI_CLASS] != ELFCLASS64) {
235                dprintf("Invalid ELF class code\n");
236                return -1;
237        }
238
239        if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) {
240                dprintf("Invalid ELF data encoding\n");
241                return -1;
242        }
243
244        if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION ||
245                        elf_hdr->e_version != MODULE_ELF_VERSION) {
246                dprintf("Invalid ELF file version\n");
247                return -1;
248        }
249
250        if (elf_hdr->e_machine != EM_386 &&
251                elf_hdr->e_machine != EM_X86_64) {
252                dprintf("Invalid ELF architecture\n");
253                return -1;
254        }
255
256        return 0;
257}
258
259
260
261int enforce_dependency(struct elf_module *req, struct elf_module *dep) {
262        struct module_dep *crt_dep;
263        struct module_dep *new_dep;
264
265        list_for_each_entry(crt_dep, &req->dependants, list) {
266                if (crt_dep->module == dep) {
267                        // The dependency is already enforced
268                        return 0;
269                }
270        }
271
272        new_dep = module_dep_alloc(req);
273        list_add(&new_dep->list, &dep->required);
274
275        new_dep = module_dep_alloc(dep);
276        list_add(&new_dep->list, &req->dependants);
277
278        return 0;
279}
280
281int clear_dependency(struct elf_module *req, struct elf_module *dep) {
282        struct module_dep *crt_dep = NULL;
283        int found = 0;
284
285        list_for_each_entry(crt_dep, &req->dependants, list) {
286                if (crt_dep->module == dep) {
287                        found = 1;
288                        break;
289                }
290        }
291
292        if (found) {
293                list_del(&crt_dep->list);
294                free(crt_dep);
295        }
296
297        found = 0;
298
299        list_for_each_entry(crt_dep, &dep->required, list) {
300                if (crt_dep->module == req) {
301                        found = 1;
302                        break;
303                }
304        }
305
306        if (found) {
307                list_del(&crt_dep->list);
308                free(crt_dep);
309        }
310
311        return 0;
312}
313
314int check_symbols(struct elf_module *module)
315{
316        unsigned int i;
317        Elf_Sym *crt_sym = NULL, *ref_sym = NULL;
318        char *crt_name;
319        struct elf_module *crt_module;
320
321        int strong_count;
322        int weak_count;
323
324        for (i = 1; i < module->symtable_size/module->syment_size; i++)
325        {
326                crt_sym = symbol_get_entry(module, i);
327                crt_name = module->str_table + crt_sym->st_name;
328
329                strong_count = 0;
330                weak_count = (ELF32_ST_BIND(crt_sym->st_info) == STB_WEAK);
331
332                for_each_module(crt_module)
333                {
334                        ref_sym = module_find_symbol(crt_name, crt_module);
335
336                        // If we found a definition for our symbol...
337                        if (ref_sym != NULL && ref_sym->st_shndx != SHN_UNDEF)
338                        {
339                                switch (ELF32_ST_BIND(ref_sym->st_info))
340                                {
341                                        case STB_GLOBAL:
342                                                strong_count++;
343                                                break;
344                                        case STB_WEAK:
345                                                weak_count++;
346                                                break;
347                                }
348                        }
349                }
350
351                if (crt_sym->st_shndx == SHN_UNDEF)
352                {
353                        // We have an undefined symbol
354                        //
355                        // We use the weak_count to differentiate
356                        // between Syslinux-derivative-specific
357                        // functions. For example, unload_pxe() is
358                        // only provided by PXELINUX, so we mark it as
359                        // __weak and replace it with a reference to
360                        // undefined_symbol() on SYSLINUX, EXTLINUX,
361                        // and ISOLINUX. See perform_relocations().
362                        if (strong_count == 0 && weak_count == 0)
363                        {
364                                dprintf("Symbol %s is undefined\n", crt_name);
365                                printf("Undef symbol FAIL: %s\n",crt_name);
366                                return -1;
367                        }
368                }
369                else
370                {
371                        if (strong_count > 0 && ELF32_ST_BIND(ref_sym->st_info) == STB_GLOBAL)
372                        {
373                                // It's not an error - at relocation, the most recent symbol
374                                // will be considered
375                                dprintf("Info: Symbol %s is defined more than once\n", crt_name);
376                        }
377                }
378                //printf("symbol %s laoded from %d\n",crt_name,crt_sym->st_value);
379        }
380
381        return 0;
382}
383
384int module_unloadable(struct elf_module *module) {
385        if (!list_empty(&module->dependants))
386                return 0;
387
388        return 1;
389}
390
391
392// Unloads the module from the system and releases all the associated memory
393int _module_unload(struct elf_module *module) {
394        struct module_dep *crt_dep, *tmp;
395        // Make sure nobody needs us
396        if (!module_unloadable(module)) {
397                dprintf("Module is required by other modules.\n");
398                return -1;
399        }
400
401        // Remove any dependency information
402        list_for_each_entry_safe(crt_dep, tmp, &module->required, list) {
403                clear_dependency(crt_dep->module, module);
404        }
405
406        // Remove the module from the module list
407        list_del_init(&module->list);
408
409        // Release the loaded segments or sections
410        if (module->module_addr != NULL) {
411                elf_free(module->module_addr);
412
413                dprintf("%s MODULE %s UNLOADED\n", module->shallow ? "SHALLOW" : "",
414                                module->name);
415        }
416
417        dprintf("Unloading module %s\n", module->name);
418        // Release the module structure
419        free(module);
420
421        return 0;
422}
423
424int module_unload(struct elf_module *module) {
425        module_ctor_t *dtor;
426
427        for (dtor = module->dtors; dtor && *dtor; dtor++)
428                (*dtor) ();
429
430        return _module_unload(module);
431}
432
433struct elf_module *unload_modules_since(const char *name) {
434        struct elf_module *m, *mod, *begin = NULL;
435
436        for_each_module(mod) {
437                if (!strcmp(mod->name, name)) {
438                        begin = mod;
439                        break;
440                }
441        }
442
443        if (!begin)
444                return begin;
445
446        for_each_module_safe(mod, m) {
447                if (mod == begin)
448                        break;
449
450                if (mod != begin)
451                        module_unload(mod);
452        }
453
454        return begin;
455}
456
457static Elf_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
458        unsigned long h = elf_hash((const unsigned char*)name);
459        Elf_Word *cr_word = module->hash_table;
460
461        Elf_Word nbucket = *cr_word++;
462        cr_word++; // Skip nchain
463
464        Elf_Word *bkt = cr_word;
465        Elf_Word *chn = cr_word + nbucket;
466
467        Elf_Word crt_index = bkt[h % module->hash_table[0]];
468        Elf_Sym *crt_sym;
469
470
471        while (crt_index != STN_UNDEF) {
472                crt_sym = symbol_get_entry(module, crt_index);
473
474                if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
475                        return crt_sym;
476
477                crt_index = chn[crt_index];
478        }
479
480        return NULL;
481}
482
483static Elf_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) {
484        unsigned long h = elf_gnu_hash((const unsigned char*)name);
485
486        // Setup code (TODO: Optimize this by computing only once)
487        Elf_Word *cr_word = module->ghash_table;
488        Elf_Word nbucket = *cr_word++;
489        Elf_Word symbias = *cr_word++;
490        Elf_Word bitmask_nwords = *cr_word++;
491
492        if ((bitmask_nwords & (bitmask_nwords - 1)) != 0) {
493                dprintf("Invalid GNU Hash structure\n");
494                return NULL;
495        }
496
497        Elf_Word gnu_shift = *cr_word++;
498
499        Elf_Addr *gnu_bitmask = (Elf_Addr*)cr_word;
500        cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords;
501
502        Elf_Word *gnu_buckets = cr_word;
503        cr_word += nbucket;
504
505        Elf_Word *gnu_chain_zero = cr_word - symbias;
506
507        // Computations
508        Elf_Bword bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
509                                               (bitmask_nwords - 1)];
510
511        unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1);
512        unsigned int hashbit2 = (h >> gnu_shift) & (MODULE_ELF_CLASS_SIZE - 1);
513
514        if ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1) {
515                unsigned long rem;
516                Elf_Word bucket;
517
518                rem = h % nbucket;
519
520                bucket = gnu_buckets[rem];
521
522                if (bucket != 0) {
523                        const Elf_Word* hasharr = &gnu_chain_zero[bucket];
524
525                        do {
526                                if (((*hasharr ^ h ) >> 1) == 0) {
527                                        Elf_Sym *crt_sym = symbol_get_entry(module, (hasharr - gnu_chain_zero));
528
529                                        if (strcmp(name, module->str_table + crt_sym->st_name) == 0) {
530                                                return crt_sym;
531                                        }
532                                }
533                        } while ((*hasharr++ & 1u) == 0);
534                }
535        }
536
537        return NULL;
538}
539
540static Elf_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module)
541{
542
543        unsigned int i;
544        Elf_Sym *crt_sym;
545
546        for (i = 1; i < module->symtable_size/module->syment_size; i++)
547        {
548                crt_sym = symbol_get_entry(module, i);
549                if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
550                {
551                        return crt_sym;
552                }
553        }
554
555        return NULL;
556}
557
558Elf_Sym *module_find_symbol(const char *name, struct elf_module *module) {
559        Elf_Sym *result = NULL;
560
561        if (module->ghash_table != NULL)
562                result = module_find_symbol_gnu(name, module);
563
564        if (result == NULL)
565        {
566                if (module->hash_table != NULL)
567                {
568                        //printf("Attempting SYSV Symbol search\n");
569                        result = module_find_symbol_sysv(name, module);
570                }
571                else
572                {
573                        //printf("Attempting Iterative Symbol search\n");
574                        result = module_find_symbol_iterate(name, module);
575                }
576        }
577
578        return result;
579}
580
581Elf_Sym *global_find_symbol(const char *name, struct elf_module **module) {
582        struct elf_module *crt_module;
583        Elf_Sym *crt_sym = NULL;
584        Elf_Sym *result = NULL;
585
586        for_each_module(crt_module) {
587                crt_sym = module_find_symbol(name, crt_module);
588
589                if (crt_sym != NULL && crt_sym->st_shndx != SHN_UNDEF) {
590                        switch (ELF32_ST_BIND(crt_sym->st_info)) {
591                        case STB_GLOBAL:
592                                if (module != NULL) {
593                                        *module = crt_module;
594                                }
595                                return crt_sym;
596                        case STB_WEAK:
597                                // Consider only the first weak symbol
598                                if (result == NULL) {
599                                        if (module != NULL) {
600                                                *module = crt_module;
601                                        }
602                                        result = crt_sym;
603                                }
604                                break;
605                        }
606                }
607        }
608
609        return result;
610}
Note: See TracBrowser for help on using the repository browser.