2019-2020-1 20199320《Linux内核原理与分析》第五周作业

第四章 系统调用的三层机制(上)

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

  1. Intel x86 CPU有4种不同的执行级别,分别是0、1、2、3,数字越小,特权越高,而Linux只采用了0,3两个特权级别,分别对应内核态和用户态。
  2. 内核态和用户态的区别:内核态时,CS:EIP的值可以是任意地址,用户态时只能访问0x00000000~0xbfffffff的地址空间。
  3. 进入内核态的两种方式:
    (1)可能是硬件中断
    (2)可能是用户态执行程序时调用了一个系统调用,陷入了内核态,叫做Trap.
  4. 用户切换到内核态时,会保存用户态寄存器上下文(包括用户态栈顶指针、当时的状态字、当时的CS:EIP的值),同时,要把内核态的寄存器的值放到当前CPU中。

二、系统调用

  1. 含义:操作系统为用户态进程与硬件设备进行交互提供的一组接口。
  2. 功能(特性):把用户从底层的硬件编程中解救出来;极大地提高系统的安全性;使用户程序具有可移植性。
  3. API:应用程序编程接口,内部使用了系统调用的封装例程,主要目的是发布系统调用。
  4. API和系统调用的关系:一个API对应一个或多个系统调用,一个系统调用可能被多个API调用。不涉及与内核交互的API内部不会封装系统调用。

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

(以sys_rename()给文件重命名的函数为例)

  1. 使用库函数API触发一个系统调用

    C语言代码如下:

    执行结果如下图:

  2. 汇编语言触发系统调用

    汇编代码如下:

    执行结果如下图:

分析:

主要汇编代码如下:

asm volatile("movl %2,%%ecx\n\t" //newname存入ecx 

      "movl %1,%%ebx\n\t" //oldname存入ebx 

      "movl $0x26,%%eax\n\t" //系统调用号存入eax 

      "int $0x80" //触发系统调用,陷入内核态

      :"=a"(ret) 

      :"b"(oldname),"c"(newname) );

这里,把系统调用号38(16进制是0x26)存入 eax,将 oldname 存入 ebx,将 newname 存入 ecx,通过执行 int $0x80 来执行系统调用,使应用程序陷入内核态,system_call 根据传入的系统调用号在系统调用列表中查找对应的内核函数,根据 ebx 和 ecx 中保存的参数调用内核函数 sys_rename,执行完后将执行结果存放到 eax 中,最后返回 eax 中的值。

四、总结:

本章主要学习了系统调用的3层机制的系统调用工作机制:当用户态进程调用一个系统调用时,CPU切换到内核态并开始执行system_call和系统调用内核函数。具体来说,通过执行int $0x80来触发系统调用,进入内核后,开始执行中断向量为128对应的中断服务程序system_call,这时,通过系统调用号将API函数和系统调用内核函数关联起来,这里需要EAX寄存器传递系统调用号。

猜你喜欢

转载自www.cnblogs.com/liangxu111/p/11701615.html