kernel: constructor support
authorPeter Oberparleiter <oberpar@linux.vnet.ibm.com>
Wed, 17 Jun 2009 23:28:03 +0000 (16:28 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 18 Jun 2009 20:03:57 +0000 (13:03 -0700)
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>
include/asm-generic/sections.h
include/asm-generic/vmlinux.lds.h
include/linux/init.h
include/linux/module.h
init/Kconfig
init/main.c
kernel/module.c

index 4ce48e878530d9141bb9429cdfbe11a67f139f4c..d083561337f2204bfd7e456e308ef75fc3b12d37 100644 (file)
@@ -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
index 6bdba10fef4a51c88af6cb9fb154b32d885d2fa9..55413e568f07d138e568ca0e0002bbf7ecdaa138 100644 (file)
                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)                                        \
index 8c2c9989626db737941654fcf8a57c60607f5053..13b633ed695e35f9b676a583d5e901c0549ddaaf 100644 (file)
@@ -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[];
index 505f20dcc1c7bcc4c19aab80e7d1353c5970b4c4..098bdb7bfacf1dd4a69bf3701e39144b847791df 100644 (file)
@@ -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 {}
index c4b3c6d51a72bae4e3f127b68c67ebdde8684bd8..1ce05a4cb5f6ffb945391dd93c8e7e172d511d8f 100644 (file)
@@ -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
index 0e7aedeaa05f4f56a6737c078331f675201505a1..1a65fdd06318f05c81e68d89fe7b80a3a1fcbbc5 100644 (file)
@@ -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();
 }
 
index 215aaab09e91e1e76839f403dc2e4474a512ef40..38928fcaff2bcb517375c3e6b19d398e4d423c05 100644 (file)
@@ -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);