linux内核模块链,linux内核模块的编译

  • Post author:
  • Post category:linux


一、linux内核模块

Linux模块是一些可以作为独立程序来编译的函数和数据类型的集合。之所以提供模块机制,是因为Linux本身是一个单内核。单内核由于所有内容都集成在一起,效率很高,但可扩展性和可维护性相对较差,模块机制可弥补这一缺陷。

Linux模块可以通过静态或动态的方法加载到内核空间,静态加载是指在内核启动过程中加载;动态加载是指在内核运行的过程中随时加载。

一个模块被加载到内核中时,就成为内核代码的一部分。模块加载入系统时,系统修改内核中的符号表,将新加载的模块提供的资源和符号添加到内核符号表中,以便模块间的通信。

内核提供了接口函数来注册我们自己的模块:

// linux/init.h

/**

* module_init() – driver initialization entry point

* @x: function to be run at kernel boot time or module insertion

*

* module_init() will either be called during do_initcalls() (if

* builtin) or at module insertion time (if a module). There can only

* be one per module.

*/

#define module_init(x) __initcall(x);

/**

* module_exit() – driver exit entry point

* @x: function to be run when driver is removed

*

* module_exit() will wrap the driver clean-up code

* with cleanup_module() when used with rmmod when

* the driver is a module. If the driver is statically

* compiled into the kernel, module_exit() has no effect.

* There can only be one per module.

*/

#define module_exit(x) __exitcall(x);

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

// linux/init.h

/**

* module_init() – driver initialization entry point

* @x: function to be run at kernel boot time or module insertion

*

* module_init() will either be called during do_initcalls() (if

* builtin) or at module insertion time (if a module).  There can only

* be one per module.

*/

#define module_init(x)    __initcall(x);

/**

* module_exit() – driver exit entry point

* @x: function to be run when driver is removed

*

* module_exit() will wrap the driver clean-up code

* with cleanup_module() when used with rmmod when

* the driver is a module.  If the driver is statically

* compiled into the kernel, module_exit() has no effect.

* There can only be one per module.

*/

#define module_exit(x)    __exitcall(x);

module_init和module_exit分别用于加载和卸载模块,其中的x的函数声明为:

int f(void);

1

intf(void);

二、编译一个自己的模块

2.1 编写一个模块

首先下载内核源码:yum groupinstall “Development Tools”,、安装好后源码在/usr/src/kernels/2.6.32-754.9.1.el6.x86_64/,注意最后面的一串内核版本,可能和uname -r不一致。

然后准备测试代码test.c:

#include

#include

static int test_init(void) {

printk(“===Test Module Start!===\n”);

return 0;

}

static int test_exit(void) {

printk(“===Test Module Has Been Closed!===”);

return 0;

}

module_init(test_init);

module_exit(test_exit);

MODULE_LICENSE(“GPL”);

MODULE_AUTHOR(“MaQian”);

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include

#include

staticinttest_init(void){

printk(“===Test Module Start!===\n”);

return0;

}

staticinttest_exit(void){

printk(“===Test Module Has Been Closed!===”);

return0;

}

module_init(test_init);

module_exit(test_exit);

MODULE_LICENSE(“GPL”);

MODULE_AUTHOR(“MaQian”);

其中linux/module.h和linux/init.h是必须包含的两个问头文件,MODULE_LICENSE是模块许可证声明,一般设置为GPL,可选。MODULE_AUTHOR是模块作者,可选。

2.2 Makefile编写

# test是模块的名字

obj-m := test.o

# 内核代码的位置

KERNEL := /usr/src/kernels/2.6.32-754.9.1.el6.x86_64/

# 当前模块的目录

PWD := $(shell pwd)

modules:

$(MAKE) -C $(KERNEL) M=$(PWD) modules

.PHONY: clean

clean:

rm -rf *.o *.ko

1

2

3

4

5

6

7

8

9

10

11

12

13

# test是模块的名字

obj-m:=test.o

# 内核代码的位置

KERNEL:=/usr/src/kernels/2.6.32-754.9.1.el6.x86_64/

# 当前模块的目录

PWD:=$(shellpwd)

modules:

$(MAKE)-C$(KERNEL)M=$(PWD)modules

.PHONY:clean

clean:

rm-rf*.o*.ko

如果不出意外,执行make即可生成我们要的模块文件test.ko,但是一般情况下,第一次编译是会失败的,会报错,错误的解决方案在最下面。

2.3 挂载模块到系统

挂载驱动使用insmod,卸载使用rmmod,先开启另外一个窗口开始打印调试信息:

