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

fuz*_*fuz 8 linux system-calls systems-programming

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

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

Bas*_*tch 8

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

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

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

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

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

也就是说,如果从进程空间中提取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]
Run Code Online (Sandbox Code Playgroud)

另见这个答案.

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

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

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

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


fuz*_*fuz 6

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

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

  • 定位物体
  • 从符号表中提取地址

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