窥探 kernel --- 系统调用过程分析
2015-12-23 20:59
381 查看
本系列文章由张同浩编写,转载请注明出处:/article/1391216.html
邮箱:muge0913@sina.com
![](http://my.csdn.net/uploads/201204/28/1335543797_3018.gif)
过程分析:
1、系统调用需要一个用户空间到内核空间的转换,不同的平台有不同的指令来完成这样的转换,这个指令也叫做操作系统陷入(operating systemtrap)指令。在linux中对于x86来说是用软中断0x80,也即是int $0x80。软中断由软件指令触发,硬中断由硬件触发。
通过软中断,系统会跳到一个预定的内核空间。它指向了系统调用处理程序(不是系统调用服务程序)system_call函数(arch/x86/kernel/entry32.h)。如上图。
2、system_call到服务程序
显然所有的系统调用都会跳到这个地址执行system_call函数。在执行int 0x80时系统调用号会被放入eax寄存器中。因为sys_call_table每个项占用4个字节。所以sys_call_table作为基地址,eax*4作为偏移量就可以找到对应的服务程序的地址。
系统调用的参数通过其他寄存器来传递。如
[cpp]
view plaincopyprint?
write(unsignedint fd,const char *buf,size_t count)
寄存器ebx,ecx,esi,edx来传递。但是前面我们说过,asmlinkage表示内核从堆栈中提取参数,而不是寄存器。因为在system_call执行时首先把这些寄存器压入堆栈了。从下面的代码中就可找到答案~~~
[cpp]
view plaincopyprint?
ENTRY(system_call)
RING0_INT_FRAME # can't unwind into user spaceanyway
pushl_cfi%eax # save orig_eax
S***E_ALL
GET_THREAD_INFO(%ebp)
#system call tracing in operation / emulation
testl$_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
jnzsyscall_trace_entry
cmpl$(nr_syscalls), %eax
jaesyscall_badsys
syscall_call:
call*sys_call_table(,%eax,4)
系统服务程序从堆栈中获取参数,并修改,最后再通过堆栈返回修改后的数值。
不是所有的系统调用都有实际内容,如sys_ni_syscll在kernel/sys_ni.c中定义:
[cpp]
view plaincopyprint?
asmlinkage long sys_ni_syscall(void){
return -ENOSYS;
}
你会发现在sys_call_table中sys_ni_syscall占据了很多内容,其实它代表着已被淘汰的系统调用。
[cpp]
view plaincopyprint?
.longsys_ni_syscall /* old stty syscallholder */
.longsys_ni_syscall /* old gtty syscallholder */
.longsys_access
.longsys_nice
.longsys_ni_syscall /* 35 - old ftime syscallholder */
.longsys_sync
.longsys_kill
.longsys_rename
.longsys_mkdir
.longsys_rmdir /* 40 */
.longsys_dup
.longsys_pipe
.longsys_times
.longsys_ni_syscall /* old prof syscallholder */
如上面可知sys_ni_syscall代替了不用的stty和gtty和prof。其实只要是被内核淘汰的系统调用都会被sys_ni_systcall代替。之所以这样是为了老的程序在新的内核上运行时不至于出现大的问题。如不应调用这个系统调用却调用了那个系统调用了。
本系列文章由张同浩编写,转载请注明出处:/article/1391216.html
邮箱:muge0913@sina.com
![](http://my.csdn.net/uploads/201204/28/1335543797_3018.gif)
过程分析:
1、系统调用需要一个用户空间到内核空间的转换,不同的平台有不同的指令来完成这样的转换,这个指令也叫做操作系统陷入(operating systemtrap)指令。在linux中对于x86来说是用软中断0x80,也即是int $0x80。软中断由软件指令触发,硬中断由硬件触发。
通过软中断,系统会跳到一个预定的内核空间。它指向了系统调用处理程序(不是系统调用服务程序)system_call函数(arch/x86/kernel/entry32.h)。如上图。
2、system_call到服务程序
显然所有的系统调用都会跳到这个地址执行system_call函数。在执行int 0x80时系统调用号会被放入eax寄存器中。因为sys_call_table每个项占用4个字节。所以sys_call_table作为基地址,eax*4作为偏移量就可以找到对应的服务程序的地址。
系统调用的参数通过其他寄存器来传递。如
[cpp]
view plaincopyprint?
write(unsignedint fd,const char *buf,size_t count)
write(unsignedint fd,const char *buf,size_t count)
寄存器ebx,ecx,esi,edx来传递。但是前面我们说过,asmlinkage表示内核从堆栈中提取参数,而不是寄存器。因为在system_call执行时首先把这些寄存器压入堆栈了。从下面的代码中就可找到答案~~~
[cpp]
view plaincopyprint?
ENTRY(system_call)
RING0_INT_FRAME # can't unwind into user spaceanyway
pushl_cfi%eax # save orig_eax
S***E_ALL
GET_THREAD_INFO(%ebp)
#system call tracing in operation / emulation
testl$_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
jnzsyscall_trace_entry
cmpl$(nr_syscalls), %eax
jaesyscall_badsys
syscall_call:
call*sys_call_table(,%eax,4)
ENTRY(system_call) RING0_INT_FRAME # can't unwind into user spaceanyway pushl_cfi%eax # save orig_eax S***E_ALL GET_THREAD_INFO(%ebp) #system call tracing in operation / emulation testl$_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp) jnzsyscall_trace_entry cmpl$(nr_syscalls), %eax jaesyscall_badsys syscall_call: call*sys_call_table(,%eax,4)
系统服务程序从堆栈中获取参数,并修改,最后再通过堆栈返回修改后的数值。
不是所有的系统调用都有实际内容,如sys_ni_syscll在kernel/sys_ni.c中定义:
[cpp]
view plaincopyprint?
asmlinkage long sys_ni_syscall(void){
return -ENOSYS;
}
asmlinkage long sys_ni_syscall(void){ return -ENOSYS; }
你会发现在sys_call_table中sys_ni_syscall占据了很多内容,其实它代表着已被淘汰的系统调用。
[cpp]
view plaincopyprint?
.longsys_ni_syscall /* old stty syscallholder */
.longsys_ni_syscall /* old gtty syscallholder */
.longsys_access
.longsys_nice
.longsys_ni_syscall /* 35 - old ftime syscallholder */
.longsys_sync
.longsys_kill
.longsys_rename
.longsys_mkdir
.longsys_rmdir /* 40 */
.longsys_dup
.longsys_pipe
.longsys_times
.longsys_ni_syscall /* old prof syscallholder */
.longsys_ni_syscall /* old stty syscallholder */ .longsys_ni_syscall /* old gtty syscallholder */ .longsys_access .longsys_nice .longsys_ni_syscall /* 35 - old ftime syscallholder */ .longsys_sync .longsys_kill .longsys_rename .longsys_mkdir .longsys_rmdir /* 40 */ .longsys_dup .longsys_pipe .longsys_times .longsys_ni_syscall /* old prof syscallholder */
如上面可知sys_ni_syscall代替了不用的stty和gtty和prof。其实只要是被内核淘汰的系统调用都会被sys_ni_systcall代替。之所以这样是为了老的程序在新的内核上运行时不至于出现大的问题。如不应调用这个系统调用却调用了那个系统调用了。
相关文章推荐
- 欢迎使用CSDN-markdown编辑器
- RMAN实战14:用RMAN恢复ORACLE归档日志、控制文件、spfile及logminer的使用
- 如何获取音乐链接地址
- 初学HTML 需要注意什么
- httponlycookie
- Perl6 -1.0 安装与运行
- 深入理解jQuery插件开发
- 2014年SCI收录遥感学科期刊26种目录
- 面向对象的六大设计原则(四):终结篇
- AC自动机模板
- alibaba-LVS版本发布
- margin:0 auto在IE中失效的解决方案
- html5中拨打电话代码
- JS小知识点----基本包装类型和引用类型
- .NET/C# 各版本变化及衍生知识点 C# 1.0/2.0
- 基础知识《九》---网络编程
- Linux内核启动过程分析
- Mysql 实现 三目运算判断
- Android Framework 概述笔记
- linux设备驱动