• 20179223《Linux内核原理与分析》第五周学习笔记


    视频内容知识学习

    一、用户态、内核态和中断

    1.内核态:处于高的执行级别下,代码可以执行特权指令,访问任意的物理地址,这时的CPU就对应内核态

    2.用户态:处于低的执行级别下,代码只能在级别允许的特定范围内活动。在日常操作下,执行系统调用的方式是通过库函数,库函数封装系统调用,为用户提供接口以便直接使用。

    3.Intel x86 CPU有四种不同的执行级别0-3,Linux只使用了其中的0 3级分别表示内核态和用户态。cs寄存器的最低两位表明了当前代码的特权级,00或者11。

    4.内核态cs:eip的值是任意的,即可以访问所有的地址空间。用户态只能访问其中的一部分内存地址(0x00000000-0xbbbbbbbf),0xc0000000以上的地址(逻辑地址而不是物理地址)只能在内核态下访问。

    5.中断处理是从用户态进入内核态的主要方式,系统调用是一种特殊的中断。从用户态切换到内核态时,中断/int指令会在堆栈上保存用户态的寄存器上下文,其中包括用户态栈顶地址、当时的状态字、当时的cs:eip的值,还有内核态的栈顶地址、内核态的状态字、中断处理程序的入口。中断发生后的第一件事就是保存现场,保存一系列的寄存器的值;中断处理结束前的最后一件事就是恢复现场,退出中断程序,恢复保存寄存器的数据。特别说明: 保护现场:就是进入中断程序,保存需要用到的寄存器的数据;恢复现场:就是退出中断程序,恢复保存寄存器的数据。

    二、系统调用

    1.系统调用的意义:操作系统为用户态进程与硬件设备进行交互提供了一组接口——系统调用。把用户从底层的硬件编程中解放出来,极大的提高了系统的安全性,使用户程序具有可移植性

    2.操作系统提供的API和系统调用的关系。应用编程接口和系统调用是不同的,API只是一个函数定义,系统调用通过软中断向内核发出一个明确的请求

    3.Libc库定义的一些API引用了封装例程(wrapper routine,唯一目的就是发布系统调用)。 一般每个系统调用对应一个封装例程,库再用这些封装例程定义出给用户的API

    4.不是每个API都对应一个特定的系统调用。API可能直接提供用户态的服务,如:一些数学函数,一个单独的API可能调用了几个系统调用,不同的API可能调用了同一个系统调用

    5.返回值。大部分封装例程返回一个整数,其值的含义依赖于相应的系统调用, -1在多数情况下表示内核不能满足进程的请求,Libc中定义的errno变量包含特定的出错码

    6.系统调用的三层皮:xyz、system_call (中断向量)和sys_xyz(中断服务程序)

    7.当用户态进程调用一个系统调用时,CPU切换到内核态并开始执行一个内核函数。在Linux中是通过执行int$0x80来执行系统调用的,这条汇编指令产生向量为128的编程异常,Intel Pentium II 中引入了sysenter指令(快速系统调用),2.6已经支持(本课程不考虑这个)

    8.传参:内核实现了很多不同的系统调用,进程必须指明需要哪个系统调用,这需要传递一个名为系统调用号的参数,使用eax寄存器

    9.系统调用也需要输入输出参数,例如:实际的值,用户态进程地址空间的变量的地址,甚至是包含指向用户态函数的指针的数据结构的地址

    10.system_call是linux中所有系统调用的入口点,每个系统调用至少有一个参数,即由eax传递的系统调用号。一个应用程序调用fork()封装例程,那么在执行into$0x80之前就把eax寄存器的值置为2(即_NR_fork)。这个寄存器的设置是libc库中的封装例程进行的,因此用户一般不关心系统调用号,进入sys_call之后,立即将eax的值压入内核堆栈

    11.寄存器传递参数具有如下限制: 1)每个参数的长度不能超过寄存器的长度,即32位 2)在系统调用号(eax)之外,参数的个数不能超过6个(ebx, ecx,edx,esi,edi,ebp) 3)超过6个怎么办?超过6个的话就把某一个寄存器作为一个指针,指向某一块内存。

    三、使用库函数API来获取系统当前时间


    声明了一个time_t tt的变量,struct tm *ttm为了输出时变成可读的,因为tt是int型的数值,通过gcc time.c -o time -m32运行./time就可获得当前的运行时间

    四、C代码中嵌入汇编代码的写法


    把0赋给eax,add%1指下面输出和输入的部分,“=m”(val3)输出为0,“c”(val1)为1,“d”(val2)为2,“c”指ecx寄存器存储val1的值,把ecx的值赋给eax,%2就是指val2,把它放到edx这个寄存器里面,val1+val2放在eax里面,然后把val1+val2存储的值放到%0,%0就是val3,=m就是写到内存变量里面去,这就实现了val1+val2=val3的功能。

    实验

    C程序库函数实现系统调用

    代码如下:

    #include <stdio.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    int main () {
         int ret = 0;
         ret = mkdir ("./testdir",0777);
         printf ("ret is: %d.
    ",ret);
         return 0;
    }
    

    mkdir函数有两个参数,第一个是待创建的目录名称;第二个是模式,这里设置为0777。

    编译成功并执行,在当前目录下生成目录testdir,如图所示

    C程序嵌入式汇编实现系统调用

    代码如下:

    #include <stdio.h>
    int main () {
      int ret =0;
      char *dir = "./testdir";
      int mode = 0777;
      asm volatile( 
           "movl $39, %%eax
    	"
           "int $0x80
    	"
           "movl %%eax, %0
    	"
            : “=m”(ret)
            :"b"(dir),"c"(mode)
    );
    printf("ret is: %d.
    ",ret);
    return 0;
    }
    

    编译成功并执行,如图所示

    使用汇编实现系统调用的核心知识点有两个:一是如何执行系统调用,二是如果系统调用有参数,如何将参数传给系统调用。

    对于使用汇编语言执行系统调用的方法比较简单,只需要将系统调用的编号传给eax寄存器之后,执行int $0x80指令就可以了,对应代码如下:

    movl $39, %%eax
    int $0x80
    

    对于传参,则需要借助除eax之外的通用寄存器(如:ebx,ecx,edx,csi,cdi),在执行汇编之前将参数依次存入ebc,ecx,....这些通用寄存器即可,对应代码如下

    :"b"(dir),"c"(mode)
    

    这里的“b”代表%ebx寄存器,“c”代表%ecx寄存器。需要注意的是,参数顺序一定要和ebx,ecx,....通用寄存器的顺序一致,如果不一致的话程序就无法正确识别参数。如:写成下面这样的话

    :"c"(dir),"b"(mode)
    

    虽然编译OK,但在执行的时候会报如下错误

    $./a.out
    ret is:-14
    

    程序总结
    通过对系统调用的两种代码实现方法的分析,我们可以知道C语言的API只不过是对OS底层系统调用的一次封装而已,本质上是通过系统中断实现的。

    实验问题

    如图所示

    在定义char *dir="./testdir1";为什么生成的目录是testdir?如图所示

    第7、8章课程学习

    1.中断就是由硬件来打断操作系统,中断使得硬件得以发出硬件通知给处理器。
    2.中断处理程序与其他内核函数的真正的区别在于,中断处理程序是被内核调用来响应中断的,而它们运行于我们称之为中断上下文的特殊上下文。中断处理程序是上半部——接收到一个中断,它就立即开始执行,能够被允许稍后完成的工作会推迟到下半部。
    3.内核提供的接口包括注册和注销中断处理程序、禁止中断、屏蔽中断线以及检查中断系统的状态。
    4.用于延迟Linux内核工作的三种机制:软中断、tasklet和工作队列。

  • 相关阅读:
    Javascript 闭包
    纯CSS实现侧边栏/分栏高度自动相等
    css实现16:9的图片比例
    CSS实现宽高成比例缩放
    div等比例缩放-------纯CSS实现自适应浏览器宽度的正方形
    websocket 实现简单网页版wechat
    Flask 简单使用,这一篇就够了!
    图灵机器人 V1 和 V2 接入方法
    Django中的cookie和session
    django 三件套(render,redirect,HttpResponse)
  • 原文地址:https://www.cnblogs.com/9223lx/p/7728125.html
Copyright © 2020-2023  润新知