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中.

原文地址:https://www.cnblogs.com/mazhuhong/p/13893980.html