zoukankan      html  css  js  c++  java
  • 2018-2019-1 20189229《Linux内核原理与分析》第六周作业

    系统调用的三层机制(下)

    本章主要讲解在内核态跟踪调试一个系统调用,进一步分析系统调用的内核处理过程。

    给MenuOS增加命令

    重现克隆新版本的meun,其中已添加了time/time-asm两个系统调用函数,time为C语言方式显示系统时间,time-asm为使用汇编方式显示系统时间。如图:

    使用gdb跟踪系统调用内核函数sys_time

    使用下列命令调试内核
    'cd .. #返回到LinuxKernel目录下'
    'qemu -Kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -S -s'

    启动gdb,将linux-3.18.6内核加载进来,连接到target remote 1234端口:
    'file linux-3.18.6/vmlinux'
    'target remote:1234'
    设置断点,在sys_call处设置断点。当系统执行中断指令:int 0x80时,CPU会自动跳转到system_call函数。那具体来了解system_call是如何跳转与执行的呢?一下为system_call函数源码,下面来分析具体system_call与中断指令int 0x80的跳转关系。

    ENTRY(system_call)
    491	RING0_INT_FRAME			# can't unwind into user space anyway
    492	ASM_CLAC
    493	pushl_cfi %eax			# save orig_eax
    494	SAVE_ALL
    495	GET_THREAD_INFO(%ebp)
    496					# system call tracing in operation / emulation
    497	testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
    498	jnz syscall_trace_entry
    499	cmpl $(NR_syscalls), %eax
    500	jae syscall_badsys
    501syscall_call:
    502	call *sys_call_table(,%eax,4)
    503syscall_after_call:
    504	movl %eax,PT_EAX(%esp)		# store the return value
    505syscall_exit:
    506	LOCKDEP_SYS_EXIT
    507	DISABLE_INTERRUPTS(CLBR_ANY)	# make sure we don't miss an interrupt
    508					# setting need_resched or sigpending
    509					# between sampling and the iret
    510	TRACE_IRQS_OFF
    511	movl TI_flags(%ebp), %ecx
    512	testl $_TIF_ALLWORK_MASK, %ecx	# current->work
    513	jne syscall_exit_work
    514
    515restore_all:
    516	TRACE_IRQS_IRET
    517restore_all_notrace:
    518#ifdef CONFIG_X86_ESPFIX32
    519	movl PT_EFLAGS(%esp), %eax	# mix EFLAGS, SS and CS
    520	# Warning: PT_OLDSS(%esp) contains the wrong/random values if we
    521	# are returning to the kernel.
    522	# See comments in process.c:copy_thread() for details.
    523	movb PT_OLDSS(%esp), %ah
    524	movb PT_CS(%esp), %al
    525	andl $(X86_EFLAGS_VM | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax
    526	cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
    527	CFI_REMEMBER_STATE
    528	je ldt_ss			# returning to user-space with LDT SS
    529#endif
    530restore_nocheck:
    531	RESTORE_REGS 4			# skip orig_eax/error_code
    532irq_return:
    533	INTERRUPT_RETURN
    

    系统调用在内核代码中的处理过程

    本节将仔细分析system_call作为一个中断服务程序的来龙去脉。
    以time为例,在用户态调用time,通过gdb跟踪内核里面的系统调用函数sys_time,触发一个系统调用到执行这个系统调用的内核处理函数,再到最后系统调用返回到用户态。如图所示:

    中断向量0x80和system_call中断服务程序入口的关系

    由代码可以看出,通过set_system_trap_gate函数绑定了中断向量0x80和system_call中断服务程序入口,一旦执行int 0x80,CPU会直接跳转到system_call这个位置。

    #ifdef CONFIG_X86_32
    839	set_system_trap_gate(SYSCALL_VECTOR, &system_call);#SYSCALL VECTOR指系统调用的中断向量;system_call为汇编代码入口
    840	set_bit(SYSCALL_VECTOR, used_vectors);
    841#endif
    

    在system_call汇编代码中的系统调用内核处理函数

    本节基于一个问题来展开,在system_call中哪个位置调用了sys_time()?前几章已了解到,系统调用是特殊的中断,因此分析system_call即可了解中断处理过程。
    简化的system_call代码段:

    ENTRY(system_call)
        RINGO_INT_FRAME
        ASM_CLAC
        push1_cfi %eax #保存系统调用号
        SAVE_ALL #保存现场,将用到的所有CPU寄存器保存到栈中
        GET_THREAD_INFO(%ebp) #ebp用于存放当前进程thread_info结构的地址
        test1 $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
        jnz syscall_trace_entry
    cmp1 $(nr_syscalls),%eax #检查系统调用号(系统调用号应小于NR_syscalls)
        jae syscall_badsys #不合法,跳入异常处理
    syscall_call:
         call *sys_call_table(,%eax,4)  #合法,对照系统调用号在系统调用表中寻找相应服务例程
         movl %eax,PT_EAX(%esp)  #保存返回值到栈中
     syscall_exit:  
         testl $_TIF_ALLWORK_MASK, %ecx   #检查是否需要处理信号
         jne syscall_exit_work   #需要,进入 syscall_exit_work
     restore_all: 
         TRACE_IRQS_IRET   #不需要,执行restore_all恢复,返回用户态
     irq_return:
         INTERRUPT_RETURN   #相当于iret
    

    整体上来讲,sys_call_table是一个系统调用的表,EAX寄存器传递的系统调用号,使用者在调用它时会根据EAX寄存器的值来调用对应的系统调用内核处理函数。具体流程见下图:

  • 相关阅读:
    3n+1问题
    判断x的m次方和y的m次方末尾三位数是否相等
    OpenJudge 计算概论1007:点评赛车
    整数划分问题【转】
    证明:平面内有5个整点,必有两个点连线的中点为整点【本资源整理自网络】
    欧几里德算法的证明
    导出本地和远程SVN项目, Export remote SVN repository
    Centos7的firewalld配置
    ESXi5.5下的Centos7虚机配置静态IP
    Dubbo消费端错误: ClassNotFoundException: org.apache.zookeeper.proto.WatcherEvent
  • 原文地址:https://www.cnblogs.com/zisong/p/9980361.html
Copyright © 2011-2022 走看看