系统调用和库函数的区别:
1、系统调用的函数实现在内核中
2、库函数实现在函数库里 libxxx.a(静态库) libxxx.so(动态库)
用户态--》内核态:
1、触发0x80中断(系统调用中断)
2、保存程序上下文
3、将系统调用号保存到eax寄存器
系统调用访问设备驱动程序
操作系统的核心部分,即内核,是一组设备驱动程序。他们是一组对系统硬件进行控制的底层接口。为了向用户提供一个一致的接口,设备驱动程序封装了所有与硬件相关的特征。硬件的特有功能通常可以通过ioctl(用于I/O控制)系统调用来提供。/dev目录中的设备文件的用法都是相同的,他们都可以被打开、读、写和关闭。例如访问普通文件的open调用同样也可以用来访问用户终端、打印机或磁带。
open:打开文件或设备
Read:从打开的设备或文件里读数据
Write:向文件或设备写数据
Close:关闭文件或设备
系统调用:只需要用很少量的函数就可以对文件和设备进行访问和控制。这些函数被称为系统调用。由UNIX(和Linux)直接提供,他们也是通向操作系统本身的接口。
库函数:用于提供用户态服务。
针对输入输出操作直接使用底层系统调用的一个问题是他们的效率非常低。
使用系统调用会影响系统的性能。与函数调用相比,系统调用的开销要大些,因为在执行系统调用时,Linux必须从运行用户代码切换到内核代码,然后再返回用户代码。减少这种开销的一个好方法就是在程序中尽量减少系统调用的次数,并且让每次系统调用完成尽可能多的工作
系统调用运行在内核空间,编写内核代码时就已经实现了该功能,库函数运行于用户空间。
系统调用执行过程:
从程序员的角度看,系统调用无关紧要;他们只需要跟AP打交道就可以了。相反,内核只跟系统调用打交道;库函数及应用程序怎么使用系统调用不是内核所关心的。但是,内核必须时刻牢记系统调用所有潜在的用途并保证他们有良好的通用性和灵活性。系统调用通常通过函数进行调用。通常用一个负的返回值来表明错误。返回一个0值通常表明成功。在Linux中,每个系统调用被赋予一个系统调用号。这样通过这个独一无二的号就可以关联系统调用。当用户空间的进程执行一个系统调用的时候,这个系统调用号就被用来指明到底是要执行那个系统调用;进程不会提及系统调用的名称。系统调用号相当关键,一旦分配就不能再有任何变更,负责编译好的应用程序就会崩溃。此外,如果一个系统调用被删除,它所占的系统调用号也不允许被回收利用。内核记录了系统调用表中的所有已注册过的系统调用的恶劣表,存储在sys_call_table中。Linux系统调用比其他许多操作系统执行要快得多。
用户空间的程序无法直接执行内核代码。他们不能直接调用内核空间中的函数,因为内核驻留在受保护的地址空间上。如果进程可以直接在内核的地址空间上读写的话。系统安全就会失去控制。所以应用程序应该以某种方式通知系统,告诉内核自己需要执行一个系统调用,希望系统切换到内核态,这样内核就可以代表应用程序来执行该系统调用。通知内核的机制是靠软中断(0x80中断)的实现的:通过引发一个异常来促使系统切换到内核态去执行异常处理程序。此时的异常处理程序实际上就是系统调用处理程序。因为所有的系统调用陷入内核的方式都一样,所以仅仅是陷入内核空间是不够的。因此必须把系统调用号一并传给内核。在X86上,系统调用号是通过eax寄存器传给内核的。在陷入内核之前,用户空间就把响应系统所对应的系统调用号放入eax中。这样系统调用处理程序一旦运行,就可以从eaxzhong 得到数据。给用户空间的返回值也通过寄存器传递。在X86系统上,它存放在eax寄存器中。(过程如上图)
5)内核态 用户态区别
内核态:运行操作系统的程序,可以调用一切资源为该操作服务。
用户态:运行用户自己编写的程序,用户可使用的资源受到极大限制。