您好,欢迎访问三七文档
边干边学——Linux内核指导Chapter5:系统调用为什么需要系统调用相关数据和代码例:系统调用getuid()的实现添加一个系统调用mysyscall再实现一个稍复杂的系统调用边干边学——Linux内核指导为什么需要系统调用(1)公共系统调用接口POSIX.1具体的系统实现Kernel用户程序调用内核提供的功能边干边学——Linux内核指导为什么需要系统调用(2)sys_foo...用户空间内核空间模式切换模式切换边干边学——Linux内核指导相关数据和代码arch/i386/kernel/traps.carch/i386/kernel/entry.S系统调用时的内核栈sys_call_tablesystem_call和ret_from_sys_callinclude/linux/unistd.h系统调用编号宏定义展开系统调用glibc展开系统调用INLINE_SYSCALL(getuid,0);边干边学——Linux内核指导系统调用时的内核栈用户空间ss用户空间espEFLAGS用户空间cs用户空间eip系统调用号可用空间可用空间eip函数返回地址局部变量用户栈内核栈中断后(SAVE_ALL前)及iret前(RESTORE_ALL后)的esp内核ss向外返回向内中断中断前及iret(系统调用返回)后的esp用户sstask_struct陷入内核时,系统自动从当前进程的TSS(任务状态段)中获得内核栈的SS和ESP,并完成栈切换边干边学——Linux内核指导系统调用时的内核栈18*Stacklayoutin'ret_from_system_call':19*ptraceneedstohaveallregsonthestack.20*iftheorderhereischanged,itneedstobe21*updatedinfork.c:copy_process,signal.c:do_signal,22*ptrace.candptrace.h23*24*0(%esp)-%ebx25*4(%esp)-%ecx26*8(%esp)-%edx27*C(%esp)-%esi28*10(%esp)-%edi29*14(%esp)-%ebp30*18(%esp)-%eax31*1C(%esp)-%ds32*20(%esp)-%es33*24(%esp)-orig_eax34*28(%esp)-%eip35*2C(%esp)-%cs36*30(%esp)-%eflags37*34(%esp)-%oldesp38*38(%esp)-%oldss39*40*currentisinregister%ebxduringanyslowentries.边干边学——Linux内核指导系统调用时的内核栈#defineSAVE_ALL\cld;\pushl%es;\pushl%ds;\pushl%eax;\pushl%ebp;\pushl%edi;\pushl%esi;\pushl%edx;\pushl%ecx;\pushl%ebx;\movl$(__KERNEL_DS),%edx;\movl%edx,%ds;\movl%edx,%es;边干边学——Linux内核指导系统调用时的内核栈#defineRESTORE_ALL\popl%ebx;\popl%ecx;\popl%edx;\popl%esi;\popl%edi;\popl%ebp;\popl%eax;\1:popl%ds;\2:popl%es;\addl$4,%esp;\3:iret;\边干边学——Linux内核指导sys_call_table398ENTRY(sys_call_table)399.longSYMBOL_NAME(sys_ni_syscall)400.longSYMBOL_NAME(sys_exit)401.longSYMBOL_NAME(sys_fork)402.longSYMBOL_NAME(sys_read)403.longSYMBOL_NAME(sys_write)404.longSYMBOL_NAME(sys_open)/*5*/…635.longSYMBOL_NAME(sys_ni_syscall)/*reservedforlremovexattr*/636.longSYMBOL_NAME(sys_ni_syscall)/*reservedforfremovexattr*/637638.reptNR_syscalls-(.-sys_call_table)/4639.longSYMBOL_NAME(sys_ni_syscall)640.endr边干边学——Linux内核指导sys_call_table+eax*4ENTRY(sys_call_table).longSYMBOL_NAME(sys_ni_...).longSYMBOL_NAME(sys_exit).longSYMBOL_NAME(sys_fork).longSYMBOL_NAME(sys_read).longSYMBOL_NAME(sys_write).longSYMBOL_NAME(sys_open)………….longSYMBOL_NAME(sys_getuid)sys_call_table首地址ENTRY(sys_call_table).longSYMBOL_NAME(sys_ni_...).longSYMBOL_NAME(sys_exit).longSYMBOL_NAME(sys_fork).longSYMBOL_NAME(sys_read).longSYMBOL_NAME(sys_write).longSYMBOL_NAME(sys_open)………….longSYMBOL_NAME(sys_getuid)sys_call_table首地址eax边干边学——Linux内核指导system_call194ENTRY(system_call)#int0x80后执行195pushl%eax#saveorig_eax196SAVE_ALL197GET_CURRENT(%ebx)198testb$0x02,tsk_ptrace(%ebx)#PT_TRACESYS199jnetracesys200cmpl$(NR_syscalls),%eax201jaebadsys202call*SYMBOL_NAME(sys_call_table)(,%eax,4)203movl%eax,EAX(%esp)#savethereturnvalue204ENTRY(ret_from_sys_call)205cli边干边学——Linux内核指导ret_from_sys_callENTRY(ret_from_sys_call)cli#need_reschedandsignalsatomictestcmpl$0,need_resched(%ebx)jnereschedulecmpl$0,sigpending(%ebx)jnesignal_returnrestore_all:RESTORE_ALL边干边学——Linux内核指导……RESTORE_ALL(system_call):pushl%eaxSAVE_ALL………………int0x80……int0x80(system_call):pushl%eaxSAVE_ALL…………压入用户ss压入用户esp压入EFLAGS压入cs压入eip压入eaxpushl%es;pushl%ds;pushl%eax;pushl%ebp;pushl%edi;pushl%esi;pushl%edx;pushl%ecx;pushl%ebx……RESTORE_ALLpopl%ebx;popl%ecx;popl%edx;popl%esi;popl%edi;popl%ebp;popl%eax;popl%ds;popl%es;addl$4,%espiret由于是陷入进来内核的,所以机器自动保存与转换堆栈。等价于弹出eax弹出eip弹出cs弹出EFLAGS弹出用户esp弹出用户ss用户空间内核空间内核堆栈中的变化注解回到用户空间边干边学——Linux内核指导arch/i386/kernel/traps.c916void__inittrap_init(void)//初始化中断描述符表IDT{……923set_trap_gate(0,÷_error);924set_trap_gate(1,&debug);925set_intr_gate(2,&nmi);926set_system_gate(3,&int3);……942set_trap_gate(19,&simd_coprocessor_error);944set_system_gate(SYSCALL_VECTOR,&system_call);边干边学——Linux内核指导系统调用编号include/asm-i386/unistd.h8#define__NR_exit19#define__NR_fork210#define_NR_read311#defineNR_write412#defineNR_open513#defineNR_close6……240#define__NR_llistxattr233241#define__NR_flistxattr234242#define__NR_removexattr235243#define__NR_lremovexattr236244#define__NR_fremovexattr237边干边学——Linux内核指导宏定义展开系统调用#define_syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)\typename(type1arg1,type2arg2,type3arg3)\{\long__res;\__asm__volatile(int$0x80\:=a(__res)\:0(__NR_##name),b((long)(arg1)),c((long)(arg2)),\d((long)(arg3)));\__syscall_return(type,__res);\}边干边学——Linux内核指导宏定义展开系统调用movl$__NR_##name,%eax//先为输入参数分配寄存器movlarg1,%ebxmovlarg2,%ecxmovlarg3,%edx#APPint$0x80//汇编代码#NO_APPmovl%eax,__res//最后处理输出参数边干边学——Linux内核指导例:系统调用getuid()的实现一个简单的程序,但包含系统调用和库函数调用#includelinux/unistd.h/*allsystemcallsneedthisheader*/intmain(){inti=getuid();printf(“HelloWorld!Thisismyuid:%d\n”,i);}假定unistd.h定义了“宏”_syscall0(int,getuid);边干边学——Linux内核指导例:系统调用getuid()的实现这个“宏”被getuid()展开后intgetuid(void){long__res;__asm__volatile(int$0x80:“=a”(__res)#输出:“”(__NR_getuid));#输入__syscall_return(int,__res);}显然,__NR_getuid(24)放入eax,并int0x80边干边学——Linux内核指导例:系统调用getuid()的实现因为系统初始化时设定了set_system_gate(SYSCALL_VECTOR,&system_call);所以进入system_call194ENTRY(system_call)195pushl%eax#saveorig_eax196SAVE_ALL197GET_CURRENT(%ebx)198
本文标题:linux系统调用
链接地址:https://www.777doc.com/doc-3684620 .html