1、用户态与内核态之间通过系统调用接口完成交流,系统调用接口的所有种类:

syscalls.h - include/linux/syscalls.h - Linux source code (v5.16.3) - Bootlin

当执行程序的时候可以通过strace命令查看程序具体使用了哪些系统调用接口。

strace工具_sydyh43的博客-CSDN博客_strace工具

2、用户态与内核态之间的切换

静态编译用户态的代码,完成反汇编。否则需要反汇编*.so动态库。

 arm-linux-gcc open.c -o open --staticarm-linux-objdump -D open > open.txt
   285f0:    e59f7074    ldr r7, [pc, #116]  ; 2866c <__libc_open+0x128>285f4:    e1a06000    mov r6, r0285f8:    e59d1004    ldr r1, [sp, #4]285fc:  e59d2024    ldr r2, [sp, #36]   ; 0x2428600:    e59d3000    ldr r3, [sp]28604:  e3e00063    mvn r0, #99 ; 0x6328608:    ef000000    svc 0x00000000

将系统调用号存放到r7寄存器中。

2.1、用户态进入到内核态

通过svc汇编指令触发异常,从而从用户态进入到内核态,跳转到vector_swi。参考ARM处理器的异常模式_sydyh43的博客-CSDN博客

/*=============================================================================* SWI handler*-----------------------------------------------------------------------------*/.align  5
ENTRY(vector_swi)
#ifdef CONFIG_CPU_V7Mv7m_exception_entry
#elsesub    sp, sp, #PT_REGS_SIZE        @ PT_REGS_SIZE=72 开辟72B,保存参数stmia sp, {r0 - r12}           @ Calling r0 - r12ARM(    add r8, sp, #S_PC       )ARM(   stmdb   r8, {sp, lr}^       )   @ Calling sp, lrTHUMB( mov r8, sp          )THUMB( store_user_sp_lr r8, r10, S_SP  )   @ calling sp, lrmrs    saved_psr, spsr         @ called from non-FIQ mode, so ok.TRACE(   mov saved_pc, lr        )str    saved_pc, [sp, #S_PC]       @ Save calling PCstr   saved_psr, [sp, #S_PSR]     @ Save CPSRstr r0, [sp, #S_OLD_R0]     @ Save OLD_R0
#endifreload_current r10, ip            @ 保存跳转过来的信息,返回用zero_fp                           @ 清除frame pointer,表示栈顶alignment_trap r10, ip, __cr_alignmentasm_trace_hardirqs_on save=0enable_irq_notracect_user_exit save=0/** Get the system call number.*/#if defined(CONFIG_OABI_COMPAT)/** If we have CONFIG_OABI_COMPAT then we need to look at the swi* value to determine if it is an EABI or an old ABI call.*/
#ifdef CONFIG_ARM_THUMBtst  saved_psr, #PSR_T_BITmovne  r10, #0             @ no thumb OABI emulationUSER( ldreq   r10, [saved_pc, #-4]    )   @ get SWI instruction
#elseUSER(  ldr r10, [saved_pc, #-4]    )   @ get SWI instruction
#endifARM_BE8(rev   r10, r10)           @ little endian instruction#elif defined(CONFIG_AEABI)/** Pure EABI user space always put syscall number into scno (r7).*/
#elif defined(CONFIG_ARM_THUMB)/* Legacy ABI only, possibly thumb mode. */tst   saved_psr, #PSR_T_BIT       @ this is SPSR from save_user_regsaddne    scno, r7, #__NR_SYSCALL_BASE    @ put OS number inUSER(    ldreq   scno, [saved_pc, #-4]   )#else/* Legacy ABI only. */USER(   ldr scno, [saved_pc, #-4]   )   @ get SWI instruction
#endif/* saved_psr and saved_pc are now dead */uaccess_disable tblget_thread_info tsk            @ 8K地址对齐,struct thread_info基地址存放在tsk(r9)adr    tbl, sys_call_table        @ load syscall table pointer 系统调用表存放在tbl(r8)#if defined(CONFIG_OABI_COMPAT)/** If the swi argument is zero, this is an EABI call and we do nothing.** If this is an old ABI call, get the syscall number into scno and* get the old ABI syscall table address.*/bics    r10, r10, #0xff000000strne  r10, [tsk, #TI_ABI_SYSCALL]streq    scno, [tsk, #TI_ABI_SYSCALL]eorne   scno, r10, #__NR_OABI_SYSCALL_BASEldrne tbl, =sys_oabi_call_table
#elif !defined(CONFIG_AEABI)bic scno, scno, #0xff000000     @ mask off SWI op-codestr  scno, [tsk, #TI_ABI_SYSCALL]eor scno, scno, #__NR_SYSCALL_BASE  @ check OS number
#elsestr    scno, [tsk, #TI_ABI_SYSCALL]
#endif/** Reload the registers that may have been corrupted on entry to* the syscall assembly (by tracing or context tracking.)*/TRACE( ldmia   sp, {r0 - r3}       )local_restart:ldr  r10, [tsk, #TI_FLAGS]       @ check for syscall tracing; thread_info->flags保存到r10中stmdb sp!, {r4, r5}           @ push fifth and sixth args;arm处理器r0~r3保存入参tst r10, #_TIF_SYSCALL_WORK     @ are we tracing syscalls?;系统调用tracingbne  __sys_trace                 @ _TIF_SYSCALL_WORK不为零(置位)跳转系统调用tracing分支@ invoke_syscall宏 四个入参tbl(r8), scno(r7), r10, __ret_fast_syscall返回函数@ 执行系统调用接口,结束后返回执行__ret_fast_syscallinvoke_syscall tbl, scno, r10, __ret_fast_syscall    @ 调用系统接口add  r1, sp, #S_OFF
2:  cmp scno, #(__ARM_NR_BASE - __NR_SYSCALL_BASE)eor   r0, scno, #__NR_SYSCALL_BASE    @ put OS number backbcs    arm_syscallmov  why, #0             @ no longer a real syscallb    sys_ni_syscall          @ not private func#if defined(CONFIG_OABI_COMPAT) || !defined(CONFIG_AEABI)/** We failed to handle a fault trying to access the page* containing the swi instruction, but we're not really in a* position to return -EFAULT. Instead, return back to the* instruction and re-enter the user fault handling path trying* to page it in. This will likely result in sending SEGV to the* current task.*/
9001:sub    lr, saved_pc, #4str lr, [sp, #S_PC]get_thread_info tskb ret_fast_syscall
#endif
ENDPROC(vector_swi)

svc 模式下的 sp 和 user 模式下的 sp 并不是同一个,因此无法使用栈直接进行传递,需要将所有的参数保存在通用寄存器中进行传递。用户态和内核态下的栈空间地址区域

用户态的栈地址cat /proc/pid/maps查看

内核态的栈地址,只需要获取struct thread_info结构体的地址current_thread_info()

最终在

invoke_syscall tbl, scno, r10, __ret_fast_syscall

完成系统调用接口的使用。其中scno(r7)就是从用户态传下来的系统调用号。

2.2、内核态返回到用户态

当执行完系统调用接口后,需要从内核态返回到用户态,跳转到__ret_fast_syscall:标签,根据thread_info->flags值(thread_info.h - arch/arm/include/asm/thread_info.h - Linux source code (v5.16.7) - Bootlin)跳转到slow_work_pending,在do_work_pending函数中完成调度schedule和信号处理do_signal。

slow_work_pending:mov    r0, sp              @ 'regs'mov  r2, why             @ 'syscall'bl    do_work_pending     @ 执行schedule和do_signal的时机cmp   r0, #0beq   no_work_pending     @ 弹栈,返回用户态movlt scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE)ldmia  sp, {r0 - r6}           @ have to reload r0 - r6b  local_restart           @ ... and off we go
ENDPROC(ret_fast_syscall)

等do_work_pending结束,跳转到no_work_pending,进入restore_user_regs,弹栈返回用户态

no_work_pending:asm_trace_hardirqs_on save = 0/* perform architecture specific actions before user return */arch_ret_to_user r1, lrct_user_enter save = 0restore_user_regs fast = 0, offset = 0

用户态与内核态之间的切换相关推荐

  1. 用户态和内核态之间的切换

    用户态和内核态之间的切换 切换方式 从用户态到内核态切换可以通过三种方式,或者说会导致从用户态切换到内核态的操作: 系统调用,这个上面已经讲解过了,在我公众号之前的文章也有讲解过.其实系统调用本身就是 ...

  2. 操作系统用户态和内核态之间的切换过程

    操作系统用户态和内核态之间的切换过程 1. 用户态和内核态的概念区别 究竟什么是用户态,什么是内核态,这两个基本概念以前一直理解得不是很清楚,根本原因个人觉得是在于因为大部分时候我们在写程序时关注的重 ...

  3. 用户态与内核态之间切换详解

    用户空间和内核空间 用户程序有用户态和内核态两种状态.用户态就是执行在用户空间中,不能直接执行系统调用.必须先切换到内核态,也就是系统调用的相关数据信息必须存储在内核空间中,然后执行系统调用. 操作硬 ...

  4. 操作系统 | 用户态和内核态的切换(中断、系统调用与过程(库函数)调用)

    文章目录 中断 过程调用 系统调用 过程调用和系统调用的区别 中断 用户态.内核态之间的切换是怎么实现的? 用户态→内核态 是通过中断实现的.并且 中断是唯一途径 . 核心态→用户态 的切换是通过执行 ...

  5. 系统调用原理与用户态以及内核态相互切换过程,以linux系统为主

    1. 讲系统调用前需要清楚的几个基本概念 1.1 内核态与用户态 内核态:当CPU执行内核的代码(CPU堆栈指针指向内核堆栈)时,我们就称此时处于内核态,内核态的代码可以使用特权指令,这些指令可以控制 ...

  6. 用户态和内核态的切换

    用户态和内核态的切换 我们经常说,一个程序依赖DMA设备来减少用户态和内核态的切换次数,以此来提升性能.那么对于它的细节是如何进行的呢?本篇,博主与你一起研究一下用户态和内核态的划分,以及这件事情的前 ...

  7. Linux系统编程33:进程信号之详解信号的捕捉过程,用户态和内核态及其切换,sigaction和signal

    文章目录 (1)用户态和内核态 (2)用户态和内核态的切换 (3)内核是如何实现信号的捕捉 (4)sigaction (1)用户态和内核态 我们说过,每个Linux进程有4GB的地址空间 其中0-3G ...

  8. 用户态和内核态的切换耗费时间的原因

    用户态和内核态的切换耗费时间的原因 总的来说,就是线程切换或者加锁解锁都是因为需要用户态和内核态的切换,从而导致的开销大. 应用程序的执行需要依托内核提供的资源,包括CPU.存储.IO等,因此内核提供 ...

  9. 进程用户态和内核态及其切换过程

    1.进程的堆栈 内核在创建进程的时候,会为进程创建相应的堆栈.每个进程会有两个栈,一个用户栈,存在于用户空间,一个内核栈,存在于内核空间.当进程在用户空间运行时,CPU堆栈指针寄存器里面的内容是用户堆 ...

  10. 进程用户态和内核态及其切换过程(转)

    1.进程的堆栈 内核在创建进程的时候,会为进程创建相应的堆栈.每个进程会有两个栈,一个用户栈,存在于用户空间,一个内核栈,存在于内核空间.当进程在用户空间运行时,CPU堆栈指针寄存器里面的内容是用户堆 ...

最新文章

  1. 使用 Matplotlib 这么久,竟不知道数据可以动起来
  2. mac -- 安装OpenCV
  3. FSLib.Extension库
  4. linux为用户配置java环境变量
  5. sql添加列,删除列,修改列
  6. 【蓝桥杯】基础练习 十六进制转八进制(Java实现)
  7. 模拟视频光端机与数字光端机究竟有何区别
  8. 华为手机怎么强制关机_华为忘记锁屏密码怎么办?多品牌手机通用解锁密码
  9. Python猜字游戏(用函数)(最新版)
  10. CentOS 6.5安装使用docker
  11. 【工程项目经验】多个静态库打包成一个静态库
  12. java txt 写入pdf_java学习笔记 读取pdf文件并写成txt文件输出
  13. 开发者最讨厌的编程语言:Perl 名列第一,PHP、Objective-C 和 Ruby 都在其中
  14. 图灵机概念的javascript演示
  15. mysql查询id为5的数据类型_MySql学习05---数据类型
  16. 理解BERT每一层都学到了什么
  17. c#定时器Timer
  18. 从零开始打造自己的PHP框架——第3章
  19. Windows下搭建SVN服务器 - Visual SVN server
  20. 【备忘】老男孩IT教育_徐培成_大数据

热门文章

  1. SONY无线PS2遥控手柄与stm32单片机通信
  2. echarts树状图
  3. 通俗解释什么是指令集
  4. 永洪科技怎么样_「永洪科技」
  5. 开源RPC框架Pigeon
  6. Win快捷键大全史上最全~ win打开资源管理器快捷键(查看内存的占用)
  7. 完整版本支付宝扫码支付 c#版本
  8. 矩阵求导公式的推导和计算(公式推导法)
  9. My Notes Keeper 注册码算法注册机
  10. python中的reshape是什么意思,Python的reshape的用法