linux kernel2.6编译启用新内核以及模块符号的导出和调用
一、为什么要编译源码?
先看看以下文章,描述的很详尽:
http://tscsh.blog.163.com/blog/static/20032010320131641225800/
http://zhidao.baidu.com/linkurl=jP0BO6nl4ZCSdEs_NNEELbQOK7IPu741vRiuONZPl5U5a1mKC8qUfuNivSKSJkOuV2L_jnqUX_G8vhNNHbLXka
http://www.ibm.com/developerworks/cn/linux/l-lkm/#icomments
在 www.kernel.org下载linux系统源码,格式为xxx.tar.xz。复制到/usr/src/下。
(2)查看当前的系统内核版本,解压缩文件:uname -r 查看版本。在/usr/src/下,用xz 及tar解压缩命令:解压tar.xz文件:先 xz -d xxx.tar.xz 将 xxx.tar.xz解压成 xxx.tar 然后,再用 tar xvf xxx.tar来解包。
(3)配置内核:cd /usr/src/linux.2.6.xx.xx进入刚才解压缩的那个文件目录cp /boot/config- 按Tab键自动补全,再接着输入 .config,回车,目的是将当前运行版本的内核配置拷贝到新内核中。make menuconfig具体配置内核,这里我选择的默认,按ESC2次,退出保存。<a> 出错,make menuconfig错误 : HOSTCC scripts/kconfig/kxgettext.o *** Unable to find the ncurses libraries or the *** required header files. *** 'make menuconfig' requires the ncurses libraries. *** *** Install ncurses (ncurses-devel) and try again. *** make[1]: *** [scripts/kconfig/dochecklxdialog] Error 1 make: *** [menuconfig] Error 2<b> 解决办法: sudo apt-get install libncurses5-dev 或者:sudo apt-get install ncurses-dev (4)编译内核:make -j4 j后面的数字为编译时候开启的进程数,一般所需要的时间在1到4个小时。(5)编译安装新内核模块:make module_install(6)安装内核:make install(7)生成启动项:sudo mkinitramfs -o /boot/initrd.img-2.6.36.61 //此处是我自己的新内核版本号sudo update -initramfs -c -k 2.6.36.61sudo -grub2 //自动修改系统引导配置,将新内核的启动项添加到grub.cfg启动文件中在当前的/home/ 目录下创建文件夹mkdir liulu_drivers,在liulu_drivers下创建两个文件夹hello和hello-1。
(1) hello/下包含有导出模块符号的被调用模块源文件hello.c以及Makefile文件:>>>>>>>>>>hello.c文件代码>>>>>>>>>>
hello.c中的hello_num为导出符号,导出符号可以时变量或者函数接口名称,使用EXPORT_SYMBOL(xxx); 申明。hello-1.ko中若要调用hello.ko导出的模块符号hello_num,需在hello-1.c中申明:extern int hello_num;此外hello-1.c中还使用了模块传入参数,使用module_param(变量名,类型,S_IRUGO);申明。
关于Makefile的说明:$(uname -r)得到当前运行的内核版本,$(pwd)为当前的路径,其具体语法含义见书本。
在<三>中已经准备好了两个模块的源文件代码,这时候就可以进行模块符号的导出及调用了,其具体的执行过程为:
hello.c代码中需申明导出符号hello_numhello-1.c中需使用extern引用hello-1.c的导出符号执行模块导出符号的调用方式一:1.先编译hello.c生成模块文件hello.ko,然后su之后,insmod hello.ko加载这个模块。
2.将hello/下编译生成的Module.symvers复制到hello-1/下,该文件包含有hello.c的导出符号对应地址,hello-1.ko需要这个文件来查找导出符号。
3.编译hello-1.c生成模块文件hell-1.ko,然后insmod hello-1.ko i=xxx加载这个模块,其中i=xxx为可选,i初始化为2,不传入参数也可以。
4.我的机器下没有直接打印出信息,使用dmesg查看系统日志,可以看到模块加载的打印信息。
注意:2与3的顺序一定不能反,否则编译找不到hello_num地址。
1.先编译hello.c生成模块文件hello.ko,然后su之后,insmod hello.ko加载这个模块。
2.在hello-1的Makefile文件中添加如下两行语句:KBUILD_EXTRA_SYMBOLS+= /home/liulu/liulu_drivers/hello/Module.symvers
export $(KBUILD_EXTRA_SYMBOLS)
这两行语句显示的再编译时指明了所需要用的导出符号的地址,然后使用export导出。
3.编译hello-1.c生成模块文件hell-1.ko,然后insmod hello-1.ko i=xxx加载这个模块,其中i=xxx为可选,i初始化为2,不传入参数也可以。
4.我的机器下没有直接打印出信息,使用dmesg查看系统日志,可以看到模块加载的打印信息。
程序运行如图所示:
(1)insmod 两个模块,无提示,成功加载。

(2)dmesg查看系统日志:

(3)先rmmod hello-1,再rmmod hello,这跟模块注册注销的顺序一样,前后相反,再查看系统打印信息:

分析:在打开Module.symvers中可以看到如下信息
0x987c032a hello_num /home/liulu/liulu_drivers/hello/hello EXPORT_SYMBOL
而模块在需找导出符号的时候查看的路径其实还有系统usr/src/$(uname -r)/下的Module.symvers,打开这个文件,可以看到里面对应的都是各个导出符号的地址。也有网友介绍过将hello_num的这行语句直接添加到系统的Module.symvers文件中,这样就相当于hello_num全局通用,不需要上述两个步骤那样繁琐,遗憾的是,在我添加之后,导致系统编译报错,目前还不知道原因是什么。