elf: Support __constructor and __destructor
authorMatt Fleming <matt.fleming@intel.com>
Thu, 22 Mar 2012 15:31:43 +0000 (15:31 +0000)
committerMatt Fleming <matt.fleming@intel.com>
Fri, 23 Mar 2012 16:54:47 +0000 (16:54 +0000)
The old way of specifying functions that need to be run before/after a
main function has never worked for ELF modules. Instead, the only way
to get similiar behaviour was by using the MODULE_INIT() and
MODULE_EXIT() macros, but no one seems to have bothered converting the
old __constructor users over. Anyway, the old way is superior because
it allows multiple functions be specified. Delete the MODULE_* macros
as there's only one user of them in the entire tree.

We can also get rid of the UNKNOWN_MODULE constant because now a
module doesn't need a __module_init_ptr symbol to be classed as a
library - if a module isn't an executable, it's a library, there's no
such thing as an unknown type.

It's no longer necessary to explicitly call
__syslinux_get_ipappend_strings() from ldlinux.c because the
__constructor tag on the version in com32/lib/syslinux will take care
of invoking it before ldlinux.c32's main() is executed.

Also, since we've refactored unload_module() to now run a module's
destructors let's minimise the number of callers by deleting
load_library() and unload_library(), which were only called by the
test module in com32/elflink.

Signed-off-by: Matt Fleming <matt.fleming@intel.com>
12 files changed:
com32/elflink/ldlinux/Makefile
com32/elflink/ldlinux/cli.c
com32/elflink/ldlinux/ipappend.c [deleted file]
com32/elflink/ldlinux/ldlinux.c
com32/include/sys/exec.h
com32/include/sys/module.h
com32/lib/Makefile
com32/lib/elf32.ld
com32/lib/sys/module/common.c
com32/lib/sys/module/elf_module.c
com32/lib/sys/module/exec.c
mk/lib.mk

index 9960277..ca4c7e2 100644 (file)
@@ -20,7 +20,7 @@ LIBS = --whole-archive $(com32)/lib/libcom32min.a
 all: ldlinux.c32 ldlinux_lnx.a
 
 ldlinux.c32 : ldlinux.o cli.o readconfig.o refstr.o colors.o getadv.o \
-               adv.o ipappend.o execute.o kernel.o get_key.o \
+               adv.o execute.o kernel.o get_key.o \
                advwrite.o setadv.o eprintf.o
        $(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
 
index 8be8c17..fb041ae 100644 (file)
@@ -454,17 +454,14 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
     return len ? ret : NULL;
 }
 
-static int cli_init(void)
+static int __constructor cli_init(void)
 {
        INIT_LIST_HEAD(&cli_history_head);
 
        return 0;
 }
 
-static void cli_exit(void)
+static void __destructor cli_exit(void)
 {
        /* Nothing to do */
 }
-
-MODULE_INIT(cli_init);
-MODULE_EXIT(cli_exit);
diff --git a/com32/elflink/ldlinux/ipappend.c b/com32/elflink/ldlinux/ipappend.c
deleted file mode 100644 (file)
index cbd02b1..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- *   Copyright 2008 H. Peter Anvin - All Rights Reserved
- *
- *   Permission is hereby granted, free of charge, to any person
- *   obtaining a copy of this software and associated documentation
- *   files (the "Software"), to deal in the Software without
- *   restriction, including without limitation the rights to use,
- *   copy, modify, merge, publish, distribute, sublicense, and/or
- *   sell copies of the Software, and to permit persons to whom
- *   the Software is furnished to do so, subject to the following
- *   conditions:
- *
- *   The above copyright notice and this permission notice shall
- *   be included in all copies or substantial portions of the Software.
- *
- *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *   OTHER DEALINGS IN THE SOFTWARE.
- *
- * ----------------------------------------------------------------------- */
-
-/*
- * syslinux/ipappend.c
- *
- * Get ipappend strings
- */
-
-#include <syslinux/config.h>
-#include <klibc/compiler.h>
-#include <com32.h>
-
-struct syslinux_ipappend_strings __syslinux_ipappend_strings;
-static const char *syslinux_ipappend_string_list[32];
-
-void __syslinux_get_ipappend_strings(void)
-{
-    static com32sys_t reg;
-    int i;
-
-    reg.eax.w[0] = 0x000f;
-    __intcall(0x22, &reg, &reg);
-
-    if (!(reg.eflags.l & EFLAGS_CF)) {
-       __syslinux_ipappend_strings.count = reg.ecx.w[0];
-       __syslinux_ipappend_strings.ptr = syslinux_ipappend_string_list;
-       for (i = 0; i < reg.ecx.w[0]; i++) {
-           syslinux_ipappend_string_list[i] =
-               MK_PTR(reg.es,
-                      *(uint16_t *) MK_PTR(reg.es, reg.ebx.w[0] + i * 2));
-       }
-    }
-}
index dcde542..03e2f60 100644 (file)
@@ -121,7 +121,6 @@ int main(int argc, char **argv)
 
        openconsole(&dev_rawcon_r, &dev_ansiserial_w);
 
