[lkml]   [1996]   [Dec]   [8]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
Patch in this message
SubjectLinking modules into the kernel: an "adequate" solution

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

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

--- 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

+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 \
+ $(DRIVERS) \
+ $(LIBS) -o nrlinux
vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs
$(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \
--- linux-2.1.13/ Sun Dec 8 17:44:59 1996
+++ linux-2.1.13/ Sun Dec 8 17:44:59 1996
@@ -0,0 +1,38 @@
+ARCH = i386
+TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
+HPATH = $(TOPDIR)/include
+CPP =$(CC) -E
+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 >
--- 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 <>
+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 [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 "" 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 @@
+# 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 <>
+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
+if [ "$THIS" -eq 1 -a "$MOD_LIST" = "" ] ; then
+ echo "No modules linked." >& 2
+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
+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 <>
+#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/ Sat Nov 23 21:59:48 1996
+++ linux-2.1.13/arch/i386/ 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

--- 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);

+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_;
* disk_name() is used by genhd.c and md.c.
* It formats the devicename of the indicated disk
@@ -741,6 +749,10 @@
+ if (init_hook != NULL)
+ init_hook();

 \ /
  Last update: 2005-03-22 13:38    [W:0.074 / U:2.276 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site