kernel: call constructors
Subsystems (3)
RFC PATCH 1/6 kernel: call constructors
From: Peter Oberparleiter <[email protected]>
Call constructors during kernel init and module load. Required by the gcov profiling infrastructure: gcc's profiling code uses constructors to register profiling data structures.
--- arch/powerpc/kernel/vmlinux.lds.S | 3 +++ include/asm-generic/sections.h | 1 + include/asm-generic/vmlinux.lds.h | 8 ++++++++ include/linux/module.h | 5 +++++ init/main.c | 10 ++++++++++ kernel/module.c | 13 +++++++++++++ 6 files changed, 40 insertions(+)
include/asm-generic/vmlinux.lds.h +8 -0
@@ -352,3 +352,11 @@ *(.data.percpu.shared_aligned) \ } \ __per_cpu_end = .; + +#define CONSTRUCTORS \ + __CTOR_LIST__ = .; \ + *(.ctors) \ + __CTOR_END__ = .; \ + __DTOR_LIST__ = .; \ + *(.dtors) \ + __DTOR_END__ = .;
arch/powerpc/kernel/vmlinux.lds.S +3 -0
@@ -193,6 +193,9 @@ SECTIONS *(.toc) } #endif + .data.gcov : { + CONSTRUCTORS + } . = ALIGN(PAGE_SIZE); _edata = .;
include/asm-generic/sections.h +1 -0
@@ -13,5 +13,6 @@ extern char __per_cpu_start[], __per_cpuextern char __kprobes_text_start[], __kprobes_text_end[];extern char __initdata_begin[], __initdata_end[];extern char __start_rodata[], __end_rodata[]; +extern char __CTOR_LIST__[], __CTOR_END__[];#endif /* _ASM_GENERIC_SECTIONS_H_ */
include/linux/module.h +5 -0
@@ -229,6 +229,8 @@ enum module_state MODULE_STATE_GOING, }; +typedef void (*ctorcall_t )(void ); +struct module {enum module_state state;
@@ -342,6 +344,9 @@ struct modulestruct marker *markers;unsigned int num_markers;#endif +/* Constructor calls. */ +ctorcall_t *ctors; +unsigned long num_ctors; };#ifndef MODULE_ARCH_INIT #define MODULE_ARCH_INIT {}
kernel/module.c +13 -0
@@ -1736,6 +1736,7 @@ static struct module *load_module(void _unsigned int unusedgplcrcindex;unsigned int markersindex;unsigned int markersstringsindex; +unsigned int ctorsindex;struct module *mod;long err =0 ;void *percpu =NULL , *ptr =NULL ;/* Stops spurious gcc warning */
@@ -1832,6 +1833,7 @@ static struct module *load_module(void _#ifdef ARCH_UNWIND_SECTION_NAME unwindex =find_sec (hdr, sechdrs, secstrings,ARCH_UNWIND_SECTION_NAME );#endif + ctorsindex =find_sec (hdr, sechdrs, secstrings,".ctors" );/* Don't keep modinfo and version sections. */ sechdrs[infoindex].sh_flags &= ~(unsigned long )SHF_ALLOC ;
@@ -2041,6 +2043,8 @@ static struct module *load_module(void _ mod->num_markers = sechdrs[markersindex].sh_size /sizeof (*mod->markers);#endif + mod->ctors = (void *) sechdrs[ctorsindex].sh_addr; + mod->num_ctors = sechdrs[ctorsindex].sh_size /sizeof (*mod->ctors);/* Find duplicate symbols */ err =verify_export_symbols (mod);
@@ -2153,6 +2157,14 @@ static struct module *load_module(void _ goto free_hdr; } +static void do_mod_ctors (struct module *mod) +{ +unsigned long i; + +for (i =0 ; i < mod->num_ctors; i++) + mod->ctors[i](); +} +/* This is where the real work happens */ asmlinkage long sys_init_module(void __user *umod,
@@ -2183,6 +2195,7 @@ sys_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 = mod->init ();
init/main.c +10 -0
@@ -683,6 +683,15 @@ asmlinkage void __init start_kernel(voidrest_init (); } +static void __init do_ctors (void ) +{ +ctorcall_t *call; + +for (call = (ctorcall_t *) __CTOR_LIST__; + call < (ctorcall_t *) __CTOR_END__; call++) + (*call)(); +} +static int __initdata initcall_debug;static int __init initcall_debug_setup (char *str)
@@ -760,6 +769,7 @@ static void __init do_basic_setup(void)usermodehelper_init ();driver_init ();init_irq_proc (); +do_ctors ();do_initcalls (); }
Quoted 22 lines · Peter Oberparleiter
From: Peter Oberparleiter <[email protected]>
Call constructors during kernel init and module load. Required by the gcov profiling infrastructure: gcc's profiling code uses constructors to register profiling data structures.
Signed-off-by Peter Oberparleiter <[email protected]>--- arch/powerpc/kernel/vmlinux.lds.S | 3 +++ include/asm-generic/sections.h | 1 + include/asm-generic/vmlinux.lds.h | 8 ++++++++ include/linux/module.h | 5 +++++ init/main.c | 10 ++++++++++ kernel/module.c | 13 +++++++++++++ 6 files changed, 40 insertions(+)Index:
linux-2.6.26-rc1/include/asm-generic/vmlinux.lds.h
===================================================================include/asm-generic/vmlinux.lds.h +0
-0@@ -352,3 +352,11 @@ *(.data.percpu.shared_aligned) \
include/asm-generic/vmlinux.lds.h line 362
Quoted 10 lines
include/asm-generic/vmlinux.lds.h +8
-0} \ __per_cpu_end = .; + +#define CONSTRUCTORS \ + __CTOR_LIST__ = .; \ + *(.ctors) \ + __CTOR_END__ = .; \ + __DTOR_LIST__ = .; \ + *(.dtors) \ + __DTOR_END__ = .;
You shall use: VMLINUX_SYMBOL() here.
And why those SHOUTING names?
All other linker symbols are lowercase.
Quoted 130 lines
Index:
linux-2.6.26-rc1/arch/powerpc/kernel/vmlinux.lds.S
===================================================================arch/powerpc/kernel/vmlinux.lds.S +3
-0@@ -193,6 +193,9 @@ SECTIONS *(.toc) } #endif + .data.gcov : { + CONSTRUCTORS + } . = ALIGN(PAGE_SIZE); _edata = .;Index:
linux-2.6.26-rc1/include/asm-generic/sections.h
===================================================================include/asm-generic/sections.h +1
-0@@ -13,5 +13,6 @@ extern char __per_cpu_start[], __per_cpuextern char __kprobes_text_start[], __kprobes_text_end[];extern char __initdata_begin[], __initdata_end[];extern char __start_rodata[], __end_rodata[]; +extern char __CTOR_LIST__[], __CTOR_END__[];#endif /* _ASM_GENERIC_SECTIONS_H_ */ Index:
linux-2.6.26-rc1/include/linux/module.h
===================================================================include/linux/module.h +5
-0@@ -229,6 +229,8 @@ enum module_state MODULE_STATE_GOING, }; +typedef void (*ctorcall_t )(void ); +struct module {enum module_state state;@@ -342,6 +344,9 @@ struct modulestruct marker *markers;unsigned int num_markers;#endif +/* Constructor calls. */ +ctorcall_t *ctors; +unsigned long num_ctors; };#ifndef MODULE_ARCH_INIT #define MODULE_ARCH_INIT {}Index:
linux-2.6.26-rc1/kernel/module.c
===================================================================kernel/module.c +13
-0@@ -1736,6 +1736,7 @@ static struct module *load_module(void _unsigned int unusedgplcrcindex;unsigned int markersindex;unsigned int markersstringsindex; +unsigned int ctorsindex;struct module *mod;long err =0 ;void *percpu =NULL , *ptr =NULL ;/* Stops spurious gcc warning */ @@ -1832,6 +1833,7 @@ static struct module *load_module(void _#ifdef ARCH_UNWIND_SECTION_NAME unwindex =find_sec (hdr, sechdrs, secstrings,ARCH_UNWIND_SECTION_NAME );#endif + ctorsindex =find_sec (hdr, sechdrs, secstrings,".ctors" );/* Don't keep modinfo and version sections. */ sechdrs[infoindex].sh_flags &= ~(unsigned long )SHF_ALLOC ;@@ -2041,6 +2043,8 @@ static struct module *load_module(void _ mod->num_markers = sechdrs[markersindex].sh_size /sizeof (*mod->markers);#endif + mod->ctors = (void *) sechdrs[ctorsindex].sh_addr; + mod->num_ctors = sechdrs[ctorsindex].sh_size /sizeof (*mod->ctors);/* Find duplicate symbols */ err =verify_export_symbols (mod);@@ -2153,6 +2157,14 @@ static struct module *load_module(void _ goto free_hdr; } +static void do_mod_ctors (struct module *mod) +{ +unsigned long i; + +for (i =0 ; i < mod->num_ctors; i++) + mod->ctors[i](); +} +/* This is where the real work happens */ asmlinkage long sys_init_module(void __user *umod,@@ -2183,6 +2195,7 @@ sys_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 = mod->init ();Index:
linux-2.6.26-rc1/init/main.c
===================================================================init/main.c +10
-0@@ -683,6 +683,15 @@ asmlinkage void __init start_kernel(voidrest_init (); } +static void __init do_ctors (void ) +{ +ctorcall_t *call; + +for (call = (ctorcall_t *) __CTOR_LIST__; + call < (ctorcall_t *) __CTOR_END__; call++) + (*call)(); +} +static int __initdata initcall_debug;static int __init initcall_debug_setup (char *str)@@ -760,6 +769,7 @@ static void __init do_basic_setup(void)usermodehelper_init ();driver_init ();init_irq_proc (); +do_ctors ();do_initcalls (); }
Quoted 11 lines · Sam Ravnborg
include/asm-generic/vmlinux.lds.h line 362
Quoted 8 lines · Peter Oberparleiter
From: Peter Oberparleiter <[email protected]>
include/asm-generic/vmlinux.lds.h +7
-0+#define CONSTRUCTORS \ + __CTOR_LIST__ = .; \ + *(.ctors) \ + __CTOR_END__ = .; \ + __DTOR_LIST__ = .; \ + *(.dtors) \ + __DTOR_END__ = .;You shall use:
VMLINUX_SYMBOL()here.
Ok, will do.
Quoted 2 lines
And why those SHOUTING names?
All other linker symbols are lowercase.
Here's the background for that: currently, almost all arch/*/vmlinux.lds.S scripts contain reference to a CONSTRUCTORS sections which is (as of yet) empty. The info pages for ld contain a description of the contents of this section (section 3.6.6 Output Section Keywords), including the following sample linker script:
__CTOR_LIST__ = .;
LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)
*(.ctors)
LONG(0)
__CTOR_END__ = .;
__DTOR_LIST__ = .;
LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)
*(.dtors)
LONG(0)
__DTOR_END__ = .;Apparently this sample script is buggy (namely the divide by 4 bit on 64 bit systems) so I changed it into the version found in the patch. This is somewhat of a trade-off between the information which should be present in a CONSTRUCTORS section according to the info page and what really is needed to implement constructor support.
I guess changing the names would be an option if required, as well as dropping the (unused) destructor bit of the linker script.
Quoted 6 lines · On Mon, 05 May 2008 17:24:04 +0200 Peter Oberparleiter…
From: Peter Oberparleiter <[email protected]>
Call constructors during kernel init and module load. Required by the gcov profiling infrastructure: gcc's profiling code uses constructors to register profiling data structures.
Looks sane.
Quoted 30 lines
--- arch/powerpc/kernel/vmlinux.lds.S | 3 +++ include/asm-generic/sections.h | 1 + include/asm-generic/vmlinux.lds.h | 8 ++++++++ include/linux/module.h | 5 +++++ init/main.c | 10 ++++++++++ kernel/module.c | 13 +++++++++++++ 6 files changed, 40 insertions(+)Index:
linux-2.6.26-rc1/include/asm-generic/vmlinux.lds.h
===================================================================include/asm-generic/vmlinux.lds.h +8
-0@@ -352,3 +352,11 @@ *(.data.percpu.shared_aligned) \ } \ __per_cpu_end = .; + +#define CONSTRUCTORS \ + __CTOR_LIST__ = .; \ + *(.ctors) \ + __CTOR_END__ = .; \ + __DTOR_LIST__ = .; \ + *(.dtors) \ + __DTOR_END__ = .;Index:
linux-2.6.26-rc1/arch/powerpc/kernel/vmlinux.lds.S
===================================================================
arch/powerpc/kernel/vmlinux.lds.S SECTIONS · line 198
Quoted 6 lines
arch/powerpc/kernel/vmlinux.lds.S +3
-0@@ -193,6 +193,9 @@ SECTIONS *(.toc) } #endif + .data.gcov : { + CONSTRUCTORS + }
Why did powerpc (and only powerpc) need this touchup? It already includes asm-generic/vmlinux.lds.h?
Quoted 117 lines
arch/powerpc/kernel/vmlinux.lds.S +0
-0. = ALIGN(PAGE_SIZE); _edata = .;Index:
linux-2.6.26-rc1/include/asm-generic/sections.h
===================================================================include/asm-generic/sections.h +1
-0@@ -13,5 +13,6 @@ extern char __per_cpu_start[], __per_cpuextern char __kprobes_text_start[], __kprobes_text_end[];extern char __initdata_begin[], __initdata_end[];extern char __start_rodata[], __end_rodata[]; +extern char __CTOR_LIST__[], __CTOR_END__[];#endif /* _ASM_GENERIC_SECTIONS_H_ */ Index:
linux-2.6.26-rc1/include/linux/module.h
===================================================================include/linux/module.h +5
-0@@ -229,6 +229,8 @@ enum module_state MODULE_STATE_GOING, }; +typedef void (*ctorcall_t )(void ); +struct module {enum module_state state;@@ -342,6 +344,9 @@ struct modulestruct marker *markers;unsigned int num_markers;#endif +/* Constructor calls. */ +ctorcall_t *ctors; +unsigned long num_ctors; };#ifndef MODULE_ARCH_INIT #define MODULE_ARCH_INIT {}Index:
linux-2.6.26-rc1/kernel/module.c
===================================================================kernel/module.c +13
-0@@ -1736,6 +1736,7 @@ static struct module *load_module(void _unsigned int unusedgplcrcindex;unsigned int markersindex;unsigned int markersstringsindex; +unsigned int ctorsindex;struct module *mod;long err =0 ;void *percpu =NULL , *ptr =NULL ;/* Stops spurious gcc warning */ @@ -1832,6 +1833,7 @@ static struct module *load_module(void _#ifdef ARCH_UNWIND_SECTION_NAME unwindex =find_sec (hdr, sechdrs, secstrings,ARCH_UNWIND_SECTION_NAME );#endif + ctorsindex =find_sec (hdr, sechdrs, secstrings,".ctors" );/* Don't keep modinfo and version sections. */ sechdrs[infoindex].sh_flags &= ~(unsigned long )SHF_ALLOC ;@@ -2041,6 +2043,8 @@ static struct module *load_module(void _ mod->num_markers = sechdrs[markersindex].sh_size /sizeof (*mod->markers);#endif + mod->ctors = (void *) sechdrs[ctorsindex].sh_addr; + mod->num_ctors = sechdrs[ctorsindex].sh_size /sizeof (*mod->ctors);/* Find duplicate symbols */ err =verify_export_symbols (mod);@@ -2153,6 +2157,14 @@ static struct module *load_module(void _ goto free_hdr; } +static void do_mod_ctors (struct module *mod) +{ +unsigned long i; + +for (i =0 ; i < mod->num_ctors; i++) + mod->ctors[i](); +} +/* This is where the real work happens */ asmlinkage long sys_init_module(void __user *umod,@@ -2183,6 +2195,7 @@ sys_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 = mod->init ();Index:
linux-2.6.26-rc1/init/main.c
===================================================================init/main.c +10
-0@@ -683,6 +683,15 @@ asmlinkage void __init start_kernel(voidrest_init (); } +static void __init do_ctors (void ) +{ +ctorcall_t *call; + +for (call = (ctorcall_t *) __CTOR_LIST__; + call < (ctorcall_t *) __CTOR_END__; call++) + (*call)(); +} +static int __initdata initcall_debug;static int __init initcall_debug_setup (char *str)@@ -760,6 +769,7 @@ static void __init do_basic_setup(void)usermodehelper_init ();driver_init ();init_irq_proc (); +do_ctors ();do_initcalls (); }
Quoted 15 lines · Andrew Morton
arch/powerpc/kernel/vmlinux.lds.S SECTIONS · line 198
Quoted 10 lines · On Mon, 05 May 2008 17:24:04 +0200 Peter Oberparleiter…
From: Peter Oberparleiter <[email protected]>
arch/powerpc/kernel/vmlinux.lds.S +3
-0@@ -193,6 +193,9 @@ SECTIONS *(.toc) } #endif + .data.gcov : { + CONSTRUCTORS + }Why did powerpc (and only powerpc) need this touchup? It already includes
asm-generic/vmlinux.lds.h?
asm-generic/vmlinux.lds.h defines CONSTRUCTORS but it needs to be referenced in the actual linker script to become active. For some reason unknown to me, CONSTRUCTORS shows up in all arch/*/vmlinux.lds.S scripts except for powerpc (see also my other reply about the CONSTRUCTORS section).