• 2020-2021-1 20209314《Linux内核原理与分析》第五周作业


    系统调用的三层机制

    用户态、内核态和中断

    • 用户态。较低的执行级别,只能访问一部分内存,只能执行一部分指令。
    • 内核态。高级执行级别,可以访问任意物理内存,可以执行特权指令。
    • 中断。系统从用户态进入内核态的主要方式。有硬件中断和软中断。系统调用就是通过软中断进入内核态。
    • Intel x86 CPU有4种不同的执行级别,分别是0、1、2、3,数字越小,特权越高,Linux操作系统中只是采用了其中0和3两个特权级别,分别对应内核态和用户态。
      API和系统调用
    • API(应用程序编程接口)就是系统调用的库函数,是一个函数定义。
    • 系统调用是通过软中断向内核发出了中断请求,int指令的执行就会触发一个中断请求,一般每个系统调用对应一个系统调用的封装例程,函数库再用这些封装历程定义出给程序员调用的API。这样把系统调用最终封装成方便程序员使用的库函数。

    实验:使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

    实现书本中的time()库函数API

    tim.c代码如下:

    #include<stdio.h>
    #include<time.h>
    int main()
    {
            time_t tt;
            struct tm *t;
            tt=time(NULL);
            t=localtime(&tt);
            printf("time:%d:%d:%d
    ",t->tm_year+1900,t->tm_mon+1,t->tm_mday);
            return 0;
    }
    

    运行结果:

    问题:刚开始显示2020 9 28我以为是我的虚拟机时间错误了,然后调用date函数查看了一下发现时间正确,所以我去查了一下localtime的定义,发现localtime是用0表示一月,所以我在程序中做了修改,让显示的月份+1。

    选用exit()系统调用进行实验

    exit.c代码如下:

    #include<stdio.h>
    #include<stdlib.h>
    int main()
    {
            int a;
            while(1)
            {
                    printf("input 1 to exit!
    ");
                    scanf("%d",&a);
                    if(a==1)
                    {
                            exit(0);
                    }
            }
            return 0;
    }
    

    运行结果:

    C代码中嵌入汇编代码,代码如下:

    #include<stdio.h>
    #include<stdlib.h>
    int main()
    {
            int a;
            while(1)
            {
                    printf("input 1 to exit!
    ");
                    scanf("%d",&a);
                    if(a==1)
                    {
                            asm volatile(
                            "movl $0x01,%%eax
    	"
                            "int $0x80
    	"
                            "movl %%eax,%0
    	"
                            :"=m" (exit)
    
                             );
                    }
            }
            return 0;
    }
    

    汇编代码调用系统调用的工作过程

    exit库函数需要的系统调用参数是系统调用号。系统调用的参数按照顺序分别放在ebx、ecx、edx、esi、edi及ebp中。
    资料网站:
    https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/exit.c
    http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/syscalls/syscall_32.tbl
    应用程序在用户态调用API函数,API将封装的系统调用号及参数保存到eax,ebx等寄存器,读取0x80中断向量触发中断,然后陷入内核态,中断服务程序根据系统调用号调用并执行对应的系统调用函数,系统调用函数执行完毕后将结果存放的eax中并返回给程序,程序返回的用户态。
    sys_exit的系统调用号为1,先将其赋给eax,使用int 0x80触发中断,然后中断处理程序保存现场,进程进入内核态。系统调用的返回值使用eax传递。将eax的值保存到定义的exit中.

  • 相关阅读:
    四 闭包函数、装饰器
    三 名称空间与作用域
    二 函数对象、函数嵌套
    一 函数定义
    函数路线
    Django_rest_framework分页
    Django Rest framework序列化流程
    Django Rest framework的限流实现流程
    mysql 数据库查看表的信息
    java JDBC编程流程步骤
  • 原文地址:https://www.cnblogs.com/mazhuhong/p/13893980.html
Copyright © 2020-2023  润新知