程序员自我修养笔记:第12章

第 12章 系统调用原理
1.普通应用程序运行在用户态下,唯一进入内核态的方式就是通过系统中断。中断分硬件中断和软件中断,软件中断一般以int 0x80号进入系统中断处理程序。中断号很好,因此一般中断号与系统调用都是1对多的关系。而Linux下的都是通过0x80号中断来触发系统调用。而通过eax传递系统调用号,参数用其他寄存器传递。
而中断的触发还伴随着用户栈到内核栈的转变,并且将ss,esp,eflags,cs,ip压入内核栈方便返回用户程序。这一切都是由int通过硬件自动完成。
0x80号的中断处理程序先是把6个用作系统调用参数的寄存器压栈,然后判断调用号没有超过边界,最后通过sys_call_table存储的系统调用表间接调用系统调用。
系统调用函数执行时,则直接通过栈获取参数,每个函数前都有asmlinkage标识符,指示编译器这个函数只从栈上获取参数。

2.由于基于int指令的系统调用在奔腾4代处理器上性能不好,于是Linux在2.5版本开始支持新型的系统调用机制,其支持一组专用的系统调用指令–sysenter和sysexit。
ldd命令获取可执行文件的共享库依赖情况时,可以看到一个共享库Linux-gate.so.1没有与任何实际文件相对应。因为它只是操作系统生成的一个虚拟动态共享库(VDSO),它总是被加载在地址0xffffe000。
通过
dd if=/proc/self/mem of=Linux-gate.dso bs=4096 skip=1048574 count=1
将它导出到一个真实文件内。
通过objdump -T可以看到vdso导出了一系列函数,其中__kernel_vsyscall函数。
通过objdump -d --start-address= --stop_address= 反汇编查看该函数前8个字节
可以看到sysenter.调用它后,系统直接跳转到某个寄存器指定的函数执行,并自动完成特权级转化,堆栈切换等功能。
参数传递上跟使用int的系统调用完全一样。也是通过这6个寄存器传递参数,内核里也是SAVE_ALL将参数置栈。

3.Windows API
Windows API是指在Windows操作系统提供给应用程序开发者的最底层、最直接与Windows打交道的接口。在Windows下,CRT是建立在Windows API之上的。还有很多对Windows API的各种包装库,比如MFC就是著名的以C++形式封装的库。
也就是说调用Windows API时并没有进入内核,而是在Windows API中调用系统调用。
而不像Linux那样,运行库直接调用系统调用。
Windows API是以dll导出函数形式暴露给应用程序的。微软把这些Windows API DLL的声明头文件、导出库、相关文件和工具一起提供给开发者,称为SDK
SDK可以单独下载,可可能被集成到VS这样的开发工具中。
在Windows NT中,所有DLL实现上都会依赖一个更底层的DLL叫做NTDLL.DLL,由它进行系统调用。
由于Windows API还比较原始,Windows在API之上还建立很多应用模块,这些模块是对Windows API的功能的扩展。
Windows API的目的在于提供应用程序的向后兼容性。因为系统调用实际是非常依赖硬件结构的接口。
其次是提供Windows本身不同版本的内核的兼容性。
Windows API以DLL的形式存在也是因为DLL本身是Windows系统的最基本的模块组织形式。
为了兼容Windows之外的操作系统,希望提供提供各种操作系统的执行环境,以兼容他们的应用程序。
子系统又被称为Windows环境子系统(Environment Subsystem)。
子系统实质上又是Windows假设在API和应用程序之间的另一个中间层。
子系统要实现二进制级别的兼容性十分困难,于是他的目标就是源代码级别的兼容,也就是实现其他操作系统的所有接口。
但是Windows子系统实际上已经被抛弃了,懂得都懂。

猜你喜欢

转载自blog.csdn.net/weixin_45719581/article/details/123207858