From ac1f0d54273636ab56a7bf68e73123ec0c273381 Mon Sep 17 00:00:00 2001 From: kpfleming Date: Thu, 22 Feb 2007 02:36:00 +0000 Subject: [PATCH] give embedded modules a helping hand by backing up and restoring their global variables when they are loaded and unloaded git-svn-id: http://svn.digium.com/svn/asterisk/trunk@56092 f38db490-d61c-443f-a65b-d21fe96a405b --- Makefile.moddir_rules | 12 ++--- Makefile.rules | 28 ++++++++++++ build_tools/make_linker_eo_script | 27 ++++++++++++ include/asterisk/module.h | 73 +++++++++++++++++++++++++++++++ main/loader.c | 8 ++++ 5 files changed, 143 insertions(+), 5 deletions(-) create mode 100755 build_tools/make_linker_eo_script diff --git a/Makefile.moddir_rules b/Makefile.moddir_rules index c614c2ab5..d2dafe329 100644 --- a/Makefile.moddir_rules +++ b/Makefile.moddir_rules @@ -34,11 +34,13 @@ $(LOADABLE_MODS:%=%.so): ASTCFLAGS+=-fPIC $(LOADABLE_MODS:%=%.so): LIBS+=$(foreach dep,$(MENUSELECT_DEPENDS_$*),$(value $(dep)_LIB)) $(LOADABLE_MODS:%=%.so): ASTLDFLAGS+=$(foreach dep,$(MENUSELECT_DEPENDS_$*),$(value $(dep)_LDFLAGS)) +$(EMBEDDED_MODS:%=%.o): ASTCFLAGS+=-DEMBEDDED_MODULE=$* + $(addsuffix .so,$(filter $(LOADABLE_MODS),$(C_MODS))): %.so: %.o $(addsuffix .so,$(filter $(LOADABLE_MODS),$(CC_MODS))): %.so: %.oo -modules.link: $(addsuffix .o,$(filter $(EMBEDDED_MODS),$(C_MODS))) -modules.link: $(addsuffix .oo,$(filter $(EMBEDDED_MODS),$(CC_MODS))) +modules.link: $(addsuffix .eo,$(filter $(EMBEDDED_MODS),$(C_MODS))) +modules.link: $(addsuffix .eoo,$(filter $(EMBEDDED_MODS),$(CC_MODS))) .PHONY: clean uninstall _all @@ -64,11 +66,11 @@ endif modules.link: @rm -f $@ - @for file in $(patsubst %,$(SUBDIR)/%,$(filter %.o,$^)); do echo "INPUT (../$${file})" >> $@; done - @for file in $(patsubst %,$(SUBDIR)/%,$(filter-out %.o,$^)); do echo "INPUT (../$${file})" >> $@; done + @for file in $(patsubst %,$(SUBDIR)/%,$(filter %.eo %.eoo,$^)); do echo "INPUT (../$${file})" >> $@; done + @for file in $(patsubst %,$(SUBDIR)/%,$(filter-out %.eo %.eoo,$^)); do echo "INPUT (../$${file})" >> $@; done clean:: - rm -f *.so *.o *.oo + rm -f *.so *.o *.oo *.eo *.eoo rm -f .*.o.d .*.oo.d rm -f modules.link diff --git a/Makefile.rules b/Makefile.rules index 9d20c5a91..e847c3af3 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -44,6 +44,22 @@ else $(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) endif +%.o: %.i + $(ECHO_PREFIX) echo " [CC] $< -> $@" +ifeq ($(AST_DEVMODE),yes) + $(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) -MMD -MT $@ -MF .$(subst /,_,$@).d -MP +else + $(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) +endif + +%.i: %.c + $(ECHO_PREFIX) echo " [CC] $< -> $@" +ifeq ($(AST_DEVMODE),yes) + $(CMD_PREFIX) $(CC) -o $@ -E $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) -MMD -MT $@ -MF .$(subst /,_,$@).d -MP +else + $(CMD_PREFIX) $(CC) -o $@ -E $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) +endif + %.o: %.s $(ECHO_PREFIX) echo " [AS] $< -> $@" ifeq ($(AST_DEVMODE),yes) @@ -76,6 +92,18 @@ endif $(ECHO_PREFIX) echo " [LDXX] $^ -> $@" $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK) $^ $(PTHREAD_LIBS) $(LIBS) +%.eo: %.o + $(ECHO_PREFIX) echo " [EMBED] $< -> $@" + $(CMD_PREFIX) $(ASTTOPDIR)/build_tools/make_linker_eo_script $* > .$@.ld + $(CMD_PREFIX) $(LD) -r -T .$@.ld -o $@ $< + $(CMD_PREFIX) rm -f .$@.ld + +%.eoo: %.o + $(ECHO_PREFIX) echo " [EMBED] $< -> $@" + $(CMD_PREFIX) $(ASTTOPDIR)/build_tools/make_linker_eo_script $* > .$@.ld + $(CMD_PREFIX) $(LD) -r -T .$@.ld -o $@ $< + $(CMD_PREFIX) rm -f .$@.ld + %: %.o $(ECHO_PREFIX) echo " [LD] $^ -> $@" $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(PTHREAD_CFLAGS) $(ASTLDFLAGS) $^ $(PTHREAD_LIBS) $(LIBS) diff --git a/build_tools/make_linker_eo_script b/build_tools/make_linker_eo_script new file mode 100755 index 000000000..39456c058 --- /dev/null +++ b/build_tools/make_linker_eo_script @@ -0,0 +1,27 @@ +#!/bin/sh + +cat << EOF +SECTIONS { +.text : { *(.text) } +.data : { __${1}_data_start = . ; *(.data) __${1}_data_end = . ;} +.rodata : { *(.rodata*) } +.bss : { __${1}_bss_start = . ; *(.bss) __${1}_bss_end = . ;} +.debug_abbrev : { *(.debug_abbrev) } +.debug_info : { *(.debug_info) } +.debug_line : { *(.debug_line) } +.debug_macinfo : { *(.debug_macinfo) } +.dtors : { *(.dtors) } +.ctors : { *(.ctors) } +.data.rel.local : { *(.data.rel.local) } +.data.rel.ro.local : { *(.data.rel.ro.local) } +.debug_frame : { *(.debug_frame) } +.eh_frame : { *(.eh_frame) } +.debug_loc : { *(.debug_loc) } +.debug_pubname : { *(.debug_pubname) } +.debug_aranges : { *(.debug_aranges) } +.debug_ranges : { *(.debug_ranges) } +.debug_str : { *(.debug_str) } +.comment : { *(.comment) } +.note.GNU-stack : { *(.note.GNU-stack) } +} +EOF diff --git a/include/asterisk/module.h b/include/asterisk/module.h index 9d51488d1..4ced03fa9 100644 --- a/include/asterisk/module.h +++ b/include/asterisk/module.h @@ -192,6 +192,8 @@ struct ast_module_info { enum ast_module_load_result (*load)(void); /* register stuff etc. Optional. */ int (*reload)(void); /* config etc. Optional. */ int (*unload)(void); /* unload. called with the module locked */ + int (*backup_globals)(void); /* for embedded modules, backup global data */ + void (*restore_globals)(void); /* for embedded modules, restore global data */ const char *name; /* name of the module for loader reference and CLI commands */ const char *description; /* user friendly description of the module. */ @@ -253,6 +255,75 @@ void ast_module_unref(struct ast_module *); and populated at the end of the module's source file... */ const static __attribute__((unused)) struct ast_module_info *ast_module_info; +#if defined(EMBEDDED_MODULE) + +#define make_var_sub(mod, type) __ ## mod ## _ ## type +#define make_var(mod, type) make_var_sub(mod, type) + +extern void make_var(EMBEDDED_MODULE, bss_start); +extern void make_var(EMBEDDED_MODULE, bss_end); +extern void make_var(EMBEDDED_MODULE, data_start); +extern void make_var(EMBEDDED_MODULE, data_end); + +static void * __attribute__((section(".embed_module"))) __global_backup; + +static int __backup_globals(void) +{ + size_t data_size = & make_var(EMBEDDED_MODULE, data_end) - & make_var(EMBEDDED_MODULE, data_start); + + if (__global_backup) + return 0; + + if (!data_size) + return 0; + + if (!(__global_backup = ast_malloc(data_size))) + return -1; + + memcpy(__global_backup, & make_var(EMBEDDED_MODULE, data_start), data_size); + + return 0; +} + +static void __restore_globals(void) +{ + size_t data_size = & make_var(EMBEDDED_MODULE, data_end) - & make_var(EMBEDDED_MODULE, data_start); + size_t bss_size = & make_var(EMBEDDED_MODULE, bss_end) - & make_var(EMBEDDED_MODULE, bss_start); + + if (bss_size) + memset(& make_var(EMBEDDED_MODULE, bss_start), 0, bss_size); + + if (!data_size || !__global_backup) + return; + + memcpy(& make_var(EMBEDDED_MODULE, data_start), __global_backup, data_size); +} + +#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...) \ + static struct ast_module_info __mod_info = { \ + .backup_globals = __backup_globals, \ + .restore_globals = __restore_globals, \ + .name = AST_MODULE, \ + .flags = flags_to_set, \ + .description = desc, \ + .key = keystr, \ + fields \ + }; \ + static void __attribute__ ((constructor)) __reg_module(void) \ + { \ + ast_module_register(&__mod_info); \ + } \ + static void __attribute__ ((destructor)) __unreg_module(void) \ + { \ + ast_module_unregister(&__mod_info); \ + } \ + const static struct ast_module_info *ast_module_info = &__mod_info + +#undef make_var +#undef make_var_sub + +#else /* !defined(EMBEDDED_MODULE) */ + #define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...) \ static struct ast_module_info __mod_info = { \ .name = AST_MODULE, \ @@ -271,6 +342,8 @@ const static __attribute__((unused)) struct ast_module_info *ast_module_info; } \ const static struct ast_module_info *ast_module_info = &__mod_info +#endif /* !defined(EMBEDDED_MODULE) */ + #define AST_MODULE_INFO_STANDARD(keystr, desc) \ AST_MODULE_INFO(keystr, AST_MODFLAG_DEFAULT, desc, \ .load = load_module, \ diff --git a/main/loader.c b/main/loader.c index 65c95ecc6..4516b3779 100644 --- a/main/loader.c +++ b/main/loader.c @@ -483,6 +483,9 @@ int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode f if (!error) ast_update_use_count(); + if (!error && !mod->lib) + mod->info->restore_globals(); + return res; } @@ -627,6 +630,11 @@ static enum ast_module_load_result load_resource(const char *resource_name, unsi return AST_MODULE_LOAD_DECLINE; } + if (!mod->lib && mod->info->backup_globals()) { + ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name); + return AST_MODULE_LOAD_DECLINE; + } + ast_clear_flag(mod, FLAG_DECLINED); if (mod->info->load)