澳门新萄京官方网站-www.8455.com-澳门新萄京赌场网址

澳门新萄京官方网站:编制程序中的API函数和种

2019-08-17 作者:澳门新萄京官方网站   |   浏览(55)

操作系统通过系统调用为运营于其上的长河提供劳动。

操作系统通过系统调用为运转于其上的历程提供服务。

具备的工程师在写程序的时候都离不开通过库函数的措施和系统调用打交道

安徽大学大 原创小说转发请注脚出处 《Linux操作系统一分配析》MOOC课程

转自:

当用户态进度发起二个种类调用, CPU 将切换成 内核态 并初步推行贰个 内核函数 。 内核函数担当响应应用程序的渴求,举个例子操作文件、进行网络通信大概申请内部存款和储蓄器能源等。

当用户态进程发起一个系统调用, CPU 将切换到 内核态 并先河奉行四个内核函数 。 内核函数负担响应应用程序的要求,举个例子操作文件、进行互连网通信大概申请内部存款和储蓄器能源等。

哪些是用户态和内核态?(从CPU指令品级的角度)

用户态、内核态和制动踏板管理进程

程序员通过库函数的章程和系统调用打交道,库函数把系统调用给封装起来了。
诚近来世CPU都有二种不一致的通令实践等第
♦ 在高施行等第下,代码能够举行特权指令,访谈大肆的物理地址,这种CPU施行等级就对应着内核态
♦ 而在对应的低档别施行情状下,代码的掌握控制范围会遇到限制。只可以在对应等第允许的界定内运动
♦ 比方:intel x86 CPU有各个不一样的实践等第0-3,Linux只行使了在那之中的0级和3级分别来表示内核态和用户态


初稿地址:Linux 编制程序中的API函数和种类调用的关联 作者:up哥小号

原稿地址:https://learn-linux.readthedocs.io
玩转Linux旧群已满,请加新群:278378501。
应接关心我们的众生号:小菜学编程 (coding-fan)

举贰个最简单易行的事例,应用进度供给输出一行文字,必要调用 write 那些系统调用:

诚如当代CPU皆有三种差别的授命实行等第,什么样的顺序能够施行什么样的吩咐
在高试行品级下,代码能够进行特权指令,访问轻易的情理地址,那时CPU实施等第就对应着内核态
而在对应的低档别试行景况下,代码的掌握控制范围会面临限制。只可以在对应品级允许的界定内活动
比喻:intel x86 CPU有各类分化的实践品级0-3,Linux只利用了个中的0级3级个别来表示内核态用户态

干什么有权力级其余分割

谨防程序猿违规访谈系统或然是别的能源而使得系统崩溃

 

举四个最简便易行的例证,应用进度须求输出一行文字,要求调用 write 这几个种类调用:

hello_world.c

什么样区分用户态和内核态?(从进程地址空间的角度)

Linux中怎么分裂用户态和内核态:

♦ cs存放器的最低两位申明了近期代码的特权级
♦ CPU每条指令的读取都以通过cs:eip那多少个寄放器:
其间cs是代码段选择寄放器,eip是偏移量寄放器。
♦ 上述剖断由硬件实现
♦ 一般的话在Linux中,地址空间是一个远近出名的注脚:
0xc0000000之上的地址空间只好在内核态下访谈,0x00000000-0xbfffffff的地方空间在三种意况下都能够访谈
注意:这里所说的地方空间是逻辑地址实际不是情理地址

在内核态时,cs和eip能够是随意的地方


API:(Application Programming Interface,应用程序编制程序接口)
  指的是我们用户程序编程调用的如read(),write(),malloc(),free()之类的调用的是glibc库提供的库函数。API直接提需求用户编制程序使用,运维在用户态。
  大家平常谈到的POSIX(Portable Operating System Interface of Unix)是本着API的正统,即针对API的函数名,重返值,参数类型等。POSIX包容也就内定那一个接口函数包容,可是并不管API具体哪些达成。

#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    char *msg = "Hello, world!n";
    write(1, msg, strlen(msg));

    return 0;
}
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
 char *msg = "Hello, world!n";
 write(1, msg, strlen(msg));

 return 0;
}

cs贮存器的最低两位注脚了当前代码的特权级
CPU每条指令的读取都以因而cs:eip那四个寄放器:
      个中  cs是代码段采用寄放器,eip是偏移量存放器
上述剖断由硬件完毕

停顿管理是从用户态步向内核态首要的不二秘诀

用户态进入内核态一般的话都是用中断来触发的,大概是硬件中断。也可能是用户态程序运维此中调用了系统调用踏入了内核态(trap)。系统调用是一种极其的行车制动器踏板。

♦ 存放器上下文
– 从用户态切换来内核态时
• 必须保留用户态的寄放器上下文,同不常间内核态相应的值放到CPU中
• 要保存哪些?
• 保存在哪个地方?
♦ 中断/int指令会在库房上保留一些寄放器的值
– 如:用户态栈顶地址、当时的状态字、当时的cs:eip的值

系统调用
  通过软中断或种类调用指令向基础发出一个眼看的央求,内核将调用内核相关函数来兑现(如sys_read(),sys_write(),sys_fork())。用户程序不能够直接调用这么些Sys_read,sys_write等函数。那些函数运转在内核态。

注解

读者恐怕会微微难题——输出文本不是用 printf 等函数吗?

确实是。 printf 是越来越高等级次序的库函数,创立在系统调用之上,达成数量格式化等功效。 因而,本质上照旧系统调用起决定性效能。

注解