> while :; do dmesg -c; sleep 1; done

1

>while:;dodmesg-c;sleep1;done

插入模块到系统:

> insmod test.ko

1

>insmodtest.ko

输出:

===Test Module Start!===

1

===TestModuleStart!===

卸载:

rmmod test.ko

1

rmmodtest.ko

输出:

===Test Module Has Been Closed!===

1

===TestModuleHasBeenClosed!===

0fcd332004ae41eb7a85668db6db1422.png

三、错误处理

3.1 Kernel configuration is invalid

make -C /usr/src/kernels/2.6.32-754.6.3.el6.x86_64/ M=/home/maqian/code/hello_netfilter modules

make[1]: Entering directory `/usr/src/linux-2.6.32′

ERROR: Kernel configuration is invalid.

include/linux/autoconf.h or include/config/auto.conf are missing.

Run ‘make oldconfig && make prepare’ on kernel src to fix it.

WARNING: Symbol version dump /usr/src/linux-2.6.32/Module.symvers

is missing; modules will have no dependencies and modversions.

Building modules, stage 2.

/usr/src/linux-2.6.32/scripts/Makefile.modpost:42: include/config/auto.conf: No such file or directory

make[2]: *** No rule to make target `include/config/auto.conf’. Stop.

make[1]: *** [modules] Error 2

make[1]: Leaving directory `/usr/src/linux-2.6.32′

make: *** [modules] Error 2

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

make-C/usr/src/kernels/2.6.32-754.6.3.el6.x86_64/M=/home/maqian/code/hello_netfiltermodules

make[1]:Enteringdirectory`/usr/src/linux-2.6.32′

ERROR:Kernelconfigurationisinvalid.

include/linux/autoconf.horinclude/config/auto.confaremissing.

Run’make oldconfig && make prepare’onkernelsrctofixit.

WARNING:Symbolversiondump/usr/src/linux-2.6.32/Module.symvers

ismissing;moduleswillhavenodependenciesandmodversions.

Buildingmodules,stage2.

/usr/src/linux-2.6.32/scripts/Makefile.modpost:42:include/config/auto.conf:Nosuchfileordirectory

make[2]:***Noruletomaketarget`include/config/auto.conf’.Stop.

make[1]:***[modules]Error2

make[1]:Leavingdirectory`/usr/src/linux-2.6.32′

make:***[modules]Error2

进入到内核代码目录,执行sudo make oldconfig && sudo make prepare,一路回车确认。

3.2 Symbol version dump xxx is missing

make -C /usr/src/kernels/2.6.32-754.6.3.el6.x86_64/ M=/home/maqian/code/hello_netfilter modules

make[1]: Entering directory `/usr/src/linux-2.6.32′

WARNING: Symbol version dump /usr/src/linux-2.6.32/Module.symvers

is missing; modules will have no dependencies and modversions.

Building modules, stage 2.

MODPOST 0 modules

/bin/sh: scripts/mod/modpost: No such file or directory

make[2]: *** [__modpost] Error 127

make[1]: *** [modules] Error 2

make[1]: Leaving directory `/usr/src/linux-2.6.32′

make: *** [modules] Error 2

1

2

3

4

5

6

7

8

9

10

11

12

13

make-C/usr/src/kernels/2.6.32-754.6.3.el6.x86_64/M=/home/maqian/code/hello_netfiltermodules

make[1]:Enteringdirectory`/usr/src/linux-2.6.32′

WARNING:Symbolversiondump/usr/src/linux-2.6.32/Module.symvers

ismissing;moduleswillhavenodependenciesandmodversions.

Buildingmodules,stage2.

MODPOST0modules

/bin/sh:scripts/mod/modpost:Nosuchfileordirectory

make[2]:***[__modpost]Error127

make[1]:***[modules]Error2

make[1]:Leavingdirectory`/usr/src/linux-2.6.32′

make:***[modules]Error2

还是在刚刚的目录执行:sudo make scripts。

当一个模块编译完成之后,使用insmod加载,使用rmmod加载,lsmod可以查看已经挂载的模块,modinfo查看一个模块的详细信息。

3.3 insmod: error inserting ‘test.ko’: -1 Invalid module format

插入驱动报错:

insmod: error inserting ‘test.ko’: -1 Invalid module format

1

insmod:errorinserting’test.ko’:-1Invalidmoduleformat

dmesg错误:

test: no symbol version for module_layout

1

test:nosymbolversionformodule_layout

检查驱动内核版本是否一致,最开始出现这个问题是因为内核代码是自己手动下载的,后面改成yum下载就好了。