-       __syslinux_get_ipappend_strings();
        parse_configs(NULL);
 
        __syslinux_init();
index 9c00e4a..ac05c27 100644 (file)
@@ -55,29 +55,6 @@ extern int exec_init(void);
 
 
 /**
- * load_library - Loads a dynamic library into the environment.
- * @name:      the name of the library to load, including the extension
- *                     (e.g. 'sort.c32')
- *
- * A dynamic library is an ELF module that may contain initialization and
- * termination routines, but not a main routine. At the same time, any memory
- * allocations using malloc() and its derivatives are made on behalf of the
- * currently executing program or the COM32 root module. If the library
- * is unloaded, no memory cleanup is performed.
- */
-extern int load_library(const char *name);
-
-/**
- * unload_library - unloads a library from the environment.
- * @name:      the name of the library to unload, including the extension
- *                     (e.g. 'sort.c32')
- *
- * Note that no memory allocated by the library code is cleaned up, as the
- * allocations belong to the innermost calling program in the call stack.
- */
-extern int unload_library(const char *name);
-
-/**
  * spawnv - Executes a program in the current environment.
  * @name:      the name of the program to spawn, including the extension
  *                     (e.g. 'hello.c32')
index fb72c4b..d10eae9 100644 (file)
@@ -24,7 +24,6 @@
 /*
  * Some common information about what kind of modules we're dealing with
  */
-#define UNKNOWN_MODULE                 -1
 #define EXEC_MODULE                    0               
 #define LIB_MODULE                     1
 
  * Initialization and finalization function signatures
  */
 
-
-/**
- * module_init_t - pointer to a initialization routine
- *
- * The initialization routine is called after all module constructors were invoked.
- * It takes no parameters and returns 0 if the module was initialized successfully,
- * or a non-zero value if errors have occurred.
- */
-typedef int (*module_init_t)(void);
-
-/**
- * module_exit_t - pointer to a finalization routine
- *
- * The finalization routine is called before the module destructors are to be invoked.
- * It simply executes some cleanup code, without error reporting.
- */
-typedef void (*module_exit_t)(void);
-
 /**
  * module_main_t - pointer to an entry routine
  *
@@ -58,6 +39,14 @@ typedef void (*module_exit_t)(void);
  */
 typedef int (*module_main_t)(int, char**);
 
