9

我想知道各种编译器是如何实现std::random_device的,所以我把它弹出到Godbolt中。

不幸的是,它唯一说的是

std::random_device::operator()():
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     QWORD PTR [rbp-8], rdi
        mov     rax, QWORD PTR [rbp-8]
        mov     rdi, rax
        call    std::random_device::_M_getval()
        leave
        ret

这不是很有帮助。我如何才能进入_M_getval()通话并检查那里的程序集?

4

1 回答 1

10

你不能“步入”函数;Godbolt 不是调试器,它是反汇编器(在“二进制”模式下,否则是编译器 asm-text 输出过滤器/查看器)。你的程序没有运行,它只是被编译。(除非您选择“二进制”输出选项,否则它只会编译为 asm,而不是机器代码,并且实际上并不链接。)

但不管术语如何,不,你不能让 Godbolt 向你展示它碰巧安装的任何版本的库的反汇编。

在桌面上单步执行程序。 (编译gcc -O3 -fno-plt以避免不得不逐步执行 PLT 惰性动态链接。)

(我做到了,并且 Arch Linux 上的 libstdc++ 6.2.1 在cpuid. 的构造函数中运行std::random_device。如果rdrand可用,它会在调用_M_getval().如果没有符号,很难弄清楚是什么。我的 Skylake 有rdseed,但没有使用它。是的,正如你评论的那样,那将是一个更好的选择。)


不同的编译器可以从相同的源生成不同版本的库函数,这是编译器资源管理器存在的要点。不,它没有由下拉列表中的每个编译器编译的单独版本的 libstdc++。

无法保证您看到的库代码与您桌面上的内容或任何内容相匹配。

不过,它确实安装了 x86-64 Linux 库,因此理论上 Godbolt 可以为您提供查找和反汇编某些库函数的选项,但该功能目前不存在。并且仅适用于“二进制”选项可用的目标;我认为对于大多数交叉编译目标来说,它只有头文件而不是库。或者也许还有其他原因,它不会为非 x86 ISA 链接和反汇编。


使用-static和二进制模式显示的东西,但不是我们想要的。

我尝试使用编译-static -fno-plt -fno-exceptions -fno-rtti -nostartfiles -O3 -march=skylake(因此 rdrand 和 rdseed 可以在它们被内联的情况下使用;他们没有)。 -fno-plt与 是多余的-static,但它在消除混乱的情况下很有用。

-static导致库代码实际上以 Godbolt 反汇编的链接二进制文件结束但是输出被限制为 500 行,并且 的定义std::random_device::_M_getval()恰好不在文件的开头附近。

-nostartfiles避免将二进制文件与_startCRT 启动文件中的等等混淆。不过,我认为 Godbolt 已经将它们从反汇编中过滤掉了,因为您在正常的二进制输出中看不到它们(没有-static)。您不会运行该程序,因此链接器找不到_start符号并默认将 ELF 入口点放在该.text部分的开头并不重要。

尽管编译时使用-fno-exceptions -fno-rtti(因此不包含函数的展开处理程序),但 libstdc++ 函数在编译时启用了异常处理。因此,将它们链接起来会引入大量异常代码。静态可执行文件从定义函数开始,如std::__throw_bad_exception():std::__throw_bad_alloc():

顺便说一句,没有-fno-exceptions,还有一个get_random_seed() [clone .cold]:定义,我认为它是一个展开处理程序。这不是您实际功能的定义。在静态二进制文件的开头附近,operator new(unsigned long) [clone .cold]:我再次认为是 libstdc++ 的异常处理程序代码。

不幸的是,我认为.text.coldor.init部分首先被链接,所以在前 500 行中看不到任何有趣的功能。


即使这行得通,它也只是二进制模式反汇编,而不是编译器 asm

即使使用调试符号,我们也不知道正在访问哪个结构成员,只知道寄存器的数字偏移量,因为 objdump 不会填充它们。

并且有很多分支,很难遵循复杂的逻辑可能性。在运行时单步执行会自动遵循实际的执行路径。


有关的:

  • 如何从 GCC/clang 程序集输出中删除“噪音”?关于使用 Matt Godbolt 的 Compiler Explorer 来做一些有用的事情。

  • Matt Godbolt 的 CppCon2017 演讲“<a href="https://youtu.be/bSkpMdDe4g4" rel="nofollow noreferrer">我的编译器最近为我做了什么?Unbolting the Compiler's Lid” 是一个很好的指南,并指出您可以克隆编译器资源库并使用您自己选择的编译器在本地设置它。您甚至可以破解它以允许更大的输出,但这显然仍然是解决问题的不好方法。

于 2019-05-21T20:58:58.583 回答