modules as shared objects
Subsystems (4)
PATCH 1/1 modules as shared objects
Attached is a first cut at loading modules from ET_DYN objects (aka shared libraries) instead of ET_REL objects (.o files).
Implemented:
* Use the dynamic symbol table (including hashed symbol lookup) as the exported symbol list for the module.
* Use the DT_INIT and DT_FINI tags for module initialization and cleanup.
Not Implemented:
* Per-arch shared library link script. Needed to eliminate the unnecessary padding added by the linker for proper paging, which of course we don't do in the kernel. On non-x86, this can be as large as 64k per segment.
* Freeing the .init.* sections. Also requires the link script. I believe the proper solution is to use a different program header with a different load tag:
#define PT_INIT_LOAD 0x60000001
In this way we don't make a mistake and discard a segment that we're not supposed to.
* KALLSYMS. The module's non-dynamic symbol table is present in the file provided by insmod, though it is present in the relocated image. Merely need to copy the table into kernel memory and save it with the module.
Another point for discussion wrt freeing .init.* sections. The way I'd like to do this is to discard the pages mapped by vmalloc, but to keep the vma in use. In this way we don't have to worry about exception table data pointing into other modules, kallsyms pointing into other modules, etc. There is not currently a function to drop pages from a vmalloc area, but it would be trivial to write. The question is: does anyone have objections to this strategy?
Patch vs bk as of ChangeSet 1.857, lightly tested on x86 and alpha. Requires the module-init-tools patch posted by dwmw2 that adds the module name as a parameter to init_module syscall.
r~
[email protected], 2002-11-23 13:23:03-08:00, [email protected]
[MODULES] Three cleanups.
(1) Alpha relocation simplification and binutils workaround.
(2) Fix legacy module init/cleanup macros.
(3) Fix core size computation typo.
[email protected], 2002-11-22 17:07:27-08:00, [email protected]
[MODULE] Install exception table for the module.
[email protected], 2002-11-22 16:00:37-08:00, [email protected]
Merge dorothy.sfbay.redhat.com:/dorothy/rth/linux/linus-2.5 into dorothy.sfbay.redhat.com:/dorothy/rth/linux/mod-2.5
[email protected], 2002-11-22 15:48:49-08:00, [email protected]
[MODULES] Put module name as first argument to init_module.
[email protected], 2002-11-22 12:56:52-08:00, [email protected]
[ALPHA] Fix exception handling for new modules interfaces.
[email protected], 2002-11-21 18:28:08-08:00, [email protected]
Merge with mainline.
[email protected], 2002-11-21 18:16:28-08:00, [email protected]
[MODULES]: Initial draft of in-kernel module loader operating on ET_DYN objects instead of ET_REL objects.
Missing still are exception handling, freeing init segment, KALLSYMS, parameter handling.
Makefile | 3 arch/alpha/kernel/Makefile | 1 arch/alpha/kernel/module.c | 113 +++ arch/alpha/kernel/traps.c | 2 arch/alpha/lib/clear_user.S | 2 arch/alpha/lib/copy_user.S | 4 arch/alpha/lib/ev6-clear_user.S | 2 arch/alpha/lib/ev6-copy_user.S | 4 arch/alpha/lib/ev6-strncpy_from_user.S | 2 arch/alpha/lib/ev67-strlen_user.S | 2 arch/alpha/lib/strlen_user.S | 2 arch/alpha/lib/strncpy_from_user.S | 2 arch/alpha/mm/extable.c | 89 -- arch/alpha/mm/fault.c | 2 arch/i386/kernel/module.c | 90 +- include/asm-alpha/elf.h | 5 include/asm-alpha/module.h | 7 include/asm-alpha/uaccess.h | 40 - include/asm-i386/module.h | 7 include/linux/elf.h | 76 +- include/linux/init.h | 20 include/linux/module.h | 96 +- include/linux/moduleloader.h | 44 - kernel/extable.c | 12 kernel/module.c | 1085 +++++++++++++-------------------- scripts/Makefile.build | 26 scripts/Makefile.clean | 2 scripts/Makefile.lib | 12 scripts/Makefile.modinst | 4 29 files changed, 775 insertions, 983 deletions
Makefile +2 -1
@@ -706,7 +706,8 @@ $(call cmd,rmclean) @find . $(RCS_FIND_IGNORE) \ \( -name '*.[oas]' -o -name '.*.cmd' -o -name '.*.d' \ - -o -name '.*.tmp' \) -type f -print | xargs rm -f + -o -name '.*.tmp' -o -name '*.klm' \) \ + -type f -print | xargs rm -f # mrproper - delete configuration + modules + core files #
arch/alpha/kernel/Makefile +1 -0
@@ -26,6 +26,7 @@ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o obj-$(CONFIG_SRM_ENV) += srm_env.o +obj-$(CONFIG_MODULES) += module.o ifdef CONFIG_ALPHA_GENERIC
arch/alpha/kernel/module.c +113 -0
113 lines not on this page · raw message
arch/alpha/kernel/traps.c +1 -1
@@ -638,7 +638,7 @@ got_exception:/* Ok, we caught the exception, but we don't want it. Is there someone to pass it along to? */ -if ((fixup =search_exception_table (pc, regs.gp)) !=0 ) { +if ((fixup =search_exception_table (pc)) !=0 ) {unsigned long newpc; newpc =fixup_exception (una_reg, fixup, pc);
arch/alpha/lib/clear_user.S +1 -1
@@ -29,7 +29,7 @@ #define EX(x,y...) \ 99: x,##y; \ .section __ex_table,"a"; \ - .gprel32 99b; \ + .long 99b - .; \ lda $31, $exception-99b($31); \ .previous
arch/alpha/lib/copy_user.S +2 -2
@@ -30,14 +30,14 @@ #define EXI(x,y...) \ 99: x,##y; \ .section __ex_table,"a"; \ - .gprel32 99b; \ + .long 99b - .; \ lda $31, $exitin-99b($31); \ .previous #define EXO(x,y...) \ 99: x,##y; \ .section __ex_table,"a"; \ - .gprel32 99b; \ + .long 99b - .; \ lda $31, $exitout-99b($31); \ .previous
arch/alpha/lib/ev6-clear_user.S +1 -1
@@ -47,7 +47,7 @@ #define EX(x,y...) \ 99: x,##y; \ .section __ex_table,"a"; \ - .gprel32 99b; \ + .long 99b - .; \ lda $31, $exception-99b($31); \ .previous
arch/alpha/lib/ev6-copy_user.S +2 -2
@@ -41,14 +41,14 @@ #define EXI(x,y...) \ 99: x,##y; \ .section __ex_table,"a"; \ - .gprel32 99b; \ + .long 99b - .; \ lda $31, $exitin-99b($31); \ .previous #define EXO(x,y...) \ 99: x,##y; \ .section __ex_table,"a"; \ - .gprel32 99b; \ + .long 99b - .; \ lda $31, $exitout-99b($31); \ .previous
arch/alpha/lib/ev6-strncpy_from_user.S +1 -1
@@ -34,7 +34,7 @@ #define EX(x,y...) \ 99: x,##y; \ .section __ex_table,"a"; \ - .gprel32 99b; \ + .long 99b - .; \ lda $31, $exception-99b($0); \ .previous
arch/alpha/lib/ev67-strlen_user.S +1 -1
@@ -30,7 +30,7 @@ #define EX(x,y...) \ 99: x,##y; \ .section __ex_table,"a"; \ - .gprel32 99b; \ + .long 99b - .; \ lda v0, $exception-99b(zero); \ .previous
arch/alpha/lib/strlen_user.S +1 -1
@@ -19,7 +19,7 @@ #define EX(x,y...) \ 99: x,##y; \ .section __ex_table,"a"; \ - .gprel32 99b; \ + .long 99b - .; \ lda v0, $exception-99b(zero); \ .previous
arch/alpha/lib/strncpy_from_user.S +1 -1
@@ -19,7 +19,7 @@ #define EX(x,y...) \ 99: x,##y; \ .section __ex_table,"a"; \ - .gprel32 99b; \ + .long 99b - .; \ lda $31, $exception-99b($0); \ .previous
arch/alpha/mm/extable.c +13 -76
119 lines not on this page · raw message
arch/alpha/mm/fault.c +1 -1
@@ -176,7 +176,7 @@ no_context:/* Are we prepared to handle this fault as an exception? */ -if ((fixup =search_exception_table (regs->pc, regs->gp)) !=0 ) { +if ((fixup =search_exception_table (regs->pc)) !=0 ) {unsigned long newpc; newpc =fixup_exception (dpf_reg, fixup, regs->pc); regs->pc = newpc;
arch/i386/kernel/module.c +33 -57
123 lines not on this page · raw message
include/asm-alpha/elf.h +5 -0
@@ -1,6 +1,11 @@#ifndef __ASM_ALPHA_ELF_H#define __ASM_ALPHA_ELF_H +/* Once upon a time, the type of the hash table entry for Elf64 was unclear. +BFD got it wrong, and Alpha is stuck with the result. */ +#define __HAVE_ARCH_ELF_SYMNDX +typedef __u64 Elf_Symndx ; +/* * ELF register definitions.. */
include/asm-alpha/module.h +6 -1
@@ -1,6 +1,11 @@#ifndef _ASM_ALPHA_MODULE_H#define _ASM_ALPHA_MODULE_H -/* Module rewrite still in progress. */ +struct mod_arch_specific +{ +}; + +/* Turn code pointer into function pointer. */ +#define adjust_initfini_address (mod, x) x#endif /* _ASM_ALPHA_MODULE_H */
include/asm-alpha/uaccess.h +20 -20
@@ -126,7 +126,7 @@ __asm__("1: ldq %0,%2\n" \"2:\n" \".section __ex_table,\"a\"\n" \ -" .gprel32 1b\n" \ +" .long 1b - .\n" \" lda %0, 2b-1b(%1)\n" \".previous" \ : "=r"(__gu_val), "=r"(__gu_err) \
@@ -136,7 +136,7 @@ __asm__("1: ldl %0,%2\n" \"2:\n" \".section __ex_table,\"a\"\n" \ -" .gprel32 1b\n" \ +" .long 1b - .\n" \" lda %0, 2b-1b(%1)\n" \".previous" \ : "=r"(__gu_val), "=r"(__gu_err) \
@@ -149,7 +149,7 @@ __asm__("1: ldwu %0,%2\n" \"2:\n" \".section __ex_table,\"a\"\n" \ -" .gprel32 1b\n" \ +" .long 1b - .\n" \" lda %0, 2b-1b(%1)\n" \".previous" \ : "=r"(__gu_val), "=r"(__gu_err) \
@@ -159,7 +159,7 @@ __asm__("1: ldbu %0,%2\n" \"2:\n" \".section __ex_table,\"a\"\n" \ -" .gprel32 1b\n" \ +" .long 1b - .\n" \" lda %0, 2b-1b(%1)\n" \".previous" \ : "=r"(__gu_val), "=r"(__gu_err) \
@@ -178,10 +178,10 @@" or %0,%1,%0\n" \"3:\n" \".section __ex_table,\"a\"\n" \ -" .gprel32 1b\n" \ +" .long 1b - .\n" \" lda %0, 3b-1b(%2)\n" \ -" .gprel32 2b\n" \ -" lda %0, 2b-1b(%2)\n" \ +" .long 2b - .\n" \ +" lda %0, 3b-2b(%2)\n" \".previous" \ : "=&r"(__gu_val), "=&r"(__gu_tmp), "=r"(__gu_err) \ : "r"(addr), "2"(__gu_err)); \
@@ -192,7 +192,7 @@" extbl %0,%2,%0\n" \"2:\n" \".section __ex_table,\"a\"\n" \ -" .gprel32 1b\n" \ +" .long 1b - .\n" \" lda %0, 2b-1b(%1)\n" \".previous" \ : "=&r"(__gu_val), "=r"(__gu_err) \
@@ -240,7 +240,7 @@ __asm__ __volatile__("1: stq %r2,%1\n" \"2:\n" \".section __ex_table,\"a\"\n" \ -" .gprel32 1b\n" \ +" .long 1b - .\n" \" lda $31,2b-1b(%0)\n" \".previous" \ : "=r"(__pu_err) \
@@ -250,7 +250,7 @@ __asm__ __volatile__("1: stl %r2,%1\n" \"2:\n" \".section __ex_table,\"a\"\n" \ -" .gprel32 1b\n" \ +" .long 1b - .\n" \" lda $31,2b-1b(%0)\n" \".previous" \ : "=r"(__pu_err) \
@@ -263,7 +263,7 @@ __asm__ __volatile__("1: stw %r2,%1\n" \"2:\n" \".section __ex_table,\"a\"\n" \ -" .gprel32 1b\n" \ +" .long 1b - .\n" \" lda $31,2b-1b(%0)\n" \".previous" \ : "=r"(__pu_err) \
@@ -273,7 +273,7 @@ __asm__ __volatile__("1: stb %r2,%1\n" \"2:\n" \".section __ex_table,\"a\"\n" \ -" .gprel32 1b\n" \ +" .long 1b - .\n" \" lda $31,2b-1b(%0)\n" \".previous" \ : "=r"(__pu_err) \
@@ -298,13 +298,13 @@"4: stq_u %1,0(%5)\n" \"5:\n" \".section __ex_table,\"a\"\n" \ -" .gprel32 1b\n" \ +" .long 1b - .\n" \" lda $31, 5b-1b(%0)\n" \ -" .gprel32 2b\n" \ +" .long 2b - .\n" \" lda $31, 5b-2b(%0)\n" \ -" .gprel32 3b\n" \ +" .long 3b - .\n" \" lda $31, 5b-3b(%0)\n" \ -" .gprel32 4b\n" \ +" .long 4b - .\n" \" lda $31, 5b-4b(%0)\n" \".previous" \ : "=r"(__pu_err), "=&r"(__pu_tmp1), \
@@ -324,9 +324,9 @@ "2: stq_u %1,0(%4)\n" \ "3:\n" \ ".section __ex_table,\"a\"\n" \ - " .gprel32 1b\n" \ + " .long 1b - .\n" \ " lda $31, 3b-1b(%0)\n" \ - " .gprel32 2b\n" \ + " .long 2b - .\n" \ " lda $31, 3b-2b(%0)\n" \ ".previous" \ : "=r"(__pu_err), \
@@ -471,7 +471,7 @@/* * About the exception table: * -* - insn is a 32-bit offset off of the kernel's or module's gp. +* - insn is a 32-bit pc-relative offset from the entry to the fault insn. * - nextinsn is a 16-bit offset off of the faulting instruction * (not off of the *next* instruction as branches are). * - errreg is the register in which to place -EFAULT.
@@ -502,7 +502,7 @@ };/* Returns 0 if exception not found and fixup.unit otherwise. */ -extern unsigned search_exception_table (unsigned long ,unsigned long ); +extern unsigned search_exception_table (unsigned long );/* Returns the new pc */ #define fixup_exception (map_reg, fixup_unit, pc) \
include/asm-i386/module.h +4 -3
@@ -1,11 +1,12 @@#ifndef _ASM_I386_MODULE_H#define _ASM_I386_MODULE_H +/* x86 is simple */ struct mod_arch_specific { }; -#define Elf_Shdr Elf32_Shdr -#define Elf_Sym Elf32_Sym -#define Elf_Ehdr Elf32_Ehdr +/* Turn code pointer into function pointer. */ +#define adjust_initfini_address (mod, x) x +#endif /* _ASM_I386_MODULE_H */
include/linux/elf.h +42 -34
102 lines not on this page · raw message
include/linux/init.h +7 -13
@@ -144,31 +144,25 @@#define device_initcall (fn) module_init(fn)#define late_initcall (fn) module_init(fn) -/* Each module knows its own name. */ -#define __DEFINE_MODULE_NAME \ - char __module_name[] __attribute__((section(".modulename"))) = \ - __stringify(KBUILD_MODNAME) -/* These macros create a dummy inline: gcc 2.9x does not count alias -as usage, hence the `unused function' warning when __init functions -are declared static. We use the dummy __*_module_inline functions -both to kill the warning and check the type of the init/cleanup -function. */ +as usage, hence the `unused function' warning when __init functions +are declared static. We use the dummy __*_module_inline functions +both to kill the warning and check the type of the init/cleanup +function. */ /* Each module must use one module_init(), or one no_module_init */ #define module_init (initfn) \ - __DEFINE_MODULE_NAME; \ static inline initcall_t __inittest(void) \ { return initfn; } \ - int __initfn(void) __attribute__((alias(#initfn))); + int _init(void) __attribute__((alias(#initfn))); -#define no_module_init __DEFINE_MODULE_NAME +#define no_module_init/* This is only required if you want to be unloadable. */ #define module_exit (exitfn) \ static inline exitcall_t __exittest(void) \ { return exitfn; } \ - void __exitfn(void) __attribute__((alias(#exitfn))); + void _fini(void) __attribute__((alias(#exitfn)));#define __setup (str,func)/* nothing */
include/linux/module.h +42 -54
153 lines not on this page · raw message
include/linux/moduleloader.h +13 -31
70 lines not on this page · raw message
kernel/extable.c +1 -11
@@ -22,8 +22,6 @@extern const struct exception_table_entry __start___ex_table[];extern const struct exception_table_entry __stop___ex_table[]; -extern const struct kernel_symbol __start___ksymtab[]; -extern const struct kernel_symbol __stop___ksymtab[];/* Protects extables and symbol tables */ spinlock_t modlist_lock =SPIN_LOCK_UNLOCKED ;
@@ -33,19 +31,11 @@LIST_HEAD (symbols);static struct exception_table kernel_extable; -static struct kernel_symbol_group kernel_symbols;void __init extable_init (void ) { -/* Add kernel symbols to symbol table */ - kernel_symbols.num_syms = (__stop___ksymtab - __start___ksymtab); - kernel_symbols.syms = __start___ksymtab; -list_add (&kernel_symbols.list, &symbols); -/* Add kernel exception table to exception tables */ - kernel_extable.num_entries = (__stop___ex_table -__start___ex_table); + kernel_extable.num_entries = (__stop___ex_table - __start___ex_table); kernel_extable.entry = __start___ex_table;list_add (&kernel_extable.list, &extables); } - -
kernel/module.c +443 -642
1,276 lines not on this page · raw message
scripts/Makefile.build +13 -13
@@ -44,7 +44,7 @@ endif __build: $(if $(KBUILD_BUILTIN),$(O_TARGET) $(L_TARGET) $(EXTRA_TARGETS)) \ - $(if $(KBUILD_MODULES),$(obj-m)) \ + $(if $(KBUILD_MODULES),$(obj-m:.o=.klm)) \ $(subdir-ym) @:
@@ -72,18 +72,6 @@ $(export-objs:.o=.s) : export_flags := $(EXPORT_FLAGS) $(export-objs:.o=.lst): export_flags := $(EXPORT_FLAGS) -# Default for not multi-part modules -modname = $(*F) - -$(multi-objs-m) : modname = $(modname-multi) -$(multi-objs-m:.o=.i) : modname = $(modname-multi) -$(multi-objs-m:.o=.s) : modname = $(modname-multi) -$(multi-objs-m:.o=.lst) : modname = $(modname-multi) -$(multi-objs-y) : modname = $(modname-multi) -$(multi-objs-y:.o=.i) : modname = $(modname-multi) -$(multi-objs-y:.o=.s) : modname = $(modname-multi) -$(multi-objs-y:.o=.lst) : modname = $(modname-multi) - quiet_cmd_cc_s_c = CC $(quiet_modtag) $@ cmd_cc_s_c = $(CC) $(c_flags) -S -o $@ $<
@@ -186,6 +174,18 @@ $(call if_changed,link_multi) targets += $(multi-used-y) $(multi-used-m) + +# +# Rule to build the .klm shared object from the .o module. +# + +klm_ldflags = -shared --version-exports-section "" + +quiet_cmd_ld_klm_o = LD $(quiet_modtag) $@ +cmd_ld_klm_o = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) $(klm_ldflags) -o $@ $< + +%.klm: %.o FORCE + $(call if_changed,ld_klm_o) # Compile programs on the host # ===========================================================================
scripts/Makefile.clean +1 -1
@@ -14,7 +14,7 @@ __subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y))) subdir-y += $(__subdir-y) -__subdir-m := $(patsubst %/,%,$(filter %/, $(obj-m))) +__subdir-m := $(patsubst %/,%,$(filter %/, $(obj-m) $(obj-m:.o=.klm))) subdir-m += $(__subdir-m) __subdir-n := $(patsubst %/,%,$(filter %/, $(obj-n))) subdir-n += $(__subdir-n)
scripts/Makefile.lib +1 -11
@@ -118,20 +118,10 @@ # These flags are needed for modversions and compiling, so we define them here # already -# $(modname_flags) #defines KBUILD_MODNAME as the name of the module it will -# end up in (or would, if it gets compiled in) -# Note: It's possible that one object gets potentially linked into more -# than one module. In that case KBUILD_MODNAME will be set to foo_bar, -# where foo and bar are the name of the modules. basename_flags = -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -modname_flags = -DKBUILD_MODNAME=$(subst $(comma),_,$(subst -,_,$(modname))) c_flags = -Wp,-MD,$(depfile) $(CFLAGS) $(NOSTDINC_FLAGS) \ $(modkern_cflags) $(EXTRA_CFLAGS) $(CFLAGS_$(*F).o) \ - $(basename_flags) $(modname_flags) $(export_flags) - -# Finds the multi-part object the current object will be linked into -modname-multi = $(subst $(space),_,$(sort $(foreach m,$(multi-used),\ - $(if $(filter $(subst $(obj)/,,$*.o), $($(m:.o=-objs)) $($(m:.o=-y))),$(m:.o=))))) + $(basename_flags) $(export_flags) # Shipped files # ===========================================================================
scripts/Makefile.modinst +2 -2
@@ -15,9 +15,9 @@ # ========================================================================== -quiet_cmd_modules_install = INSTALL $(obj-m) +quiet_cmd_modules_install = INSTALL $(obj-m:.o=.klm) cmd_modules_install = mkdir -p $(MODLIB)/kernel && \ - cp $(obj-m) $(MODLIB)/kernel/ + cp $(obj-m:.o=.klm) $(MODLIB)/kernel/ modules_install: $(subdir-ym) ifneq ($(obj-m),)
In message <[email protected]> you write:
Quoted 8 lines
* Freeing the .init.* sections. Also requires the link script. I believe the proper solution is to use a different program header with a different load tag:
#define
PT_INIT_LOAD0x60000001In this way we don't make a mistake and discard a segment that we're not supposed to.
Were you thinking of dropping the dynamic at the same time (ie. putting the dynamic and init sections in the tail using the linker script)? Hmm, I guess not since you
I think an "mod_arch_free_partial(struct module *mod, void *start, void *end)" function which archs could use to do whatever fancy magic they wanted (eg. trim exception and really drop the pages, or your vmalloc_drop_pages() function, or nothing at all). x86_64, sparc, sparc64, ppc and arm do/will have their own allocators already.
Quoted 1 line
+module_core_size(const ElfW(Ehdr) *hdr, struct module *module,
I *really* hate this ElfW(type) notation. I know it's used in binutils etc, but it's a visual bitch to parse. Please please please at least use the #defines or typedefs within the generic kernel/module.c so it's readable.
Other than some gratuitous reformatting 8), looks really good. Implementing PPC now.
Thanks,
Rusty.
--
Anyone who quotes me in their sig is an idiot. -- Rusty Russell.