linux内核 sp什么意思,浅析基于ARM的Linux下的系统调用的实现

您所在的位置:网站首页 sp版是啥意思 linux内核 sp什么意思,浅析基于ARM的Linux下的系统调用的实现

linux内核 sp什么意思,浅析基于ARM的Linux下的系统调用的实现

2023-08-04 16:22| 来源: 网络整理| 查看: 265

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):

e08f7b601bd10acac31c3c910325318a.png

即:r10 为 0xEF000000

显然,bics这条指令下面的两个语句由于条件不成立,无法获得执行。这条指令的作用是获得系统调用号

可以参考这个手册,看一下svc执行的格式:

http://files.cnblogs.com/pengdonglin137/DUI0203IC_rvct_developer_guide.pdf

069d68625a7df223005d013889a872dc.png

可以看到,[23:0]存放的就是svc指令后面的那个立即数,也即系统调用号。

不过需要注意的是:我们这里并没有这样做,我们的做法是(a.dis中可以看到):

fb10c635f5d73324982f7185ccaae86a.png

使用的是svc 0,后面跟的并不是系统调用号,而是0,这里把系统调用号存放在了寄存器r7中(a.dis中):

091bc7518537b2e67fe61920d57c8e91.png

可以看到,由于使用的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

c2c9ed493cd281aa86d8a6f5178c4c01.gif [1] [2] [3] [4] 610626052e95c7fbe3d254abc769d9ad.gif



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3