Linux内核模块编译加载教程:入门编写并运行你的第一个模块

为什么要自己编译内核模块?

内核模块是Linux系统动态加载进内核的一段代码,用来扩展功能而不需要重新编译整个内核。
比如添加新硬件驱动、文件系统支持或网络过滤等。
对于运维和开发者来说,掌握 Linux内核模块编译加载教程 是深入系统底层的第一步。
下面我会用最直接的步骤,带你从头写一个最简单的模块,并且让它跑起来。

第一步:准备好编译环境

编译内核模块需要三样东西:编译器(gcc)、构建工具(make)以及当前内核对应的开发包(kernel headers)。

1. 查看当前内核版本

uname -r

记住输出的版本号,比如 5.15.0-91-generic

2. 安装编译工具和内核头文件

Debian/Ubuntu 系:

sudo apt update
sudo apt install build-essential linux-headers-$(uname -r)

CentOS/RHEL 系:

sudo yum install epel-release  # 如果需要
sudo yum install kernel-devel kernel-headers

安装完成后,确认 /lib/modules/$(uname -r)/build 是一个有效链接。

如果提示找不到 linux-headers-$(uname -r),说明当前内核版本比较特殊(如自定义内核),需要手动安装匹配的头文件。这是新手最常见的第一个坑。

第二步:编写一个“Hello World”模块

新建一个文件夹,在里面创建两个文件:hello.cMakefile

hello.c 代码

#include 
#include 
#include 

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Hello World kernel module");

static int __init hello_init(void)
{
    printk(KERN_INFO "Hello, kernel module!\n");
    return 0;
}

static void __exit hello_exit(void)
{
    printk(KERN_INFO "Goodbye, kernel module!\n");
}

module_init(hello_init);
module_exit(hello_exit);

Makefile 配置

obj-m := hello.o

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

default:
	$(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean

注意:Makefiledefault:clean: 前面的缩进必须用 Tab,不能用空格,否则编译会报错。

第三步:编译模块

make

如果一切顺利,你会看到大量输出,最终出现 Building modules, stage 2. 等提示。
当前目录下会生成 hello.ko 文件。

使用 ls -lh hello.ko 查看文件大小,正常应该在几KB到十几KB之间。

常见编译报错及解决

  • /lib/modules/xxx/build: No such file or directory:忘记安装内核头文件,或者安装的版本与当前内核不匹配。重新安装正确的 linux-headers-$(uname -r)
  • implicit declaration of function:代码里漏掉了头文件,或者使用了旧版内核不支持的函数。检查 hello.c 中的包含。
  • make: * /lib/modules/xxx/build: 权限不足**:sudo make 试试,或者检查文件夹权限。

第四步:加载、查看和卸载模块

加载模块

sudo insmod hello.ko

没有消息就是最好的消息。
如果提示 insmod: ERROR: could not insert module hello.ko: Invalid module format,说明编译时的内核版本与当前运行内核不匹配,请确认 uname -r 一致。

查看模块是否加载成功

lsmod | grep hello

如果显示类似 hello 16384 0,说明模块已在内存中。

查看模块输出信息(dmesg)

dmesg | tail -10

你会看到一行:[ xxx.xxxxxx] Hello, kernel module!
如果信息太多,可以清空后重新查看:sudo dmesg -c 再加载一次。

卸载模块

sudo rmmod hello

再次 dmesg | tail -3,你会看到 Goodbye, kernel module!

第五步:避坑指南与验证技巧

常遇到的坑

  1. 内核版本严格匹配:编译的内核模块只能在相同版本(甚至相同 .config)的内核上加载。升级内核后必须重新编译。
  2. 符号导出冲突:如果模块使用了其他模块未导出的符号,加载时会报 Unknown symbol。解决方法是用 depmod 确保依赖关系。
  3. 函数声明过时:在内核 5.10+ 中,一些旧版接口(如 __init 位置)已变化,多参考当前内核 Documentation
  4. 安全启动 (Secure Boot):有些系统开启了 UEFI 安全启动,会阻止加载未签名模块。可以临时关闭或给模块签名。

如何验证模块真正生效

除了 dmesg 打印信息,你还可以让模块做一些可见的操作,例如修改内核参数。
但作为初学者,能用 lsmod 看到它、用 dmesg 看到输出,就已经成功走通了 Linux内核模块编译加载教程 的全流程。

你现在可以修改 hello.c 里的 printk 内容,重新编译加载,体验迭代过程。
所有命令和路径都已在上面给出,零基础可以直接复制运行。
如果你遇到任何报错,先对照本文的避坑部分检查版本和权限,大多数问题都能解决。

分享到:
上一篇
Linux网卡多队列优化网络性能
下一篇
Linux启动项管理精简开机服务:Linux启动项管理
1
系统公告

高考专属福利来袭|凭准考证免费领香港 CN2 云服务器

值高考落幕之际,泽御云开启考生专属回馈 + 产品限时特惠双重活动,助力学子暑期学习建站 高考 考生专属福利 全体应届高考生,凭高考准考证即可免费申领【香港 CN2 轻量云服务器,4 核 4G AMD 处理器】,免费使用周期 30 天,可用于搭建个人站点、编程实操、技术实训,祝各位考生金榜题名,前程似锦! 泽御云资质齐全合规自营机房,线路覆盖香港 CN2、国内 BGP、内蒙电信、美国精品线路,售后全天候技术支持。 官方网站:www.zeyuyun.com,活动限时有效,优惠逾期不再保留。
服务中心
客服
在线客服
24小时为您服务
咨询
联系我们
联系我们,为您的业务提供专属服务。
24/7 技术支持
如果您遇到寻求进一步的帮助,请过工单与我们进行联系。
24/7 即时支持
泽御云
售前客服
泽御云
泽御云
售后客服
泽御云
技术支持
评价
您对当前页面的整体感受是否满意?
😞
非常不满意
😕
不满意
😐
一般
🙂
满意
😊
非常满意