在 strace 中捕获 vDSO

Capture vDSO in strace

我想知道是否有办法捕获(换句话说观察)vDSO 调用,例如 strace 中的 gettimeofday

另外,有没有办法在不加载 linux-vdso.so.1(标志或环境变量)的情况下执行二进制文件?

最后,如果我编写一个程序从辅助向量中删除 linux-vdso.so.1 地址,然后 execve 我的程序呢?有人试过吗?

您可以使用 ltrace 而不是 strace 捕获对通过 vDSO 实现的系统调用的调用。这是因为对通过 vDSO 实现的系统调用的调用与 "normal" 系统调用不同,并且 strace 用于跟踪系统调用的方法不适用于 vDSO 实现的系统调用。要详细了解 strace 的工作原理,请查看 this blog post I wrote about strace. And, to learn more about how ltrace works, check out this other blog post I wrote about ltrace

不,不加载 linux-vdso.so.1 就无法执行二进制文件。至少,在我的 libc 版本上 Ubuntu 不精确。 libc/eglibc/etc 的较新版本当然有可能将此添加为一项功能,但似乎不太可能。请参阅下一个答案了解原因。

如果从辅助向量中删除地址,您的二进制文件可能会崩溃。 libc 有一个 piece of code ,它将首先尝试遍历 vDSO ELF 对象,如果失败,将回退到硬编码的 vsyscall 地址。避免这种情况的唯一方法是在禁用 vDSO 的情况下编译 glibc。

不过,如果您真的、真的不想使用 vDSO,还有另一种解决方法。您可以尝试使用 glibc's syscall function 并传入 gettimeofday 的系统调用编号。这将强制 glibc 通过内核而不是 vDSO 调用 gettimeofday

我在下面提供了一个示例程序来说明这一点。您可以通过阅读我的 syscall blog post.

了解更多关于系统调用如何工作的信息
#include <sys/time.h>
#include <stdio.h>

#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>

int
main(int argc, char *argv[]) {
    struct timeval tv;
    syscall(SYS_gettimeofday, &tv);

    return 0;
}

gcc -o test test.c编译并用strace -ttTf ./test 2>&1 | grep gettimeofday跟踪:

09:57:32.651876 gettimeofday({1467305852, 651888}, {420, 140735905220705}) = 0 <0.000006>