Linux vdso机制

2023-12-14 06:36
文章标签 linux 机制 vdso

本文主要是介绍Linux vdso机制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 一、简介
  • 二、vdso
    • 2.1 用户态
    • 2.2 内核态
    • 2.3 内核源码解析
  • 参考资料

一、简介

Linux中的vdso(Virtual Dynamic Shared Object)是一种特殊的动态共享对象,它在用户空间和内核空间之间提供了一种高效的接口。vdso机制的目的是减少用户空间程序与内核之间频繁的上下文切换开销,提高系统性能。

“vDSO”(虚拟动态共享对象)是一个小型的共享库,内核会自动将其映射到所有用户空间应用程序的地址空间中。应用程序通常无需关注这些细节,因为vDSO最常由C库调用。这样,可以以正常方式编码,使用标准函数,而C库会负责使用通过vDSO可用的任何功能。

vDSO的存在是为什么?内核提供了一些系统调用,用户空间代码经常使用这些调用,以至于这些调用可能主导整体性能。这既是由于调用的频率,又是由于从用户空间退出并进入内核所产生的上下文切换开销。

vdso包含一组特定的函数,这些函数在用户空间中执行,但其实现是由内核提供的。用户空间程序可以通过调用这些函数来访问一些系统功能,而无需陷入内核态。

vdso的一个重要用途是实现系统调用的快速路径。当用户空间程序执行系统调用时,通常需要进行一次上下文切换,将控制权从用户态切换到内核态。然而,某些系统调用是非常频繁且开销较小的,这种上下文切换的开销可能会成为性能瓶颈。vdso提供了一个快速路径,通过在用户空间中执行特定的系统调用函数,避免了不必要的上下文切换,从而提高了系统调用的性能。

在Linux中,vdso通常以linux-vdso.so.X的形式存在于/proc/self/maps中,并且被映射到每个进程的地址空间中。这样,用户空间程序可以直接调用vdso中的函数,而无需显式加载和链接vdso库。

总结来说,vdso是Linux中用于优化系统调用性能的一种机制,它提供了一组在用户空间执行的特定系统调用函数,以减少用户态和内核态之间的上下文切换开销,并提高系统性能。

备注:
vdso只包括了几个特定的系统调用:

clock_gettime
gettimeofday
getcpu
time
clock_getres

比如gettimeofday:
一个经常被使用的系统调用是gettimeofday(2)。这个系统调用既可以被用户空间应用程序直接调用,也可以被C库间接调用。想象一下时间戳、定时循环或轮询,所有这些都经常需要知道当前的时间。这些信息也不是机密的,任何特权模式(root或非特权用户)的应用程序都会得到相同的答案。因此,内核会安排将回答这个问题所需的信息放置在进程可以访问的内存中。现在,调用gettimeofday(2)变成了一个普通的函数调用和几次内存访问。

二、vdso

2.1 用户态

# ldd /usr/bin/lslinux-vdso.so.1 (0x00007ffca7b40000)......
# cat /proc/1/maps
55637a23d000-55637a26f000 r--p 00000000 08:05 59514907                   /usr/lib/systemd/systemd
55637a26f000-55637a32d000 r-xp 00032000 08:05 59514907                   /usr/lib/systemd/systemd
55637a32d000-55637a383000 r--p 000f0000 08:05 59514907                   /usr/lib/systemd/systemd
55637a383000-55637a3c9000 r--p 00145000 08:05 59514907                   /usr/lib/systemd/systemd
55637a3c9000-55637a3ca000 rw-p 0018b000 08:05 59514907                   /usr/lib/systemd/systemd
55637c14a000-55637c416000 rw-p 00000000 00:00 0                          [heap]......7f008b2bf000-7f008b2c0000 rw-p 00000000 00:00 0
7ffd3bc40000-7ffd3bd42000 rw-p 00000000 00:00 0                          [stack]
7ffd3bd4f000-7ffd3bd53000 r--p 00000000 00:00 0                          [vvar]
7ffd3bd53000-7ffd3bd55000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]

其中:

7ffd3bd53000-7ffd3bd55000 r-xp 00000000 00:00 0                          [vdso]

可以看到vdso内存大小:0x2000 = 4096 * 2,即两个虚拟页面的大小。

vdso的起始虚拟地址在进程1是:0x7ffd3bd53000,转化为十进制即140725607280640,将这段内存dump到文件中:

# dd if=/proc/1/mem of=/tmp/linux-vdso.so skip=140725607280640 ibs=1 count=8192
dd: /proc/1/mem: cannot skip to specified offset
8192+0 records in
16+0 records out
8192 bytes (8.2 kB, 8.0 KiB) copied, 0.00971912 s, 843 kB/s

由于vDSO是一个完整的ELF镜像,可以对其进行符号查找:

