From 8e0ed96bff75801f7430da88d83ea1b52827b123 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Thu, 22 Mar 2012 15:31:43 +0000 Subject: [PATCH] elf: Support __constructor and __destructor 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 --- com32/elflink/ldlinux/Makefile | 2 +- com32/elflink/ldlinux/cli.c | 7 +-- com32/elflink/ldlinux/ipappend.c | 58 ------------------------ com32/elflink/ldlinux/ldlinux.c | 1 - com32/include/sys/exec.h | 23 ---------- com32/include/sys/module.h | 32 +++++--------- com32/lib/Makefile | 3 +- com32/lib/elf32.ld | 10 +---- com32/lib/sys/module/common.c | 10 ++++- com32/lib/sys/module/elf_module.c | 93 ++++++++++++++++++++++++++++++--------- com32/lib/sys/module/exec.c | 87 +++--------------------------------- mk/lib.mk | 2 +- 12 files changed, 103 insertions(+), 225 deletions(-) delete mode 100644 com32/elflink/ldlinux/ipappend.c diff --git a/com32/elflink/ldlinux/Makefile b/com32/elflink/ldlinux/Makefile index 9960277..ca4c7e2 100644 --- a/com32/elflink/ldlinux/Makefile +++ b/com32/elflink/ldlinux/Makefile @@ -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) diff --git a/com32/elflink/ldlinux/cli.c b/com32/elflink/ldlinux/cli.c index 8be8c17..fb041ae 100644 --- a/com32/elflink/ldlinux/cli.c +++ b/com32/elflink/ldlinux/cli.c @@ -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 index cbd02b1..0000000 --- a/com32/elflink/ldlinux/ipappend.c +++ /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 -#include -#include - -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, ®, ®); - - 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)); - } - } -} diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c index dcde542..03e2f60 100644 --- a/com32/elflink/ldlinux/ldlinux.c +++ b/com32/elflink/ldlinux/ldlinux.c @@ -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(); diff --git a/com32/include/sys/exec.h b/com32/include/sys/exec.h index 9c00e4a..ac05c27 100644 --- a/com32/include/sys/exec.h +++ b/com32/include/sys/exec.h @@ -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') diff --git a/com32/include/sys/module.h b/com32/include/sys/module.h index fb72c4b..d10eae9 100644 --- a/com32/include/sys/module.h +++ b/com32/include/sys/module.h @@ -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 @@ -32,24 +31,6 @@ * 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 diff --git a/com32/lib/Makefile b/com32/lib/Makefile index 66cfcbf..bee1a02 100644 --- a/com32/lib/Makefile +++ b/com32/lib/Makefile @@ -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) \ diff --git a/com32/lib/elf32.ld b/com32/lib/elf32.ld index 158badb..ddf6e04 100644 --- a/com32/lib/elf32.ld +++ b/com32/lib/elf32.ld @@ -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)) } diff --git a/com32/lib/sys/module/common.c b/com32/lib/sys/module/common.c index 71ee0f0..b22e9c8 100644 --- a/com32/lib/sys/module/common.c +++ b/com32/lib/sys/module/common.c @@ -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); diff --git a/com32/lib/sys/module/elf_module.c b/com32/lib/sys/module/elf_module.c index 7d8dad4..ffdcd52 100644 --- a/com32/lib/sys/module/elf_module.c +++ b/com32/lib/sys/module/elf_module.c @@ -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: diff --git a/com32/lib/sys/module/exec.c b/com32/lib/sys/module/exec.c index 71d3192..29d0a2f 100644 --- a/com32/lib/sys/module/exec.c +++ b/com32/lib/sys/module/exec.c @@ -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) diff --git a/mk/lib.mk b/mk/lib.mk index 604b91a..ea817e6 100644 --- 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 -- 2.7.4