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内核定时器使用及说明

《Linux内核定时器使用及说明》文章详细介绍了Linux内核定时器的特性、核心数据结构、时间相关转换函数以及操作API,通过示例展示了如何编写和使用定时器,包括按键消抖的应用... 目录1.linux内核定时器特征2.Linux内核定时器核心数据结构3.Linux内核时间相关转换函数4.Linux内核定时

Linux镜像文件制作方式

《Linux镜像文件制作方式》本文介绍了Linux镜像文件制作的过程,包括确定磁盘空间布局、制作空白镜像文件、分区与格式化、复制引导分区和其他分区... 目录1.确定磁盘空间布局2.制作空白镜像文件3.分区与格式化1) 分区2) 格式化4.复制引导分区5.复制其它分区1) 挂载2) 复制bootfs分区3)

JAVA线程的周期及调度机制详解

《JAVA线程的周期及调度机制详解》Java线程的生命周期包括NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED,线程调度依赖操作系统,采用抢占... 目录Java线程的生命周期线程状态转换示例代码JAVA线程调度机制优先级设置示例注意事项JAVA线程

Java中自旋锁与CAS机制的深层关系与区别

《Java中自旋锁与CAS机制的深层关系与区别》CAS算法即比较并替换,是一种实现并发编程时常用到的算法,Java并发包中的很多类都使用了CAS算法,:本文主要介绍Java中自旋锁与CAS机制深层... 目录1. 引言2. 比较并交换 (Compare-and-Swap, CAS) 核心原理2.1 CAS

Spring Boot 集成 mybatis核心机制

《SpringBoot集成mybatis核心机制》这篇文章给大家介绍SpringBoot集成mybatis核心机制,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值... 目录Spring Boot浅析1.依赖管理(Starter POMs)2.自动配置(AutoConfigu

Linux服务器数据盘移除并重新挂载的全过程

《Linux服务器数据盘移除并重新挂载的全过程》:本文主要介绍在Linux服务器上移除并重新挂载数据盘的整个过程,分为三大步:卸载文件系统、分离磁盘和重新挂载,每一步都有详细的步骤和注意事项,确保... 目录引言第一步:卸载文件系统第二步:分离磁盘第三步:重新挂载引言在 linux 服务器上移除并重新挂p

Linux下屏幕亮度的调节方式

《Linux下屏幕亮度的调节方式》文章介绍了Linux下屏幕亮度调节的几种方法,包括图形界面、手动调节(使用ACPI内核模块)和外接显示屏调节,以及自动调节软件(CaliseRedshift和Reds... 目录1 概述2 手动调节http://www.chinasem.cn2.1 手动屏幕调节2.2 外接显

Linux(centos7)虚拟机没有IP问题及解决方案

《Linux(centos7)虚拟机没有IP问题及解决方案》文章介绍了在CentOS7中配置虚拟机网络并使用Xshell连接虚拟机的步骤,首先,检查并配置网卡ens33的ONBOOT属性为yes,然后... 目录输入查看ZFhrxIP命令:ip addr查看,没有虚拟机IP修改ens33配置文件重启网络Xh

linux实现对.jar文件的配置文件进行修改

《linux实现对.jar文件的配置文件进行修改》文章讲述了如何使用Linux系统修改.jar文件的配置文件,包括进入文件夹、编辑文件、保存并退出编辑器,以及重新启动项目... 目录linux对.jar文件的配置文件进行修改第一步第二步 第三步第四步总结linux对.jar文件的配置文件进行修改第一步进

Redis的安全机制详细介绍及配置方法

《Redis的安全机制详细介绍及配置方法》本文介绍Redis安全机制的配置方法,包括绑定IP地址、设置密码、保护模式、禁用危险命令、防火墙限制、TLS加密、客户端连接限制、最大内存使用和日志审计等,通... 目录1. 绑定 IP 地址2. 设置密码3. 保护模式4. 禁用危险命令5. 通过防火墙限制访问6.