+/**
+ * module_ctor_t - pointer to a constructor or destructor routine
+ *
+ * A module may have multiple routines that need to be executed before
+ * or after the main routine. These are the constructors and
+ * destructors, respectively.
+ */
+typedef void (*module_ctor_t) (void);
 
 /**
  * struct elf_module - structure encapsulating a module loaded in memory.
@@ -95,11 +84,10 @@ struct elf_module {
        struct list_head        dependants;             // Head of module dependants list
        struct list_head        list;           // The list entry in the module list
 
-       module_init_t           *init_func;     // The initialization entry point
-       module_exit_t           *exit_func;     // The module finalization code
+       module_ctor_t           *ctors;         // module constructors
+       module_ctor_t           *dtors;         // module destructors
        module_main_t           main_func; // The main function (for executable modules)
 
-
        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
index 66cfcbf..bee1a02 100644 (file)
@@ -47,7 +47,7 @@ LIBPCI_OBJS = \
 LIBSYSLINUX_OBJS = \
        syslinux/reboot.o syslinux/keyboard.o                           \
        syslinux/features.o syslinux/config.o   \
-       syslinux/ipappend.o syslinux/dsinfo.o syslinux/version.o        \
+       syslinux/dsinfo.o syslinux/version.o    \
        syslinux/pxe_get_cached.o syslinux/pxe_get_nic.o                \
        syslinux/pxe_dns.o                                              \
        syslinux/video/fontquery.o syslinux/video/forcetext.o           \
@@ -179,6 +179,7 @@ CORELIBOBJS = \
        $(LIBMODULE_OBJS)
 
 MINLIBOBJS = \
+       syslinux/ipappend.o \
        $(LIBOTHER_OBJS) \
        $(LIBGCC_OBJS) \
        $(LIBCONSOLE_OBJS) \
index 158badb..ddf6e04 100644 (file)
@@ -91,13 +91,9 @@ SECTIONS
        __ctors_start = .;
     KEEP (*(SORT(.ctors.*)))
     KEEP (*(.ctors))
-    LONG(0x00000000)
-    __module_init_ptr = .;
     KEEP (*(.ctors_modinit))
-    LONG(0x00000000)
-    __module_main_ptr = .;
     KEEP (*(.ctors_modmain))
-    LONG(0x00000000)
+       __ctors_end = .;
   }
   
   .dtors          :
@@ -105,10 +101,8 @@ SECTIONS
        __dtors_start = .;
     KEEP (*(SORT(.dtors.*)))
     KEEP (*(.dtors))
-    LONG(0x00000000)
-    __module_exit_ptr = .;
     KEEP (*(.dtors_modexit))
-    LONG(0x00000000)
+       __dtors_end = .;
   }
   
   .jcr            : { KEEP (*(.jcr)) }
index 71ee0f0..b22e9c8 100644 (file)
@@ -381,7 +381,7 @@ int module_unloadable(struct elf_module *module) {
 
 
 // Unloads the module from the system and releases all the associated memory
-int module_unload(struct elf_module *module) {
+int _module_unload(struct elf_module *module) {
        struct module_dep *crt_dep, *tmp;
        // Make sure nobody needs us
        if (!module_unloadable(module)) {
@@ -410,6 +410,14 @@ int module_unload(struct elf_module *module) {
        return 0;
 }
 
+int module_unload(struct elf_module *module) {
+       module_ctor_t *dtor;
+
+       for (dtor = module->dtors; *dtor; dtor++)
+               (*dtor) ();
+
+       return _module_unload(module);
+}
 
 static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
        unsigned long h = elf_hash((const unsigned char*)name);
index 7d8dad4..ffdcd52 100644 (file)
@@ -398,40 +398,79 @@ static int resolve_symbols(struct elf_module *module) {
        return 0;
 }
 
+static int extract_operations(struct elf_module *module) {
+       Elf32_Sym *ctors_start, *ctors_end;
+       Elf32_Sym *dtors_start, *dtors_end;
+       module_ctor_t *ctors, *dtors;
 
+       ctors_start = module_find_symbol("__ctors_start", module);
+       ctors_end = module_find_symbol("__ctors_end", module);
 
-static int extract_operations(struct elf_module *module) {
-       Elf32_Sym *init_sym = module_find_symbol(MODULE_ELF_INIT_PTR, module);
-       Elf32_Sym *exit_sym = module_find_symbol(MODULE_ELF_EXIT_PTR, module);
-       Elf32_Sym *main_sym = module_find_symbol("main", module);
-
-       if (init_sym) {
-               module->init_func = (module_init_t*)module_get_absolute(
-                       init_sym->st_value, module);
-               if (*(module->init_func) == NULL) {
-                       module->init_func = NULL;
+       if (ctors_start && ctors_end) {
+               module_ctor_t *start, *end;
+               int nr_ctors = 0;
+               int i, size;
+
+               start = module_get_absolute(ctors_start->st_value, module);
+               end = module_get_absolute(ctors_end->st_value, module);
+
+               nr_ctors = end - start;
+
+               size = nr_ctors * sizeof(module_ctor_t);
+               size += sizeof(module_ctor_t); /* NULL entry */
+
+               ctors = malloc(size);
+               if (!ctors) {
+                       printf("Unable to alloc memory for ctors\n");
+                       return -1;
                }
