You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Linux内核模块安装时出现Unknown Symbol错误:_do_fork符号无法识别的问题求助

解决内核模块加载时_do_fork符号未找到的问题

你已经做了导出符号、重编译内核这些基础操作,但还是遇到符号解析失败的问题,结合你用的4.10.14内核版本,我整理了几个可能的排查方向,你可以逐一试试:

1. 先确认你运行的是刚编译的内核

很多时候我们编译完内核后,要么没更新引导项,要么重启时选错了内核,导致运行的还是旧版本。你可以:

  • 执行uname -r查看当前内核版本
  • 对比/my_linux_source_path/include/config/kernel.release里的版本号
    如果两者不一样,说明你没启动到修改后的内核。先执行make install更新内核镜像,再用update-grub更新引导配置,重启时选对对应的内核版本。

2. 检查内核编译的符号导出配置

内核的符号导出需要特定配置项支持,你得确认以下两个选项是开启的:

  • CONFIG_KALLSYMS=y:这个是导出内核符号的基础配置,默认应该开着,但最好去/my_linux_source_path/.config里搜一下确认
  • CONFIG_KALLSYMS_ALL=y:如果要导出所有符号(包括原本静态的),这个选项也得开
    要是没开,就用make menuconfig进入配置界面,在「Kernel hacking」→「Compile-time checks and compiler options」下找到这两个选项,勾上后重新编译内核和模块。

3. 确保模块Makefile完全正确

你的模块必须关联到你修改后的内核源码树编译,不能直接用gcc编译。正确的Makefile应该是这样的:

obj-m += program2.o
KERNELDIR := /my_linux_source_path  # 替换成你的内核源码路径
PWD := $(shell pwd)

all:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

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

编译模块时直接执行make就行,这样会用内核源码里的编译规则,确保模块关联的是你修改后的符号表。

4. 核对_do_fork的函数签名完全一致

你在program2.c里的extern声明必须和fork.c里的定义丝毫不差,包括参数类型、数量和顺序。建议直接从内核源码里复制正确的声明,避免手动输入出错:

// 直接从kernel/fork.h或者fork.c里复制,确保完全匹配
extern long _do_fork(unsigned long clone_flags,
		     unsigned long stack_start,
		     unsigned long stack_size,
		     int __user *parent_tidptr,
		     int __user *child_tidptr,
		     unsigned long tls);

另外,别忘了包含<linux/sched.h>头文件,不然__user这个内核宏会被编译器当成未知类型,也会导致符号签名不匹配。

5. 验证_do_fork确实在运行的内核中导出

你可以用cat /proc/kallsyms | grep _do_fork查看当前内核的符号表,如果输出为空,说明内核根本没导出这个符号。这时候要再检查:

  • EXPORT_SYMBOL_GPL(_do_fork);是不是放在_do_fork函数定义的后面
  • 重新编译内核时,要按make clean && make bzImage && make modules && make modules_install && make install的顺序来,确保所有相关文件都更新了

最后,你的模块用了MODULE_LICENSE("GPL");,和EXPORT_SYMBOL_GPL是兼容的,这部分没问题。

内容的提问来源于stack exchange,提问作者Josh Lee

火山引擎 最新活动