Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1944838
  • 博文数量: 383
  • 博客积分: 10011
  • 博客等级: 上将
  • 技术积分: 4061
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-24 18:53
文章分类

全部博文(383)

文章存档

2011年(1)

2010年(9)

2009年(276)

2008年(97)

我的朋友

分类: LINUX

2009-04-09 21:49:37

Driver porting: compiling external modules

The 2.5 development series saw extensive changes to the kernel build mechanism and the complete replacement of the module loading code. One result of these changes is that compiling loadable modules has gotten a bit more complicated. In the 2.4 days, a makefile for an external module could be put together in just about any old way; typically a form like the following was used:

2.5开发系列在kernel构建机制上有了很大的改变,原来模块的加载代码(2.4kernel)也完全被替换,开发了新的模块加载方法。这些改变的结果使得现在编译一个可加载模块比以前稍微复杂了些。在2.4kernel时期,一个外部模块的makefile文件可以使用任何老式方法进行编写,这种典型的老式方法格式如下:

    KERNELDIR = /usr/src/linux

    CFLAGS = -D__KERNEL__ -DMODULE -I$(KERNELDIR)/include -O

    all: module.o

Real-world makefiles, of course, tended to be a bit more complicated, but the job of creating a loadable module was handled in a single, simple compilation step. All you really needed was a handy set of kernel headers to compile against.

真实的makefile(指2.4kernel),当然要稍微复杂些,但是创建一个可加载模块仅需要单一而简单的编译步骤。你在编译时所需要的就是一套唾手可得的内核头文件。

 

With the 2.6 kernel, you still need those headers. You also, however, need a configured kernel source tree and a set of makefile rules describing how modules are built. There's a few reasons for this:

2.6kernel里,你仍然需要内核头文件。但是,你还需要配置好的内核代码树和一套描述模块如何构建的makefile规则。这样做的原因如下:

 

Ø         The new module loader needs to have some extra symbols defined at compilation time. Among other things, it needs to have the KBUILD_BASENAME and KBUILD_MODNAME symbols defined.

  Ø       新的模块加载器在编译模块时需要额外的已定义符号,其中,它需要已定义好的KBUILD_BASENAMEKBUILD_MODNAME符号。
 

Ø         All loadable modules now need to go through a linking step - even those which are built from a single source file. The link brings in init/vermagic.o from the kernel source tree; this object creates a special section in the loadable module describing the environment in which it was built. It includes the compiler version used, whether the kernel was built for SMP, whether kernel preemption is enabled, the architecture which was compiled for, and, of course, the kernel version. A difference in any of these parameters can render a module incompatible with a given running kernel; rather than fail in mysterious ways, the new module loader opts to detect these compatibilities and refuse to load the module.

Ø        所有的可加载模块现在都需要一个链接步骤,即使这个模块只通过一个文件来实现。这个链接步骤将内核代码树中的init/vermagic.o文件链接到了模块。这个.o文件(也称为对象文件)给可加载模块提供了一个特殊的段(也可以成为节),在其中描述了模块的构建环境,包括:使用的编译器版本、内核是否构建为SMP、内核抢占是否使能、编译的体系结构(如i386ARM等)、内核版本。一个模块的这些项里如果有任何一项与kernel不同,就会致使这个模块与运行的kernel不兼容。新的模块加载器将检测这些不兼容性并且拒绝加载模块。

 

As of this writing (2.5.59), the "vermagic" scheme is fallible in that it assumes a match between the kernel's vermagic.o file and the way the module is being built. That will normally be the case, but people who change compiler versions or perform some sort of compilation trickery could get burned.

在写这篇文章的时候(内核版本是2.5.59),”vermagic”策略很容易被触犯,因为它规定了kernel需要和任何一个模块根据vermagic.o进行匹配检验。正常情况确实应该这样,但是当我们想更改编译器版本的时候或者进行一些编译欺骗技巧的操作时,这种策略让人头疼。

 

Ø         The new symbol versioning scheme ("modversions") requires a separate post-compile processing step and yet another linkable object to hold the symbol checksums.

新的符号版本策略(”modversions”)要求一个单独的后编译处理过程,可是其他的已链接模块拒绝进行符号检验。(译者:这段着实有些含糊,需要看其他资料)

 

One could certainly, with some effort, write a new, standalone makefile which would handle the above issues. But that solution, along with being a pain, is also brittle; as soon as the module build process changes again, the makefile will break. Eventually that process will stabilize, but, for a while, further changes are almost guaranteed.

