[syslinux] [PATCH 09/19] elf: Support __constructor and __destructor

Matt Fleming matt at console-pimps.org
Fri Mar 23 11:02:43 PDT 2012


From: Matt Fleming <matt.fleming at intel.com>

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 at intel.com>
---
 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 <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 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
 
-- 
1.7.4.4




More information about the Syslinux mailing list