You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 03:35:21