在三十一个人x86的机器上,有4G的进程地址空间(逻辑地址),在内核态的时候全都能够访谈,在用户态的时候,只好访谈0x00000000-0xbfffffff的地方空间。也正是说0xc0000000以上的地方空间只可以在内核态下访谈

暂停产生后率先件事正是保留现场 SAVE_ALL

维护现场 正是踏入暂停程序,保存供给利用的贮存器的多少
东山复起现场 就是脱离中断程序,复苏保存贮存器的数量

两侧境海关系:

调用流程

那么,在应用程序内,调用两个种类调用的流程是怎样的啊?

我们以多少个倘使的系统调用 xyz 为例,介绍一遍系统调用的富有环节。

澳门新萄京官方网站 1

如上图,系统调用执行的流程如下:

  1. 应用程序 代码调用系统调用( xyz ),该函数是三个包装系统调用的 库函数 ;
  2. 库函数 ( xyz )担任筹划向基础传递的参数,并触发 软中断 以切换来根本;
  3. CPU 被 软中断 打断后,执行 停顿管理函数 ,即 系统调用管理函数 ( system_call);
  4. 系统调用管理函数 调用 系统调用服务例程 ( sys_xyz ),真正起首拍卖该种类调用;

读者大概会有个别难点——输出文本不是用 printf 等函数吗?

暂停管理是从用户态步入内核态首要的方式

停顿管理达成前最终一件事是还原现场 RESTORE_ALL

澳门新萄京官方网站 2

  平时API函数库(如glibc)中的函数会调用封装例程,封装例程担负发起系统调用(通过发软中断或系统调用指令),这么些都运作在用户态。内核开首抽出系统调用后,cpu从用户态切换来内核态(cpu处于什么情形,程序就叫处于什么样意况,所以重重地点也说程序从用户态切换成内核态,实际是cpu运营等级的切换,平常cpu 运维在3级表示用户态,cpu 运维在0级表示内核态),内核调用相关的内核函数来拍卖再慢慢再次来到给封装例程,cpu举办三回内核态到用户态的切换,API函数从包装例程获得结果,再管理完后回来给用户。
 可是API函数不料定需求展开系统调用,如某个数学函数,不要求开始展览系统调用,直接glibc里面就给处理了,整个经过运营在用户态。
  所以作为我们编写linux用户程序的时候,是无法平素调用内核里面的函数的,内核里面包车型客车函数位于进度设想地址空间里面包车型地铁基业空间,用户空间函数及函数库都处于进度设想地址空间里面包车型客车用户空间,用户空间调用内核空间的函数唯有两个坦途,那些通道就是系统调用指令,所以一般要调用glibc等库的接口函数,glibc也是用户空间的,但glibc自个儿完毕了调用特殊的宏汇编系统调用指令张开cpu运市价况的切换,把进度从用户空间切换成基本空间。

试行态切换

应用程序 ( application program )与 库函数 ( libc )之间, 系统调用管理函数 ( system call handler )与 系统调用服务例程 ( system call service routine )之间, 均是常见函数调用,应该简单掌握。 而 库函数 与 系统调用管理函数 之间,由于涉及用户态与内核态的切换,要复杂一些。

Linux 通过 软中断 实现从 用户态 到 内核态 的切换。 用户态 与 内核态 是单独的实行流,因而在切换时,必要准备 执行栈 并保存 寄存器 。

根本落成了成都百货上千两样的连串调用(提供分裂功用),而 系统调用管理函数 唯有一个。 因而,用户进度必须传递贰个参数用于区分,那就是 系统调用号 ( system call number )。 在 Linux 中, 系统调用号 一般经过 eax 寄存器 来传递。

总结起来, 实行态切换 进度如下:

  1. 应用程序 在 用户态 图谋好调用参数,施行 int 指令触发 软中断 ,中断号为 0x80 ;
  2. CPU 被软中断打断后,试行相应的 停顿管理函数 ,这时便已步入 内核态 ;
  3. 系统调用管理函数 准备 基本执行栈 ,并保留全数 寄存器 (一般用汇编语言达成);
  4. 系统调用管理函数 根据 系统调用号 调用对应的 C 函数—— 系统调用服务例程 ;
  5. 系统调用处理函数 准备 返回值 并从 内核栈 中恢复 寄存器 ;
  6. 系统调用管理函数 执行 ret 指令切换回 用户态 ;

当真是。 printf 是更加高档案的次序的库函数,创设在系统调用之上,完成多少格式化等功能。 由此,本质上或许系统调用起决定性功效。

当从用户态切换来内核态的时候,必须用户态的贮存器上下文物保护存起来,同时设置内核态的存放器内容
停顿/int指令会在仓房上保留一些寄存器的值
      如:用户态栈顶地址、当时的状态字、当时的 cs:eip 的值
再正是设置内核态的栈顶地址、内核态的状态字,中断管理程序的进口地址 cs:eip 的值(对于系统调用来说,它是指向system_call函数)

停顿管理的总体进程

澳门新萄京官方网站 3


用户态函数实践全经过(这里只讲要求开始展览系统调用的函数)澳门新萄京官方网站 4

编制程序实施

下面,通过一个简短的次序,看看应用程序怎么样在 用户态 计划参数并经过 int 指令触发 软中断 以陷入 内核态 执行 系统调用 :

.section .rodata

msg:
    .ascii "Hello, world!n"

.section .text

.global _start

_start:
    # call SYS_WRITE
    movl $4,  
		

本文由澳门新萄京官方网站发布于澳门新萄京官方网站,转载请注明出处:澳门新萄京官方网站:编制程序中的API函数和种

关键词: