Linux内核模块的编译
Linux内核采用了模块化的设计,允许内核在运行时插入或删除代码。这些代码组合在一起,形成了所谓的模块。
支持模块的好处是内核可以尽可能的小,可选的功能和驱动则利用模块来提供。
Hello, World!
/* hello world module */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int __init hello_init(void) // 初始化函数,模块装载时被调用
{
printk("<1> Hello, World!\n");
return 0;
}
static void __exit hello_exit(void) // 退出函数,模块卸载的时候被调用
{
printk(KERN_ALERT "hello module exit.\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("hello world");
MODULE_DESCRIPTION("first module");
模块的出口和入口都通过调用module_init()
来注册到系统中,唯一的参数是模块的初始化函数。它其实是一个宏调用而非函数。
所有初始化函数必须满足如下形式:
int my_init(void);
类似的,退出函数使用module_exit()
来注册,对应的函数作为出口函数,负责在返回(具体指了卸载内核模块)之前清理资源。
如果模块被静态地编译进内核,则这部分不会被调用,因为内核不需要卸载操作。
构建内核模块
内核模块的构建需要使用Makefile,使用一下模板可以完成编译:
ifneq ($(KERNELRELEASE),)
obj-m += main.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := "$(shell pwd)"
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
rm main.mod.c main.mod.o main.o modules.order Module.symvers .main.ko.cmd main.mod .main.mod.* .main.o.* -rf
endif
另外在Clion中使用如下的CMakeLists.txt,可以消除错误的报错信息并拥有相应的代码提示。在运行时不需要指定可执行目标,直接运行编译即可在根目录编译产生main.ko
(即为一个内核模块),使用insmod
命令加载即可。
cmake_minimum_required(VERSION 3.15)
project(default)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -nostdinc")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -nostdinc")
set(KERNEL_ROOT /usr/src/linux)
include_directories(
# kernel headers
"${KERNEL_ROOT}/include"
"${KERNEL_ROOT}/arch/arm64/include"
"${KERNEL_ROOT}/arch/arm/include"
"${KERNEL_ROOT}/mm"
"/usr/include"
)
add_definitions(-D__KERNEL__=1)
add_custom_target(default_custom COMMAND make -C "${default_SOURCE_DIR}"
CLION_EXE_DIR="${PROJECT_BINARY_DIR}")
Last updated
Was this helpful?