《Linux内核分析》
第四章 系统调用的三层机制(上)
4.1 用户态、内核态和中断
- 与系统调用打交道的方式是通过库函数的方式
- 用户态与内核态的区分
- 内核态:高的执行级别下,代码可以执行特权指令,访问任意的物理内存
- 用户态:低级别指令
- 系统调用也是一种中断
- 中断处理是从用户态进入内核态的主要方式
当用户态切换到内核态时,就要把用户态寄存器上下文保存起来,同时要把内核态的寄存器的值放到当前CPU中
4.2 系统调用概述
- 系统调用的意义:
错做系统为用户态进程与硬件设备进行交互提供了一组接口 - 系统调用的功能和特性:
- 把用户从底层的硬件编程中解放出来
- 极大地提高系统安全新
使用户程序具有可移植性
4.2.1 操作系统提供的API和系统调用的关系
- API:应用程序编程接口
- 只是函数定义
- 系统调用时通过软中断向内核发出了中断请求
- libc函数库定义的一些API内部使用了系统调用的封装例程,唯一目的是发布系统调用
- 每个系统调用对应一个系统调用的封装例程
- 函数库再用这些封装例程定义出给程序员调用的API
- 不是每个API都对应一个特定的系统调用(一对一,一对多,多对一)
- 返回值
- 大多数系统调用的封装例程返回一个整数,其值的含义依赖于对应的系统调用
- 返回值-1在多数情况下表示内核不能满足进程的请求
- libc中进一步定义的errno变量包含特定的出错码
4.2.2 出发系统调用及参数传递方式
- 当用户态进程调用一个系统调用时,CPU切换到内核态并开始执行一个system_call和系统调用内核函数
- 传参
- 内核实现了很多不同的系统调用
- 使用EAX寄存器传递一个名为系统调用号的参数
4.3 使用库函数API和C代码中嵌入汇编代码触发同一个系统调用
4.3.1 使用库函数API触发一个系统调用
- 代码
#include<stdio.h>
#include<sys/types.h>
int main(void)
{
int u_id;
printf("%u\n",u_id);
return 0;
}
- 运行截图
4.3.2 C代码中嵌入汇编代码出发一个系统调用
- 代码
#include <stdio.h>
#include <unistd.h>
int main(void){
int u_id;
asm volatile(
"movl $0x14, %%eax\n\t" //将系统调用号赋给eax寄存器
"int $0x80\n\t" //执行系统调用
"movl %%eax, %0\n\t" //将系统调用执行后的返回值赋给变量tt
:"=m"(u_id)
);
printf("%u\n",u_id);
return 0;
}
- 运行截图