Unresolved References

Naturally it is not sufficient to store only the checksums of the exported functions of a module. It is more important to note the checksums of all symbols used because these must be compared with the versions made available by the kernel when modules are inserted.

In the second part of module compilation,27 the following steps are performed to insert version information for all referenced symbols of a module into the module binary files:

1. modpost is called as follows:

[email protected]> scripts/modpost vmlinux modulel module2 module3 ... modulen

Not only the name of the kernel image but also the names of all previously generated .o module binaries are specified. modpost is a utility that comes with the kernel sources. It produces two lists, a global list containing all symbols made available (regardless of whether by the kernel or by a module), and a specific list for each module with all unresolved module references.

2. modprobe then iterates through all modules and tries to find the unresolved references in the list of all symbols. This succeeds if the symbol is defined either by the kernel itself or in another module.

A new module.mod.c file is created for each module. Its contents look like this (for the vfat module, e.g.):

[email protected]> cat vfat.mod.c #include <linux/module.h> #include <linux/vermagic.h> #include <linux/compiler.h>

MODULE_INFO(vermagic, VERMAGIC_STRING);

struct module _this_module

_attribute_((section(".gnu.linkonce.this_module"))) =

.name = KBUILD_MODNAME,

26The weak attribute creates a (weakly) linked variable. If it is not supplied with a value, no error is reported — as it would be for a normal variable. It is ignored instead. This is necessary because genksyms does not generate a checksum for some symbols.

27In the first part of compilation, all module source files were compiled into .o object files that contain version information on the exported symbols but not the referenced symbols.

.init = init_module, #ifdef CONFIG_MODULE_UNLOAD

.exit = cleanup_module, #endif

static const struct modversion_info _versions[]

_attribute_used_

0x8533a6dd, "struct_module" , 0x21ab58c2, "fat_detach" , 0xd8ec2862, "_mark_inode_dirty" ,

0x3c15a491, Mfat_dir_empty" 0x9a290a43, Md_instantiate"

static const char _module_depends[]

__attribute_used__

"depends=fat";

In the file, two variables located in different sections of the binary file are defined:

a. All symbols referenced by the module — together with the checksum that they need and that was copied from the symbol definition in the kernel or in another module — are stored in the modversions_info array in the_modversions section.

When a module is inserted, this information is used to check whether the running kernel has the correct versions of the required symbols.

b. A list of all modules on which the processed module depends is located in the module_depends array in the .modinfo section. In our example, the VFAT module depends on the FAT module.

It is a simple matter for modprobe to create the depends list. If module A references a symbol that is not defined in the kernel itself but in another module B, the name of B is noted in the depends list of A.

3. In the last step, the kernel compiles the resulting .mod.o file into an object file and links it with the existing .o object file of the module using ld; the resulting file is named module.ko and is the finished kernel module that can be loaded with insmod.

Continue reading here: Version Control Functions

Was this article helpful?

0 0