标签:
郭皓 原创作品转载请注明出处 《Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000
用户态:当进程在执行用户自己的代码时,则称其处于用户态,即此时处理器在特权级最低的(3级)用户代码中运行。
内核态:当一个进程执行系统调用而陷入内核代码中执行时,我们就称进程处于内核态,此时处理器处于特权级最高的(0级)内核代码中执行。
PS:CPU指令执行级别
中断:
用户态和内核态的转换:
中断处理的完整过程
进入中断程序,保存寄存器数据 SAVE_ALL -..//内核代码,完成中断服务,发生进程调度 RESTORE_ALL//退出中断程序,恢复寄存器数据 iret(pop cs:eip/ss:esp/eflags from kernel stack)//对应着中断信号或int指令,与发生时CPU动作相反
系统调用:
这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作。而系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现。
系统调用的意义:
API和系统调用:
应用编程接口(application program interface,API)和系统调用是不同的
Libc库定义的一些API引用了封装例程(wrapper routine,唯一目的就是发布系调用)
不是每个API都对应一个特定的系统调用。
返回值:
应用程序、封装例程、系统调用处理程序及系统调用服务例程之间的关系
xyz():API 其中封装了一个系统调用Intel 0x80触发一个中断
中断向量0x80对应内核代码系统调用起点system_call
中断服务程序(sys_xyz)
系统调用三层皮:
当用户态进程调用一个系统调用时, CPU切换到内核态并开始执行一个内核函数。
传参:
内核实现了很多不同的系统调用,进程必须指明需要哪个系统调用,这需要传递一个名为系统调用号的参数
系统调用也需要输入输出参数,例如
system_call是linux中所有系统调用的入口点,每个系统调用至少有一个参数,即由eax传递的系统调用号
• 寄存器传递参数具有如下限制:
• 1)每个参数的长度不能超过寄存器的长度,即32位
• 2)在系统调用号( eax)之外,参数的个数不能超过6个( ebx,ecx, edx, esi, edi, ebp)
三、实验:使用库函数API和c代码中嵌入汇编代码触发同一系统调用
1.使用库函数API获取系统当前进程pid值
在这里我使用的是获取进程pid的库函数getpid()
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <unistd.h> 5 int main(int argc, const char *argv[]) 6 { 7 pid_t tt; 8 tt = getpid(); 9 printf("%u\n", tt); 10 return 0; 11 }
2.使用c代码中嵌入汇编代码
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <unistd.h> 5 int main(int argc, const char *argv[]) 6 { 7 pid_t tt; 8 asm volatile( 9 "mov $0x14, %%eax\n\t"//系统调用号14放在eax中 10 "int $0x80\n\t" //系统调用中断 11 "mov %%eax, %0\n\t"//取出eax中返回的值 12 :"=m" (tt) 13 ); 14 printf("%u\n", tt); 15 return 0; 16 }
总结:
通过本周的学习,更加熟悉了系统调用的本质,以及系统调用和中断的关联。系统调用是用户态和内核态的桥梁,而具体的措施就是中断。
20135327郭皓--Linux内核分析第四周 扒开系统调用的三层皮(上)
标签:
原文地址:http://www.cnblogs.com/20135327leme/p/5296183.html