如何配置Kbuild编译Linux内核模块的自定义section并生成__start_符号?
内核模块自定义section配置方案
在用户空间程序中,通过__attribute__((section("foo")))可以将变量放入自定义section,并通过__start_foo、__end_foo符号访问该section首尾,但该逻辑直接移植到内核模块时会触发Unknown symbol __start_foo错误——这是因为内核模块的Kbuild体系默认会丢弃未被显式引用的自定义section,且不会自动生成section首尾符号。
以下是解决该问题的具体配置和代码调整步骤:
1. Kbuild Makefile配置
在模块的Makefile中添加链接器参数,强制导出__start_foo和__end_foo符号,避免链接器丢弃相关section:
obj-m += simple_test.o # 强制链接器保留foo section的首尾符号 KBUILD_LDFL_MODULE += -Wl,--undefined=__start_foo -Wl,--undefined=__end_foo
或者针对单个目标文件配置:
obj-m += simple_test.o LDFLAGS_simple_test.o += -Wl,--undefined=__start_foo -Wl,--undefined=__end_foo
参数说明:--undefined=symbol告诉链接器将指定符号标记为未定义,强制链接器保留该符号对应的section,防止被优化丢弃。
2. 代码层面调整
(1)确保变量不被编译器优化
为自定义section的变量添加__attribute__((used))属性,防止编译器因变量未被直接引用而将其优化掉:
// 放入foo section的变量,添加used属性强制保留 static int var_on_foo __attribute__((section("foo"), used)) = 10; static int var_on_foo2 __attribute__((section("foo"), used)) = 20;
(2)显式声明section首尾符号
在访问section的代码中,显式声明__start_foo和__end_foo的外部符号:
extern int __start_foo[]; extern int __end_foo[]; static void __init foo_section_test(void) { int *ptr; // 遍历foo section中的所有数据 for (ptr = __start_foo; ptr < __end_foo; ptr++) { printk(KERN_INFO "foo section value: %d\n", *ptr); } } static void __exit foo_section_exit(void) { // 退出逻辑 } module_init(foo_section_test); module_exit(foo_section_exit); MODULE_LICENSE("GPL");
原理说明
内核模块的编译链接流程与用户空间不同:
- 编译器可能会优化掉未被直接引用的变量,
used属性强制保留这些变量; - 链接器默认会丢弃未被显式引用的section,
--undefined参数强制链接器保留section并导出首尾符号,确保内核模块加载时能识别这些符号。
内容的提问来源于stack exchange,提问作者eddy
相关产品推荐
相关产品推荐

