再话Linux系统调用
对用户程序调用系统API的时候,会发生软中断0X80, 在软中断0X80之后做的工作我们开始分析:
说明:出于对他人知识分享的尊重,需要指明本文中关于寄存器的使用参考了司徒彦南先生于2002年4月8日的文档《简明X86汇编语言教程》
//within file linux-3.9.3/arch/x86/kernel/entry-32.S
ENTRY(system_call) //已由用户态陷入到内核态中
RING0_INT_FRAME
ASM_CLAC
pushl_cfi %eax
//非常核心!保存相关寄存器的值,将来如何恢复之前进程的数据全部由这些寄存器来决定
SAVE_ALL
// 通常ebp寄存器被高级语言编译器用以建造‘堆栈帧’来保存函数或过程的局部变量
//
此时可以知道将来返回到那个函数的那个部位
GET_THREAD_INFO(%ebp)
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
jnz syscall_trace_entry
cmpl $(NR_syscalls), %eax
jae syscall_badsys
syscall_call:
//真正的系统调用!sys_call_table就是之前文章中列出的系统调用表的数组
call *sys_call_table(,%eax,4)
movl %eax,PT_EAX(%esp) //保存系统调用的返回值
syscall_exit:
LOCKDEP_SYS_EXIT
DISABLE_INTERRUPTS(CLBR_ANY) //屏蔽其他系统调用
TRACE_IRQS_OFF
//寄存器ecx是通用寄存器,在保护模式中,可以作为内存偏移指针
//(
此时,DS作为 寄存器或段选择器),此时为返回到系统调用之前做准备
movl TI_flags(%ebp), %ecx
testl $_TIF_ALLWORK_MASK, %ecx //TEST 测试.(两操作数作与运算,仅修改标志位,不回送结果).
jne syscall_exit_work
restore_all:
TRACE_IRQS_IRET
restore_all_notrace:
movl PT_EFLAGS(%esp), %eax
# Warning: PT_OLDSS(%esp) contains the wrong/random values if we
# are returning to the kernel.
# See comments in process.c:copy_thread() for details.
movb PT_OLDSS(%esp), %ah
movb PT_CS(%esp), %al
andl $(X86_EFLAGS_VM | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax
cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
CFI_REMEMBER_STATE
je ldt_ss //返回到用户空间,系统调用返回
restore_nocheck:
RESTORE_REGS 4 //忽略orig_eax和error_code
irq_return:
INTERRUPT_RETURN
其中比较重要的SAVE_ALL到底保存了哪些重要的寄存器,我们列出代码来欣赏一下:
//within file linux-3.9.3/arch/x86/kernel/entry_32.S
.macro SAVE_ALL
cld
PUSH_GS
pushl_cfi %fs
/*CFI_REL_OFFSET fs, 0;*/
pushl_cfi %es
/*CFI_REL_OFFSET es, 0;*/
pushl_cfi %ds
/*CFI_REL_OFFSET ds, 0;*/
pushl_cfi %eax
CFI_REL_OFFSET eax, 0
pushl_cfi %ebp
CFI_REL_OFFSET ebp, 0
pushl_cfi %edi
CFI_REL_OFFSET edi, 0
pushl_cfi %esi
CFI_REL_OFFSET esi, 0
pushl_cfi %edx
CFI_REL_OFFSET edx, 0
pushl_cfi %ecx
CFI_REL_OFFSET ecx, 0
pushl_cfi %ebx
CFI_REL_OFFSET ebx, 0
movl $(__USER_DS), %edx
movl %edx, %ds
movl %edx, %es
movl $(__KERNEL_PERCPU), %edx
movl %edx, %fs
SET_KERNEL_GS %edx
.endm
已经比较明了的知道了,用户进程发生系统中断之后内核所做的工作了,并且也知道了系统调用中断之后是如何保存的返回值,并正确的返回到用户空间。 Happy coding!
还没有评论,来说两句吧...