ldlinux: Use DT_NEEDED for module dependencies
authorMatt Fleming <matt.fleming@linux.intel.com>
Mon, 6 Jun 2011 13:12:45 +0000 (14:12 +0100)
committerMatt Fleming <matt.fleming@linux.intel.com>
Tue, 7 Jun 2011 14:59:58 +0000 (15:59 +0100)
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 <matt.fleming@linux.intel.com>
.gitignore
com32/elflink/ldlinux/execute.c
com32/include/sys/exec.h
com32/lib/sys/module/elf_module.c
com32/lib/sys/module/exec.c
core/elflink/load_env32.c
elf_gen_dep.sh [deleted file]

index 05f0d14..98ea19f 100644 (file)
@@ -50,4 +50,3 @@
 *GPATH
 *GRTAGS
 *GTAGS
-modules.dep
index 635e327..dff59e6 100644 (file)
@@ -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 */
index 656f8e2..9c00e4a 100644 (file)
 #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.
  *
index 8db4220..7d8dad4 100644 (file)
@@ -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");
index 1ed3263..71d3192 100644 (file)
@@ -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();
index 793ecd5..e639653 100644 (file)
@@ -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 (executable)
index 1badb64..0000000
+++ /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!