x64 Ubuntu Linux添加自定义hello系统调用编译内核报未定义引用错误如何解决
5.10.26内核自定义hello系统调用编译链接报错修复方案
报错核心原因
本次undefined reference报错是x86_64架构下系统调用自动命名规则匹配错位、表项配置错误、代码不符合内核规范、构建配置遗漏四个问题叠加导致的,之前操作中的典型错误包括:
- 混淆了系统调用表的自动前缀逻辑:Linux 5.10+内核在x86_64架构下,会自动为
syscall_64.tbl中登记的系统调用追加__x64_前缀生成实际链接的符号,完全不需要手动在表项或函数定义里加这个前缀 syscall_64.tbl表项填写格式错误:表项的四列规则为「系统调用号」「ABI类型(64表示64位)」「用户态调用名」「对应内核函数名」,之前误将函数名写成printmsg,和代码里定义的hello相关函数完全不匹配- 代码编写不符合内核系统调用规范:裸写
asmlinkage long sys_xxx的写法在5.10内核中会被编译规则过滤,无法生成可被链接器识别的标准符号 - 未将自定义源码加入内核编译列表:hello.c文件没有被内核Makefile关联,实际未参与编译流程,自然无法在链接阶段找到对应符号
分步修复操作
- 修正
syscall_64.tbl配置
打开arch/x86/entry/syscall_64.tbl,将之前乱改的表项替换为:
不要手动添加548 64 hello sys_hello__x64_前缀,不要把函数名改成printmsg或其他无关名称,保留系统调用号548即可(5.10.26版本中该号未被官方调用占用) - 重写hello.c代码,替换原有裸写函数的内容为内核标准系统调用定义:
注:#include <linux/kernel.h> #include <linux/syscalls.h> SYSCALL_DEFINE0(hello) { printk("Hello World\n"); return 0; }SYSCALL_DEFINE0是无参数系统调用的标准定义宏,编译时会自动生成符合x86_64规范的__x64_sys_hello符号,不需要手动写函数名,避免出现前缀套娃的命名错误 - 关联源码到内核构建流程
建议将hello.c放置在内核源码的kernel/目录下,编辑同目录下的Makefile,在编译对象列表中追加一行:
确保hello.c会被实际编译进内核镜像obj-y += hello.o - 清理残留缓存后重新编译
先执行make clean清除之前修改留下的旧符号配置,再启动内核编译,避免增量编译时的旧符号残留导致重复报错
问题对应说明
最初的报错undefined reference to '__x64___x64_sys_hello'就是两次操作叠加的结果:最初写sys_hello时,内核自动追加__x64_前缀要找__x64_sys_hello,但裸写的sys_hello没有生成对应的标准符号;之后手动给函数再加上__x64_前缀时,内核又自动追加一次前缀,最终链接器要找带双前缀的__x64___x64_sys_hello,自然无法匹配到实际存在的符号。
内容的提问来源于stack exchange,提问作者Muhammad Iqbal
相关产品推荐
相关产品推荐