曾有人想费些心思写一个崭新的、标准独立的供模块使用的makefile来处理上述的问题。但这个解决办法不仅伴随痛苦(指费心思),而且也是很脆弱的。一旦模块的构建过程发生了改变,这个makefile就会被破坏。最终当模块构建过程最终稳定下来,而更新的变化我担保又出现了。(译者:是的,linux kernel不断向前发展、变化,相应的编译和构建模块的过程也在变化,所以我们只能不断学习和吸收)

 

So, now that you are convinced that you want to use the kernel build system for external modules, how is that to be done? The first step is to learn how kernel makefiles work in general; from a recent kernel's Documentation/kbuild directory is recommended reading. The makefile magic needed for a simple kernel module is minimal, however. In fact, for a single-file module, a single-line makefile will suffice:

所以,现在当你确信你将使用内核构造系统来构造你的外部模块,怎么做呢?第一步就是学习内核的makefile通常是怎么工作的:在内核代码的/Documentation/kbuild目录下的makefile.txt这篇文档值得一读。构造一个简单的内核模块所需要的makefile魔术是很小的。事实上,对于一个只有一个文件的模块,只需要一个只有一行命令的makefile就足够了:

       obj-m := module.o
 

(where module is replaced with the actual name of the resulting module, of course). The kernel build system, on seeing that declaration, will compile module.o from module.c, link it with vermagic.o, and leave the result in module.ko, which can then be loaded into the kernel.

(这里的module指的是模块的实际名字),内核的构建系统,看到这句声明,会将module.c编译为module.o,然后把它和vermagic.o链接在一起,最后产生了mokule.ko文件,这个文件就是我们所需要的加载到内核的模块文件。

 

A multi-file module is almost as easy:

       obj-m := module.o

       module-objs := file1.o file2.o

In this case, file1.c and file2.c will be compiled, then linked into module.ko.

多文件模块也很容易编写makefile,如下:

obj-m := module.o

       module-objs := file1.o file2.o

在这种情况下,file1.cfile2.c将被编译,最后链接到module.ko

 

Of course, all this assumes that you can get the kernel build system to read and deal with your makefile. The magic command to make that happen is something like the following:

当然,上述所说的模块编译成功是假定你能够让内核构建系统来读取和处理你的makefile。这需要如下的一句魔术命令来实现:

make -C /path/to/source SUBDIRS=$PWD modules

 

Where /path/to/source is the path to the source directory for the (configured and built) target kernel. This command causes make to head over to the kernel source to find the top-level makefile; it then moves back to the original directory to build the module of interest.

/path/to/source指的是你的配置和编译好的内核代码树。这句魔术命令使make先跳转到内核代码树找到顶级makefile执行(内核代码的makefile,然后又跳转到模块所在的目录进行模块编译。

 

Of course, typing that command could get tiresome after a while. A trick posted by Gerd Knorr can make things a little easier, though. By looking for a symbol defined by the kernel build process, a makefile can determine whether it has been read directly, or by way of the kernel build system. So the following will build a module against the source for the currently running kernel:

当然,敲打这个命令不仅就令人厌烦了。Gerd Knorr发明了一个小技巧,可以使编译时不用老敲这个魔术命令。他使用的技巧是这样的:给模块编写的makefile,可以通过一个由内核构建系统所定义的符号,来判断自己是否已经被直接读取执行,还是通过内核构建系统进行处理后跳转回来再执行。所以,下面的makefile格式用到了这个技巧,用它可以构建模块,这个构建过程依赖于当前运行内核的本身代码资源:

    ifneq ($(KERNELRELEASE),)

    obj-m     := module.o

 

    else

    KDIR     := /lib/modules/$(shell uname -r)/build

    PWD             := $(shell pwd)

 

    default:

       $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

    endif

 

Now a simple "make" will suffice. The makefile will be read twice; the first time it will simply invoke the kernel build system, while the actual work will get done in the second pass. A makefile written in this way is simple, and it should be robust with regard to kernel build changes.

现在,你只需简单的敲入一个”make”命令就足够了。你为你的模块编写的这个makefile将会被读两次:第一次它被内核构建系统调用,第二次进行实际的模块编译。写成这种格式的makefile是简洁的,也是健壮的,经受得起内核构建的改变。

阅读(1483) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~