From: Matt Fleming Date: Mon, 6 Jun 2011 13:12:45 +0000 (+0100) Subject: ldlinux: Use DT_NEEDED for module dependencies X-Git-Tag: syslinux-5.00-pre1~39^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=558de6072a2fae89a27d10119b3ea49a4741db16;p=platform%2Fupstream%2Fsyslinux.git ldlinux: Use DT_NEEDED for module dependencies The ELF file format uses DT_NEEDED entries in the dynamic section to name any shared library dependencies. Instead of rolling our own dependency logic via the modules.dep file and elf_gen_dep.sh script use the DT_NEEDED entries. Signed-off-by: Matt Fleming --- diff --git a/.gitignore b/.gitignore index 05f0d14..98ea19f 100644 --- a/.gitignore +++ b/.gitignore @@ -50,4 +50,3 @@ *GPATH *GRTAGS *GTAGS -modules.dep diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c index 635e327..dff59e6 100644 --- a/com32/elflink/ldlinux/execute.c +++ b/com32/elflink/ldlinux/execute.c @@ -132,7 +132,6 @@ void execute(const char *cmdline, enum kernel_type type) } argv[argc] = NULL; - module_load_dependencies(kernel, "modules.dep"); spawn_load(kernel, argc, argv); } else if (type == KT_KERNEL) { /* Need add one item for kernel load, as we don't use @@ -141,7 +140,6 @@ void execute(const char *cmdline, enum kernel_type type) } else if (type == KT_CONFIG) { /* kernel contains the config file name */ char *spawn_load_param[2] = { args, NULL }; - module_load_dependencies("ui.c32", "modules.dep"); spawn_load(kernel, 1, spawn_load_param); } else { /* process the image need int 22 support */ diff --git a/com32/include/sys/exec.h b/com32/include/sys/exec.h index 656f8e2..9c00e4a 100644 --- a/com32/include/sys/exec.h +++ b/com32/include/sys/exec.h @@ -20,16 +20,6 @@ #define EXEC_ROOT_NAME "_root_.c32" /** - * MODULES_DEP - The name of the standard module dependency file - * - * This is the file which contains information about the module dependency - * graph ( what other modules it depends on ). The file format is identical - * to the standard linux modules.dep file... for more information check out the - * man page ). - */ -#define MODULES_DEP "modules.dep" - -/** * spawn_load - Load a library module or executes an executable one * @name the name of the library/executable to use, including the extension * (e.g. 'sort.c32') @@ -43,8 +33,6 @@ */ extern int spawn_load(const char *name, int argc, char **argv); -extern int module_load_dependencies(const char*name,const char*dep_file); - /** * exec_init - Initialize the dynamic execution environment. * diff --git a/com32/lib/sys/module/elf_module.c b/com32/lib/sys/module/elf_module.c index 8db4220..7d8dad4 100644 --- a/com32/lib/sys/module/elf_module.c +++ b/com32/lib/sys/module/elf_module.c @@ -18,6 +18,8 @@ #include "elfutils.h" #include "common.h" +#define MAX_NR_DEPS 64 + static int check_header(Elf32_Ehdr *elf_hdr) { int res; @@ -178,6 +180,8 @@ out: return res; } +static int nr_needed; +static Elf32_Word needed[MAX_NR_DEPS];; static int prepare_dynlinking(struct elf_module *module) { Elf32_Dyn *dyn_entry = module->dyn_table; @@ -185,7 +189,18 @@ static int prepare_dynlinking(struct elf_module *module) { while (dyn_entry->d_tag != DT_NULL) { switch (dyn_entry->d_tag) { case DT_NEEDED: - // TODO: Manage dependencies here + /* + * It's unlikely there'll be more than + * MAX_NR_DEPS DT_NEEDED entries but if there + * are then inform the user that we ran out of + * space. + */ + if (nr_needed < MAX_NR_DEPS) + needed[nr_needed++] = dyn_entry->d_un.d_ptr; + else { + printf("Too many dependencies!\n"); + return -1; + } break; case DT_HASH: module->hash_table = @@ -447,11 +462,45 @@ int module_load(struct elf_module *module) { CHECKED(res, load_segments(module, &elf_hdr), error); //printf("bleah... 3\n"); // Obtain dynamic linking information + nr_needed = 0; CHECKED(res, prepare_dynlinking(module), error); //printf("check... 4\n"); // //dump_elf_module(module); + /* Find modules we need to load as dependencies */ + if (module->str_table) { + int i, n; + + /* + * nr_needed can be modified by recursive calls to + * module_load() so keep a local copy on the stack. + */ + n = nr_needed; + for (i = 0; i < n; i++) { + size_t len, j; + char *dep, *p; + + dep = module->str_table + needed[i]; + + /* strip everything but the last component */ + j = len = strlen(dep); + if (!len) + continue; + + p = dep + len - 1; + while (j > 0 && *p && *p != '/') { + p--; + j--; + } + + if (*p++ == '/') { + char argv[2] = { p, NULL }; + spawn_load(p, 1, argv); + } + } + } + // Check the symbols for duplicates / missing definitions CHECKED(res, check_symbols(module), error); //printf("check... 5\n"); diff --git a/com32/lib/sys/module/exec.c b/com32/lib/sys/module/exec.c index 1ed3263..71d3192 100644 --- a/com32/lib/sys/module/exec.c +++ b/com32/lib/sys/module/exec.c @@ -346,150 +346,6 @@ int spawn_load(const char *name, int argc, char **argv) */ } -/* - * Avoid circular dependencies. - * - * It's possible that someone messed up the modules.dep file and that - * it includes circular dependencies, so we need to take steps here to - * avoid looping in module_load_dependencies() forever. - * - * We build a singly-linked list of modules that are in the middle of - * being loaded. When they have completed loading their entry is - * removed from this list in LIFO order (new entries are always added - * to the head of the list). - */ -struct loading_dep { - const char *name; - struct module_dep *next; -}; -static struct loading_dep *loading_deps; - -/* - * Remember that because we insert elements in a LIFO order we need to - * start from the end of the list and work towards the front so that - * we print the modules in the order in which we tried to load them. - * - * Yay for recursive function calls. - */ -static void print_loading_dep(struct loading_dep *dep) -{ - if (dep) { - print_loading_dep(dep->next); - printf("\t\t\"%s\"\n", dep->name); - } -} - -int module_load_dependencies(const char *name,const char *dep_file) -{ - FILE *d_file=fopen(dep_file,"r"); - char line[2048],aux[2048],temp_name[MODULE_NAME_SIZE],slbz[24]; - int i=0,j=0,res=0; - struct loading_dep *dep; - - if(d_file==NULL) - { - DBG_PRINT("Could not open object file '%s'\n",dep_file); - return -1; - } - - /* - * Are we already in the middle of loading this module's - * dependencies? - */ - for (dep = loading_deps; dep; dep = dep->next) { - if (!strcasecmp(dep->name, name)) - break; /* found */ - } - - if (dep) { - struct loading_dep *last, *prev; - - /* Dup! */ - printf("\t\tCircular depedency detected when loading " - "modules!\n"); - printf("\t\tModules dependency chain looks like this,\n\n"); - print_loading_dep(loading_deps); - printf("\n\t\t... and we tried to load \"%s\" again\n", name); - - return -1; - } else { - dep = malloc(sizeof(*dep)); - if (!dep) { - printf("Failed to alloc memory for loading_dep\n"); - return -1; - } - - dep->name = name; - dep->next = loading_deps; - - /* Insert at the head of the list */ - loading_deps = dep; - } - - /* Note from feng: - * new modues.dep has line like this: - * a.c32: b.32 c.c32 d.c32 - * with desktop glibc - * sscanf(line,"%[^:]: %[^\n]", temp_name, aux); - * works, which doesn't work here - */ - memset(temp_name, 0, sizeof(temp_name)); - memset(aux, 0, sizeof(aux)); - while (1) { - if(fgets(line,2048,d_file)==NULL) - break; - - //sscanf(line,"%s %[^\t\n]s",temp_name,aux); - //sscanf(line,"%[^:]: %[^\n]", temp_name, aux); - //sscanf(line,"%[^:]: %[^\n]\n", temp_name, aux); - - sscanf(line,"%[^:]:", temp_name); - if (!strncmp(name, temp_name, strlen(name))) { - /* The next 2 chars should be ':' and ' ' */ - i = strlen(temp_name); - if (line[i] != ':' || line[i+1] != ' ') - break; - - i +=2; - j = 0; - while (line[i] != '\n') - aux[j++] = line[i++]; - aux[j] = '\0'; - //dprintf("found dependency: temp_name = %s, aux = %s, name = %s", temp_name, aux, name); - break; - } - } - fclose(d_file); - - /* Reuse temp_name for dependent module name buffer */ - memset(temp_name, 0, sizeof(temp_name)); - i = 0; - while (aux[i]) { - sscanf(aux + i, "%s", temp_name); - //dprintf("load module: %s", temp_name); - i += strlen(temp_name); - i++; /* skip a space */ - - if (strlen(temp_name)) { - char *argv[2] = { temp_name, NULL }; - int ret; - - ret = module_load_dependencies(temp_name, - MODULES_DEP); - if (!ret) { - if (spawn_load(temp_name, 1, argv) < 0) - continue; - } - } - } - - /* Remove our entry from the head of loading_deps */ - loading_deps = loading_deps->next; - free(dep); - - return 0; -} - void exec_term(void) { modules_term(); diff --git a/core/elflink/load_env32.c b/core/elflink/load_env32.c index 793ecd5..e639653 100644 --- a/core/elflink/load_env32.c +++ b/core/elflink/load_env32.c @@ -75,6 +75,5 @@ void load_env32(com32sys_t * regs) init_module_subsystem(&core_module); - module_load_dependencies(LDLINUX, "modules.dep"); spawn_load(LDLINUX, 1, argv); } diff --git a/elf_gen_dep.sh b/elf_gen_dep.sh deleted file mode 100755 index 1badb64..0000000 --- a/elf_gen_dep.sh +++ /dev/null @@ -1,130 +0,0 @@ -#!/bin/sh - -####################################################### -# Round 1: get all the loacl and external symbols -####################################################### - -for i in core/isolinux.elf core/pxelinux.elf com32/*/*.c32 com32/*/*/*.c32 -do - # module=$(echo $i | sed "s/^\(.*\).o$/\1/") - - # remove the path infomation - module=$(echo $i | sed "s/^.*\/\(.*\)$/\1/") - - readelf -s $i > temp.txt - #Get the last 2 items of each line - cut -c47- temp.txt > $module.txt - rm temp.txt - - #Get the unresolved symbols - sed -n -e "/UND $/d" -e "/_GLOBAL_OFFSET_TABLE_/d" -e "s/^.UND.\(.*\)$/\1/p" $module.txt > $module.ext - - #Get the local symbols - sed -n -e "/UND/d" -e "/ABS/d" -e "/...[0-9] $/d" -e "/...[0-9] \./d" -e "/...[0-9]/p" $module.txt > $module.int - sed -i -e "s/^.....//g" $module.int - sed -i -e "s/^\(.*\)$/\1 <$module>/g" $module.int - # Delete all whitespace - sed -i -e "s/^[ \t]*$//g" $module.int - - cat $module.int >> all.txt -done - - -touch modules.dep - -####################################################### -# Round 2: get all the loacl and external symbols -####################################################### - -# Consolidate the dependent modules to one line and remove -# the redundant ones, and the "core" -rm_cr () -{ - touch rmcr.tmp - all_dep=$module: - space=' ' - - while read line - do - # skip the module which is alreay on the list - grep $line rmcr.tmp > /dev/null && continue - - # grep extlinux/isolinux and remove them - echo $line | grep extlinux > /dev/null && continue - echo $line | grep isolinux > /dev/null && continue - echo $line | grep pxelinux > /dev/null && continue - echo $line | grep ldlinux > /dev/null && continue - - all_dep=$all_dep$space$line - echo $all_dep > rmcr.tmp - done - - echo $all_dep >> modules.dep - rm rmcr.tmp -} - -# Find the symbol belongs to which module by screening all.txt, do it -# one by one, and the result "resolve.tmp" will be a file like: -# a.c32 -# b.c32 -# c.c32 -resolve_sym () -{ - touch resolve.tmp - - while read symbol - do - # If no one provides the symbol we're trying to - # resolve then add it to the list of unresolved - # symbols. - grep -q $symbol all.txt - if [ $? -ne 0 ]; then - # We only need to add the symbol once - if [[ ! "$unresolved_symbols" =~ "$symbol" ]]; then - unresolved_symbols="$unresolved_symbols $symbol" - fi - else - #echo $symbol - sed -n -e "s/^$symbol <\(.*\)>/\1/p" all.txt | head -n1 >> resolve.tmp - #grep $symbol all.txt - fi - done - - rm_cr < resolve.tmp - rm resolve.tmp -} - -#only test name start with a/b -#rm [c-z]*.ext - -if [ -e modules.dep ] -then - rm modules.dep - touch modules.dep -fi - -# Don't need to resolve the core symbols -for i in extlinux isolinux pxelinux -do - if [ -e $i.elf.ext ] - then - rm $i.elf.ext - fi -done - -for i in *.ext -do - module=$(echo $i | sed "s/^\(.*\).ext$/\1/") - resolve_sym < $i -done - -# Do some cleanup -rm *.txt -rm *.ext -rm *.int - -if [ "$unresolved_symbols" ]; then - echo "WARNING: These symbols could not be resolved:" $unresolved_symbols -fi - -echo ELF modules dependency is bult up, pls check modules.dep!