标签:
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
【知识点梳理】
(一)用户态、内核态和中断处理过程
1.内核态:在高的执行级别下,代码可以执行特权指令,访问任意的物理地址,这时的CPU就对应内核态
2.用户态:在低级别的指令状态下,代码 只能在级别允许的特定范围内活动。在日常操作下,执行系统调用的方式是通过库函数,库函数封装系统调用,为用户提供接口以便直接使用。
3.在Linux下0级表示内核态,3级表示用户态。
4.内核态cs:eip的值是任意的,即可以访问所有的地址空间。用户态只能访问其中的一部分内存地址。
5.中断处理是从用户态进入内核态的主要方式,系统调用是一种特殊的中断。中断/int指令会在堆栈上保存用户态的寄存器上下文,其中包括用户态栈顶地址、当时的状态字、cs:eip的值,以及内核态的栈顶地址、当时的状态字、中断处理程序入口。中断处理结束前的最后一件事就是恢复现场,退出中断程序,恢复保存寄存器的数据。
例:
interrupt(ex:int 0X80)//发生系统调用 save
cs:eip/ss:esp/eflags(current)to kernel stack //保存cs:eip的值,保存当前堆栈段寄存器当前栈顶和标志位寄存器 load cs:eip(entry of a specific ISR)andss:eip(point to kenerl stack) //把当前的中断信号或系统调用相关中断服务例程入口加载到cs:eip中,把当前的堆栈段和esp加载到CPU
SAVE_ALL//保存现场 ...//内核代码,完成中断服务,发生进程调度
RESTORE_ALL//恢复现场
iret - pop cs:eip/ss:esp/eflags from kernel stack//iret对应相反的中断指令
中断发生后的第一件事就是保存现场,结束前最后一件事是恢复现场。
中断处理的完整过程
(二)系统调用概述
系统调用概述和系统调用的三层皮
1.系统调用的意义
操作系统为用户态进程与硬件设备进行交互提供了一组接口——系统调用
2.API和系统调用
API是一个系统调用封装成的一个函数定义
系统调用通过软中断向内核发出一个明确的请求
Libc库定义的一些API引用了封装例程,目的是发布系统调用,让程序员写代码的时候可以通过函数调用而非汇编指令触发一个系统调用
一般每个系统调用对应一个封装例程,库再用这些封装例程定义出给用户的API
应用编程接口(application program interface, API) 和系统调用是不同的
不是每个API都对应一个特定的系统调用。
返回值
3.应用程序、封装例程、系统调用处理程序及系统调用服务例程之间的关系
系统调用的三层皮:xyz(API)、system_call(中断向量)、sys_xyz(中断服务程序)
(1)系统调用程序及服务例程
当用户态进程调用一个系统调用时,CPU切换到内核态并开始执行一个内核函数。
传参:
(2)参数传递
系统调用也需要输入输出参数,例如
system_call是linux中所有系统调用的入口点,每个系统调用至少有一个参数 ,即由eax传递的系统调用号
(三)使用库函数API和C代码中嵌入汇编代码触发同一个系统调用
1.使用库函数API获取系统当前时间
2.C代码中嵌入汇编代码的方法(复习)
3.使用C代码中嵌入汇编代码触发系统调用获取系统当前时间
三、作业
1.实验过程
分析汇编代码调用系统调用的工作过程,特别是参数的传递的方式等。
(1)通过库函数chomd函数改变文件的权限为只读
代码如下:
#include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <stdio.h> int main() { int rc; rc = chmod("/etc/passwd", 0444); if (rc == -1) fprintf(stderr, "chmod failed, errno = %d\n", errno); else printf("chmod success!\n"); return 0; }
在普通用户下编译运用,输出结果为:
上面系统调用返回的值为-1,说明系统调用失败,错误码为1,
即无权限进行该操作,我们以普通用户权限是无法修改 /etc/passwd 文件的属性的,结果正确。
(2)使用C代码中嵌入汇编代码触发系统调用改变文件的权限为只读
代码如下:
#include <stdio.h> #include <sys/types.h> #include <sys/syscall.h> #include <errno.h> int main() { long rc; char *file_name = "/etc/passwd"; unsigned short mode = 0444; asm( "int $0x80" : "=a" (rc) : "0" (SYS_chmod), "b" ((long)file_name), "c" ((long)mode) ); if ((unsigned long)rc >= (unsigned long)-132) { errno = -rc; rc = -1; } if (rc == -1) fprintf(stderr, "chmode failed, errno = %d\n", errno); else printf("success!\n"); return 0; }
如果 eax 寄存器存放的返回值(存放在变量 rc 中)在 -1~-132 之间,就必须要解释为出错码(在/usr/include/asm-generic/errno.h
文件中定义的最大出错码为 132),这时,将错误码写入 errno 中,置系统调用返回值为 -1;否则返回的是 eax 中的值。
结果如图:
上面程序在 32位Linux下以普通用户权限编译运行结果与前面两个相同。
2.总结
LINUX内核分析第四周学习总结——扒开应用系统的三层皮(上)
标签:
原文地址:http://www.cnblogs.com/huangbobo/p/5284376.html