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 4ce48e878530..d083561337f2 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[]; | |||
| 14 | extern char __initdata_begin[], __initdata_end[]; | 14 | extern char __initdata_begin[], __initdata_end[]; |
| 15 | extern char __start_rodata[], __end_rodata[]; | 15 | extern char __start_rodata[], __end_rodata[]; |
| 16 | 16 | ||
| 17 | /* Start and end of .ctors section - used for constructor calls. */ | ||
| 18 | extern char __ctors_start[], __ctors_end[]; | ||
| 19 | |||
| 17 | /* function descriptor handling (if any). Override | 20 | /* function descriptor handling (if any). Override |
| 18 | * in asm/sections.h */ | 21 | * in asm/sections.h */ |
| 19 | #ifndef dereference_function_descriptor | 22 | #ifndef dereference_function_descriptor |
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 6bdba10fef4a..55413e568f07 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h | |||
| @@ -440,12 +440,21 @@ | |||
| 440 | INIT_TASK \ | 440 | INIT_TASK \ |
| 441 | } | 441 | } |
| 442 | 442 | ||
| 443 | #ifdef CONFIG_CONSTRUCTORS | ||
| 444 | #define KERNEL_CTORS() VMLINUX_SYMBOL(__ctors_start) = .; \ | ||
| 445 | *(.ctors) \ | ||
| 446 | VMLINUX_SYMBOL(__ctors_end) = .; | ||
| 447 | #else | ||
| 448 | #define KERNEL_CTORS() | ||
| 449 | #endif | ||
| 450 | |||
| 443 | /* init and exit section handling */ | 451 | /* init and exit section handling */ |
| 444 | #define INIT_DATA \ | 452 | #define INIT_DATA \ |
| 445 | *(.init.data) \ | 453 | *(.init.data) \ |
| 446 | DEV_DISCARD(init.data) \ | 454 | DEV_DISCARD(init.data) \ |
| 447 | CPU_DISCARD(init.data) \ | 455 | CPU_DISCARD(init.data) \ |
| 448 | MEM_DISCARD(init.data) \ | 456 | MEM_DISCARD(init.data) \ |
| 457 | KERNEL_CTORS() \ | ||
| 449 | *(.init.rodata) \ | 458 | *(.init.rodata) \ |
| 450 | DEV_DISCARD(init.rodata) \ | 459 | DEV_DISCARD(init.rodata) \ |
| 451 | CPU_DISCARD(init.rodata) \ | 460 | CPU_DISCARD(init.rodata) \ |
diff --git a/include/linux/init.h b/include/linux/init.h index 8c2c9989626d..13b633ed695e 100644 --- a/include/linux/init.h +++ b/include/linux/init.h | |||
| @@ -134,6 +134,9 @@ typedef void (*exitcall_t)(void); | |||
| 134 | extern initcall_t __con_initcall_start[], __con_initcall_end[]; | 134 | extern initcall_t __con_initcall_start[], __con_initcall_end[]; |
| 135 | extern initcall_t __security_initcall_start[], __security_initcall_end[]; | 135 | extern initcall_t __security_initcall_start[], __security_initcall_end[]; |
| 136 | 136 | ||
| 137 | /* Used for contructor calls. */ | ||
| 138 | typedef void (*ctor_fn_t)(void); | ||
| 139 | |||
| 137 | /* Defined in init/main.c */ | 140 | /* Defined in init/main.c */ |
| 138 | extern int do_one_initcall(initcall_t fn); | 141 | extern int do_one_initcall(initcall_t fn); |
| 139 | extern char __initdata boot_command_line[]; | 142 | extern char __initdata boot_command_line[]; |
diff --git a/include/linux/module.h b/include/linux/module.h index 505f20dcc1c7..098bdb7bfacf 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
| @@ -363,6 +363,12 @@ struct module | |||
| 363 | local_t ref; | 363 | local_t ref; |
| 364 | #endif | 364 | #endif |
| 365 | #endif | 365 | #endif |
| 366 | |||
| 367 | #ifdef CONFIG_CONSTRUCTORS | ||
| 368 | /* Constructor functions. */ | ||
| 369 | ctor_fn_t *ctors; | ||
| 370 | unsigned int num_ctors; | ||
| 371 | #endif | ||
| 366 | }; | 372 | }; |
| 367 | #ifndef MODULE_ARCH_INIT | 373 | #ifndef MODULE_ARCH_INIT |
| 368 | #define MODULE_ARCH_INIT {} | 374 | #define MODULE_ARCH_INIT {} |
diff --git a/init/Kconfig b/init/Kconfig index c4b3c6d51a72..1ce05a4cb5f6 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
| @@ -16,6 +16,11 @@ config DEFCONFIG_LIST | |||
| 16 | default "$ARCH_DEFCONFIG" | 16 | default "$ARCH_DEFCONFIG" |
| 17 | default "arch/$ARCH/defconfig" | 17 | default "arch/$ARCH/defconfig" |
| 18 | 18 | ||
| 19 | config CONSTRUCTORS | ||
| 20 | bool | ||
| 21 | depends on !UML | ||
| 22 | default y | ||
| 23 | |||
| 19 | menu "General setup" | 24 | menu "General setup" |
| 20 | 25 | ||
| 21 | config EXPERIMENTAL | 26 | config EXPERIMENTAL |
diff --git a/init/main.c b/init/main.c index 0e7aedeaa05f..1a65fdd06318 100644 --- a/init/main.c +++ b/init/main.c | |||
| @@ -720,6 +720,17 @@ asmlinkage void __init start_kernel(void) | |||
| 720 | rest_init(); | 720 | rest_init(); |
| 721 | } | 721 | } |
| 722 | 722 | ||
| 723 | /* Call all constructor functions linked into the kernel. */ | ||
| 724 | static void __init do_ctors(void) | ||
| 725 | { | ||
| 726 | #ifdef CONFIG_CONSTRUCTORS | ||
| 727 | ctor_fn_t *call = (ctor_fn_t *) __ctors_start; | ||
| 728 | |||
| 729 | for (; call < (ctor_fn_t *) __ctors_end; call++) | ||
| 730 | (*call)(); | ||
| 731 | #endif | ||
| 732 | } | ||
| 733 | |||
| 723 | int initcall_debug; | 734 | int initcall_debug; |
| 724 | core_param(initcall_debug, initcall_debug, bool, 0644); | 735 | core_param(initcall_debug, initcall_debug, bool, 0644); |
| 725 | 736 | ||
| @@ -800,6 +811,7 @@ static void __init do_basic_setup(void) | |||
| 800 | usermodehelper_init(); | 811 | usermodehelper_init(); |
| 801 | driver_init(); | 812 | driver_init(); |
| 802 | init_irq_proc(); | 813 | init_irq_proc(); |
| 814 | do_ctors(); | ||
| 803 | do_initcalls(); | 815 | do_initcalls(); |
| 804 | } | 816 | } |
| 805 | 817 | ||
diff --git a/kernel/module.c b/kernel/module.c index 215aaab09e91..38928fcaff2b 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -2216,6 +2216,10 @@ static noinline struct module *load_module(void __user *umod, | |||
| 2216 | mod->unused_gpl_crcs = section_addr(hdr, sechdrs, secstrings, | 2216 | mod->unused_gpl_crcs = section_addr(hdr, sechdrs, secstrings, |
| 2217 | "__kcrctab_unused_gpl"); | 2217 | "__kcrctab_unused_gpl"); |
| 2218 | #endif | 2218 | #endif |
| 2219 | #ifdef CONFIG_CONSTRUCTORS | ||
| 2220 | mod->ctors = section_objs(hdr, sechdrs, secstrings, ".ctors", | ||
| 2221 | sizeof(*mod->ctors), &mod->num_ctors); | ||
| 2222 | #endif | ||
| 2219 | 2223 | ||
| 2220 | #ifdef CONFIG_MARKERS | 2224 | #ifdef CONFIG_MARKERS |
| 2221 | mod->markers = section_objs(hdr, sechdrs, secstrings, "__markers", | 2225 | mod->markers = section_objs(hdr, sechdrs, secstrings, "__markers", |
| @@ -2389,6 +2393,17 @@ static noinline struct module *load_module(void __user *umod, | |||
| 2389 | goto free_hdr; | 2393 | goto free_hdr; |
| 2390 | } | 2394 | } |
| 2391 | 2395 | ||
| 2396 | /* Call module constructors. */ | ||
| 2397 | static void do_mod_ctors(struct module *mod) | ||
| 2398 | { | ||
| 2399 | #ifdef CONFIG_CONSTRUCTORS | ||
| 2400 | unsigned long i; | ||
| 2401 | |||
| 2402 | for (i = 0; i < mod->num_ctors; i++) | ||
| 2403 | mod->ctors[i](); | ||
| 2404 | #endif | ||
| 2405 | } | ||
| 2406 | |||
| 2392 | /* This is where the real work happens */ | 2407 | /* This is where the real work happens */ |
| 2393 | SYSCALL_DEFINE3(init_module, void __user *, umod, | 2408 | SYSCALL_DEFINE3(init_module, void __user *, umod, |
| 2394 | unsigned long, len, const char __user *, uargs) | 2409 | unsigned long, len, const char __user *, uargs) |
| @@ -2417,6 +2432,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, | |||
| 2417 | blocking_notifier_call_chain(&module_notify_list, | 2432 | blocking_notifier_call_chain(&module_notify_list, |
| 2418 | MODULE_STATE_COMING, mod); | 2433 | MODULE_STATE_COMING, mod); |
| 2419 | 2434 | ||
| 2435 | do_mod_ctors(mod); | ||
| 2420 | /* Start the module */ | 2436 | /* Start the module */ |
| 2421 | if (mod->init != NULL) | 2437 | if (mod->init != NULL) |
| 2422 | ret = do_one_initcall(mod->init); | 2438 | ret = do_one_initcall(mod->init); |
