美文网首页
12章 系统调用(System Call) 与 API

12章 系统调用(System Call) 与 API

作者: my_passion | 来源:发表于2022-07-17 10:36 被阅读0次

    1 系统调用: 应用程序 (含 运行库 ) 与 OS Kernel 间 接口

        (1) Linux 系统调用
        
            eax 
                `内核态: 表示 `系统调用号`
                    1   exit: 退出进程
                    2   fork: 创建进程
                    3   read: 读 文件或IO
                    4   write: 写 文件或IO
                    ...
                    
                系统调用 返回 `用户态`: 作 `系统调用 returnValue`
                
        (2) 系统调用: 各 OS 不兼容
            
            解决:  加 `中间层: 运行库 -> 标准库`
    

    2 系统调用 原理

    用户态: 应用程序 
      |
      |  进入: 用 中断 (Interrupt)
      |/                
    内核态     
    

    2.1 中断

    (1) 是什么?
    
        是 `硬件或软件` 的 `请求`, 要求 `CPU 暂停` 当前工作 `转手 去处理` 更重要的工作
        
    (2) 如何被 CPU 获取 ?
    
        信号 机制, 信号就是一种 中断
        
            1] 键盘 `有键按下` 时, 键盘芯片 `发信号 给 CPU`
            
            2] `CPU 收到 信号`, 知道 有键按下, `去询问` 键盘被按下的是 `哪个键`
    
    (3) 属性
    
        中断号 (从 0 开始)
        
        `中断处理程序 (ISR, Interrupt Service Routine): Linux 下 int 0x80 相应的 ISR 恒为 system_call`
    
    (4) 类型 
        
        硬件中断
            硬件异常 或 其他事件, 如 电源掉电、键盘被按下的是
            
        软件中断
            Linux int0x80 指令
    

    (5) Linux 中断: 中断号 0x80

        [1] eax 存 `系统调用号`
    
        [2] 中断指令 int 0x80 触发 系统调用
            
            1] 查 中断向量表: pointer array
                                                             Linux
                第 n 项: functionPtr 指向 `第 n 号中断的 ISR   =    system_call` 
            
            2] 查 `系统调用表` + 系统调用号 -> `系统调用 (sys_fork) 的 funcAddr`
    

    2.2 Linux 中断流程

    (1) 触发 中断 : int 0x80

        main -> fork
        
        // fork 的伪代码
        pid_t fork(void)
        {
            long __res;
            
            eax = __NR_fork; // (1) `系统调用号`(宏 __NR_fork) 放 eax 
            int 0x80         // (2) 中断号 0x80 的 指令 int 0x80 触发 系统调用 -> 进入 内核态
            __res = eax      // (3) 返回用户态: eax 可用于存 `系统调用 的 返回值`
            __syscall_return(pid_t, __res) // (4) 宏: check 系统调用 的 returnValue, `转换为 errno 错误码`  
        }       
    

    (2) 用户栈/态 <- - - 切换 - - -> 内核栈/态

    1) int 指令 (触发)

        [1] 先 切换栈
        
            用户栈(态) -> (被 CPU 自动) 切换到 -> 内核栈(态)
            
            如何切?
                1] `找到 内核栈` (每个进程 都有自己的 内核栈)
                1] `用户态 register(SS ESP EFLAGS CS EIP 依次压栈)` 保存到 内核栈
                3] ESP 指向 内核栈栈顶
        
        2) 再 执行 ISR
    

    2) iret 指令

        内核栈(态) -> 用户栈(态)
        
        弹栈: 弹出 用户态 register
    

    3) 当前栈

    SS : 指向 当前栈所在 Page
    ESP: 指向 栈顶 (用户栈/内核栈)
    

    4) PC = CS:EIP = CS << 4 | EIP

    (3) sys 系统调用 如何获取 用户参数 ?

        1) 用户 para1~6 -> 被保存到(用 ... 传递) 6 个 register ebx/ecx/edx/esi/edi/ebp 
        
        2) 6 个 register 被 system_call 调的 宏 SAVE_ALL 保存到 `内核栈` 
        
        3) 宏 asmlinkage 让 `sys 系统调用` 只从 内核栈上取 `用户 para/6个register`
    
    CPU 中断过程.jpg 中断流程: Linux OS.jpg 中断时 用户栈 和 内核栈 切换.jpg 系统调用 流程: Linux OS.jpg 系统调用 时 内核栈分布.jpg 系统调用 中 如何向 OS Kernel 传 用户态 参数: Linux OS.jpg

    相关文章

      网友评论

          本文标题:12章 系统调用(System Call) 与 API

          本文链接:https://www.haomeiwen.com/subject/hjgrirtx.html