注册 登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

lazydba

hello

 
 
 

日志

 
 

通过系统调用学习linux  

2011-03-28 11:36:01|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
系统调用是应用程序和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__
  评论这张
 
阅读(1115)| 评论(1)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018