Linux源码学习笔记:syscalls

来源:互联网 发布:淘宝网10至20包邮 编辑:程序博客网 时间:2024/06/01 22:51

最近一段时间,研究Linux源码,虽然断断续续的没有投入太多的时间,但也有不少收获。学习新知识的时候,一定要带着问题,不断的寻找答案。下面就是我在学习过程中整理的一些笔记,一开始不算完整,后面陆陆续续的不断补充。


我分析的源码是基于当前最新的3.16主版本。

1. 首先应该弄明白下面的一个问题:<unistd.h>具体引用的是哪个文件?相互之间的引用关系?

2. 以下这些系统调用的宏定义是怎么展开的?
SYSCALL_DEFINE0(...)
SYSCALL_DEFINE1(...)
SYSCALL_DEFINE2(...)
SYSCALL_DEFINE3(...)
SYSCALL_DEFINE4(...)

这些宏定义在:include/linux/syscalls.h文件中:
#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__)

应用举例:
SYSCALL_DEFINE0(getxuid)
{
    current_pt_regs()->r20 = sys_geteuid();
    return sys_getuid();
}

SYSCALL_DEFINE0(getpid)
{
    return task_tgid_vnr(current);
}

SYSCALL_DEFINE1(exit, int, error_code)
{
    do_exit((error_code&0xff)<<8);
}

SYSCALL_DEFINE1(dup, unsigned int, fildes)
{
    int ret = -EBADF;
    struct file *file = fget_raw(fildes);
    if (file) {
        ret = get_unused_fd();
        if (ret >= 0)
            fd_install(ret, file);
        else
            fput(file);
    }
    return ret;
}

SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
{
    return do_rmdir(AT_FDCWD, pathname);
}

SYSCALL_DEFINE2(munmap, unsigned long, addr, size_t, len)
{
    profile_munmap(addr);
    return vm_munmap(addr, len);
}

SYSCALL_DEFINE2(dup2, unsigned int, oldfd, unsigned int, newfd)
{
    if (unlikely(newfd == oldfd)) { /* corner case */
        struct files_struct *files = current->files;
        int retval = oldfd;
        rcu_read_lock();
        if (!fcheck_files(files, oldfd))
            retval = -EBADF;
        rcu_read_unlock();
        return retval;
    }
    return sys_dup3(oldfd, newfd, 0);
}

SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
{
    struct siginfo info;
    info.si_signo = sig;
    info.si_errno = 0;
    info.si_code = SI_USER;
    info.si_pid = task_tgid_vnr(current);
    info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
    return kill_something_info(sig, &info, pid);
}

SYSCALL_DEFINE2(chmod, const char __user *, filename, umode_t, mode)
{
    return sys_fchmodat(AT_FDCWD, filename, mode);
}

3. sys_call_table是怎么实现的?
作用应该是给每一个系统调用赋一个整数值作为系统调用号。这一个数组怎么和具体每一个系统调用函数关联起来的?

在文件<arch/score/kernel/sys_call_table.c>中有如下定义:
#undef __SYSCALL
#define __SYSCALL(nr, call) [nr] = (call),
void *sys_call_table[__NR_syscalls] = {
#include <asm/unistd.h>
};

而#include <asm/unistd.h>中又逐层的展开其他的unistd.h定义,主要是系统调用的消息号定义。

4. 理清楚不同体系结构的对应的系统调用号的引用关系?
和系统调用号有关的头文件主要有:
<arch/arm/include/uapi/asm/unistd.h>
<include/uapi/asm-generic/unistd.h>

arch目录下各个不同体系结构的系统调用号的定义不同。

5.
sys_ni_syscall() 除了返回ENOSYS以外什么也没有做,ENOSYS对应的错误是指当调用到一个无效的系统函数。但是为什么定义这么一个函数,我还是不太清楚,后续我再找人问问。

6. 系统调用函数通过0x80中断进行调用:
通过中断进行调用的方法的参数传递:功能号和返回值通过 %eax 来传递。
参数一般在5个以下的通过寄存器 %ebx,%ecx,%edx,%esi,%edi来传递,如果参数个数大于5个,则要通过堆栈来传递,按照c语言的参数传递方式,最后一个参数最先进栈。同时,把%esp传递给%ebx

7.中段响应的入口函数:
代码在init/main.c文件:
asmlinkage __visible void __init start_kernel(void)
{
...

    /* 
    * Set up the scheduler prior starting any interrupts (such as the
    * timer interrupt). Full topology setup happens at smp_init()
    * time - but meanwhile we still have a functioning scheduler.
    */
    sched_init();
...
}


0 0
原创粉丝点击