diff options
author | Stefan Bucur <stefanb@zytor.com> | 2008-06-12 20:25:47 +0300 |
---|---|---|
committer | Stefan Bucur <stefan@stefan-ubumac.(none)> | 2009-03-15 10:02:14 +0200 |
commit | c452160ab1e3f591f50dde0a7168d5275e17efb8 (patch) | |
tree | b3967a3aa4a56cf5a564487e48b27fd4ae8a9c7e | |
parent | c43ab81a5f04e294edf3fbb4691647a0174bf310 (diff) | |
download | syslinux-elf-c452160ab1e3f591f50dde0a7168d5275e17efb8.tar.gz syslinux-elf-c452160ab1e3f591f50dde0a7168d5275e17efb8.tar.xz syslinux-elf-c452160ab1e3f591f50dde0a7168d5275e17efb8.zip |
The first functional prototype of module linking.
Although the code is currently a little messy, one
could see that when she loads hello_def and hello_ref
modules (in that order), the functions that
handle the shared symbol perform correctly when
tested by the main program. There is one initialization
function that stores 100 in the symbol, and a second one
that reads the symbol, returns its value and increments it.
-rw-r--r-- | elf/Makefile | 15 | ||||
-rw-r--r-- | elf/TODO | 3 | ||||
-rw-r--r-- | elf/elf_module.c | 73 | ||||
-rw-r--r-- | elf/elftest.c | 65 | ||||
-rw-r--r-- | elf/hello_def.c | 16 | ||||
-rw-r--r-- | elf/hello_ref.c (renamed from elf/hello.c) | 8 |
6 files changed, 129 insertions, 51 deletions
diff --git a/elf/Makefile b/elf/Makefile index e5edfaa3..e7d0ba64 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -10,7 +10,7 @@ RM = rm -f ################ # Build options -CFLAGS = -Wall -DELF_USERSPACE_TEST +CFLAGS = -g3 -O0 -Wall -DELF_USERSPACE_TEST LDFLAGS = @@ -20,8 +20,6 @@ LDFLAGS = # Test executable name TESTPROG = elftest -# Test module name -TESTMODULE = hello.so ############### # Make targets @@ -38,10 +36,13 @@ $(TESTPROG): elftest.o elf_module.o elf_utils.o # The shared module to test on -test-module: $(TESTMODULE) +test-module: hello_def.so hello_ref.so -# $(TESTMODULE): CFLAGS += -fPIC -$(TESTMODULE): hello.o + +hello_def.so: hello_def.o + $(CC) -shared -o $@ $^ + +hello_ref.so: hello_ref.o $(CC) -shared -o $@ $^ @@ -49,5 +50,5 @@ $(TESTMODULE): hello.o clean: -$(RM) *.o -$(RM) $(TESTPROG) - -$(RM) $(TESTMODULE) + -$(RM) *.so diff --git a/elf/TODO b/elf/TODO new file mode 100644 index 00000000..9dc92fe3 --- /dev/null +++ b/elf/TODO @@ -0,0 +1,3 @@ +* Check to see whether the module is already inserted. +* Perform unloading cleanup properly. +* Create a macro for reporting debugging information. diff --git a/elf/elf_module.c b/elf/elf_module.c index 7e3b7dde..a91b1f1b 100644 --- a/elf/elf_module.c +++ b/elf/elf_module.c @@ -364,29 +364,60 @@ static int prepare_dynlinking(struct elf_module *module) { static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) { Elf32_Word *dest = module_get_absolute(rel->r_offset, module); + // The symbol reference index Elf32_Word sym = ELF32_R_SYM(rel->r_info); unsigned char type = ELF32_R_TYPE(rel->r_info); + // The symbol definition (if applicable) + Elf32_Sym *sym_def = NULL; + struct elf_module *sym_module = NULL; + Elf32_Addr sym_addr = 0x0; + + if (sym > 0) { + // Find out details about the symbol + + // The symbol reference + Elf32_Sym *sym_ref = + (Elf32_Sym*)(module->sym_table + sym * module->syment_size); + + // The symbol definition + sym_def = + global_find_symbol(module->str_table + sym_ref->st_name, + &sym_module); + + if (sym_def == NULL) { + fprintf(stderr, "Cannot perform relocation for symbol %s\n", + module->str_table + sym_ref->st_name); + return 0; + } + + // Compute the absolute symbol virtual address + sym_addr = (Elf32_Addr)module_get_absolute(sym_def->st_value, sym_module); + + } + switch (type) { case R_386_NONE: // Do nothing break; case R_386_32: + *dest += sym_addr; break; case R_386_PC32: + *dest += sym_addr - (Elf32_Addr)dest; break; case R_386_COPY: + if (sym_addr > 0) { + memcpy((void*)dest, (void*)sym_addr, sym_def->st_size); + } break; case R_386_GLOB_DAT: - break; case R_386_JMP_SLOT: + // Maybe TODO: Keep track of the GOT entries allocations + *dest = sym_addr; break; case R_386_RELATIVE: - *dest = module->base_addr + *dest; - break; - case R_386_GOTOFF: - break; - case R_386_GOTPC: + *dest += module->base_addr; break; default: fprintf(stderr, "Relocation type %d not supported\n", type); @@ -488,7 +519,7 @@ static int check_symbols(struct elf_module *module) { int weak_count; // The chain count gives the number of symbols - for (i = 0; i < module->hash_table[1]; i++) { + for (i = 1; i < module->hash_table[1]; i++) { crt_sym = (Elf32_Sym*)(module->sym_table + i * module->syment_size); crt_name = module->str_table + crt_sym->st_name; @@ -515,12 +546,12 @@ static int check_symbols(struct elf_module *module) { // We have an undefined symbol if (strong_count == 0 && weak_count == 0) { fprintf(stderr, "Symbol %s is undefined\n", crt_name); - return -1; + //return -1; } } else { if (strong_count > 0 && ELF32_ST_BIND(ref_sym->st_info) == STB_GLOBAL) { - fprintf(stderr, "Symbol %s is defined more than once\n", crt_name); - return -1; + fprintf(stderr, "Warning: Symbol %s is defined more than once\n", crt_name); + //return -1; } } } @@ -553,12 +584,21 @@ int module_load(struct elf_module *module) { // DEBUG print_elf_ehdr(elf_hdr); + // Load the segments in the memory CHECKED(res, load_segments(module), error); + // Obtain dynamic linking information CHECKED(res, prepare_dynlinking(module), error); // DEBUG print_elf_symbols(module); + // Check the symbols for duplicates / missing definitions + CHECKED(res, check_symbols(module), error); + + // Add the module at the beginning of the module list + list_add(&module->list, &modules); + + // Perform the relocations CHECKED(res, resolve_symbols(module), error); // The file image is no longer needed @@ -606,8 +646,8 @@ Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) { Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module) { struct elf_module *crt_module; - Elf32_Sym *crt_sym; - Elf32_Sym *result; + Elf32_Sym *crt_sym = NULL; + Elf32_Sym *result = NULL; list_for_each_entry(crt_module, &modules, list) { crt_sym = module_find_symbol(name, crt_module); @@ -620,10 +660,13 @@ Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module) { } return crt_sym; case STB_WEAK: - if (module != NULL) { - *module = crt_module; + // Consider only the first weak symbol + if (result == NULL) { + if (module != NULL) { + *module = crt_module; + } + result = crt_sym; } - result = crt_sym; break; } } diff --git a/elf/elftest.c b/elf/elftest.c index 3495ad11..7013938e 100644 --- a/elf/elftest.c +++ b/elf/elftest.c @@ -11,7 +11,28 @@ void print_usage() { fprintf(stderr, "Usage:\n"); - fprintf(stderr, "\telftest objfile [symbol ...]\n"); + fprintf(stderr, "\telftest objfile ...\n"); +} + +void test_hello() { + int i; + + struct elf_module *module; + Elf32_Sym *symbol; + + symbol = global_find_symbol("undef_func", &module); + + void (*undef_func)(int) = module_get_absolute(symbol->st_value, module); + + symbol = global_find_symbol("test_func", &module); + + int (*test_func)(void) = module_get_absolute(symbol->st_value, module); + + undef_func(0); + + for (i=0; i < 10; i++) { + printf("%d\n", test_func()); + } } int main(int argc, char **argv) { @@ -28,45 +49,35 @@ int main(int argc, char **argv) { return 1; } - module_name = argv[0]; - res = modules_init(); - + if (res < 0) { fprintf(stderr, "Could not initialize module subsystem\n"); exit(1); } - module = module_alloc(module_name); - - if (module == NULL) { - fprintf(stderr, "Could not allocate the module\n"); - goto error; - } - - res = module_load(module); - - if (res < 0) { - fprintf(stderr, "Could not load the module\n"); - goto error; - } - - argc--; - argv++; - while (argc > 0) { - if (module_find_symbol(argv[0], module) != NULL) { - printf("Symbol %s found\n", argv[0]); - } else { - printf("Symbol %s not found\n", argv[0]); + module_name = argv[0]; + + module = module_alloc(module_name); + + if (module == NULL) { + fprintf(stderr, "Could not allocate the module\n"); + goto error; + } + + res = module_load(module); + + if (res < 0) { + fprintf(stderr, "Could not load the module\n"); + goto error; } argc--; argv++; } - - module_unload(module); + test_hello(); modules_term(); diff --git a/elf/hello_def.c b/elf/hello_def.c new file mode 100644 index 00000000..2ad60233 --- /dev/null +++ b/elf/hello_def.c @@ -0,0 +1,16 @@ + +int undef_symbol; + +void undef_func(int param) { + undef_symbol = 100; +} + +static int hello_init(void) { + // Do nothing + + return 0; +} + +static void hello_exit(void) { + // Do nothing +} diff --git a/elf/hello.c b/elf/hello_ref.c index 1dd46d92..f7b798b4 100644 --- a/elf/hello.c +++ b/elf/hello_ref.c @@ -11,12 +11,16 @@ int exported_symbol; // Undefined function extern void undef_func(int param); -int hello_init() { +int test_func(void) { + return undef_symbol++; +} + +static int hello_init(void) { undef_symbol++; return 0; } -void hello_exit() { +static void hello_exit(void) { undef_func(undef_symbol); } |