链接内核模块时如何从kernel.sym文件引用内核符号?
解决内核模块链接时引用内核符号的问题
问题根源
你用objcopy --extract-symbols生成的kernel.sym本质是一个带符号表的ELF可执行文件,链接器不会将其视为可用于解析符号的库文件,因此-l:kernel.sym会报错。
可行解决方案
方案1:生成符号地址链接脚本
利用内核符号地址固定的特性,直接生成链接脚本告知链接器符号的绝对地址:
从
kernel.elf提取全局符号及对应地址,生成链接脚本:nm -g -f posix build/kernel.elf | grep -v 'U' | awk '{print "PROVIDE(" $1 " = 0x" $2 ");"}' > build/kernel_syms.ldsnm -g -f posix:输出全局符号,采用posix格式(符号名+地址+类型)grep -v 'U':过滤掉未定义的符号awk:将符号转换为链接器可识别的PROVIDE语句,直接指定符号地址
链接内核模块时,将该脚本传入链接器:
假设你已有模块的链接脚本module.lds,执行:ld -T module.lds -T build/kernel_syms.lds build/module.o -o build/module.ko链接器会通过
kernel_syms.lds中的定义,直接解析模块中引用的printf、malloc等符号地址。
方案2:生成符号存根静态库
创建包含内核符号地址的存根目标文件,打包为静态库供链接器使用:
从
kernel.elf提取符号,生成汇编存根文件:nm -g -f posix build/kernel.elf | grep -v 'U' | awk '{print ".global " $1 "\n" $1 ": .quad 0x" $2}' > build/kernel_syms.S该脚本会为每个内核全局符号生成一个全局定义,指向其固定地址。
编译汇编文件为目标文件:
x86_64-elf-gcc -c build/kernel_syms.S -o build/kernel_syms.o(注意替换为你的交叉编译工具链前缀,若使用原生gcc则直接用
gcc)将目标文件打包为静态库:
ar rcs build/kernel_syms.a build/kernel_syms.o链接模块时,将该静态库作为输入:
ld -T module.lds build/module.o build/kernel_syms.a -o build/module.ko或通过
-Lbuild -lkernel_syms的方式引用库。
方案3:修正kernel.sym的格式
如果坚持使用kernel.sym,可将其转换为链接器可识别的可重定位目标文件:
先从
kernel.sym提取符号表,转换为可重定位格式:objcopy -O elf64-x86-64 -B i386:x86-64 --rename-section .symtab=.symtab,alloc,load,readonly,data build/kernel.sym build/kernel_syms_rel.o该命令会将
kernel.sym的符号表段标记为可加载的只读数据段,转换为可重定位目标文件格式。链接模块时直接使用该目标文件:
ld -T module.lds build/module.o build/kernel_syms_rel.o -o build/module.ko
注意事项
- 确保模块链接脚本
module.lds正确设置了模块的内存布局(如加载地址、段属性),与内核加载模块的逻辑匹配。 - 若内核符号有变更,需重新生成对应的链接脚本、存根库或目标文件,保证符号地址的一致性。
内容的提问来源于stack exchange,提问作者Yarm
相关产品推荐
相关产品推荐

