本周的实验浅析了系统调用的工作过程,下面通过使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用加深对其过程的理解。
系统调用列表:http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/syscalls/syscall_32.tbl
本次实验使用了20号系统调用getpid来获取当前内核名称和其它信息。
// C语言使用库函数API #include <stdio.h> #include <unistd.h> int main() { pid_t tt; tt = getpid(); printf("%u\n", tt); return 0; }
// C代码中嵌入汇编代码 #include <stdio.h> #include <unistd.h> int main() { pid_t tt; asm volatile ( "movl $0x20, %%eax\n\t" "int $0x80\n\t" "movl %%eax, %0\n\t" :"=m"(tt) ); printf("%u\n", tt); return 0; }
上述两种方法都已实现,截图如下:
C语言内嵌汇编代码要求先声明输出参数,然后声明输出参数值。因为上述代码中不需要传入参数,所以只有一个输出值。
对于内嵌汇编调用 system_call():
1. 系统调用号放入 eax 中。
2. 系统调用的参数,按顺序存入相应寄存器中。
3. 返回值使用 eax 传递值。
因为中断( 包括异常 )是从用户态进入内核态的唯一方式,所以在上述代码中使用了中断( "int $0x80\n\t" 这句 ),然后中断处理程序SAVE_ALL保存现场,随后就进入了内核态进行下一步的操作。
通过本周的作业,更加熟悉了系统调用的本质,以及系统调用和中断的关联。系统调用是用户态和内核态的桥梁,而具体的措施就是中断。上面我们采用内嵌汇编编写的代码,在运行时,通过eax准备系统调用号,使用ebx、ecx等传递具体参数,当我们触发0x80中断时,经过中断处理程序,我们就进入了内核态。
通过这一周的学习,更加熟悉了系统调用的本质,和系统调用与中断的关联。
中断处理的完整过程( 由中断信号或者 int 指令完成 ):
系统调用的三层皮:xyz( API )、system_call( 中断向量 )和 sys_xyz( 服务程序 )。
李若森
原创作品转载请注明出处
《Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000