Hero Image
RISC-V Syscall 系列 3:什么是 vDSO?

概述 本文阐述了什么是 vDSO 技术,以及该技术解决的问题是什么,解决效果如何,并举例说明用户程序如何使用它。 说明:文中涉及的 Linux 源码是基于 5.17 版本 背景 在 Linux 众多的系统调用中,有一部分存在以下特点: 系统调用本身很快,主要时间花费在 trap 过程 无需高特权级别权限 这部分系统调用如果能够直接在用户空间中执行,则能够对性能有较大的改善。gettimeofday 就是一个典型的例子,它仅仅只是读取内核中的时间信息,而且对于许多应用程序来说,读取系统时间是必要的同时也是频率很高的行为。 为了改善这部分系统调用的性能,先后出现了 vsyscall, vDSO 机制来加速系统调用。 vsyscall vsyscall 或 virtual system call 是第一种也是最古老的一种用于加快系统调用的机制,最早在 Linux 2.5.53 被引入内核。vsyscall 的工作原则其实十分简单。Linux 内核在用户空间映射一个包含一些变量及一些系统调用的实现的内存页。因此这些系统调用将在用户空间下执行,而不需要触发 trap 机制进入内核。 但是 vsyscall 存在以下问题: vsyscall 映射到内存的固定位置 ffffffffff600000 处,有潜在的安全风险 vsyscall 内存页不包含符号表等信息,在程序出错时进行 core dump 会比较麻烦 为了解决上述问题,从而设计了 vDSO 机制,也就是本文讨论的主题。 vDSO vDSO (virtual dynamic shared object) 也是一种系统调用加速机制。vDSO 和 vsyscall 的基本原理类似,都是通过映射到用户空间的代码和数据来模拟系统调用,来达到加速的目的。而它们的主要区别在于: vDSO 是一个 ELF 格式的动态库,拥有完整的符号表信息 依赖 ASLR 技术,对 vDSO 的地址进行随机化 linux-vdso.

Hero Image
RISC-V Syscall 系列 2:Syscall 过程分析

概述 本文主要对 Linux 在 RISC-V 架构下的 Syscall 机制进行分析,探究计算机是如何一步一步从应用程序开始,到执行 Syscall,最后返回应用程序的全过程。 文章因涉及技术术语,建议读者阅读本文前先熟悉以下知识: Syscall 概念 RISC-V 规范 C 语言 说明:文中涉及的 Linux 源码是基于 5.17 版本 Syscall 开始 首先,Syscall 是如何开始的呢?当应用程序需要使用操作系统提供的一系列功能时,一般会通过操作系统提供的 C 标准库来进行 Syscall 的调用。而实际上,C 标准库的内部则使用了 ecall 指令来触发了整个 Syscall 流程。 ecall 先介绍一下 ecall 指令。ecall 指令以前叫做 scall,用于执行环境的变更,它会根据当前所处模式触发不同的执行环境切换异常: in U-mode: environment-call-from-U-mode exception in S-mode: environment-call-from-S-mode exception in M-mode: environment-call-from-M-mode exception Syscall 场景下是在 U-mode(用户模式)下执行 ecall 指令,主要会触发如下变更: 处理器特权级别由 User-mode(用户模式)提升为 Supervisor-mode(内核模式) 当前指令地址保存到 sepc 特权寄存器 设置 scause 特权寄存器 跳转到 stvec 特权寄存器指向的指令地址 简单来说,ecall 指令将权限提升到内核模式并将程序跳转到指定的地址。操作系统内核和应用程序其实都是相同格式的文件,最关键的区别就是程序执行的特权级别不同。所以 Syscall 的本质其实就是提升特权权限到内核模式,并跳转到操作系统指定的用于处理 Syscall 的代码地址。