SystemCall系统调用流程

用户空间

bionic/libc/kernel/uapi/asm-generic/unistd.h 系统调用号的宏定义

#define __NR_sysinfo 179

bionic/libc/arch-arm64/syscalls/sysinfo.S 汇编定义相关函数的中断调用过程

#include <private/bionic_asm.h>

ENTRY(sysinfo)
    mov     x8, __NR_sysinfo
    svc     #0

    cmn     x0, #(MAX_ERRNO + 1)
    cneg    x0, x0, hi
    b.hi    __set_errno_internal

    ret
END(sysinfo)

将调用号__NR_sysinfo传给寄存器r8,最终内核将收到这个调用号

内核空间

内核中调用号的定义在include/uapi/asm-generic/unistd.h中

#define __NR_sysinfo 179
__SC_COMP(__NR_sysinfo, sys_sysinfo, compat_sys_sysinfo)

系统调用的申明在include/linux/syscalls.h中

asmlinkage long sys_sysinfo(struct sysinfo __user *info);

arch/arm/kernel/calls.S 在内核中有与系统调用号对应的系统调用表

CALL(sys_sysinfo)
SYSCALL_DEFINE

sys_sysinfo()定义在内核源码找不到直接定义,而是通过syscalls.h文件中的SYSCALL_DEFINE宏定义。这些宏的展开参考Linux系统调用(syscall)原理

#define SYSCALL_DEFINE0(sname)                  \
    SYSCALL_METADATA(_##sname, 0);              \
    asmlinkage long sys_##sname(void)

#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)

#define SYSCALL_DEFINEx(x, sname, ...)              \
    SYSCALL_METADATA(sname, x, __VA_ARGS__)         \
    __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)

kernel/sys.c最终函数

SYSCALL_DEFINE1(sysinfo, struct sysinfo __user *, info)
{
    struct sysinfo val;

    do_sysinfo(&val);

    if (copy_to_user(info, &val, sizeof(struct sysinfo)))
        return -EFAULT;

    return 0;
}
技巧

如果你要查找系统调用的最终函数,只要记住SYSCALL_DEFINEx(x, sname, ...)
比如kill函数原型是int kill(pid_t pid, int sig), 因此只需要grep -rn 'SYSCALL_DEFINE2(kill'就可以查找到, 其中2是函数原型的参数个数,kill是函数名
sysinfo函数原型int sysinfo(struct sysinfo *info),则是grep -rn 'SYSCALL_DEFINE1(sysinfo'就可以查找到,最终结果

$ grep -rn 'SYSCALL_DEFINE1(sysinfo'
kernel/sys.c:2567:SYSCALL_DEFINE1(sysinfo, struct sysinfo __user *, info)
kernel/sys.c:2597:COMPAT_SYSCALL_DEFINE1(sysinfo, struct compat_sysinfo __user *, info)
$ grep -rn 'SYSCALL_DEFINE2(kill'
kernel/signal.c:2970:SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)

posted @ 2022-09-28 22:45  梦过无声  阅读(201)  评论(0编辑  收藏  举报