内核模块是可动态加载的代码,包含 module_init(加载时执行)和 module_exit(卸载时执行);用 Makefile 编译为 .ko,insmod 加载、rmmod 卸载、lsmod 查看、dmesg 看日志;模块运行在内核态,不能用 C 库,用 printk 打印,注意并发和安全。
本文概述
内核模块是 Linux 驱动基础,面试常考:module_init/exit、编译加载、内核态特点。回答要给最小模块代码。
核心要点
内核模块动态加载/卸载,不需要重新编译内核
module_init(xxx_init) 加载时调用,module_exit(xxx_exit) 卸载时调用
编译为 .ko,Makefile 用 obj-m += xxx.o,make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
insmod xxx.ko 加载,rmmod xxx 卸载,lsmod 查看,dmesg 看 printk 输出
内核态:不能用 C 库(printf/malloc),用 printk/kmalloc,注意并发(锁)和安全(copy_to_user)

面试官考察点
内核模块基础题。面试官看你是否写过模块。重点听:module_init/exit、编译、加载。
回答思路
给最小模块代码和编译加载命令。
参考回答
最小模块代码(hello.c)。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
static int __init hello_init(void){
printk(KERN_INFO "Hello, kernel!\n");
return 0;
}
static void __exit hello_exit(void){
printk(KERN_INFO "Bye, kernel!\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Hello module");
Makefile。
obj-m += hello.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
编译加载。
make # 编译出 hello.ko
insmod hello.ko # 加载
dmesg | tail # 看到 "Hello, kernel!"
lsmod | grep hello # 查看已加载
rmmod hello # 卸载
dmesg | tail # 看到 "Bye, kernel!"
内核态 vs 用户态。
| 项目 | 用户态 | 内核态 |
|---|---|---|
| C 库 | 可用(glibc) | 不可用 |
| 打印 | printf | printk(带日志级别) |
| 内存分配 | malloc | kmalloc/vmalloc |
| 内存访问 | 受保护 | 可访问所有内存 |
| 并发 | 多进程/线程 | 中断/软中断/多 CPU,要用锁 |
| 崩溃影响 | 进程崩溃 | 内核 panic,系统死机 |
注意。
printk 有日志级别(KERN_EMERG~KERN_DEBUG),dmesg 显示受 console_loglevel 控制;
模块参数用 module_param(name, type, perm),加载时 insmod hello.ko name=value;
导出符号用 EXPORT_SYMBOL(func),其他模块可以调用;
卸载时必须释放所有资源(内存、中断、设备),否则泄漏;
内核模块必须和内核版本一致(vermagic),否则加载失败。












