Linux内核的系统调用---linux内核学习笔记(四)
内容一:实验报告相关说明。
所学课程:《Linux内核分析》MOOC课程
链接:http://mooc.study.163.com/course/USTC-1000029000
代码来源于孟宁老师的课件
虚拟实验室实验截图
实验结果图
实验代码截图
内容二:个人程序简介
嵌入汇编的代码如下
1 #include <stdio.h> 2 #include <unistd.h> 3 int main() 4 { 5 int t=0; 6 asm volatile( 7 "mov $0,%%ebx\n\t" 8 "mov $0x40,%%eax\n\t" 9 "int $0x80\n\t" 10 "mov %%eax,%0\n\t" 11 :"=m"(t) 12 ); 13 // t = getppid(); 14 printf("the number of pid is:%d",t); 15 }
整个嵌入汇编代码的作用就等价于 t = getppid();
个人使用的系统调用是
64 i386 getppid sys_getppid
十进制数64转为16进制为 0x40
getppid 的作用:取得父进程的进程识别码,对应头文件为#include<unistd.h>
内容三:嵌入式代码分析
系统调用通过软中断向内核发出明确请求。
1:内核实现了很多不同的系统调用,进程必须指明需要哪个系统调用,这需要传递一个名为系统调用号的参数,需要使用eax寄存器,
因为我用的系统调用对应的调用号为 0x40所以通过如下指令:
"mov $0x40,%%eax\n\t" 告诉内核,自己需要的系统调用为 getppid。
2:int $0x80 为AT&T语法的中断指令。这条汇编指令产生向量为128的编程异常,这个编程异常对应的是系统门描述符,门描述符中含有一个预设的内核空间地址,它指向了系统调用处理程序:system_call(),所有的系统调用都会统一地转到这个地址。Linux为每个系统调用都进行了编号(0—NR_syscall),同时在内核中保存了一张系统调用表,该表中保存了系统调用编号和其对应的服务例程,因此在系统调入通过系统门陷入内核前,需要把系统调用号一并传入内核,这个传递动作是通过在执行int0x80前,把调用号装入eax寄存器实现。即前面的语句。
3:mov %%eax,%0\n\t 函数调用返回的值也存放在寄存器eax中,此语句将系统调用的返回值赋给内存变量t。
内容四:小结
1:了解了X86平台下有4种运行级别,Linux只用了其中2中,一种是内核态,一种是用户态。区分可以看其能够访问的逻辑地址。
用户态进入内核态靠的是中断机制。这个自己之前了解过的 Cortex-M3内核一样,从用户级切换到特权级,需要异常机制。
2:(网上摘抄部分)从逻辑上来说,系统调用可被看成是一个内核与用户空间程序交互的接口,它好比一个中间人,把用户进程的请求传达给内核,
待内核把请求处理完毕后再将处理结果送回给用户空间。系统服务之所以需要通过系统调用来提供给用户空间的根本原因是为了对系统进行“保护”,
Linux的运行空间分为内核空间与用户空间,它们各自运行在不同的级别中,逻辑上相互隔离。所以用户进程在通常情况下不允许访问内核数据,也
无法使用内核函数,它们只能在用户空间操作用户数据,调用用户空间函数,但是很多情况下,用户进程需要获得系统服务(调用系统程序),这时就
必须利用系统提供给用户的“特殊接口”——系统调用了,它的特殊性主要在用户访问内核的路径是事先规定好的,只能从规定位置进入内核,而不准许
肆意跳入内核。系统调用并非直接和程序员或系统管理员打交道,它仅仅是一个通过软中断机制(我们后面讲述)向内核提交请求,获取内核服务的接口。而在实际使用中
程序员调用的多是用户编程接口。
系统调用的整个过程包括
2.1:调用libc库的封装函数,该封装函数将系统调用号压入EAX寄存器。
2.2:触发中断,interrupt(ex:int 0x80)
2.3: SAVE_ALL (具体保存的寄存器参考老师的课程)
2.4:中断服务,内核代码,发生调度
2.5:RESTORE_ALL (与SAVE_ALL相逆)
2.6:iret (该指令与中断信号(包括int指令)发生时cpu做的动作正好相反)
3:初步区分了系统调用,API,和封装例程等概念的区别。不过还是有点混淆。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步