diff options
author | Peter Oberparleiter <oberpar@linux.vnet.ibm.com> | 2009-06-17 19:28:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-18 16:03:57 -0400 |
commit | b99b87f70c7785ab1e253c6220f4b0b57ce3a7f7 (patch) | |
tree | ec5688052334448ec8edd3a1a9cb95cd68501ac7 | |
parent | e24aca672ff06aff0e6a1045efab86043ea5f735 (diff) |
kernel: constructor support
Call constructors (gcc-generated initcall-like functions) during kernel
start and module load. Constructors are e.g. used for gcov data
initialization.
Disable constructor support for usermode Linux to prevent conflicts with
host glibc.
Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
Acked-by: WANG Cong <xiyou.wangcong@gmail.com>
Cc: Sam Ravnborg <sam@ravnborg.org>
Cc: Jeff Dike <jdike@addtoit.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Huang Ying <ying.huang@intel.com>
Cc: Li Wei <W.Li@Sun.COM>
Cc: Michael Ellerman <michaele@au1.ibm.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Heiko Carstens <heicars2@linux.vnet.ibm.com>
Cc: Martin Schwidefsky <mschwid2@linux.vnet.ibm.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-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); |