前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >system_call到iret过程分析

system_call到iret过程分析

作者头像
De4dCr0w
发布2019-02-27 14:10:54
1.1K0
发布2019-02-27 14:10:54
举报
文章被收录于专栏:二进制漏洞研究

基础知识

中断的分类

(1)中断有两种,一种是由CPU外部硬件产生的,另一种是由CPU本身执行程序的过程中产生的;外部中断即我们所说的中断(interrupt),外部中断是异步的,由硬件产生,我们无法预测它什么时候发生; (2)x86软件产生的中断是由“INT n”同步产生的,由程序产生,只要CPU执行了一条INT指令,就知道在开始执行下一条指令前就会进入中断服务程序,我们又称此类中断为“陷阱”;int 80为系统调用的陷阱号; (3)异常,是被动的,如页面异常,除数为0的异常; 因此系统调用是中断中的陷阱的一种,系统调用只发生在用户空间,必然会发生用户栈和内核栈的切换。

中断的过程

  在linux内核启动过程中,start_kernel中trap_init()函数初始化了中断门,通过set_system_intr_gate->set_gate进行设置,通过write_idt_entry将中断信息写进中断描述符表IDT,中断描述符表(Interrupt Descriptor Table,IDT)是一个系统表,它与每一个中断或异常向量相联系,每一个向量在表中存放的是相应的中断或异常处理程序的入口地址,当处于实模式下时,IDT 被初始化并由 BIOS 程序所使用。然而,一旦 Linux 开始接管,IDT 就被移到另一个区域,并进行第二次初始化。    当中断发生时,通过中断描述符表IDT获取中断服务程序入口地址,调用相应的中断服务程序,而int 0x80的中断服务程序就是system_call

实验过程

修改test.c文件

将fork和fork-asm函数添加到test.c文件中,如下图:

运行效果如下:

system_call代码分析

system_call代码

代码语言:javascript
复制
ENTRY(system_call)
	RING0_INT_FRAME			# can't unwind into user space anyway
	ASM_CLAC
	pushl_cfi %eax			# save orig_eax
	SAVE_ALL
	GET_THREAD_INFO(%ebp)
					# system call tracing in operation / emulation
	testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
	jnz syscall_trace_entry
	cmpl $(NR_syscalls), %eax
	jae syscall_badsys
syscall_call:
	call *sys_call_table(,%eax,4)
syscall_after_call:
	movl %eax,PT_EAX(%esp)		# store the return value
syscall_exit:
	LOCKDEP_SYS_EXIT
	DISABLE_INTERRUPTS(CLBR_ANY)	# make sure we don't miss an interrupt
					# setting need_resched or sigpending
					# between sampling and the iret
	TRACE_IRQS_OFF
	movl TI_flags(%ebp), %ecx
	testl $_TIF_ALLWORK_MASK, %ecx	# current->work
	jne syscall_exit_work

下面我们看看SAVE_ALL执行了哪些操作,对fork系统调用一文中我们对linux-0.11内核版本的进行分析,了解到system_call会保存用户态堆栈的相关寄存器,下面就是对应的保存操作

SAVE_ALL代码

代码语言:javascript
复制
.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

  我们通过syscall_call进行系统调用(这部分已经在fork系统调用一文中阐述过了)后,在syscall_after_call中进行返回,返回的结果保存在eax寄存器中。然后顺序执行到syscall_exit,这部分首先关闭中断,保证不被其它中断和信号打扰。然后判断是否响应其它中断或信号,如果所有标志都没设置,就直接restore_all,恢复原来进程的执行,如果有的话就进入syscall_exit_work。然后判断是否还有任务,如果有就跳转到work_pending。

work_pending代码

代码语言:javascript
复制
work_pending:
	testb $_TIF_NEED_RESCHED, %cl
	jz work_notifysig
work_resched:
	call schedule
	LOCKDEP_SYS_EXIT
	DISABLE_INTERRUPTS(CLBR_ANY)	# make sure we don't miss an interrupt
        ...
	jz restore_all

  在work_pending中先判断NEED_RESCHED位,如果置位了就执行work_resched段代码,被动调度当前进程,调度完还会继续判断是否还有任务,是否还有调度进程,这里是一个循环处理,直到判断没置位,就继续处理当前进程未处理的信号,最后会跳转到resume_userspace,恢复到用户态。

resume_userspace

代码语言:javascript
复制
ENTRY(resume_userspace)
	LOCKDEP_SYS_EXIT
 	DISABLE_INTERRUPTS(CLBR_ANY)	# make sure we don't miss an interrupt
					# setting need_resched or sigpending
					# between sampling and the iret
	TRACE_IRQS_OFF
	movl TI_flags(%ebp), %ecx
	andl $_TIF_WORK_MASK, %ecx	# is there any work to be done on
					# int/exception return?
	jne work_pending
	jmp restore_all
END(ret_from_exception)

  在系统调用或中断,异常返回到用户态之前内核都会检查是否有信号在当前进程中挂起,然后转而去处理这些信号。

具体的从system_call开始到iret结束之间的整个过程如下图:

参考资料: http://www.2cto.com/os/201404/292864.html http://blog.csdn.net/yaozhenguo2006/article/details/7313956 理解系统调用的原理(二)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基础知识
    • 中断的分类
      • 中断的过程
      • 实验过程
        • 修改test.c文件
        • system_call代码分析
        相关产品与服务
        腾讯云代码分析
        腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,助力维护团队卓越代码文化。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档