您的位置:首页 > 运维架构 > Linux

通过系统调用学习linux

2015-02-12 15:38 239 查看
系统调用是应用程序和linux内核交互的主要接口,或许可以通过学习各个系统调用的具体实现来加深对linux的理解。

应用程序运行在用户态,syscall的实现是运行在内核态,需要有一种机制从用户态切换到内核态,然后才能执行syscall的代码,状态转换通常是由cpu提供的指令来实现,如中断int 0x80(cpu当然也可以提供其他实现,如x86下的sysenter)。内核启动的时候会设置好中断表,中断表可以理解为中断号码和中断处理程序的一个映射,比如int 0x80对应的中断处理程序就是系统调用处理程序,在x86_64下,处理程序叫做system_call,在arch/x86/kernel/entry_64.S里实现。

每个系统调用都有一个编号,system_call通过系统调用编号来调用具体的系统调用:call *sys_call_table(,%rax,8) 。

x86_64下sys_call_table的定义可以在arch/x86/kernel/Syscall_64.c里面找到,它include了arch/x86/include/asm/unistd_64.h这个文件:

/*

 * This file contains the system call numbers.

 *

 * Note: holes are not allowed.

 */

/* at least 8 syscall per cacheline */

#define __NR_read                0

__SYSCALL(__NR_read, sys_read)

#define __NR_write                1

__SYSCALL(__NR_write, sys_write)

#define __NR_open                2

__SYSCALL(__NR_open, sys_open)

#define __NR_close                3

__SYSCALL(__NR_close, sys_close)

#define __NR_stat                4

__SYSCALL(__NR_stat, sys_newstat)

#define __NR_fstat                5

sys_call_table将每个系统调用编号和具体的系统调用实现关联起来。系统调用的具体实现分布在内核代码各处。如open这个系统调用是在fs/open.c中实现的:

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)

{

    long ret;

    if (force_o_largefile())

        flags |= O_LARGEFILE;

    ret = do_sys_open(AT_FDCWD, filename, flags, mode);

    /* avoid REGPARM breakage on x86: */

    asmlinkage_protect(3, ret, filename, flags, mode);

    return ret;

}

SYSCALL_DEFINE3是一个宏,在include/linux/syscalls.h里定义:

#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__)

上面宏展开之后,应当是这个样子:

sys_open (const char __user *, filename, int, flags, int, mode)

{

   ...

}

sys_open的具体实现是在do_sys_open这个函数里完成,这个函数和一般c编写的函数没有太大的差别,这不过它是允许在内核态的。

各个系统调用基本处理流程基本上应该是差不多的,通过搜索SYSCALL_DEFINE[0-6],可以找到各个系统调用的具体实现。

如 find /path/to/src -name *.c | xargs grep 'SYSCALL_DEFINE[0-6]'

__END__
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux 内核 应用程序