区别
用户态:供应用程序运行的空间,只能受限制地访问内存
内核态:控制计算机的硬件资源,例如协调CPU资源,分配内存资源,并且提供稳定的环境
为什么要划分
1. 安全性
给不同的操作给与不同的“权限”。有些指令是非常危险的,如果错用,将导致系统崩溃,比如清内存、设置时钟等。如果允许所有的程序都可以使用这些指令,那么系统崩溃的概率将大大增加。
2. 稳定性
隔离了操作系统代码与应用程序代码。即便是单个应用程序出现错误也不会影响到操作系统的稳定性,其它的程序还可以正常的运行。
如何从用户态进入内核态
1. 系统调用
系统调用的实现(2种)
中断方式
在 Linux 的实现中,所有的系统调用共用 128 号中断,对应中断处理程序是 system_call。system_call 会根据 EAX (某个寄存器) 传入的系统调用标号跳转并执行相应的系统调用程序。函数执行完成之后,会把结果放到 EAX 中返回给应用程序。
SYSENTER 指令
中断方式很多过程都是固定的,如查找中断处理程序入口等,过于冗余。为了省去这些多余的检查,Intel 在 Pentium II CPU 中加入了新的 SYSENTER 指令,专门用来执行系统调用。
系统调用的使用(2种)
glibc
glibc 是 Linux 下使用的开源的标准 C 库。例如C库接口malloc申请动态内存,malloc的实现内部最终还是会调用 brk() 或者 mmap() 系统调用来分配内存。
syscall
系统调用函数,包含在#include
int access(const char *pathname, int mode); // 检查用户对文件的权限
int brk(void *addr); // 更改程序中断的位置,增加程序中断的次数会给进程分配内存;减少中断会释放内存。
int dup(int oldfd); // 复制文件描述符
int execve(const char *pathname, char *const argv[], char *const envp[]); // 替换当前进程的用户空间,从而执行一个新程序的代码
pid_t fork(void); // 创建进程
int ioctl(int fd, unsigned long request, ...); // io设备控制,可以设置io设备的参数
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); // 映射或者解除映射一个文件/设备到内存
int stat(const char *restrict pathname, struct stat *restrict statbuf); // 获取文件信息
long syscall(long number, ...); // 是一个小型库函数,它调用系统调用,系统调用的汇编语言接口具有带有指定参数的指定编号。例如,在调用C库中没有包装器函数的系统调用时,使用syscall()是有用的。
2. 中断
过程:关中断-保存断点-中断服务程序寻址-保存现场-开中断-执行中断服务程序-关中断-恢复现场-开中断-中断返回
中断的时机:每条指令的结束检查是否有中断
感觉中断没啥好写的。。待续吧



