open 函数 与 系统调用关系

本文详细探讨了用户层面的open函数如何通过编译器转换为系统调用,涉及软中断、异常模式切换及系统调用表。通过swi指令进入内核模式,调用sys_open实现文件操作,最后解释了sys_call_table与系统调用的对应关系。
摘要由CSDN通过智能技术生成

用户层面 open

   先说一个简单实验


int main(int argc,char *argv[])
{
    int ret=0;
    char buff[256]={0};
 
    //用自己的open来打开文件 
    ret = open("testtest.c",O_RDONLY,0777);
    printf("********************%d\n", ret);
    read(ret,buff,30);
    printf("*********************%s\n",buff);
 
    close(ret);
    return 0;

}

编译器的工作调用

摘自 https://blog.csdn.net/coldsnow33/article/details/12977139

io/fcntl.h中有open()的定义,这个open()就是应用程序的open啊。
extern int open (__const char *__file, int __oflag, ...) __nonnull ((1));
intl/loadmsgcat.c中继续找,原来是个宏;
  # define open(name, flags) open_not_cancel_2 (name, flags)
sysdeps/unix/sysv/linux/not-cancel.h
  #define open_not_cancel_2(name, flags) \
  INLINE_SYSCALL (open, 2, (const char *) (name), (flags))
sysdeps/unix/sysv/linux/arm/sysdep.h找到这里看看INLINE_SYSCALL宏是个什么东西。

 

#undef INLINE_SYSCALL
#define INLINE_SYSCALL(name, nr, args...)                \
  ({ unsigned int _sys_result = INTERNAL_SYSCALL (name, , nr, args);    \
     if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result, ), 0))    \
       {                                \
     __set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, ));        \
     _sys_result = (unsigned int) -1;                \
       }                                \
     (int) _sys_result; })


# define INTERNAL_SYSCALL_RAW(name, err, nr, args...)        \
  ({                                \
       register int _a1 asm ("r0"), _nr asm ("r7");        \
       LOAD_ARGS_##nr (args)                    \
       _nr = name;                        \
       asm volatile ("swi    0x0    @ syscall " #name    \
             : "=r" (_a1)                \
             : "r" (_nr) ASM_ARGS_##nr            \
             : "memory");                \
       _a1; })

swi是一条软中断指令,swi执行后处理器就会从usr模式切换到超级用户svc模式,svc也是一种异常模式。

发生swi 软中断要调用  el0_svc(ARM64)代码位置在 arch/arm64/kernel/entry.s

/*
 * SVC handler.
 */
    .align    6
el0_svc:
    mov    x0, sp
    bl    el0_svc_handler
    b    ret_to_user
ENDPROC(el0_svc)

 

/*
 * EL0 mode handlers.
 */
    .align    6
el0_sync:
    kernel_entry 0
    mrs    x25, esr_el1            // read the syndrome register
    lsr    x24, x25, #ESR_ELx_EC_SHIFT    // exception class
    cmp    x24, #ESR_ELx_EC_SVC64        // SVC in 64-bit state
    b.eq    el0_svc
    cmp    x24, #ESR_ELx_EC_DABT_LOW    // data abort in EL0
    b.eq    el0_da
    cmp    x24, #ESR_ELx_EC_IABT_LOW    // instruction abort in EL0
    b.eq    el0_ia
    cmp    x24, #ESR_ELx_EC_FP_ASIMD    // FP/ASIMD access
    b.eq    el0_fpsimd_acc
    cmp    x24, #ESR_ELx_EC_SVE        // SVE access
    b.eq    el0_sve_acc
    cmp    x24, #ESR_ELx_EC_FP_EXC64    // FP/ASIMD exception
    b.eq    el0_fpsimd_exc
    cmp    x24, #ESR_ELx_EC_SYS64        // configurable trap
    b.eq    el0_sys

代码位置在 arch/arm64/kernel/syscall.c

     sys_call_table为系统调用表

asmlinkage void el0_svc_handler(struct pt_regs *regs)
{
    sve_user_discard();
    el0_svc_common(regs, regs->regs[8], __NR_syscalls, sys_call_table);  //sys_call_table 为系统调用表
}

el0_svc_common

               ->invoke_syscall

                             -> __invoke_syscall(regs, syscall_fn)

syscall_fn = syscall_table[array_index_nospec(scno, sc_nr)];  //sc_nr 是系统调用号,  也是  在进入软中断之前作为参数 传递的,通过这编号找到 open close ,red 等对应系统调用函数

static long __invoke_syscall(struct pt_regs *regs, syscall_fn_t syscall_fn)
{
    return syscall_fn(regs);       //把参数传给系统调用,完成调用过程
}
 

 现在我们写的程序 通过编译器编译 和 汇编指令,和系统接口函数对应上了

下面再说了  sys_call_table 怎么和下面的 sys_open 对上的,再说这个之前 必须提到 posix , API可以在各种不同的操作系统上实现给应用程序提供完全相同的接口,

而它们本身在这些系统上的实现却可能迥异,系统sys_call_table 也是按照posix排序实现系统调用的。

 

内核层面 open

fs/open.c文件里面有如下

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
    if (force_o_largefile())
        flags |= O_LARGEFILE;

    return do_sys_open(AT_FDCWD, filename, flags, mode);
}

在 include/linux/syscalls.h 里面有这个宏的定义


#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)

 

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

 

 

展开宏最终变成 sys_open

我们来说下 sys_open   ( vfs  调用)

 

 


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值