+
+               memset(ctors, 0, size);
+               for (i = 0; i < nr_ctors; i++)
+                       ctors[i] = start[i];
+
+               module->ctors = ctors;
        }
 
-       if (exit_sym) {
-               module->exit_func = (module_exit_t*)module_get_absolute(
-                       exit_sym->st_value, module);
-               if (*(module->exit_func) == NULL) {
-                       module->exit_func = NULL;
+       dtors_start = module_find_symbol("__dtors_start", module);
+       dtors_end = module_find_symbol("__dtors_end", module);
+
+       if (dtors_start && dtors_end) {
+               module_ctor_t *start, *end;
+               int nr_dtors = 0;
+               int i, size;
+
+               start = module_get_absolute(dtors_start->st_value, module);
+               end = module_get_absolute(dtors_end->st_value, module);
+
+               nr_dtors = end - start;
+
+               size = nr_dtors * sizeof(module_ctor_t);
+               size += sizeof(module_ctor_t); /* NULL entry */
+
+               dtors = malloc(size);
+               if (!dtors) {
+                       printf("Unable to alloc memory for dtors\n");
+                       free(ctors);
+                       return -1;
                }
-       }
 
-       if (main_sym)
-               module->main_func =
-                       module_get_absolute(main_sym->st_value, module);
+               memset(dtors, 0, size);
+               for (i = 0; i < nr_dtors; i++)
+                       dtors[i] = start[i];
+
+               module->dtors = dtors;
+       }
 
        return 0;
 }
 
 // Loads the module into the system
 int module_load(struct elf_module *module) {
-       int res;
+       int res, i;
+       Elf32_Sym *main_sym;
        Elf32_Ehdr elf_hdr;
+       module_ctor_t *ctor;
 
        // Do not allow duplicate modules
        if (module_find(module->name) != NULL) {
@@ -505,8 +544,11 @@ int module_load(struct elf_module *module) {
        CHECKED(res, check_symbols(module), error);
        //printf("check... 5\n");
 
-       // Obtain constructors and destructors
-       CHECKED(res, extract_operations(module), error);
+       main_sym = module_find_symbol("main", module);
+       if (main_sym)
+               module->main_func =
+                       module_get_absolute(main_sym->st_value, module);
+
        //printf("check... 6\n");
 
        // Add the module at the beginning of the module list
@@ -515,6 +557,9 @@ int module_load(struct elf_module *module) {
        // Perform the relocations
        resolve_symbols(module);
 
+       // Obtain constructors and destructors
+       CHECKED(res, extract_operations(module), error);
+
        //dprintf("module->symtable_size = %d\n", module->symtable_size);
 
        //print_elf_symbols(module);
@@ -529,6 +574,10 @@ int module_load(struct elf_module *module) {
                        (module->init_func == NULL) ? NULL : *(module->init_func),
                        (module->exit_func == NULL) ? NULL : *(module->exit_func));
        */
+
+       for (ctor = module->ctors; *ctor; ctor++)
+               (*ctor) ();
+
        return 0;
 
 error:
index 71d3192..29d0a2f 100644 (file)
@@ -47,64 +47,7 @@ int exec_init(void)
 int get_module_type(struct elf_module *module)
 {
        if(module->main_func) return EXEC_MODULE;
-       else if(module->init_func) return LIB_MODULE;
-       return UNKNOWN_MODULE;
-}
-
-int load_library(const char *name)
-{
-       int res;
-       struct elf_module *module = module_alloc(name);
-
-       if (module == NULL)
-               return -1;
-
-       res = module_load(module);
-       if (res != 0) {
-               module_unload(module);
-               return res;
-       }
-
-       if (module->main_func != NULL) {
-               DBG_PRINT("Cannot load executable module as library.\n");
-               module_unload(module);
-               return -1;
-       }
-
-       if (module->init_func != NULL) {
-               res = (*(module->init_func))();
-               if (res)
-                       DBG_PRINT("Initialization error! function returned: %d\n", res);
-       } else {
-               DBG_PRINT("No initialization function present.\n");
-       }
-
-       if (res != 0) {
-               module_unload(module);
-               return res;
-       }
-
-       return 0;
-}
-
-int unload_library(const char *name)
-{
-       int res;
-       struct elf_module *module = module_find(name);
-
-       if (module == NULL)
-               return -1;
-
-       if (!module_unloadable(module)) {
-               return -1;
-       }
-
-       if (module->exit_func != NULL) {
-               (*(module->exit_func))();
-       }
-
-       res = module_unload(module);
-       return res;
+       return LIB_MODULE;
 }
 
 jmp_buf __process_exit_jmp;
@@ -243,7 +186,6 @@ int spawn_load(const char *name, int argc, char **argv)
        //malloc_tag_t prev_mem_tag;
        struct elf_module *module = module_alloc(name);
        struct elf_module *prev_module;
-
        int type;
 
        dprintf("enter: name = %s", name);
@@ -277,7 +219,7 @@ int spawn_load(const char *name, int argc, char **argv)
 
        res = module_load(module);
        if (res != 0) {
-               module_unload(module);
+               _module_unload(module);
                return res;
        }
 
@@ -288,23 +230,7 @@ int spawn_load(const char *name, int argc, char **argv)
        dprintf("type = %d, prev = %s, cur = %s",
                type, prev_module->name, cur_module->name);
 
-       if(type==LIB_MODULE)
-       {
-               if (module->init_func != NULL) {
-                       res = (*(module->init_func))();
-                       DBG_PRINT("Initialization function returned: %d\n", res);
-               } else {
-                       DBG_PRINT("No initialization function present.\n");
-               }
-
-               if (res != 0) {
-                       cur_module = prev_module;
-                       module_unload(module);
-                       return res;
-               }
-               return 0;
-       }
-       else if(type==EXEC_MODULE)
+       if(type==EXEC_MODULE)
        {
                previous = __syslinux_current;
                //prev_mem_tag = __mem_get_tag_global();
@@ -323,7 +249,6 @@ int spawn_load(const char *name, int argc, char **argv)
                else
                        exit((module->main_func)(argc, argv)); /* Actually run! */
 
-
                // Clean up the allocation context
                //__free_tagged(module);
                // Restore the allocation context
@@ -340,10 +265,8 @@ int spawn_load(const char *name, int argc, char **argv)
 
                return ((unsigned int)ret_val & 0xFF);
        }
-       /*
-       module_unload(module);
-       return -1;
-       */
+
+       return 0;
 }
 
 void exec_term(void)
index 604b91a..ea817e6 100644 (file)
--- a/mk/lib.mk
+++ b/mk/lib.mk
@@ -39,7 +39,7 @@ OPTFLAGS  = -Os -march=i386 -falign-functions=0 -falign-jumps=0 \
 WARNFLAGS = $(GCCWARN) -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Winline
 
 CFLAGS  = $(OPTFLAGS) $(REQFLAGS) $(WARNFLAGS) $(LIBFLAGS)
-LDFLAGS        = -m elf_i386 --hash-style=gnu
+LDFLAGS        = -m elf_i386 --hash-style=gnu -T $(com32)/lib/elf32.ld
 
 .SUFFIXES: .c .o .a .so .lo .i .S .s .ls .ss .lss