• ch2_1系统调用接口


    1. 操作系统接口

    什么是操作系统接口:

    答: 接口函数 调用操作系统中的内部函数, 术语为系统调用, system_call

    需要注意的是,应用程序进行系统调用时, 并非直接调用系统中的函数, 而是首先调用一个接口函数, 该接口函数然后才会去调用系统内部的函数。

    1.1 系统调用

    普通应用程序(应用软件): 程序中会调用一些重要的函数, 这些重要的函数便是 一个个操作系统 提供的接口函数, 接口函数才是提供给应用程序调用操作系统功能的函数。

    由于这些接口函数调用的是操作系统内部实现的函数,
    区别于应用程序中普通的函数调用,
    这种调用系统内部的函数, 便称之为 系统调用system call

    为了将操作系统提供的这些函数的接口规范好, 形成统一的格式:
    Posix: portable operating system interface of Unix;

    从而方便了应用程序可以在不同的操作系统中运行.

    也就是说, 用户写的应用程序, 调用的只是一个接口函数。

    1.2 为什么要有系统调用

    起因, 应用程序运行时在内存中,操作系统也在内存中, 为什么应用程序想访问 操作系统的提供的功能函数,

    为什么不能 直接去取从内存中去取呢?

    答: 操作系统是一个重要的存在,
    他掌控了计算机硬件这个国家中,重要的资源, 比方硬件资源, 和用户的密码和数据,
    如果,随意的一个应用程序,就可以访问, 捞到用户的密码, 以及任意的掌控这个计算机的资源。
    如果,这个应用程序有恶意的行为, 那么 对用户的信息安全,将会造成伤害, 对计算机的硬件资源也会造成伤害。

    所以,不可以给应用程序直接访问 系统中的函数和功能。

    所以系统调用的作用,

    1. 不让应用程序 随意的jump
    2. 凭什么,使用什么手段不让应用程序jump
    3. 不让应用程序直接访问, 那么应用程序该如何使用操作系统提供的功能。

    1.3 内核态与用户态

    不同的程序, 运行时处在不同的级别,

    • 用户态
    • 内核态

    一般系统的程序运行时 是处于核心态中,
    普通用户的 应用程序 运行时 处在 用户态中;

    在这里插入图片描述

    计算机对内存的使用,都是一段一段的使用,硬件上实现将内存隔成两个区域:

    • 用户态下的程序 属于用户段;
    • 核心态下的程序属于内核段,

    不同的态,他们所拥有的特权级别不同。

    1.4 权限级别的规定

    0:内核态处于特权级别, 可以访问任何数据;
    3: 用户态权限数值;

    数值越低, 权限的级别越高。
    数值越大, 权限级别越低,

    所以只用当: 目标特权级的数值 >= 当前特权级的数值时, 才可以访问。

    1.5 存储权限级别的判断

    而无论什么段, 都需要用到段寄存器;

    • DPL(destination Privage level): 目标特权级,操作系统在初始化的时候设计好, 对应的数值放在GDT 表中。
    • CPL: 当前特权级别, 对应的数值放在 cs 寄存器中。

    在这里插入图片描述

    通过比较 DPL , CPL 的数值, 权限级别低的不可以访问权限级别高的。

    只有当DPL >= CPL , 才可以访问内核态。

    在系统初始化的时候, head.S 执行的过程中,会针对内核的代码和内核态的数据建立 GDT表,其中的DPL 初始化成 0,

    在初始化完成后,进入用户态,
    执行应用程序的过程中, cs 段寄存器中存放的当前应用程序的特权级别, 此时 CPL = 3, 当通过系统调用时, CPL 会短暂的变成0, 当返回用户态的时候, 又变成3;

    而程序每次执行跳转 jmp, 还是 mov 这两个指令时,
    都需要访问 GDT 表, 因为访问了段寄存器了, 需要通过段来进入内核态。

    访问 GDT 表时候,比较 DPL >= CPL 所对应的数值是否成立。

    2. 接口函数

    接口函数,也叫应用程序接口, API(Application Programming Interface), 他将系统内部的函数重新封装了一次, 起到了一个承上启下的作用;

    对于应用程序, 接口函数提供给他调用。
    对于系统内部函数, 接口函数负责调用他。

    接口函数本身并没有 实现 具体的功能, 他起到了作用

    1. 提供系统调用的中断, 方便进入内核;
    2. 提供需要调用的功能号, 通过功能号 索引到系统内部需要调用的函数。

    2.2 调用过程

    1. 首先,普通应用程序调用的是一个接口函数, 不同的接口函数本身会对应不同的调用功能号

    2. 然后,接口函数会调用中断 int 0x80 ,并将该函数调用功能号存放到寄存器eax 中。

    3. 通过中断进入内核, 由功能号去定位所需要调用的系统函数。

    如图中所示:
    应用程序中调用: printf 函数, 调用函数库中的printf 函数:
    接口函数: 存在于c 函数库中的 write接口函数,
    系统函数: write 接口函数 调用系统内部实现功能的 write 函数,
    在这里插入图片描述

    2.2 系统调用功能号

    3. 图形按钮的系统调用接口

    1. 鼠标 点击下去, 通过中断 捕获点击, 放入到系统内部中的 消息队列中;
    2. 应用程序需要有一个函数, 该函数实现了系统调用: (get Message:
      功能是读取操作系统内核中的消息队列, 将其中的消息一个个 读入到应用程序中;
    3. 根据 取出的消息类型不同, 执行该消息所对应的函数;

    消息处理机制

    • 一个循环调用一个函数,该函数不断从内核中将消息取出来。
    • 每取出一个消息, 都会调用与之对应的消息处理函数。
  • 相关阅读:
    3_springboot_shiro_jwt_多端认证鉴权_Redis缓存管理器.md
    SpringBoot配置输出的日志文件
    【Java并发编程 】同步——volatile 关键字
    vue3+vite+jest配置 单元测试总结
    8位bmp文件获取像素
    MySQL 最朴素的监控方式
    Java字符/字符串互转
    go底层TCP网络编程剖析
    mybatis—plus
    Unity 工具 之 Azure 微软 【GPT4o】HttpClient 异步流式请求的简单封装
  • 原文地址:https://blog.csdn.net/chumingqian/article/details/128142172