aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2012-03-22 15:31:43 +0000
committerMatt Fleming <matt.fleming@intel.com>2012-03-23 16:54:47 +0000
commit8e0ed96bff75801f7430da88d83ea1b52827b123 (patch)
tree8435f50b9a37407b3591576636d285f012cd39ee
parenta0ff1769893dc47028694ee51824bf681672876c (diff)
downloadsyslinux-8e0ed96bff75801f7430da88d83ea1b52827b123.tar.gz
syslinux-8e0ed96bff75801f7430da88d83ea1b52827b123.tar.xz
syslinux-8e0ed96bff75801f7430da88d83ea1b52827b123.zip
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 <matt.fleming@intel.com>
-rw-r--r--com32/elflink/ldlinux/Makefile2
-rw-r--r--com32/elflink/ldlinux/cli.c7
-rw-r--r--com32/elflink/ldlinux/ipappend.c58
-rw-r--r--com32/elflink/ldlinux/ldlinux.c1
-rw-r--r--com32/include/sys/exec.h23
-rw-r--r--com32/include/sys/module.h32
-rw-r--r--com32/lib/Makefile3
-rw-r--r--com32/lib/elf32.ld10
-rw-r--r--com32/lib/sys/module/common.c10
-rw-r--r--com32/lib/sys/module/elf_module.c93
-rw-r--r--com32/lib/sys/module/exec.c87
-rw-r--r--mk/lib.mk2
12 files changed, 103 insertions, 225 deletions
diff --git a/com32/elflink/ldlinux/Makefile b/com32/elflink/ldlinux/Makefile
index 99602771..ca4c7e25 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 8be8c17d..fb041aeb 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 cbd02b15..00000000
--- 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 <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));
- }
- }
-}
diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c
index dcde5427..03e2f60d 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 9c00e4a5..ac05c276 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 fb72c4bc..d10eae9c 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 66cfcbf4..bee1a023 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 158badbb..ddf6e048 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 71ee0f03..b22e9c8a 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 7d8dad42..ffdcd525 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 71d31929..29d0a2fd 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 604b91a6..ea817e66 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