Linux自定义系统调用调用sys_open/sys_write的头文件与链接问题
自定义Linux内核系统调用调用sys_open/sys_write的问题解决
问题场景
开发自定义系统调用时,尝试直接调用内核原生的sys_open和sys_write,已包含<linux/syscalls.h>头文件,但编译出现隐式声明错误;添加extern声明后编译通过,却触发链接阶段的undefined reference错误。
初始代码
#include <linux/kernel.h> #include <linux/syscalls.h> #include <linux/cpu.h> #include <linux/sched/isolation.h> //#include <../tools/include/nolibc/sys.h> SYSCALL_DEFINE1(my_test, int , cpuid){ umode_t m=0; int fd=sys_open("abc.txt", O_RDWR, m); sys_write(fd, "I AM ABHISHEK\n", 14); return 0; }
编译错误信息
my_syscalls/my_test.c: In function ‘__do_sys_my_test’: my_syscalls/my_test.c:9:12: error: implicit declaration of function ‘sys_open’; did you mean ‘seq_open’? [-Werror=implicit-function-declaration] 9 | int fd=sys_open("abc.txt", O_RDWR); | ^~~~~~~~ | seq_open my_syscalls/my_test.c:10:5: error: implicit declaration of function ‘sys_write’; did you mean ‘ksys_write’? [-Werror=implicit-function-declaration] 10 | sys_write(fd, "I AM ABHISHEK\n", 14); | ^~~~~~~~~ | ksys_write
添加extern后的代码
#include <linux/kernel.h> #include <linux/syscalls.h> #include <linux/cpu.h> #include <linux/sched/isolation.h> // #include <../tools/include/nolibc/sys.h> extern asmlinkage long sys_write(unsigned int fd, const char __user *buf, size_t count); extern asmlinkage long sys_open(const char __user *filename, int flags, umode_t mode); SYSCALL_DEFINE1(my_test, int , cpuid){ umode_t mode=0; int fd=sys_open("abc.txt", O_RDWR,mode); sys_write(fd, "I AM ABHISHEK\n", 14); return 0; }
链接错误信息
abhishek@abhishek:~/OS_Proj/linux-6.0.19_full_fledged_backup$ make -j16 ... ld: my_syscalls/my_test.o: in function `__do_sys_my_test': /home/abhishek/OS_Proj/linux-6.0.19_full_fledged_backup/my_syscalls/my_test.c:15: undefined reference to `sys_open' ld: /home/abhishek/OS_Proj/linux-6.0.19_full_fledged_backup/my_syscalls/my_test.c:16: undefined reference to `sys_write' make: *** [Makefile:1169: vmlinux] Error 1
问题原因及解决方法
1. 为何包含<linux/syscalls.h>仍出现隐式声明?
Linux内核中,sys_xxx系列系统调用函数的声明被条件编译宏(如#ifdef __SYSCALL_DEFINED)包裹,默认不会对普通内核代码暴露。这是内核的设计规范:不鼓励直接调用sys_xxx函数,而是推荐使用内核内部封装的ksys_xxx系列函数(如ksys_open、ksys_write),这些函数的声明会正常对外提供。
2. 正确解决编译与链接错误的步骤
方法一:使用内核推荐的ksys_xxx函数(首选)
直接替换sys_open和sys_write为ksys_open和ksys_write,无需额外extern声明,<linux/syscalls.h>会正确导出它们的声明,同时解决链接问题。
注意:ksys_write的buf参数是const char __user *类型,指向用户空间地址。直接传入内核空间的字符串字面量会触发内存访问错误,需先将内核字符串拷贝到用户空间,或改用内核文件操作接口。以下是修正后的代码示例:
#include <linux/kernel.h> #include <linux/syscalls.h> #include <linux/cpu.h> #include <linux/sched/isolation.h> #include <linux/uaccess.h> // 提供copy_to_user等安全内存操作函数 SYSCALL_DEFINE1(my_test, int , cpuid){ umode_t mode = 0; // 添加O_CREAT确保文件不存在时自动创建 int fd = ksys_open("abc.txt", O_RDWR | O_CREAT, mode); if (fd >= 0) { char kernel_buf[] = "I AM ABHISHEK\n"; // 分配一页用户空间内存 char __user *user_buf = (char __user *)__get_free_page(GFP_KERNEL); if (user_buf) { // 将内核字符串拷贝到用户空间 copy_to_user(user_buf, kernel_buf, sizeof(kernel_buf)); // 写入文件(减去字符串终止符) ksys_write(fd, user_buf, sizeof(kernel_buf)-1); // 释放用户空间内存 free_page((unsigned long)user_buf); } // 关闭文件描述符 ksys_close(fd); } return 0; }
方法二:若必须使用sys_xxx函数(不推荐)
sys_xxx函数的符号默认未导出到内核符号表,且部分内核版本中sys_xxx是静态链接的,导致链接时找不到符号。若一定要用,需:
- 修改内核配置,确保相关系统调用符号被导出(依赖具体内核版本,无通用方法);
- 或直接在代码中包含系统调用的实现文件,但这会破坏内核模块化设计,不建议新手尝试。
额外注意事项
- 内核中操作文件时,优先使用
filp_open、vfs_write、filp_close等内核文件接口,而非用户态风格的open/write/close,更符合内核编程规范; - 处理
__user类型指针时,必须使用copy_to_user、copy_from_user等安全函数,避免直接访问用户空间内存导致系统崩溃。
内容的提问来源于stack exchange,提问作者Abhishek Ghosh
相关产品推荐
相关产品推荐

