We’ve seen how insmod resolves undefined
symbols against the table of public kernel symbols. The table contains
the addresses of global kernel items—functions and
variables—that are needed to implement modularized drivers. The
public symbol table can be read in text form from the file
/proc/ksyms
(assuming, of course, that your
kernel has support for the /proc
filesystem—which it really should).
When a module is loaded, any symbol exported by the module becomes
part of the kernel symbol table, and you can see it appear in
/proc/ksyms
or in the output of the
ksyms command.
New modules can use symbols exported by your module, and you can stack new modules on top of other modules. Module stacking is implemented in the mainstream kernel sources as well: the msdos filesystem relies on symbols exported by the fat module, and each input USB device module stacks on the usbcore and input modules.
Module stacking is useful in complex projects. If a new abstraction is implemented in the form of a device driver, it might offer a plug for hardware-specific implementations. For example, the video-for-linux set of drivers is split into a generic module that exports symbols used by lower-level device drivers for specific hardware. According to your setup, you load the generic video module and the specific module for your installed hardware. Support for parallel ports and the wide variety of attachable devices is handled in the same way, as is the USB kernel subsystem. Stacking in the parallel port subsystem is shown in Figure 2-2; the arrows show the communications between the modules (with some example functions and data structures) and with the kernel programming interface.
When using stacked modules, it is helpful to be aware of the modprobe utility. modprobe functions in much the same way as insmod, but it also loads any other modules that are required by the module you want to load. Thus, one modprobe command can sometimes replace several invocations of insmod (although you’ll still need insmod when loading your own modules from the current directory, because modprobe only looks in the tree of installed modules).
Layered modularization can help reduce development time by simplifying each layer. This is similar to the separation between mechanism and policy that we discussed in Chapter 1.
In the usual case, a module implements its own functionality without
the need to export any symbols at all. You will need to export
symbols, however, whenever other modules may benefit from using
them. You may also need to include specific instructions to avoid
exporting all non-static
symbols, as most versions
(but not all) of modutils export all of
them by default.
The Linux kernel header files provide a convenient way to manage the visibility of your symbols, thus reducing namespace pollution and promoting proper information hiding. The mechanism described in this section works with kernels 2.1.18 and later; the 2.0 kernel had a completely different mechanism, which is described at the end of the chapter.
If your module exports no symbols at all, you might want to make that explicit by placing a line with this macro call in your source file:
EXPORT_NO_SYMBOLS;
The macro expands to an assembler directive and may appear anywhere
within the module. Portable code, however, should place it within the
module initialization function (init_module),
because the version of this macro defined in
sysdep.h
for older kernels will work only there.
If, on the other hand, you need to export a subset of symbols from
your module, the first step is defining the preprocessor macro
EXPORT_SYMTAB
. This macro must be defined
before including
module.h. It is common to define it at compile
time with the -D compiler flag in
Makefile
.
If EXPORT_SYMTAB
is defined, individual symbols are
exported with a couple of macros:
EXPORT_SYMBOL (name); EXPORT_SYMBOL_NOVERS (name);
Either version of the macro will make the given symbol available
outside the module; the second version
(EXPORT_SYMBOL_NOVERS
) exports the symbol with no
versioning information (described in Chapter 11).
Symbols must be exported outside of any function because the macros
expand to the declaration of a variable. (Interested readers can look
at <linux/module.h>
for the details, even
though the details are not needed to make things work.)
Get Linux Device Drivers, Second Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.