本页目录

Kbuild 与模块

覆盖: Kconfig/Kbuild → Makefile 语法 → 内核模块编译 → out-of-tree module → module signing → EXPORT_SYMBOL → module loading 内核版本: 2.6 ~ 6.x

Kbuild 构建系统

Kconfig: 配置项

每个子目录: Kconfig 文件 → 定义菜单, 选项, 依赖
  → make menuconfig/nconfig → 读 Kconfig → 生成 .config

config 条目:
  config MY_FEATURE
    tristate "My Feature"    ← y(内建), m(模块), n(不编译)
    depends on PCI
    select CRC32
    help
      This feature does...

  boolean: y/n
  tristate: y/m/n
  int/hex/string: 值

Kbuild Makefiles

# 子目录 Makefile:
obj-y += core.o           # 编入内核 (CONFIG_XXX=y)
obj-m += driver.o         # 编译为模块 (CONFIG_XXX=m)
obj-$(CONFIG_MYDRV) += mydrv.o  # 根据 config 决定 y/m/n

# 多文件模块:
obj-m := mymod.o
mymod-objs := mod-main.o mod-helper.o

编译流程

make defconfig          # 默认配置 (arch 相关)
make menuconfig         # 交互式配置
make -j$(nproc)         # 并行编译 → vmlinux + modules
make modules_install    # 安装模块到 /lib/modules/<version>/
make install            # 安装内核 + initramfs

内核模块

基本骨架

#include <linux/module.h>
#include <linux/kernel.h>

static int __init my_init(void) {
    pr_info("my_module: loaded\n");
    return 0;  // 0=success, -ENODEV=no device, -ENOMEM=no memory
}

static void __exit my_exit(void) {
    pr_info("my_module: unloaded\n");
}

module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Example kernel module");
MODULE_AUTHOR("Name <email>");

模块加载/卸载

insmod mymodule.ko         # 加载 + 依赖检查
rmmod mymodule             # 卸载
modprobe mymodule          # 加载 + 自动加载依赖模块
modprobe -r mymodule       # 卸载 + 递归卸载依赖

# 查看已加载模块
lsmod
cat /proc/modules

模块参数

static int myparam = 42;
module_param(myparam, int, 0644);  // sysfs: /sys/module/mymod/parameters/myparam
// 使用: insmod mymodule.ko myparam=100

Module Signing

// CONFIG_MODULE_SIG=y → 编译时对模块签名
// 内核启动时: 验证签名 → 不匹配 → 拒绝加载 (除非 sig_enforce=0)
// UEFI Secure Boot: 强制启用签名验证

// 内核 keyring:
//   .builtin_trusted_keys: 编译时嵌入的密钥
//   .secondary_trusted_keys: 运行时添加 (需有 builtin 签名)

EXPORT_SYMBOL

// 将符号 (函数/变量) 导出到公共符号表:
EXPORT_SYMBOL(my_function);        // 所有模块可用
EXPORT_SYMBOL_GPL(my_function2);   // 仅 GPL 模块可用 (许可证检查)

// 原理: 编译时把符号记录在 __ksymtab section → 模块加载时 resolve

Out-of-Tree Module Build

# 外部模块的 Kbuild (不在内核树中):
obj-m := mydriver.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

all:
    make -C $(KDIR) M=$(PWD) modules

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

参考

  • 源码⁠: scripts/kconfig/, scripts/Makefile.*, kernel/module/
  • 内核文档⁠: Documentation/kbuild/, Documentation/kbuild/modules.rst

关键词: Kconfig, Kbuild, kernel module, EXPORT_SYMBOL, module param, module signing, out-of-tree