aboutsummaryrefslogtreecommitdiffstats
path: root/elf
diff options
context:
space:
mode:
authorStefan Bucur <stefanb@zytor.com>2008-06-11 23:45:50 +0300
committerStefan Bucur <stefanb@zytor.com>2008-06-11 23:45:50 +0300
commitb56dd67e88eaceffd924a495bca3bf8590f2cd7e (patch)
tree2764fbc418cd61da079b9df3dacbc432ce5e679a /elf
parent0faff07bff238831dc4135d3cbb0047b216cb7c3 (diff)
downloadsyslinux-elf-b56dd67e88eaceffd924a495bca3bf8590f2cd7e.tar.gz
syslinux-elf-b56dd67e88eaceffd924a495bca3bf8590f2cd7e.tar.xz
syslinux-elf-b56dd67e88eaceffd924a495bca3bf8590f2cd7e.zip
Implemented symbol verification and global searching.
The global searching routine yields priority to the GLOBAL symbols, and uses WEAK symbols only when GLOBAL symbols are not found.
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile1
-rw-r--r--elf/elf_module.c235
-rw-r--r--elf/elf_module.h6
-rw-r--r--elf/hello.c2
4 files changed, 222 insertions, 22 deletions
diff --git a/elf/Makefile b/elf/Makefile
index 30f5059e..e5edfaa3 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -40,6 +40,7 @@ $(TESTPROG): elftest.o elf_module.o elf_utils.o
# The shared module to test on
test-module: $(TESTMODULE)
+# $(TESTMODULE): CFLAGS += -fPIC
$(TESTMODULE): hello.o
$(CC) -shared -o $@ $^
diff --git a/elf/elf_module.c b/elf/elf_module.c
index 0a78b7c0..7e3b7dde 100644
--- a/elf/elf_module.c
+++ b/elf/elf_module.c
@@ -52,6 +52,29 @@ static void print_elf_ehdr(Elf32_Ehdr *ehdr) {
printf("Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize,
sizeof(Elf32_Ehdr));
}
+
+static void print_elf_symbols(struct elf_module *module) {
+ Elf32_Word *bkt = module->hash_table + 2;
+ Elf32_Word *chn = module->hash_table + 2 + module->hash_table[0];
+ Elf32_Word i, crt_index;
+ Elf32_Sym *crt_sym;
+
+ printf("Bucket count: %d \n", module->hash_table[0]);
+ printf("Chain count: %d (Non GNU-Hash: %d)\n", module->hash_table[1],
+ module->ghash_table[1]);
+
+ for (i = 0; i < module->hash_table[0]; i++) {
+ printf("Bucket %d:\n", i);
+ crt_index = bkt[i];
+
+ while (crt_index != STN_UNDEF) {
+ crt_sym = (Elf32_Sym*)(module->sym_table + crt_index*module->syment_size);
+
+ printf("%s\n", module->str_table + crt_sym->st_name);
+ crt_index = chn[crt_index];
+ }
+ }
+}
#endif //ELF_USERSPACE_TEST
#ifdef ELF_USERSPACE_TEST
@@ -256,14 +279,14 @@ static int load_segments(struct elf_module *module) {
if (cr_pht->p_type == PT_LOAD) {
// Copy the segment at its destination
- memcpy((void*)(module->base_addr + cr_pht->p_vaddr),
+ memcpy(module_get_absolute(cr_pht->p_vaddr, module),
module->_file_image + cr_pht->p_offset,
cr_pht->p_filesz);
printf("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n",
cr_pht->p_filesz,
cr_pht->p_vaddr,
- module->base_addr + cr_pht->p_vaddr);
+ (Elf32_Addr)module_get_absolute(cr_pht->p_vaddr, module));
}
}
@@ -305,16 +328,20 @@ static int prepare_dynlinking(struct elf_module *module) {
// TODO: Manage dependencies here
break;
case DT_HASH:
- module->hash_table = (Elf32_Word*)(dyn_entry->d_un.d_ptr + module->base_addr);
+ module->hash_table =
+ (Elf32_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
break;
case DT_GNU_HASH: // TODO: Add support for this one, too (50% faster)
- module->ghash_table = (Elf32_Word*)(dyn_entry->d_un.d_ptr + module->base_addr);
+ module->ghash_table =
+ (Elf32_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
break;
case DT_STRTAB:
- module->str_table = (char*)(dyn_entry->d_un.d_ptr + module->base_addr);
+ module->str_table =
+ (char*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
break;
case DT_SYMTAB:
- module->sym_table = (void*)(dyn_entry->d_un.d_ptr + module->base_addr);
+ module->sym_table =
+ module_get_absolute(dyn_entry->d_un.d_ptr, module);
break;
case DT_STRSZ:
module->strtable_size = dyn_entry->d_un.d_val;
@@ -322,6 +349,9 @@ static int prepare_dynlinking(struct elf_module *module) {
case DT_SYMENT:
module->syment_size = dyn_entry->d_un.d_val;
break;
+ case DT_PLTGOT: // The first entry in the GOT
+ module->got = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
}
dyn_entry++;
@@ -331,39 +361,168 @@ static int prepare_dynlinking(struct elf_module *module) {
return 0;
}
+static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
+ Elf32_Word *dest = module_get_absolute(rel->r_offset, module);
+
+ Elf32_Word sym = ELF32_R_SYM(rel->r_info);
+ unsigned char type = ELF32_R_TYPE(rel->r_info);
+
+ switch (type) {
+ case R_386_NONE:
+ // Do nothing
+ break;
+ case R_386_32:
+ break;
+ case R_386_PC32:
+ break;
+ case R_386_COPY:
+ break;
+ case R_386_GLOB_DAT:
+ break;
+ case R_386_JMP_SLOT:
+ break;
+ case R_386_RELATIVE:
+ *dest = module->base_addr + *dest;
+ break;
+ case R_386_GOTOFF:
+ break;
+ case R_386_GOTPC:
+ break;
+ default:
+ fprintf(stderr, "Relocation type %d not supported\n", type);
+ return -1;
+ }
+
+ return 0;
+}
+
static int resolve_symbols(struct elf_module *module) {
Elf32_Dyn *dyn_entry = module->_dyn_info;
+ int i, res;
+
+ Elf32_Word plt_rel_size = 0;
+ void *plt_rel = NULL;
+
+ void *rel = NULL;
+ Elf32_Word rel_size = 0;
+ Elf32_Word rel_entry = 0;
+
+ // The current relocation
+ Elf32_Rel *crt_rel;
while (dyn_entry->d_tag != DT_NULL) {
switch(dyn_entry->d_tag) {
- case DT_RELA:
-
- case DT_RELASZ:
-
- case DT_RELAENT:
+ // PLT relocation information
case DT_PLTRELSZ:
+ plt_rel_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_PLTREL:
+ if (dyn_entry->d_un.d_val != DT_REL) {
+ fprintf(stderr, "Unsupported PLT relocation\n");
+ return -1;
+ }
+ case DT_JMPREL:
+ plt_rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
- case DT_PLTGOT: // The first entry in the GOT
-
+ // Standard relocation information
+ case DT_REL:
+ rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_RELSZ:
+ rel_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_RELENT:
+ rel_entry = dyn_entry->d_un.d_val;
+ break;
+
+ // Module initialization and termination
case DT_INIT:
-
+ // TODO Implement initialization functions
+ break;
case DT_FINI:
+ // TODO Implement finalization functions
+ break;
+ }
+
+ dyn_entry++;
+ }
+
+ if (rel_size > 0) {
+ // Process standard relocations
+ for (i = 0; i < rel_size/rel_entry; i++) {
+ crt_rel = (Elf32_Rel*)(rel + i*rel_entry);
- case DT_REL:
+ res = perform_relocation(module, crt_rel);
- case DT_RELSZ:
+ if (res < 0)
+ return res;
+ }
+
+ }
+
+ if (plt_rel_size > 0) {
+ // TODO: Permit this lazily
+ // Process PLT relocations
+ for (i = 0; i < plt_rel_size/sizeof(Elf32_Rel); i++) {
+ crt_rel = (Elf32_Rel*)(plt_rel + i*sizeof(Elf32_Rel));
- case DT_RELENT:
+ res = perform_relocation(module, crt_rel);
- case DT_PLTREL:
+ if (res < 0)
+ return res;
+ }
+ }
+
+ return 0;
+}
+
+static int check_symbols(struct elf_module *module) {
+ int i;
+ Elf32_Sym *crt_sym, *ref_sym;
+ char *crt_name;
+ struct elf_module *crt_module;
+
+ int strong_count;
+ int weak_count;
+
+ // The chain count gives the number of symbols
+ for (i = 0; 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;
+
+ strong_count = 0;
+ weak_count = 0;
+
+ list_for_each_entry(crt_module, &modules, list) {
+ ref_sym = module_find_symbol(crt_name, crt_module);
- case DT_JMPREL:
- printf("Recognized DYN tag: %d\n", dyn_entry->d_tag);
- break;
+ // If we found a definition for our symbol...
+ if (ref_sym != NULL && ref_sym->st_shndx != SHN_UNDEF) {
+ switch (ELF32_ST_BIND(ref_sym->st_info)) {
+ case STB_GLOBAL:
+ strong_count++;
+ break;
+ case STB_WEAK:
+ weak_count++;
+ break;
+ }
+ }
}
- dyn_entry++;
+ if (crt_sym->st_shndx == SHN_UNDEF) {
+ // We have an undefined symbol
+ if (strong_count == 0 && weak_count == 0) {
+ fprintf(stderr, "Symbol %s is undefined\n", crt_name);
+ 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;
+ }
+ }
}
return 0;
@@ -397,6 +556,9 @@ int module_load(struct elf_module *module) {
CHECKED(res, load_segments(module), error);
CHECKED(res, prepare_dynlinking(module), error);
+ // DEBUG
+ print_elf_symbols(module);
+
CHECKED(res, resolve_symbols(module), error);
// The file image is no longer needed
@@ -429,6 +591,7 @@ Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) {
Elf32_Word crt_index = bkt[h % module->hash_table[0]];
Elf32_Sym *crt_sym;
+
while (crt_index != STN_UNDEF) {
crt_sym = (Elf32_Sym*)(module->sym_table + crt_index*module->syment_size);
@@ -440,3 +603,31 @@ Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) {
return NULL;
}
+
+Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module) {
+ struct elf_module *crt_module;
+ Elf32_Sym *crt_sym;
+ Elf32_Sym *result;
+
+ list_for_each_entry(crt_module, &modules, list) {
+ crt_sym = module_find_symbol(name, crt_module);
+
+ if (crt_sym != NULL && crt_sym->st_shndx != SHN_UNDEF) {
+ switch (ELF32_ST_BIND(crt_sym->st_info)) {
+ case STB_GLOBAL:
+ if (module != NULL) {
+ *module = crt_module;
+ }
+ return crt_sym;
+ case STB_WEAK:
+ if (module != NULL) {
+ *module = crt_module;
+ }
+ result = crt_sym;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
diff --git a/elf/elf_module.h b/elf/elf_module.h
index 8a8d4830..0cd325de 100644
--- a/elf/elf_module.h
+++ b/elf/elf_module.h
@@ -36,6 +36,7 @@ struct elf_module {
Elf32_Word *ghash_table; // The GNU style hash table
char *str_table; // The string table
void *sym_table; // The symbol table
+ void *got; // The Global Offset Table
Elf32_Word strtable_size; // The size of the string table
Elf32_Word syment_size; // The size of a symbol entry
@@ -74,5 +75,10 @@ extern int module_load(struct elf_module *module);
extern int module_unload(struct elf_module *module);
extern Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module);
+extern Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module);
+
+static inline void *module_get_absolute(Elf32_Addr addr, struct elf_module *module) {
+ return (void*)(module->base_addr + addr);
+}
#endif /*ELF_MODULE_H_*/
diff --git a/elf/hello.c b/elf/hello.c
index 0ab84de4..1dd46d92 100644
--- a/elf/hello.c
+++ b/elf/hello.c
@@ -6,6 +6,8 @@
// Undefined symbol
extern int undef_symbol;
+int exported_symbol;
+
// Undefined function
extern void undef_func(int param);