Linux从用户层到内核层系列 – TCP/IP协议栈部分系列11: 再话Linux系统调用

释放双眼,带上耳机,听听看~!

再话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!

给TA打赏
共{{data.count}}人
人已打赏
安全运维

WordPress网站专用docker容器环境带Waf

2020-7-18 20:04:44

安全运维

运维安全-Gitlab管理员权限安全思考

2021-9-19 9:16:14

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索