linux内核 sp什么意思,浅析基于ARM的Linux下的系统调用的实现 |
您所在的位置:网站首页 › sp版是啥意思 › linux内核 sp什么意思,浅析基于ARM的Linux下的系统调用的实现 |
12: tbl .req r8 @ syscall table pointer 13: why .req r8 @ Linux syscall (!= 0) 14: tsk .req r9 @ current thread_info .req 是伪汇编,以 scno .req r7 为例,表示scno是寄存器r7的别名。 get_thread_info tsk 其中,tsk是寄存器r9的别名,get_thread_info是一个宏定义,如下: 1: .macro get_thread_info, rd 2: mov rd, sp, lsr #13 3: mov rd, rd, lsl #13 4: .endm 即:将sp进行8KB对齐后的值赋给寄存器r9,什么意思? 这个就涉及到Linux的内核栈了。Linux为每个进程都分配了一个8KB的内核栈,在内核栈的尾端存放有关于这个进程的struct therad_info结构: 1: struct thread_info { 2: unsigned long flags; /* low level flags */ 3: int preempt_count; /* 0 => preemptable, bug */ 4: mm_segment_t addr_limit; /* address limit */ 5: struct task_struct *task; /* main task structure */ 6: struct exec_domain *exec_domain; /* execution domain */ 7: __u32 cpu; /* cpu */ 8: __u32 cpu_domain; /* cpu domain */ 9: struct cpu_context_save cpu_context; /* cpu context */ 10: __u32 syscall; /* syscall number */ 11: __u8 used_cp[16]; /* thread used copro */ 12: unsigned long tp_value; 13: struct crunch_state crunchstate; 14: union fp_state fpstate __attribute__((aligned(8))); 15: union vfp_state vfpstate; 16: #ifdef CONFIG_ARM_THUMBEE 17: unsigned long thumbee_state; /* ThumbEE Handler Base register */ 18: #endif 19: struct restart_block restart_block; 20: }; 通过上面的操作,寄存器r9中就是这个进程的thread_info结构的起始地址。 sys_call_table entry-common.S (archarmkernel) 1: .type sys_call_table, #object 2: ENTRY(sys_call_table) 3: #include "calls.S" 4: #undef ABI 5: #undef OBSOLETE 其中,calls.S的内容如下: 1: /* 2: * linux/arch/arm/kernel/calls.S 3: * 4: * Copyright (C) 1995-2005 Russell King 5: * 6: * This program is free software; you can redistribute it and/or modify 7: * it under the terms of the GNU General Public License version 2 as 8: * published by the Free Software Foundation. 9: * 10: * This file is included thrice in entry-common.S 11: */ 12: /* 0 */ CALL(sys_restart_syscall) 13: CALL(sys_exit) 14: CALL(sys_fork_wrapper) 15: CALL(sys_read) 16: CALL(sys_write) 17: /* 5 */ CALL(sys_open) 18: CALL(sys_close) 19: CALL(sys_ni_syscall) /* was sys_waitpid */ 20: CALL(sys_creat) 21: CALL(sys_link) 22: /* 10 */ CALL(sys_unlink) 23: CALL(sys_execve_wrapper) 24: CALL(sys_chdir) 25: CALL(OBSOLETE(sys_time)) /* used by libc4 */ 26: CALL(sys_mknod) 27: ...... 28: /* 355 */ CALL(sys_signalfd4) 29: CALL(sys_eventfd2) 30: CALL(sys_epoll_create1) 31: CALL(sys_dup3) 32: CALL(sys_pipe2) 33: /* 360 */ CALL(sys_inotify_init1) 34: CALL(sys_preadv) 35: CALL(sys_pwritev) 36: #ifndef syscalls_counted 37: .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls 38: #define syscalls_counted 39: #endif 40: .rept syscalls_padding 41: CALL(sys_ni_syscall) 42: .endr 关于这个部分的更多介绍参见: http://www.cnblogs.com/pengdonglin137/p/3714981.html bics r10, r10, #0xff000000 执行这个操作的时候,r10中存放的是SWI instruction,在我们的例子中就是(a.dis): 即:r10 为 0xEF000000 显然,bics这条指令下面的两个语句由于条件不成立,无法获得执行。这条指令的作用是获得系统调用号 可以参考这个手册,看一下svc执行的格式: http://files.cnblogs.com/pengdonglin137/DUI0203IC_rvct_developer_guide.pdf 可以看到,[23:0]存放的就是svc指令后面的那个立即数,也即系统调用号。 不过需要注意的是:我们这里并没有这样做,我们的做法是(a.dis中可以看到): 使用的是svc 0,后面跟的并不是系统调用号,而是0,这里把系统调用号存放在了寄存器r7中(a.dis中): 可以看到,由于使用的sys_open系统调用,所以把它的系统调用号5存放到了寄存器r7当中 ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine 这里的scno是就是寄存器r7的别名,它的值是sys_open的系统调用号5,由于在calls.S中每个系统调用标号占用4个字节,所以这个将scno的值乘以4然后再加上tbl,tbl是系统调用表sys_call_table的基地址。然后就跳入开始执行sys_open了。 asmlinkage long sys_open(const char __user *filename, int flags, int mode); 那么sys_open在哪呢?在内核源码中直接搜索sys_open,无法搜到它的实现代码,实际上它是在fs/open.c中实现的: 1: SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode) 2: { 3: long ret; 4: 5: if (force_o_largefile()) 6: flags |= O_LARGEFILE; 7: 8: ret = do_sys_open(AT_FDCWD, filename, flags, mode); 9: /* avoid REGPARM breakage on x86: */ 10: asmlinkage_protect(3, ret, filename, flags, mode); 11: return ret; 12: } 其中SYSCALL_DEFINE3是一个宏: syscalls.h (includelinux) #define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__) SYSCALL_DEFINEx也是一个宏: syscalls.h (includelinux) #define SYSCALL_DEFINEx(x, sname, ...) __SYSCALL_DEFINEx(x, sname, __VA_ARGS__) __SYSCALL_DEFINEx仍然是个宏: syscalls.h (includelinux) #define __SYSCALL_DEFINEx(x, name, ...) asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__)) 所以展开后的结果就是: asmlinkage long sys_open(__SC_DECL3(__VA_ARGS__)) 其中,__SC_DECL3定义如下: syscalls.h (includelinux) 1: #define __SC_DECL1(t1, a1) t1 a1 2: #define __SC_DECL2(t2, a2, ...) t2 a2, __SC_DECL1(__VA_ARGS__) 3: #define __SC_DECL3(t3, a3, ...) t3 a3, __SC_DECL2(__VA_ARGS__) 所以最终的结果如下: 1: asmlinkage long sys_open(const char __user *filename, int flags, int mode) 2: { 3: long ret; 4: 5: if (force_o_largefile()) 6: flags |= O_LARGEFILE; 7: 8: ret = do_sys_open(AT_FDCWD, filename, flags, mode); 9: /* avoid REGPARM breakage on x86: */ 10: asmlinkage_protect(3, ret, filename, flags, mode); 11: return ret; 12: 13: } 关于sys_open本身的实现这里就不深入分析了。 接下来看一下返回。 adr lr, ret_fast_syscall @ return address 当sys_open中return后,便跳入ret_fast_syscall处开始执行: 1: /* 2: * This is the fast syscall return path. We do as little as 3: * possible here, and this includes saving r0 back into the SVC 4: * stack. 5: */ 6: ret_fast_syscall: 7: UNWIND(.fnstart ) 8: UNWIND(.cantunwind ) 9: disable_irq @ disable interrupts 10: ldr r1, [tsk, #TI_FLAGS] @将thread_info中的flags成员存放到r1中 11: tst r1, #_TIF_WORK_MASK 12: bne fast_work_pending 13: 14: /* perform architecture specific actions before user return */ 15: arch_ret_to_user r1, lr 16: 17: @ fast_restore_user_regs 18: ldr r1, [sp, #S_OFF + S_PSR] @ get calling cpsr 19: ldr lr, [sp, #S_OFF + S_PC]! @ get pc [1] [2] [3] [4] |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |