最近的 Linux 内核(至少在 amd64 上)提供了一个名为的魔术对象文件,该文件linux-vdso.so.1
将系统调用接口抽象到内核,允许内核选择最佳调用约定。如果你用 C 编写代码,glibc 会自动使用这个对象。
现在,如果我想在不使用 glibc 的情况下编写程序,我该如何使用这个对象?它提供的接口是否记录在某处?调用约定呢?
最近的 Linux 内核(至少在 amd64 上)提供了一个名为的魔术对象文件,该文件linux-vdso.so.1
将系统调用接口抽象到内核,允许内核选择最佳调用约定。如果你用 C 编写代码,glibc 会自动使用这个对象。
现在,如果我想在不使用 glibc 的情况下编写程序,我该如何使用这个对象?它提供的接口是否记录在某处?调用约定呢?
这取决于您的实现是否将C接口用于低级实用程序。
如果您的语言实现无需通过C包装器即可直接访问系统调用,则您不需要使用 VDSO(例如,您可以生成适当的SYSENTER
机器指令来执行系统调用),但您可以决定使用 VDSO,然后利用其中。在这种情况下,您的语言甚至不需要遵循所有 ABI 约定,只需遵循内核的约定。(例如,您不需要 ABI 在寄存器上提供调用者安全调用安全区分,甚至可以避免使用任何堆栈)。
甚至没有使用的语言实现的一个例子libc.so
是Bones 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>
您机器上的头文件。
例如; 正在运行(在zsh
64 位 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 等。)
我发现 Linux 内核树中的这些文件很有帮助:
Documentation/ABI/stable/vdso
(什么是 vDSO 对象?)Documentation/vDSO/parse_vdso.c
(vDSO 对象的参考解析器)vDSO对象是一个虚拟的动态共享对象,在linux下总是映射到一个amd64进程的地址空间。它可用于实现快速系统调用。要访问 vDSO 对象中的函数,您需要
这两件事都可以通过CC0许可的参考实现parse_vdso.c来完成。