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, <0 => 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]

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

  1. u-boot的linux内核映像加载,基于U_Boot的Linux内核映像加载与引导功能实现.pdf

    基于U_Boot的Linux内核映像加载与引导功能实现 20 10 8 ( ) Aug . 2010 10 4 Journal of Langfang T eachers College( N atu ...

  2. Linux内核源码分析:基于最新的Linux 4.0内核(学习路线总结)

    今天给大家分享的是基于最新的Linux 4.0内核学习路线总结,本文由8个专题组成,文末附上学习路线思维导图. 一.进程管理专题 1.进程原理 1.1 进程生命周期 1.2 task_struct结构 ...

  3. [转载]基于ARM的linux内核裁剪与移植

    基于ARM的linux内核裁剪与移植 http://bbs.elecfans.com/forum.php?mod=viewthread&tid=185020  wutaimin( 楼主 ) 2 ...

  4. Linux内核3.0移植并基于Initramfs根文件系统启动

    Linux内核移植与启动 Target borad:FL2440 Bootloader:U-boot-2010.09 交叉编译器:buildroot-2012.08 1.linux内核基础知识 首先, ...

  5. arm linux 工控,基于ARM和Linux通用工控平台设计 - ARM - 电子发烧友网

    交叉编译 交叉编译就是在一个平台上生成另一个平台上的可执行代码.所谓平台,实际上包含两个概念:体系结构及操作系统.根据上述建立的开发环境,目标平台是基于ARM体系结构的运行嵌入式Linux操作系统,而 ...

  6. arm linux考勤,定稿毕业论文_基于ARM与Linux的员工刷卡考勤系统喜欢就下吧(范文1)...

    <毕业论文_基于ARM与Linux的员工刷卡考勤系统.doc>由会员分享,可免费在线阅读全文,更多与<(定稿)毕业论文_基于ARM与Linux的员工刷卡考勤系统(喜欢就下吧)> ...

  7. OpenCV基于ARM的Linux系统的交叉编译

    OpenCV基于ARM的Linux系统的交叉编译 基于ARM的Linux系统的交叉编译 先决条件 获取OpenCV源代码 获取最新的稳定OpenCV版本 从Git存储库中获取最新的OpenCV 构建O ...

  8. arm Linux 低成本方案,参赛作品《低成本基于ARM+Linux平台搭建web服务器的物联网学习板》...

    [报名阶段需要填写的内容] 1. 参赛者姓名(必填项): 王徕泽 2. 单位或学校名称(选填项): 徕泽电子工作室 3. 当前职务或职称(选填项): 室长 4. 参赛作品的名字(必填项): 低成本基于 ...

  9. linux 网络对讲,基于ARM与Linux的全数字化可视对讲系统的设计与实现

    摘要: 在信息化飞速发展的今天智能家居系统已越来越多的被人们所接受,从楼宇可视对讲到紧急情况报警,再到远程家电控制,智能家居系统在人们的日常生活中扮演着重要的角色.传统的可视对讲系统都是基于模拟音视频 ...

最新文章

  1. 使用WebDriver + Java + Junit做自动化测试教程
  2. Android setTag()/getTag()
  3. TCP/IP网络协议的通俗理解,socket,http,soap。
  4. phpstorm运行java项目_phpstorm的提速设置
  5. 解决 SSH 不能输入中文的问题
  6. Javascript 常见使用误区
  7. sliverlight3 学习 2, 布局
  8. 和平精英现在服务器暂时未开放,和平精英为什么登陆不进去 和平精英服务器分批登陆是什么意思...
  9. 怎么把文件导入云服务器,怎么把文件放到云服务器里
  10. Spring Boot + Prometheus + Grafana 打造可视化监控,一目了然!
  11. 网站刷关键词_B2B关键词调研:如何精准地定位B端客户?(下)
  12. Chaotica for Mac(分形艺术图形设计工具)
  13. win10 安装mysql 卡死_win10安装Mysql5.5卡住假死
  14. MUI调用照片以及裁剪和图库照片上传到服务器【后端部分Flask+MUI】
  15. 福岛邦彦在多少年创立了卷积神经网络
  16. 查看ASA日志服务器信息,Cisco ASA防火墙的日志管理
  17. ESP32-C3 SPI salve示例错误
  18. 降低电源纹波噪声的方法
  19. 捣鼓车间 | 学生获奖作品:戒烟帽
  20. 程序员软技能:职场、学习、生活,代码之外生存之南

热门文章

  1. 2021-09-18P1328 [NOIP2014 提高组] 生活大爆炸版石头剪刀布P2058 [NOIP2016 普及组] 海港
  2. cesium加载geoJson格式的图斑方法
  3. Carsim安装失败,干啥都没用,改了许可证,加了BIA,解决见下图
  4. ae怎样设置gpu渲染
  5. matlab求解二维矩阵并画图,Matlab教程2_ 绘图 _ 二维(2)
  6. <if test=“state!=null and state==‘0‘ “> mybatis中使用if test判断参数值得问题
  7. 青蛙与蚊子(C++结构体练习题)
  8. 基于单片机(STC89C52)的数字频率计
  9. 一个测试人员的工作该怎么开展
  10. 使用主密钥和钱包方法加密数据