aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Bucur <stefanb@zytor.com>2008-07-25 00:39:35 -0700
committerStefan Bucur <stefan@stefan-ubumac.(none)>2009-03-15 10:08:55 +0200
commitc3926ce6eaecb5f62b702e5977ef473f3d832140 (patch)
tree7c59d405b4f2bae8917791820f5853d2ed27fa2a
parentfde412ebc21ae2ec9b3b69838fc6867adc9641ce (diff)
downloadsyslinux-elf-c3926ce6eaecb5f62b702e5977ef473f3d832140.tar.gz
syslinux-elf-c3926ce6eaecb5f62b702e5977ef473f3d832140.tar.xz
syslinux-elf-c3926ce6eaecb5f62b702e5977ef473f3d832140.zip
Implemented shallow ELF loading and used it on the COM32 module.
-rw-r--r--.gitignore1
-rw-r--r--com32/elflink/Makefile4
-rw-r--r--com32/elflink/elf_module.c216
-rw-r--r--com32/elflink/elf_module.h23
-rw-r--r--com32/elflink/elf_utils.c2
-rw-r--r--com32/elflink/test_com32.c10
6 files changed, 215 insertions, 41 deletions
diff --git a/.gitignore b/.gitignore
index 00c44387..c3d15666 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,7 @@
*.sec
*.sys
*_bin.c
+*.dyn
*~
\#*
.\#*
diff --git a/com32/elflink/Makefile b/com32/elflink/Makefile
index d010e121..fa3be12c 100644
--- a/com32/elflink/Makefile
+++ b/com32/elflink/Makefile
@@ -36,7 +36,7 @@ LNXCFLAGS = -W -Wall -O -g -I../libutil/include
LNXSFLAGS = -g
LNXLDFLAGS = -g
SFLAGS = -D__COM32__ -march=i386
-LDFLAGS = -n -T ../lib/com32.ld
+LDFLAGS = -T ../lib/com32.ld
OBJCOPY = objcopy
PPMTOLSS16 = ../ppmtolss16
LIBGCC := $(shell $(CC) --print-libgcc)
@@ -90,7 +90,7 @@ test_memalign.elf : test_memalign.o $(LIBS)
test_com32.elf: CFLAGS += -DELF_DEBUG
test_com32.elf: test_com32.o elf_module.o elf_utils.o $(LIBS)
- $(LD) $(LDFLAGS) -o $@ $^
+ $(LD) -n $(LDFLAGS) -o $@ $^
$(OBJCOPY) --extract-symbol $@ _root_.dyn
tidy dist:
diff --git a/com32/elflink/elf_module.c b/com32/elflink/elf_module.c
index 7d7235a4..44ac23b6 100644
--- a/com32/elflink/elf_module.c
+++ b/com32/elflink/elf_module.c
@@ -44,25 +44,14 @@ static void print_elf_ehdr(Elf32_Ehdr *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;
+ unsigned int i;
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];
+ for (i = 1; i < module->symtable_size; i++) {
+ crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size);
- 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);
- printf("%s\n", module->str_table + crt_sym->st_name);
- crt_index = chn[crt_index];
- }
}
}
#endif //ELF_DEBUG
@@ -185,7 +174,7 @@ struct elf_module *module_find(const char *name) {
// Performs verifications on ELF header to assure that the open file is a
// valid SYSLINUX ELF module.
-static int check_header(Elf32_Ehdr *elf_hdr) {
+static int check_header_common(Elf32_Ehdr *elf_hdr) {
// Check the header magic
if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 ||
elf_hdr->e_ident[EI_MAG1] != ELFMAG1 ||
@@ -212,14 +201,24 @@ static int check_header(Elf32_Ehdr *elf_hdr) {
return -1;
}
- if (elf_hdr->e_type != MODULE_ELF_TYPE) {
- fprintf(stderr, "The ELF file must be a shared object\n");
+ if (elf_hdr->e_machine != MODULE_ELF_MACHINE) {
+ fprintf(stderr, "Invalid ELF architecture\n");
return -1;
}
+ return 0;
+}
- if (elf_hdr->e_machine != MODULE_ELF_MACHINE) {
- fprintf(stderr, "Invalid ELF architecture\n");
+static int check_header(Elf32_Ehdr *elf_hdr) {
+ int res;
+
+ res = check_header_common(elf_hdr);
+
+ if (res != 0)
+ return res;
+
+ if (elf_hdr->e_type != MODULE_ELF_TYPE) {
+ fprintf(stderr, "The ELF file must be a shared object\n");
return -1;
}
@@ -231,6 +230,21 @@ static int check_header(Elf32_Ehdr *elf_hdr) {
return 0;
}
+static int check_header_shallow(Elf32_Ehdr *elf_hdr) {
+ int res;
+
+ res = check_header_common(elf_hdr);
+
+ if (res != 0)
+ return res;
+
+ if (elf_hdr->e_shoff == 0x00000000) {
+ fprintf(stderr, "SHT missing\n");
+ return -1;
+ }
+
+ return 0;
+}
/*
*
* The implementation assumes that the loadable segments are present
@@ -366,6 +380,92 @@ out:
return res;
}
+static int load_shallow_sections(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
+ int i;
+ int res = 0;
+ void *sht = NULL;
+ void *buffer = NULL;
+ Elf32_Shdr *crt_sht;
+ Elf32_Off buff_offset;
+
+ Elf32_Off min_offset = 0xFFFFFFFF;
+ Elf32_Off max_offset = 0x00000000;
+ Elf32_Word max_align = 0x1;
+
+ Elf32_Off sym_offset = 0xFFFFFFFF;
+ Elf32_Off str_offset = 0xFFFFFFFF;
+
+
+ char *sh_strtable;
+
+ // We buffer the data up to the SHT
+ buff_offset = module->_cr_offset;
+
+ buffer = malloc(elf_hdr->e_shoff - buff_offset);
+ // Get to the SHT
+ image_read(buffer, elf_hdr->e_shoff - buff_offset, module);
+
+ // Load the SHT
+ sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize);
+ image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module);
+
+ // Get the string table of the section names
+ crt_sht = (Elf32_Shdr*)(sht + elf_hdr->e_shstrndx * elf_hdr->e_shentsize);
+ sh_strtable = (char*)(buffer + (crt_sht->sh_offset - buff_offset));
+
+ for (i = 0; i < elf_hdr->e_shnum; i++) {
+ crt_sht = (Elf32_Shdr*)(sht + i*elf_hdr->e_shentsize);
+
+ if (strcmp(".symtab", sh_strtable + crt_sht->sh_name) == 0) {
+ // We found the symbol table
+ min_offset = MIN(min_offset, crt_sht->sh_offset);
+ max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size);
+ max_align = MAX(max_align, crt_sht->sh_addralign);
+
+ sym_offset = crt_sht->sh_offset;
+
+ module->syment_size = crt_sht->sh_entsize;
+ module->symtable_size = crt_sht->sh_size / crt_sht->sh_entsize;
+ }
+ if (strcmp(".strtab", sh_strtable + crt_sht->sh_name) == 0) {
+ // We found the string table
+ min_offset = MIN(min_offset, crt_sht->sh_offset);
+ max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size);
+ max_align = MAX(max_align, crt_sht->sh_addralign);
+
+ str_offset = crt_sht->sh_offset;
+
+ module->strtable_size = crt_sht->sh_size;
+ }
+ }
+
+ if (elf_malloc(&module->module_addr, max_align,
+ max_offset - min_offset) != 0) {
+ fprintf(stderr, "Could not allocate sections\n");
+ goto out;
+ }
+
+ // Copy the data
+ image_seek(min_offset, module);
+ image_read(module->module_addr, max_offset - min_offset, module);
+
+ // Setup module information
+ module->module_size = max_offset - min_offset;
+ module->str_table = (char*)(module->module_addr + (str_offset - min_offset));
+ module->sym_table = module->module_addr + (sym_offset - min_offset);
+
+out:
+ // Release the SHT
+ if (sht != NULL)
+ free(sht);
+
+ // Release the buffer
+ if (buffer != NULL)
+ free(buffer);
+
+ return res;
+}
+
static int prepare_dynlinking(struct elf_module *module) {
Elf32_Dyn *dyn_entry = module->dyn_table;
@@ -378,7 +478,7 @@ static int prepare_dynlinking(struct elf_module *module) {
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)
+ case DT_GNU_HASH:
module->ghash_table =
(Elf32_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
break;
@@ -404,6 +504,12 @@ static int prepare_dynlinking(struct elf_module *module) {
dyn_entry++;
}
+ // Now compute the number of symbols in the symbol table
+ if (module->ghash_table != NULL) {
+ module->symtable_size = module->ghash_table[1];
+ } else {
+ module->symtable_size = module->hash_table[1];
+ }
return 0;
}
@@ -626,7 +732,7 @@ static int check_symbols(struct elf_module *module) {
int weak_count;
// The chain count gives the number of symbols
- for (i = 1; i < module->hash_table[1]; i++) {
+ for (i = 1; i < module->symtable_size; i++) {
crt_sym = (Elf32_Sym*)(module->sym_table + i * module->syment_size);
crt_name = module->str_table + crt_sym->st_name;
@@ -679,6 +785,9 @@ int module_load(struct elf_module *module) {
return res;
}
+ // The module is a fully featured dynamic library
+ module->shallow = 0;
+
CHECKED(res, image_read(&elf_hdr, sizeof(Elf32_Ehdr), module), error);
// Checking the header signature and members
@@ -723,6 +832,42 @@ error:
return res;
}
+int module_load_shallow(struct elf_module *module) {
+ int res;
+ Elf32_Ehdr elf_hdr;
+
+ res = image_load(module);
+
+ if (res < 0)
+ return res;
+
+ module->shallow = 1;
+
+ CHECKED(res, image_read(&elf_hdr, sizeof(Elf32_Ehdr), module), error);
+
+ // Checking the header signature and members
+ CHECKED(res, check_header_shallow(&elf_hdr), error);
+
+ // DEBUG
+#ifdef ELF_DEBUG
+ print_elf_ehdr(&elf_hdr);
+#endif // ELF_DEBUG
+
+ CHECKED(res, load_shallow_sections(module, &elf_hdr), error);
+
+ // DEBUG
+#ifdef ELF_DEBUG
+ print_elf_symbols(module);
+#endif // ELF_DEBUG
+
+ return 0;
+
+error:
+ image_unload(module);
+
+ return res;
+}
+
// Unloads the module from the system and releases all the associated memory
int module_unload(struct elf_module *module) {
struct module_dep *crt_dep, *tmp;
@@ -740,7 +885,7 @@ int module_unload(struct elf_module *module) {
// Remove the module from the module list
list_del_init(&module->list);
- // Release the loaded segments
+ // Release the loaded segments or sections
elf_free(module->module_addr);
// Release the module structure
free(module);
@@ -833,14 +978,35 @@ static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *mo
return NULL;
}
+static Elf32_Sym *module_find_symbol_iterate(const char *name,
+ struct elf_module *module) {
+
+ unsigned int i;
+ Elf32_Sym *crt_sym;
+
+ for (i=1; i < module->symtable_size; i++) {
+ crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size);
+
+ if (strcmp(name, module->str_table + crt_sym->st_name) == 0) {
+ return crt_sym;
+ }
+ }
+
+ return NULL;
+}
+
Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) {
Elf32_Sym *result = NULL;
if (module->ghash_table != NULL)
result = module_find_symbol_gnu(name, module);
- if (result == NULL)
- result = module_find_symbol_sysv(name, module);
+ if (result == NULL) {
+ if (module->hash_table != NULL)
+ result = module_find_symbol_sysv(name, module);
+ else
+ result = module_find_symbol_iterate(name, module);
+ }
return result;
}
diff --git a/com32/elflink/elf_module.h b/com32/elflink/elf_module.h
index 1454ee71..b93dc0df 100644
--- a/com32/elflink/elf_module.h
+++ b/com32/elflink/elf_module.h
@@ -22,30 +22,33 @@ typedef void (*module_exit_func)();
// Structure encapsulating a module loaded in memory
struct elf_module {
char name[MODULE_NAME_SIZE]; // The module name
-
+
+ int shallow; // Whether the module contains any code
+
struct list_head required; // Head of the required modules list
struct list_head dependants; // Head of module dependants list
struct list_head list; // The list entry in the module list
-
+
module_init_func init_func; // The initialization entry point
module_exit_func exit_func; // The module finalization code
-
-
+
+
void *module_addr; // The module location in the memory
Elf32_Addr base_addr; // The base address of the module
Elf32_Word module_size; // The module size in memory
-
+
Elf32_Word *hash_table; // The symbol hash table
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_Dyn *dyn_table; // Dynamic loading information table
-
+
Elf32_Word strtable_size; // The size of the string table
Elf32_Word syment_size; // The size of a symbol entry
-
-
+ Elf32_Word symtable_size; // The size of the symbol table
+
+
// Transient - Data available while the module is loading
FILE *_file; // The file object of the open file
Elf32_Off _cr_offset; // The current offset in the open file
@@ -54,7 +57,7 @@ struct elf_module {
// Structure encapsulating a module dependency need
struct module_dep {
struct list_head list; // The list entry in the dependency list
-
+
struct elf_module *module;
};
@@ -68,6 +71,8 @@ extern struct elf_module *module_alloc(const char *name);
// Loads the module into the system
extern int module_load(struct elf_module *module);
+// Loads a module containing only symbol information into the system
+extern int module_load_shallow(struct elf_module *module);
// Unloads the module from the system and releases all the associated memory
extern int module_unload(struct elf_module *module);
diff --git a/com32/elflink/elf_utils.c b/com32/elflink/elf_utils.c
index be320772..97f27b95 100644
--- a/com32/elflink/elf_utils.c
+++ b/com32/elflink/elf_utils.c
@@ -42,7 +42,7 @@ int elf_malloc(void **memptr, size_t alignment, size_t size) {
if ((alignment & (alignment - 1)) != 0)
return EINVAL;
if (alignment % sizeof(void*) != 0)
- return EINVAL;
+ alignment = sizeof(void*);
start_addr = malloc(size + (alignment > sizeof(struct memalign_info) ?
alignment : sizeof(struct memalign_info)));
diff --git a/com32/elflink/test_com32.c b/com32/elflink/test_com32.c
index 71b19d4c..9be31cd0 100644
--- a/com32/elflink/test_com32.c
+++ b/com32/elflink/test_com32.c
@@ -5,9 +5,11 @@
#include "elf_module.h"
#define KLIBC_NAME "klibc.dyn"
+#define ROOT_NAME "_root_.dyn"
#define ELF_DIRECTORY "/dyn/"
+static struct elf_module *mod_root;
static struct elf_module *mod_klibc;
int modules_com32_setup() {
@@ -19,16 +21,16 @@ int modules_com32_setup() {
return res;
////////////////////////////////////////
- // Load the klibc module
+ // Load the root module
// Create its associated structure
- mod_klibc = module_alloc(ELF_DIRECTORY KLIBC_NAME);
+ mod_root = module_alloc(ELF_DIRECTORY ROOT_NAME);
- if (mod_klibc == NULL) {
+ if (mod_root == NULL) {
return -1;
}
- res = module_load(mod_klibc);
+ res = module_load_shallow(mod_root);
if (res != 0) {
return res;