2.9. I386体系中系统调用实现
linux实现系统调用有两种机制:
lcall7/lcall27调用方式;
0x80号软中断;
Linux附带的程序使用0x80方式,同时外来程序如UNIX (Solaris, UnixWare 7等)使用lcall7机制。由于历史原因,lcall7机制包含了lcall27机制,但是处理函数却命名为lcall7_func,所以这是令人误解的。
当系统启动时,arch/i386/kernel/traps.c:trap_init函数被调用,设置IDT,这样向量0x80就指向了arch/i386/kernel/entry.S文件中描述的系统调用向量表的地址。
当一个用户空间的应用触发系统调用时,参数由寄存器传递,并且应用执行'int 0x80'指令。这个指令进入内核模式,然后处理器跳转到system_cal入口。具体如下:
1) 保存寄存器;
2) 为KERNEL_DS设置%ds 和 %es,这样所有相关数据(和额外的段)就在内核地址空间被建立。
3) 如果%eax的值大于NR_syscalls (当前是 256),返回ENOSYS错误。
4) 如果任务满足tsk.>;ptrace & PF_TRACESYS 条件,则执行专门处理。这用于支持strace 或者debugger这样的程序。
5) 调用sys_call_table+4*(syscall_number from %eax)。这个表在同一个文件arch/i386/kernel/entry.S中初始化,指向各自的系统调用处理函数,在linux下这些函数以sys_开头。这些C系统调用处理函数在堆栈中获取他们的参数。
6) 进入系统调用(system call return path)。这个部分不仅被0x80使用,而且被lcall7, lcall27使用。它处理任务tasklets,检查是否需要调用schedule,检查是否有信号待处理,如果是,则处理这些信号。
Linux系统为系统调用提供6个参数支持。他们分别寄存于%ebx, %ecx, %edx, %esi, %edi,%ebp。系统调用号存储到%eax。
linux内核启动(2)——2.9.I386体系中系统调用实现
最新推荐文章于 2024-09-14 19:34:20 发布