VDSO - Linux手册页
Linux程序员手册 第7部分
更新日期: 2019-08-02
名称
vdso-虚拟ELF动态共享对象概述
语法
#包括
无效* vdso =(uintptr_t)getauxval(AT_SYSINFO_EHDR);
说明
" vDSO"(虚拟动态共享对象)是一个小的共享库,内核会自动将其映射到所有用户空间应用程序的地址空间中。应用程序通常不需要关注这些细节,因为vDSO最常被C库调用。这样,您可以使用标准函数以常规方式进行编码,而C库将使用通过vDSO提供的任何功能。
为什么vDSO完全存在?内核提供了一些系统调用,这些调用提供了最终使用户空间代码频繁使用的程度,以至于此类调用可以支配整体性能。这是由于调用频率以及退出用户空间并进入内核而导致的上下文切换开销所致。
本文档的其余部分适用于好奇和/或C库编写者,而不是一般开发人员。如果您尝试在自己的应用程序中调用vDSO而不是使用C库,则很可能做错了。
Example background
进行系统调用可能很慢。在x86 32位系统中,您可以触发软件中断(int $ 0x80)以告诉内核您希望进行系统调用。但是,该指令很昂贵:它会通过处理器的微代码以及内核中的完整中断处理路径。较新的处理器具有更快的(但向后不兼容)指令来启动系统调用。 C库可以使用vDSO中内核提供的功能,而不是要求C库确定运行时该功能是否可用。
请注意,该术语可能会造成混淆。在x86系统上,用于确定进行系统调用的首选方法的vDSO函数名为" __kernel_vsyscall",但在x86-64上,术语" vsyscall"也表示一种过时的方式来询问内核,该时间是什么时候或呼叫者在哪个CPU上。
一个经常使用的系统调用是gettimeofday(2)。此系统调用既可以由用户空间应用程序直接调用,也可以由C库间接调用。考虑时间戳,定时循环或轮询-所有这些经常需要知道现在是几点。此信息也不是秘密的-任何特权模式下的任何应用程序(root或任何非特权用户)都将获得相同的答案。因此,内核将回答该问题所需的信息安排在进程可以访问的内存中。现在,对gettimeofday(2)的调用从系统调用变为正常的函数调用以及一些内存访问。
Finding the vDSO
vDSO的基地址(如果存在)通过内核通过AT_SYSINFO_EHDR标记传递给初始辅助向量中的每个程序(请参见getauxval(3))。
您不得假定vDSO被映射到用户内存映射中的任何特定位置。通常,每次创建新的过程映像时(在execve(2)时),基址通常在运行时随机分配。出于安全原因这样做是为了防止"返回libc"攻击。
对于某些体系结构,还有一个AT_SYSINFO标记。它仅用于定位vsyscall入口点,并且经常被省略或设置为0(表示不可用)。此标记是对最初vDSO工作的回溯(请参见下面的历史记录),应避免使用它。
File format
由于vDSO是完整的ELF图像,因此可以在其上进行符号查找。这允许在较新的内核版本中添加新的符号,并允许C库在不同内核版本下运行时在运行时检测可用功能。通常,C库会在第一个调用中进行检测,然后将结果缓存为后续调用。
所有符号也都已版本化(使用GNU版本格式)。这允许内核在不破坏向后兼容性的情况下更新功能签名。这意味着更改函数接受的参数以及返回值。因此,在vDSO中查找符号时,必须始终包括与您期望的ABI相匹配的版本。
通常,vDSO遵循为所有符号加上" _vdso"或" _kernel"前缀的命名约定,以便将它们与其他标准符号区分开。例如," gettimeofday"函数被命名为" __vdso_gettimeofday"。
在调用这些函数中的任何一个时,都可以使用标准的C调用约定。无需担心奇怪的寄存器或堆栈行为。
备注
Source
编译内核时,它将自动为您编译并链接vDSO代码。您会经常在特定于体系结构的目录下找到它:
查找arch / $ ARCH /-名称aq * vdso * .so * aq -o-名称aq * gate * .so * aq
vDSO names
vDSO的名称因架构而异。它通常会出现在glibc的ldd(1)输出中。确切名称与任何代码都无关紧要,因此请勿对其进行硬编码。
单元格不一致
strace(1), seccomp(2), and the vDSO
跟踪使用strace(1)进行的系统调用时,由vDSO导出的符号(系统调用)将不会出现在跟踪输出中。这些系统调用同样对seccomp(2)过滤器不可见。
ARCHITECTURE-SPECIFIC NOTES
以下小节提供了有关vDSO的特定于体系结构的说明。
请注意,所使用的vDSO是基于用户空间代码的ABI而不是内核的ABI。因此,例如,当您运行i386 32位ELF二进制文件时,无论在i386 32位内核还是x86-64 64位内核下运行,都将获得相同的vDSO。因此,应使用用户空间ABI的名称来确定以下哪一部分是相关的。
ARM functions
下表列出了vDSO导出的符号。
单元格不一致
此外,ARM端口具有一个充满实用程序功能的代码页。由于这只是代码的原始页面,因此没有用于进行符号查找或版本控制的ELF信息。它确实提供了对不同版本的支持。
有关此代码页上的信息,最好参考内核文档,因为它非常详细,涵盖了您需要了解的所有内容:Documentation / arm / kernel_user_helpers.txt。
aarch64 functions
下表列出了vDSO导出的符号。
单元格不一致
bfin (Blackfin) functions (port removed in Linux 4.17)
由于此CPU缺少内存管理单元(MMU),因此通常不会设置vDSO。而是在启动时将一些原始函数映射到内存中的固定位置。然后,用户空间应用程序直接调用该区域。除了嗅探原始操作码外,没有任何向后兼容性的规定,但是由于它是嵌入式CPU,因此可以避免其他事情-它运行的某些对象格式甚至都不基于ELF(它们是bFLT / FLAT) 。
有关此代码页上的信息,最好参考公共文档:
http://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:fixed-code
mips functions
下表列出了vDSO导出的符号。
单元格不一致
ia64 (Itanium) functions
下表列出了vDSO导出的符号。
单元格不一致
安腾端口有些棘手。除了上面的vDSO,它还具有"轻量级系统调用"(也称为"快速系统调用"或" fsys")。您可以通过__kernel_syscall_via_epc vDSO帮助程序来调用它们。此处列出的系统调用与您直接通过syscall(2)调用时具有相同的语义,因此请参阅相关文档。下表列出了通过此机制可用的功能。
function |
clock_gettime |
getcpu |
getpid |
getppid |
gettimeofday |
set_tid_address |
parisc (hppa) functions
parisc端口具有一个带有实用功能的代码页,称为网关页。它没有使用常规的ELF辅助向量方法,而是通过SR2寄存器将页面的地址传递给进程。页面上的权限使得仅执行那些地址即可自动以内核特权而不是用户空间执行。这样做是为了匹配HP-UX的工作方式。
由于这只是代码的原始页面,因此没有用于进行符号查找或版本控制的ELF信息。只需通过分支指令调用适当的偏移量即可,例如:
ble(%sr2,%r0)
单元格不一致
ppc/32 functions
下表列出了vDSO导出的符号。带有*的功能仅在内核为PowerPC64(64位)内核时可用。
单元格不一致
__kernel_clock_getres和__kernel_clock_gettime接口不支持CLOCK_REALTIME_COARSE和CLOCK_MONOTONIC_COARSE时钟。内核回退到实际的系统调用。
ppc/64 functions
下表列出了vDSO导出的符号。
单元格不一致
__kernel_clock_getres和__kernel_clock_gettime接口不支持CLOCK_REALTIME_COARSE和CLOCK_MONOTONIC_COARSE时钟。内核回退到实际的系统调用。
riscv functions
下表列出了vDSO导出的符号。
单元格不一致
s390 functions
下表列出了vDSO导出的符号。
单元格不一致
s390x functions
下表列出了vDSO导出的符号。
单元格不一致
sh (SuperH) functions
下表列出了vDSO导出的符号。
单元格不一致
i386 functions
下表列出了vDSO导出的符号。
单元格不一致
x86-64 functions
下表列出了vDSO导出的符号。所有这些符号也都可以不带" _vdso"前缀使用,但是您应该忽略这些符号并坚持以下名称。
单元格不一致
x86/x32 functions
下表列出了vDSO导出的符号。
单元格不一致
History
vDSO最初只是一个功能-vsyscall。在较早的内核中,您可能会在进程的内存映射中看到该名称,而不是" vdso"。随着时间的流逝,人们意识到这种机制是将更多功能传递给用户空间的好方法,因此,它被重新构想成当前格式的vDSO。
另外参见
syscalls(2),getauxval(3),proc(5)
Linux源代码树中的文档,示例和源代码:
Documentation/ABI/stable/vdso Documentation/ia64/fsys.txt Documentation/vDSO/* (includes examples of using the vDSO) find arch/ -iname aq*vdso*aq -o -iname aq*gate*aq
出版信息
这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/。