# objdump -T /tmp/linux-vdso.so/tmp/linux-vdso.so:     file format elf64-x86-64DYNAMIC SYMBOL TABLE:
0000000000000a10  w   DF .text  0000000000000413  LINUX_2.6   clock_gettime
0000000000000690 g    DF .text  0000000000000348  LINUX_2.6   __vdso_gettimeofday
0000000000000e30  w   DF .text  0000000000000060  LINUX_2.6   clock_getres
0000000000000e30 g    DF .text  0000000000000060  LINUX_2.6   __vdso_clock_getres
0000000000000690  w   DF .text  0000000000000348  LINUX_2.6   gettimeofday
00000000000009e0 g    DF .text  0000000000000029  LINUX_2.6   __vdso_time
0000000000000ec0 g    DF .text  000000000000009c  LINUX_2.6   __vdso_sgx_enter_enclave
00000000000009e0  w   DF .text  0000000000000029  LINUX_2.6   time
0000000000000a10 g    DF .text  0000000000000413  LINUX_2.6   __vdso_clock_gettime
0000000000000000 g    DO *ABS*  0000000000000000  LINUX_2.6   LINUX_2.6
0000000000000e90 g    DF .text  0000000000000025  LINUX_2.6   __vdso_getcpu
0000000000000e90  w   DF .text  0000000000000025  LINUX_2.6   getcp

2.2 内核态

vDSO 会向用户提供的 syscall:

// linux-5.13/arch/x86/entry/vdso/vdso.lds.S/** This controls what userland symbols we export from the vDSO.*/
VERSION {LINUX_2.6 {global:clock_gettime;__vdso_clock_gettime;gettimeofday;__vdso_gettimeofday;getcpu;__vdso_getcpu;time;__vdso_time;clock_getres;__vdso_clock_getres;__vdso_sgx_enter_enclave;local: *;};
}

即:

__vdso_clock_gettime
__vdso_gettimeofday
__vdso_getcpu
__vdso_time
__vdso_clock_getres
__vdso_sgx_enter_enclave

通常,vDSO遵循将所有符号以“_vdso”或“_kernel”作为前缀的命名约定,以便将它们与其他标准符号区分开。例如,“gettimeofday”函数的名称是“__vdso_gettimeofday”。

可以看到用户态vdso虚拟地址内容一样。

2.3 内核源码解析

内核具体源码解析请参考:
https://tinylab.org/riscv-syscall-part4-vdso-implementation/
https://www.bookstack.cn/read/linux-insides-zh/SysCall-linux-syscall-3.md
https://zhuanlan.zhihu.com/p/611286101

参考资料

Linux 5.13
https://man7.org/linux/man-pages/man7/vdso.7.html
https://blog.rustforever.top/2022/02/10/linux/syscall/vdso/
https://zhuanlan.zhihu.com/p/620578643
https://cloud.tencent.com/developer/article/1517837

这篇关于Linux vdso机制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/491492

相关文章

嵌入式Linux之使用设备树驱动GPIO的实现方式

《嵌入式Linux之使用设备树驱动GPIO的实现方式》:本文主要介绍嵌入式Linux之使用设备树驱动GPIO的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、设备树配置1.1 添加 pinctrl 节点1.2 添加 LED 设备节点二、编写驱动程序2.1

嵌入式Linux驱动中的异步通知机制详解

《嵌入式Linux驱动中的异步通知机制详解》:本文主要介绍嵌入式Linux驱动中的异步通知机制,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、异步通知的核心概念1. 什么是异步通知2. 异步通知的关键组件二、异步通知的实现原理三、代码示例分析1. 设备结构

Linux搭建单机MySQL8.0.26版本的操作方法

《Linux搭建单机MySQL8.0.26版本的操作方法》:本文主要介绍Linux搭建单机MySQL8.0.26版本的操作方法,本文通过图文并茂的形式给大家讲解的非常详细,感兴趣的朋友一起看看吧... 目录概述环境信息数据库服务安装步骤下载前置依赖服务下载方式一:进入官网下载,并上传到宿主机中,适合离线环境

JVM垃圾回收机制之GC解读

《JVM垃圾回收机制之GC解读》:本文主要介绍JVM垃圾回收机制之GC,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、死亡对象的判断算法1.1 引用计数算法1.2 可达性分析算法二、垃圾回收算法2.1 标记-清除算法2.2 复制算法2.3 标记-整理算法2.4

windows和Linux使用命令行计算文件的MD5值

《windows和Linux使用命令行计算文件的MD5值》在Windows和Linux系统中,您可以使用命令行(终端或命令提示符)来计算文件的MD5值,文章介绍了在Windows和Linux/macO... 目录在Windows上:在linux或MACOS上:总结在Windows上:可以使用certuti

Linux之systemV共享内存方式

《Linux之systemV共享内存方式》:本文主要介绍Linux之systemV共享内存方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、工作原理二、系统调用接口1、申请共享内存(一)key的获取(二)共享内存的申请2、将共享内存段连接到进程地址空间3、将

快速修复一个Panic的Linux内核的技巧

《快速修复一个Panic的Linux内核的技巧》Linux系统中运行了不当的mkinitcpio操作导致内核文件不能正常工作,重启的时候,内核启动中止于Panic状态,该怎么解决这个问题呢?下面我们就... 感谢China编程(www.chinasem.cn)网友 鸢一雨音 的投稿写这篇文章是有原因的。为了配置完

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

Linux命令之firewalld的用法

《Linux命令之firewalld的用法》:本文主要介绍Linux命令之firewalld的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux命令之firewalld1、程序包2、启动firewalld3、配置文件4、firewalld规则定义的九大

Linux之计划任务和调度命令at/cron详解

《Linux之计划任务和调度命令at/cron详解》:本文主要介绍Linux之计划任务和调度命令at/cron的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux计划任务和调度命令at/cron一、计划任务二、命令{at}介绍三、命令语法及功能 :at