Messages in this thread Patch in this message |  | | From | (David Hinds) | Subject | Linking modules into the kernel: an "adequate" solution | Date | 9 Dec 1996 01:58:52 GMT |
| |
Here's something I put together to allow drivers compiled as loadable modules to be linked into a kernel image. The scheme I worked out is a bit more complicated than I'd like, and has some shortcomings that I haven't figured out how to fix yet, but it does work.
What this patch will do is to let you link one or more module object files into a vmlinux image, which can then be processed into a bootable kernel. The overhead is minimal (maybe 16 bytes per module linked this way). There is a more detailed description of how to use the stuff, and how it works, in the new linux/Documentation/klink.txt file.
I think "unified" driver objects (where the same object file can either be loaded at run time or linked into a bootable kernel) are a nice thing. The main problem I see (which isn't solved by this patch) is that modules and resident drivers have very different schemes for processing optional parameters. It would be nice to have a unified scheme that would work for both types of drivers, but I'm not sure what would be best. Any suggestions?
-- Dave Hinds dhinds@hyper.stanford.edu
--- linux-2.1.13/Makefile.orig Sat Nov 23 22:02:16 1996 +++ linux-2.1.13/Makefile Sun Dec 8 17:44:58 1996 @@ -170,6 +170,17 @@ boot: vmlinux @$(MAKE) -C arch/$(ARCH)/boot +ifdef CONFIG_LINKABLE_MODULES +LINKFLAGS := $(LINKFLAGS) -defsym init_hook_1=0 + +nrlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs + $(LD) -r $(HEAD) init/main.o init/version.o \ + $(ARCHIVES) \ + $(FILESYSTEMS) \ + $(DRIVERS) \ + $(LIBS) -o nrlinux +endif + vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \ $(ARCHIVES) \ --- linux-2.1.13/nrlinux.mk.orig Sun Dec 8 17:44:59 1996 +++ linux-2.1.13/nrlinux.mk Sun Dec 8 17:44:59 1996 @@ -0,0 +1,38 @@ +ARCH = i386 + +.EXPORT_ALL_VARIABLES: + +TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi) +HPATH = $(TOPDIR)/include + +ROOT_DEV = CURRENT +SVGA_MODE=-DSVGA_MODE=NORMAL_VGA + +HOSTCC =gcc -I$(HPATH) +HOSTCFLAGS = + +CROSS_COMPILE = + +AS =$(CROSS_COMPILE)as +LD =$(CROSS_COMPILE)ld +CC =$(CROSS_COMPILE)gcc -D__KERNEL__ -I$(HPATH) +CPP =$(CC) -E +AR =$(CROSS_COMPILE)ar +NM =$(CROSS_COMPILE)nm +STRIP =$(CROSS_COMPILE)strip +MAKE =make +AWK =gawk + +all: vmlinux + +include .config +include arch/$(ARCH)/Makefile + +vmlinux: nrlinux + DEF=`nm nrlinux | sed -ne \ + 's/ *U \(.*\)\(_R[0-9a-f]*\)/-defsym \1\2=\1/p; \ + s/ *U \(init_hook_.*\)/-defsym \1=0/p'` ; \ + $(LD) $(LINKFLAGS) $$DEF nrlinux -o vmlinux + $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | sort > System.map + +dummy: --- linux-2.1.13/Documentation/klink.txt.orig Sun Dec 8 17:44:59 1996 +++ linux-2.1.13/Documentation/klink.txt Sun Dec 8 17:44:59 1996 @@ -0,0 +1,85 @@ +Linking Loadable Modules into the Linux Kernel + +by David Hinds <dhinds@hyper.stanford.edu> + +The standard Linux implementation of device drivers and loadable +modules is inconvenient because different object files are needed for +linking a driver into the kernel, versus installing a driver at run +time. This document describes a scheme whereby drivers compiled as +loadable modules can be linked into the kernel without recompilation. + +1. How to do it? + +If you are reading this document, you have already installed the +"klink" package. To start, configure a kernel and enable the new +option, "support for linking modules into the kernel". Now, instead +of building one of the usual kernel targets, do "make nrlinux" to +build a non-relocated kernel image. + +To link loadable modules to the non-relocated image, use the "klink" +script, in the scripts subdirectory. Its syntax is: + + scripts/klink [image] [module ...] + +for example: + + scripts/klink nrlinux modules/serial.o + +The script will create a new "nrlinux" with the module(s) attached. +Running "klink" with no module arguments will list all the modules +attached to the specified image. Linking a module cannot be undone +without re-building a clean "nrlinux" image. + +Now, to convert a "nrlinux" image to a bootable kernel, use: + + make -f nrlinux.mk [target] + +where [target] is any of the normal kernel image targets: vmlinux, +vmlinuz, zImage, bzImage, zlilo, bzlilo, and so on. The alternate +makefile is important: if it is left out, "make" will not use the +altered "nrlinux" file to create the target. + +2. How does it work? + +Enabling CONFIG_LINKABLE_MODULES inserts a "hook" in the driver +initialization code in drivers/block/genhd.c, which is a pointer to an +undefined init function. "nrlinux" is like "vmlinux", however it is +linked with "-r" so that it can have undefined references and can be +re-linked later. + +The "klink" script compiles the "init_hook.c" source file so that it +will mesh with the undefined reference in "nrlinux", and will invoke +the init_module() function of a loadable module. The init_hook object +file and the module itself are linked with "nrlinux". Then, the +init_module and cleanup_module symbols are stripped from "nrlinux", so +that linking additional modules will not result in multiple definition +errors. The init_hook stub also includes a new undefined reference +that can be used to link additional modules. Thus, the module init +functions are arranged into a linked list. + +The "nrlinux.mk" makefile specifies how to build a "vmlinux" from a +"nrlinux" image. There is a bit of trickiness here because modules +compiled with CONFIG_MODVERSIONS enabled will reference other kernel +functions through their versioned names (i.e., kmalloc_Rd32fe23b +instead of kmalloc). So, the "ld" command is constructed to map all +module version symbols to their corresponding simple names. Also, the +trailing initialization hook is defined as 0, which the init code will +recognize as representing the end of the linked list. + +3. To do + +This scheme does not solve the problem of configuring modules versus +configuring kernel drivers. Modules are normally configured by +setting parameters at "insmod" time, while kernel drivers parse the +boot command line. The two schemes are not really compatible. As it +stands, there is no way to specify parameters for modules linked into +the kernel with klink. + +One scheme for doing this might be to have another initialization hook +which runs a special function that parses boot options and treats them +like insmod parameters. This would require putting some kernel symbol +information in the kernel image, for symbols that represent parameters +that can be configured. I don't see any straightforward way of +picking them out automatically. It might be nice if these variables +had some identifying features in a module object file... like maybe if +they were put in their own segment. --- linux-2.1.13/scripts/klink.orig Sun Dec 8 17:44:58 1996 +++ linux-2.1.13/scripts/klink Sun Dec 8 17:48:13 1996 @@ -0,0 +1,49 @@ +#!/bin/sh +# +# A script for incrementally linking a non-relocated kernel image +# with one or more loadable kernel modules. +# +# Usage: +# +# klink [nrlinux] [module ...] +# +# Written by David Hinds <dhinds@hyper.stanford.edu> +# + +IMG=$1 +shift +MOD_LIST=$* + +nm $IMG | grep "init_hook" > /tmp/nm.$$ +sed -n -e "s/_o$/.o/;s/.*_\([0-9]*\)_is_\(.*\)/ \1: \2/p" /tmp/nm.$$ +THIS=`sed -n -e "s/ *U init_hook_\([0-9]*\)/\1/p" /tmp/nm.$$` +rm /tmp/nm.$$ + +if [ "$THIS" = "" ] ; then + echo "$IMG is not a linkable kernel image." >& 2 + exit 1 +fi +if [ "$THIS" -eq 1 -a "$MOD_LIST" = "" ] ; then + echo "No modules linked." >& 2 +fi +if [ "$MOD_LIST" = "" ] ; then exit 0 ; fi + +for MOD in $MOD_LIST ; do + NEXT=`expr $THIS + 1` + if [ ! -r $MOD ] ; then + echo "can't open $MOD" >& 2 ; exit 1 + fi + echo "+ $THIS: $MOD" + NAME=`echo $MOD | sed -e 's+.*/++;s/\./_/g'` + DEF="-defsym init_hook_${THIS}_is_$NAME=0" + DEF="$DEF -defsym init_module_$THIS=init_module" + cc -DTHIS=$THIS -DNEXT=$NEXT -o /tmp/h$$.o -c ${0%klink}init_hook.c + ld -r -o $IMG.N $DEF $IMG /tmp/h$$.o $MOD + if [ $? -ne 0 ] ; then break ; fi + strip -N init_module -N cleanup_module -N kernel_version $IMG.N + mv $IMG.N $IMG + THIS=$NEXT +done + +rm -f /tmp/h$$.o + --- linux-2.1.13/scripts/init_hook.c.orig Sun Dec 8 17:44:59 1996 +++ linux-2.1.13/scripts/init_hook.c Sun Dec 8 17:48:21 1996 @@ -0,0 +1,21 @@ +/* + Stub for hooking the module initialization functions of loadable + modules when linked into the kernel. + + Written by David Hinds <dhinds@hyper.stanford.edu> +*/ + +#define NULL 0 +#define CONCAT(a, b) a ## b +#define TACK(a, b) CONCAT(a, b) + +typedef void init_hook_t(void); +extern init_hook_t TACK(init_hook_, THIS), TACK(init_hook_, NEXT); + +void TACK(init_hook_, THIS)(void) +{ + static init_hook_t *init_hook = TACK(init_hook_, NEXT); + TACK(init_module_, THIS)(); + if (init_hook != NULL) + init_hook(); +} --- linux-2.1.13/arch/i386/config.in.orig Sat Nov 23 21:59:48 1996 +++ linux-2.1.13/arch/i386/config.in Sun Dec 8 17:46:38 1996 @@ -15,6 +15,7 @@ if [ "$CONFIG_MODULES" = "y" ]; then bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD + bool 'Support for linking modules into the kernel' CONFIG_LINKABLE_MODULES fi endmenu --- linux-2.1.13/drivers/block/genhd.c.orig Sat Nov 23 21:58:58 1996 +++ linux-2.1.13/drivers/block/genhd.c Sun Dec 8 17:44:58 1996 @@ -54,6 +54,14 @@ extern int scsi_dev_init(void); extern int net_dev_init(void); +#ifdef CONFIG_LINKABLE_MODULES +typedef void init_hook_t(void); +extern init_hook_t init_hook_1; +static init_hook_t *init_hook = &init_hook_1; +extern int mod_use_count_; +int mod_use_count_; +#endif + /* * disk_name() is used by genhd.c and md.c. * It formats the devicename of the indicated disk @@ -741,6 +749,10 @@ #endif #ifdef CONFIG_INET net_dev_init(); +#endif +#ifdef CONFIG_LINKABLE_MODULES + if (init_hook != NULL) + init_hook(); #endif console_map_init();
|  |