如何利用自己的编程语言利用VDSO对象?

时间:2013-03-24 19:12:37

标签: linux system-calls systems-programming

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

现在,如果我想在不使用glibc的情况下编写程序,我该如何使用这个对象?它提供的界面是否记录在某处?召唤惯例怎么样?

3 个答案:

答案 0 :(得分:8)

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

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

甚至不使用libc.so的语言实施示例是Bones Scheme。你可以找到其他几个。

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

AFAIU,VDSO是一个ELF共享对象,位于ffffffffff600000-ffffffffff601000段中(在我的Debian / AMD64上,最近编译的3.8.3内核);完全检查cat /proc/self/maps所在的位置。因此,您只需要了解ELF共享对象的组织并从中检索符号。见this& that个链接。 VDSO使用C约定来调用x86-64 ABI规范中记录的。

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

ELF是一种记录良好的格式。 x86-64 ABI conventions也是如此  (它精确定义了C调用约定,以及进程'图像的确切开始。另请参见execve(2))手册页,当然还有内核文档,所以我不明白你的问题是什么。我同意理解ELF需要时间(我10年前做过,但我的记忆生疏)。另请阅读计算机上的<elf.h>标题文件。

例如;运行(在64位Debian x86-64上的zsh下)

 % 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]

另见this answer

您可能希望在运行时内部使用能够简单地解析VDSO的动态链接器的最小版本。你当然想要了解一个过程开始的确切状态,特别是auxv,辅助向量的作用(我真的忘记了这些细节,但我记得它们很重要)。参见例如this article

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

您可能还想阅读linux assembly howto,这也解释了一些事情(但更多关于x86而不是x86-64)

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

答案 1 :(得分:4)

在挖掘互联网时我找到了这个链接

  

http://www.linuxjournal.com/content/creating-vdso-colonels-other-chicken

我认为它回答了你的问题

答案 2 :(得分:4)

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

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

  • 找到对象
  • 从符号表中提取地址

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