第五周学习内容
庖丁解牛Linux内核分析第四章:系统调用的三层机制(上)
Linux内核分析实验四
学到的一些知识
4.1用户态、内核态、中断
- 宏观上Linux操作系统的体系架构分为用户态和内核态
- Intel x86 CPU有4种不同的执行级别,分别是0、1、2、3,数字越小,特权越高,而Linux只采用了0,3两个特权级别,分别对应内核态和用户态,用户态和内核态很显著的区分方法就是CS:EIP的指向范围,拿32位系统来说,总共有2的32次方地址空间,也就是4GB,内核态可以访问全部地址空间,但是用户态只能访问0x00000000~0xbfffffff的地址空间,这里说的地址都是逻辑地址。
- 中断处理是从用户态进入内核态的主要方式
- int指令触发中断机制会在堆栈上保存一些寄存器的值,用户态栈顶地址、当时的状态字、当时的CS:EIP的值。同时会将内核态的栈顶地址、内核态的状态字放入CPU对应的寄存器。
- Linux下系统调用通过int 0x80中断完成
4.2系统调用概述
- 系统调用的意义是操作系统为用户态进程与硬件设备进行交互提供了一组接口,系统调用具有以下功能和特性
- 把用户从底层的硬件编程中解救出来
- 极大地提高系统的安全性
- 使用户程序具有可移植性
- 一般每个系统调用对应一个系统调用的封装例程
- 系统调用的3层机制分别为xyz(),system_call和sys_xyz()
- 内核实现了很多不同的系统调用,用户态进程必须指明需要哪个系统调用,这需要使用EAX寄存器传递一个名为系统调用号的参数,例如调用time需要传入38。
- 内嵌汇编常用的修饰限定符
- abcd代表eax-edx寄存器,q代表将输入变量放入其中任意一个,s代表esi,d代表edi,r代表将输入变量放入其中任意一个。m表示内存变量
实验内容
使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用
我选用了getpid这个系统调用。直接调用如下图:
为了得到getpid对应的调用号,在shell里进入/usr/include/asm文件夹,发现有两个文件,一个是unistd_32.h,另一个是unistd_64.h,分别对应32位和64位系统的系统调用列表,此处我们要在64位下进行系统调用,打开unistd_64.h这个文件,如下所示
查到getpid对应调用号位39,用16进制表示为0x27,根据书中所学,在原C代码中进行修改,加入汇编代码,执行,如下所示