9

最近的 Linux 内核(至少在 amd64 上)提供了一个名为的魔术对象文件,该文件linux-vdso.so.1将系统调用接口抽象到内核,允许内核选择最佳调用约定。如果你用 C 编写代码,glibc 会自动使用这个对象。

现在,如果我想在不使用 glibc 的情况下编写程序,我该如何使用这个对象?它提供的接口是否记录在某处?调用约定呢?

4

2 回答 2

9

这取决于您的实现是否将C接口用于低级实用程序。

如果您的语言实现无需通过C包装器即可直接访问系统调用,则您不需要使用 VDSO(例如,您可以生成适当的SYSENTER机器指令来执行系统调用),但您可以决定使用 VDSO,然后利用其中。在这种情况下,您的语言甚至不需要遵循所有 ABI 约定,只需遵循内核的约定。(例如,您不需要 ABI 在寄存器上提供调用者安全调用安全区分,甚至可以避免使用任何堆栈)。

甚至没有使用的语言实现的一个例子libc.soBones Scheme。你可以找到其他几个。

我对 VDSO 的理解是,它是由内核提供的一种抽象,用于抽象出各种 x86 处理器系列之间在实现系统调用时的各种小差异(与用户空间 -> 内核转换相关)。如果您选择了特定的处理器目标,则不需要 VDSO,而且您总是可以避免使用它。

AFAIU,VDSO 是一个 ELF 共享对象,位于(在我的 Debian/AMD64 上,带有最近编译的 3.8.3 内核)中ffffffffff600000-ffffffffff601000;准确检查cat /proc/self/maps它的位置)。因此,您只需要了解 ELF 共享对象的组织结构并从中检索符号即可。看到这个&那个链接。VDSO 使用 x86-64 ABI 规范中记录的 C 调用约定。

也就是说,如果您从进程空间中提取 VDSO 并将其写入磁盘文件,则结果是格式良好的 ELF 共享对象

ELF是一种有据可查的格式。x86-64 ABI 约定也是如此 (它精确定义了 C 调用约定,以及进程的映像如何启动。另请参见execve(2))手册页,当然还有内核文档,所以我不明白你有什么问题。我同意理解 ELF 需要时间(我 10 年前做过,但我的记忆已经生疏了)。另请阅读<elf.h>您机器上的头文件。

例如; 正在运行(在zsh64 位 Debian x86-64 下)

 % file $(which sash)
 /bin/sash: ELF 64-bit LSB executable, x86-64, version 1 (SYSV),
      statically linked, for GNU/Linux 2.6.26,
      BuildID[sha1]=0x0347fcc08fba2f811f58af99f26111d0f579a9f6, stripped

 % ldd $(which sash)
 not a dynamic executable

  % sash
  Stand-alone shell (version 3.7)
  > ps |grep sash
  21635 pts/3    00:00:00 sash
  > cat /proc/21635/maps
  00400000-004da000 r-xp 00000000 08:01 4985590                            /bin/sash
  006da000-006dc000 rw-p 000da000 08:01 4985590                            /bin/sash
  006dc000-006e1000 rw-p 00000000 00:00 0 
  017e3000-01806000 rw-p 00000000 00:00 0                                  [heap]
  7fe4950e5000-7fe4950e7000 rw-p 00000000 00:00 0 
  7fff3f130000-7fff3f151000 rw-p 00000000 00:00 0                          [stack]
  7fff3f173000-7fff3f175000 r-xp 00000000 00:00 0                          [vdso]
  ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

另请参阅此答案

您可能希望在运行时内部有一个能够简单解析 VDSO 的动态链接器的最小版本。您当然想了解进程启动的确切状态,尤其是auxv辅助向量的作用(我真的忘记了这些细节,但我记得它们很重要)。参见例如这篇文章

实际上,可靠地启动您的运行时可能比 VDSO 问题更难。

您可能还想阅读linux 程序集 howto,它也解释了一些事情(但更多关于 x86 的内容比 x86-64 更多)

顺便说一句, http : //musl-libc.org/ 的代码(这是一个替代 libc)更容易阅读和理解(你会很容易地了解他们如何进行动态链接、pthreads 等。)

于 2013-03-24T19:51:18.807 回答
5

我发现 Linux 内核树中的这些文件很有帮助:

vDSO对象是一个虚拟的动态共享对象,在linux下总是映射到一个amd64进程的地址空间。它可用于实现快速系统调用。要访问 vDSO 对象中的函数,您需要

  • 定位对象
  • 从符号表中提取地址

这两件事都可以通过CC0许可的参考实现parse_vdso.c来完成。

于 2013-03-24T20:55:14.177 回答