例如现在有三个文件:
exp.c
exps.c
exp.h
这是目前做实验的代码,其中exps中是工具函数,其内容被exp.c调用,exp.h是exps.c文件中函数的声明以及一些结构体的定义。
下面介绍将exp.c与exps.c编译为一个模块ex.ko,以及在这个过程中遇到的一系列问题。
由于exps.c中是一些工具函数,所以在exps.c中不需要module_init、module_exit等来进行修饰,而exp.c要调用exps.c,并且里面含有模块的入口函数和出口函数,所以在exp.c中使用module_init、module_exit等模块结构。
一个模块只有一个入口和出口,所以只有一对module_init、module_exit,同时要添加上MODULE_LICENSE("GPL")。
实验代码不方便贴出来,但是方法已经过真机测试,现在在我的虚拟机上随便写几个函数来演示一下:
exp.c:
#include
#include
#include
#include "exp.h"
extern void exps_init(int e);
static int table_init(void)
{
printk("TABLE: table init \n");
exps_init(50);
return 0;
}
static void table_exit(void)
{
printk("TABLE: table exit \n");
}
module_init(table_init);
module_exit(table_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Me");
MODULE_DESCRIPTION("module test");
extern导入符号是必要的,测试了如果不导入符号,会报如下错误:
error: implicit declaration of function ‘exps_init’ [-Werror=implicit-function-declaration]
即使这句extern 写在exp.h中也不行。
exps.c:
#include "exp.h"
#include
void print(int e)
{
printk("parameter is %d \n",e);
}
void exps_init(int e)
{
printk("hello, this is exps \n");
print(e);
}
在exps.c中,符号exps_init会被exp.c调用,这里既可以使用EXPORT_SYMBOL来导出这个符号,也可以不使用EXPORT_SYMBOL,测试了都没有问题。
exp.h:
#ifndef _LINUX_EXP_COMMON_H_
#define _LINUX_EXP_COMMON_H_
void exps_int(int e);
#endif
Makefile:
ifneq ($(KERNELRELEASE),)
obj-m:=ex.o
ex-objs:=exp.o exps.o
else
#generate the path
CURRENT_PATH:=$(shell pwd)
CONFIG_MODULE_SIG = n
#the absolute path
LINUX_KERNEL_PATH:=/lib/modules/$(shell uname -r)/build
#complie object
default:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
endif
Makefile是关键,首先 obj-m指定模块名,然后再根据模块名-objs:=依赖的文件。
最开始我想将模块名设置为exp,但是和我的文件重名了,这时候编译虽然成功了,但是插入模块会报如下错误:
[ 2045.410335] exp: module license 'unspecified' taints kernel.
[ 2045.410338] Disabling lock debugging due to kernel taint
所以我不能选择exp或者exps作为模块名~
依赖文件不需要顺序,比如既可以是:
ex-objs:=exp.o exps.o
也可以是:
ex-objs:=exps.o exp.o
使用make编译得到如下内容:
insmod 插入模块后,dmesg就可以得到想要的信息:
多个文件也是一样,比如这里我再增加了一个expss.c文件,该文件中函数expss_init被exps.c中函数调用:
此时exps.c:
#include "exp.h"
#include
extern int expss_init(int e);
void print(int e)
{
printk("parameter is %d \n",e);
}
void exps_init(int e)
{
printk("hello, this is exps \n");
e = expss_init(e);
print(e);
}
expss.c:
#include
#include "exp.h"
int expss_init(int e)
{
return (e+10);
}
Makefile:
ifneq ($(KERNELRELEASE),)
obj-m:=ex.o
ex-objs:=expss.o exps.o exp.o
else
#generate the path
CURRENT_PATH:=$(shell pwd)
CONFIG_MODULE_SIG = n
#the absolute path
LINUX_KERNEL_PATH:=/lib/modules/$(shell uname -r)/build
#complie object
default:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
endif
编译出文件如下:
插入模块运行如下: