| Crates.io | build_vdso |
| lib.rs | build_vdso |
| version | 0.1.0 |
| created_at | 2026-01-21 03:04:01.322951+00 |
| updated_at | 2026-01-21 03:04:01.322951+00 |
| description | 用于构建vDSO的工具库,与vdso_helper配合使用 |
| homepage | https://github.com/rosy233333/vdso_crate_template/blob/main/README.md |
| repository | https://github.com/rosy233333/vdso_crate_template |
| max_upload_size | |
| id | 2058136 |
| size | 25,957 |
vDSO(Virtual Dynamic Shared Object,虚拟动态共享对象)是 Linux 内核提供的一种机制,用来高效地将某些内核服务暴露给用户空间,而无需进行用户态到内核态的系统调用(syscall)切换。
其原理为:在内核空间中加载一个二进制共享库文件(vDSO),以及这个共享库文件访问的数据区(vVAR)。之后,将vDSO和vVAR均映射到用户空间,使用户程序可直接访问vDSO中提供的接口,并间接访问vVAR的数据。通过该方式,即可实现代码和数据在用户态和内核态间、在不同用户程序间的共享。
为何需要单独的vVAR数据区,而不是使用vDSO中的数据段?
vDSO被整体映射到一个只读区域。因此vDSO的数据段只能存储只读数据,而可变数据需要存储在vVAR中。vDSO功能的实现中,分别加载vDSO的代码段和数据段,并赋予相应的读写权限。但有两种可变数据需要区分:(1)共享的可变数据,在一个地址空间中的修改可以反映到其它地址空间中;(2)私有的可变数据,每个地址空间持有不同的拷贝,修改互不影响。因此我们使用vVAR存储共享的可变数据,而使用vDSO中的数据段存储私有的可变数据。关于vDSO的更详细介绍参考RISC-V Syscall 系列 4:vDSO 实现原理分析。
前文已提及,vDSO技术可用于用户和内核之间、用户进程之间的代码与数据共享。其可应用于一些需要如上的代码数据共享的领域,例如共享任务调度、异步系统调用和进程间通信。本项目即使用vDSO机制实现上述的功能。
本仓库中的两个crate,vdso_helper和build_vdso,用于支持使用Rust语言方便地开发和构建vDSO共享库:
vdso_helper:封装了vDSO代码所需的操作,包括(1)访问vVAR数据和(2)定义可由环境变量修改的常量。build_vdso:将vDSO代码的构建流程整合到vDSO外部代码的构建流程中,并构建可被vDSO外部代码依赖的API库。通过它们实现的,vDSO开发和构建流程如图所示:

基于本项目开展了如下的工作:
目前本项目的工作在AsyncOS上运行,未适配Linux。
vDSO库no_std、lib类型的Rust crate,并创建一个模块api和源文件api.rs。vdso_helper,使用其中的vvar_data!和get_vvar_data!定义和访问共享数据。vdso_helper中的mut_cfg!和use_mut_cfg!定义在编译期由环境变量指定的常量。api.rs中,且使用以下的函数定义:#[unsafe(no_mangle)]
pub extern "C" fn 函数名(参数) -> 返回值 {
函数体
}
注意:不是所有对外提供的函数都需要放入api.rs(例如对外提供某些类型关联的方法)。但是,如果该对外提供函数(直接或间接地)访问了共享数据,则必须放入api.rs中。
vDSO库vDSO外部代码的build.rs中使用build_vdso,配置BuildConfig构建参数,并传入build_vdso函数以构建vDSO库。vDSO和vVAR:在外部代码所在的地址空间中映射一块区域,并如此设置:首先保留一块VvarData大小的区域,设置为可读可写。在其之后的下一页加载第2步中的so文件,并为各个段设置合适的可读/可写/可执行权限。vVAR区域与vDSO区域的基址都需要对齐到config::PAGES_SIZE_4K。vDSO的加载基址。vDSO的API。vDSO和vVAR映射到其地址空间,并向用户进程传递vDSO的基址。用户进程即可通过第4、5步的方式使用vDSO。