1.系统调用
系统调用是内核的出口,说的是操作系统提供给用户程序调用的一组特殊接口,从逻辑上来说,
系统调用可以被看做是内核与用户空间交互的接口,好比一个中间人,将用户的请求传达给内核,
当内核处理完了以后再将处理的结果返回给用户,下图是open系统调用与内核交互的一个过程.
2.跟踪进程所调用的系统调用
strace可以看所有的程序的系统调用,不同子系统的系统调用可以用不同的命令查看.
3.中断异常和系统调用的比较
实际上这三者本质上是属于一类的,处理方式上很类似,但是它们也是不尽相同的,
它们的差异:
1.源头不同:
中断是外设发生的请求;
异常是应用程序意向不到的行为产生的错误;
系统调用是应用程序请求OS提供的服务.
2.响应方式不同:
中断是异步的;
异常是同步的;
系统调用既可以是异步也可以是同步.
3.处理机制不同:
中断服务程序整个是在内核态下运行,对用户来说完全是透明的;
异常出现的时候,马上就要执行异常处理程序,此时或杀死进程或重新执行引起异常的指令;
系统调用是用户发出请求以后就在那里等待OS来提供服务.
4.举例说明从用户态函数到系统调用
在程序中调用了fwrite这个函数,这个函数它实际上在libc库中调用了
系统调用write,然后从用户态陷入内核态查找系统调用表,对应的系统
服务例程是sys_write().
5.系统调用的一般处理流程
当用户态的进程调用一个系统调用的时候,它在libc的封装例程中实际上会调用int0x80
或者syscnter指令切换到内核态,而且就开始执行内核的sys_call系统调用处理程序,
这里关键就是sys_call系统调用处理程序,它做什么工作呢?
首先它会在内核态保存大多数寄存器的内容,也就是压栈操作,
然后调用系统调用服务例程处理系统调用,
通过中断的返回指令从系统调用中返回.
6.系统调用的基本概念
系统调用的基本概念:
1.系统调用号:
用来唯一的标识每个系统调用的,它作为系统调用表的下标,到用户空间的进程,执行一个系统调用的
时候,该系统调用号就被用来指明到底执行哪个系统调用服务例程;
2.系统调用表:
用来把系统调用和相应的服务例程关联起来的一张表,该表的sys_call_table数组中,需要特别说明,
不同的内核版本中,系统调用号和系统调用所在的头文件是有所差别的.
上图二中的部分系统调用列表可以看出,
系统调用号存放在%eax寄存器中,
内核的服务例程是以sys打头的,
所在的头文件不尽相同,
参数存放在寄存器中,一般参数不超过六个(包括系统调用号)
7.从用户态跟踪一个系统调用到内核
第一步:在用户程序中调用fork系统调用;
第二步:在libc库中将fork对应的系统调用号放入到%eax寄存器中;
第三步:通过int 0x80陷入到内核态;
第四步:在中断描述符表IDT中查找到系统调用的入口0x80,进入linux内核的entry_32/64.S文件中;
第五步:从sys_call_table中找到sys_fork的入口地址;
第六步:执行fork.c中的do_fork代码,此时就真正地进入到内核来执行这个系统调用了.
第六步:当这个系统调用执行完以后,就通过iret指令返回用户态.
D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\arch\x86\entry\entry_32.S
D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\arch\x86\entry\entry_64.S
D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\arch\microblaze\kernel\syscall_table.S
D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\arch\parisc\kernel\syscall_table.S
D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\arch\m32r\kernel\syscall_table.S
问题:
microblaze,parisc,m32r分别代表什么体系架构?老师上面写的是i386,
为什么我的源码里没有这个分支?
8.系统调用机制的优化
9.系统调用的实例-日志手机系统
系统调用是用户程序与系统打交道的入口,
系统调用的安全直接关系到系统的安全,
如果一个用户恶意地不断调用fork就会导致系统负载增加,
所以如果能够收集到是谁调用了一些有危险的系统调用以及
系统调用的时间或者其他的信息的话,将有助于系统管理员
进行事后的追踪,从而提高系统的安全性.
本示例将在下一讲给出,下一讲也会说到如何添加一个系统调用.
10.小结
系统调用时应用与内核之间的一个接口,
linux内核中系统调用的具体实现是与linux内核结构相关的,
因此在x86,arm下看系统调用的源码的话实际上是很不一样的,
所以针对不同的体系架构大家要有针对性地看不同的源码,
在这里我们只给出了一般性的原理.
下一讲中会给出如何添加一个系统调用,在实际的系统中是否要
添加一个系统调用是要经过认真评估的.
11.动手实践
关于系统调用动手实践是必不可少的,
图中的资料中涉及一些与系统调用相关的性能,上下文切换等深层次问题,
同时也穿插讲述了一些内核的调试方法,希望大家动手实践,在较早的2.6.X
和最新的5.x中调试系统调用日志手机系统,并且给出分析结果.
12.带着思考离开