The Kernel Symbol Table

We’ve seen how insmod resolves undefined symbols against the table of public kernel symbols. The table contains 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.

When your module is loaded, any global symbol you declare 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 the ppp driver stacks on the header compression module.

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, a frame buffer video driver can export symbols to be used by a lower-level VGA driver. Each user loads the frame buffer module and the specific VGA module for his or her installed hardware.

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.

Registering Symbol Tables

An alternative to exporting all the global symbols of your module is to use the function register_symtab, which is the official kernel interface to symbol-table management. The programming interface described here applies to the 1.2.13 and 2.0 kernels. See the section Section 17.1 in Chapter 17, for details about changes introduced in the 2.1 development kernels.

The function register_symtab, as its name suggests, is used to register a whole symbol table in the kernel’s main table. This technique is somewhat cleaner than relying on static and global symbols, in that the programmer centralizes the information about what is made available to other modules and what isn’t. This is a better approach than scattering static declarations all over the source file.

If a module calls register_symtab from its initialization function, global symbols are no longer exported; only symbols that are listed in the explicit symbol table are exported to the kernel.

The advantage of declaring a centralized symbol table is most relevant when writing modules that span multiple source files. Many functions and variables can be left global so the source files can share the relevant information; the symbol table later selects what really needs to be exported for use by other modules.

Filling a symbol table structure is a tricky task, but kernel developers have written header files to simplify the task. The following lines of code show how a symbol table is declared and exported:

static struct symbol_table skull_syms = {

#include <linux/symtab_begin.h>
        X(skull_fn1),
        X(skull_fn2),
        X(skull_variable),
#include <linux/symtab_end.h>
	};

register_symtab(&skull_syms);

Interested readers can examine <linux/symtab_begin.h>, but it’s one of the most difficult headers in the kernel. It’s not actually necessary to understand the X macro to benefit from its use.

register_symtab is able to override the static or global declaration of symbols because it is called after the module has been loaded into the running kernel. register_symtab replaces the public symbols exported by default for the current module with the explicit symbol table.

The override is possible because insmod hands the table of global symbols to the system call sys_init_module, which in turn registers the table before calling init_module. Any explicit call to register_symtab thus replaces the symbol table associated with the module.

If your module doesn’t need to export any symbols, and you don’t want to declare everything as static, just hide global symbols by adding the following line to init_module. This call to register_symtab simply overwrites the module’s default symbol table with an empty one:

register_symtab(NULL);

If the source file does not offer hooks for additional modules to be stacked on it, it’s always a good idea to hide all the symbols by using the one-liner above.

When the module is unloaded from the kernel, any public symbol it declared is automatically discarded from the main symbol table. This applies to both global symbols and explicit symbol tables.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.112.1