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