diff options
| -rw-r--r-- | include/asm-generic/sections.h | 3 | ||||
| -rw-r--r-- | include/asm-generic/vmlinux.lds.h | 9 | ||||
| -rw-r--r-- | include/linux/init.h | 3 | ||||
| -rw-r--r-- | include/linux/module.h | 6 | ||||
| -rw-r--r-- | init/Kconfig | 5 | ||||
| -rw-r--r-- | init/main.c | 12 | ||||
| -rw-r--r-- | kernel/module.c | 16 | 
7 files changed, 54 insertions, 0 deletions
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index 4ce48e87853..d083561337f 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -14,6 +14,9 @@ extern char __kprobes_text_start[], __kprobes_text_end[];  extern char __initdata_begin[], __initdata_end[];  extern char __start_rodata[], __end_rodata[]; +/* Start and end of .ctors section - used for constructor calls. */ +extern char __ctors_start[], __ctors_end[]; +  /* function descriptor handling (if any).  Override   * in asm/sections.h */  #ifndef dereference_function_descriptor diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 6bdba10fef4..55413e568f0 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -440,12 +440,21 @@  		INIT_TASK						\  	} +#ifdef CONFIG_CONSTRUCTORS +#define KERNEL_CTORS()	VMLINUX_SYMBOL(__ctors_start) = .; \ +			*(.ctors)			   \ +			VMLINUX_SYMBOL(__ctors_end) = .; +#else +#define KERNEL_CTORS() +#endif +  /* init and exit section handling */  #define INIT_DATA							\  	*(.init.data)							\  	DEV_DISCARD(init.data)						\  	CPU_DISCARD(init.data)						\  	MEM_DISCARD(init.data)						\ +	KERNEL_CTORS()							\  	*(.init.rodata)							\  	DEV_DISCARD(init.rodata)					\  	CPU_DISCARD(init.rodata)					\ diff --git a/include/linux/init.h b/include/linux/init.h index 8c2c9989626..13b633ed695 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -134,6 +134,9 @@ typedef void (*exitcall_t)(void);  extern initcall_t __con_initcall_start[], __con_initcall_end[];  extern initcall_t __security_initcall_start[], __security_initcall_end[]; +/* Used for contructor calls. */ +typedef void (*ctor_fn_t)(void); +  /* Defined in init/main.c */  extern int do_one_initcall(initcall_t fn);  extern char __initdata boot_command_line[]; diff --git a/include/linux/module.h b/include/linux/module.h index 505f20dcc1c..098bdb7bfac 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -363,6 +363,12 @@ struct module  	local_t ref;  #endif  #endif + +#ifdef CONFIG_CONSTRUCTORS +	/* Constructor functions. */ +	ctor_fn_t *ctors; +	unsigned int num_ctors; +#endif  };  #ifndef MODULE_ARCH_INIT  #define MODULE_ARCH_INIT {} diff --git a/init/Kconfig b/init/Kconfig index c4b3c6d51a7..1ce05a4cb5f 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -16,6 +16,11 @@ config DEFCONFIG_LIST  	default "$ARCH_DEFCONFIG"  	default "arch/$ARCH/defconfig" +config CONSTRUCTORS +	bool +	depends on !UML +	default y +  menu "General setup"  config EXPERIMENTAL diff --git a/init/main.c b/init/main.c index 0e7aedeaa05..1a65fdd0631 100644 --- a/init/main.c +++ b/init/main.c @@ -720,6 +720,17 @@ asmlinkage void __init start_kernel(void)  	rest_init();  } +/* Call all constructor functions linked into the kernel. */ +static void __init do_ctors(void) +{ +#ifdef CONFIG_CONSTRUCTORS +	ctor_fn_t *call = (ctor_fn_t *) __ctors_start; + +	for (; call < (ctor_fn_t *) __ctors_end; call++) +		(*call)(); +#endif +} +  int initcall_debug;  core_param(initcall_debug, initcall_debug, bool, 0644); @@ -800,6 +811,7 @@ static void __init do_basic_setup(void)  	usermodehelper_init();  	driver_init();  	init_irq_proc(); +	do_ctors();  	do_initcalls();  } diff --git a/kernel/module.c b/kernel/module.c index 215aaab09e9..38928fcaff2 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2216,6 +2216,10 @@ static noinline struct module *load_module(void __user *umod,  	mod->unused_gpl_crcs = section_addr(hdr, sechdrs, secstrings,  					    "__kcrctab_unused_gpl");  #endif +#ifdef CONFIG_CONSTRUCTORS +	mod->ctors = section_objs(hdr, sechdrs, secstrings, ".ctors", +				  sizeof(*mod->ctors), &mod->num_ctors); +#endif  #ifdef CONFIG_MARKERS  	mod->markers = section_objs(hdr, sechdrs, secstrings, "__markers", @@ -2389,6 +2393,17 @@ static noinline struct module *load_module(void __user *umod,  	goto free_hdr;  } +/* Call module constructors. */ +static void do_mod_ctors(struct module *mod) +{ +#ifdef CONFIG_CONSTRUCTORS +	unsigned long i; + +	for (i = 0; i < mod->num_ctors; i++) +		mod->ctors[i](); +#endif +} +  /* This is where the real work happens */  SYSCALL_DEFINE3(init_module, void __user *, umod,  		unsigned long, len, const char __user *, uargs) @@ -2417,6 +2432,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,  	blocking_notifier_call_chain(&module_notify_list,  			MODULE_STATE_COMING, mod); +	do_mod_ctors(mod);  	/* Start the module */  	if (mod->init != NULL)  		ret = do_one_initcall(mod->init);  |