通过系统调用学习linux

系统调用是应用程序和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__
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值