Linux从用户层到内核层系列 - TCP/IP协议栈部分系列11: 再话Linux系统调用
来源:互联网 发布:网络原创女歌手郑靖雯 编辑:程序博客网 时间:2024/06/07 17:29
题记:本系列文章的目的是抛开书本从源代码和使用的角度分析Linux内核和相关源代码,byhankswang和你一起玩转linux开发
轻松搞定TCP/IP协议栈,原创文章欢迎交流, byhankswang@gmail.com
欢迎加入到CHLK - Linux开发交流群 QQ:327084515 讨论Linux开发相关问题
再话Linux系统调用
本文是系列博文《Linux从用户层到内核层系列 - TCP/IP协议栈部分系列6:linux 系统调用中断向量表》的姊妹篇,在那篇博文中列举出了X86体系结构32位和64为的中断向量号,本文讲解如何从用户层系统调用进入到该向量表中,并分析在此过程中的用户进程和内核进程的切换,以及在内核执行完系统调用后是如何返回的。
《Linux从用户层到内核层系列 - TCP/IP协议栈部分系列6:linux 系统调用中断向量表》URL:http://blog.csdn.net/byhankswang/article/details/9284023
对用户程序调用系统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!
- Linux从用户层到内核层系列 - TCP/IP协议栈部分系列11: 再话Linux系统调用
- Linux从用户层到内核层系列 - TCP/IP协议栈部分系列6:linux 系统调用中断向量表
- Linux从用户层到内核层系列 - TCP/IP协议栈部分系列1: linux内核协议栈协议的注册
- Linux从用户层到内核层系列 - TCP/IP协议栈部分系列4: IP层IP封包中TTL值何时修改
- Linux从用户层到内核层系列 - TCP/IP协议栈部分系列10:linux内核协议栈中对于socket相关API的实现
- Linux从用户层到内核层系列 - TCP/IP协议栈部分系列7: 基础知识之 - Linux内核源码目录与内核编译选项
- Linux从用户层到内核层系列 - TCP/IP协议栈部分系列2: 协议栈各种协议的初始化
- Linux从用户层到内核层系列 - TCP/IP协议栈部分系列5:内核定时器的定义与使用及STP定时器
- Linux从用户层到内核层系列 - TCP/IP协议栈部分系列8: 基础知识之 - Linux环境变量使用Tip
- Linux从用户层到内核层系列 - TCP/IP协议栈部分系列3: bridge(网桥)FDB表中MAC地址的更新
- Linux从用户层到内核层系列 - TCP/IP协议栈部分系列9: 基础知识之 - 操作系统中常用存储介质详解
- Linux从用户层到内核层系列 - GNU系列之glibc介绍
- Linux从用户层到内核层系列 - 进程管理系列1: 进程之子承父业
- Linux从用户层到内核层系列 - 开源项目之Libxml2
- Linux从用户层到内核层系列 - Kernel compiling: Questions & Note
- Linux从用户层到内核层系列 - GNU系列之你所不知道的printf
- Linux 内核网络协议栈 ------ 数据从接收到ip层
- Linux 内核网络协议栈 ------ 数据从接收到ip层
- shell脚本自动记录登陆后的IP地址和某用户名所操作的历史记录
- 1015:构建矩阵
- iOS多线程
- hdu1231 最大连续子序列
- 1013:摆积木
- Linux从用户层到内核层系列 - TCP/IP协议栈部分系列11: 再话Linux系统调用
- Firebug使用之二--Command Line
- 浙大研究生复试上机考试2005——畅通工程
- Wdk FAQ : [FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO] Why is this flag used here? (minifilter)
- java入门学习(八)数据类型之四类八种基础类型
- 1012:外币兑换
- u-boot简介
- cocos2d-x学习笔记—图片按钮
- C++四种强制转换