使用 godbolt 进入标准库调用

2024-01-15

我想知道各个编译器是如何实现的std::random_device,所以我把它放进去godbolt https://godbolt.org/z/24H4SZ.

不幸的是,它唯一说的是

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()打电话并检查那里的集会吗?


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

但无论术语如何,您都无法让 Godbolt 向您展示它碰巧安装的任何版本的库的反汇编。

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

(我这样做了,Arch Linux 上的 libstdc++ 6.2.1 运行cpuid在构造函数中std::random_device. If rdrand可用,它在调用时使用它_M_getval()。仅通过反汇编来弄清楚这一点是很棘手的。有多个级别的函数调用和分支,如果没有符号,就很难弄清楚什么是什么。我的 Skylake 有rdseed可用,但没有使用它。是的,正如您所评论的,那将是一个更好的选择。)


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

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

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


Using -static二进制模式显示了一些东西,但不是我们想要的。

I tried https://godbolt.org/z/Ya3wez编译用-static -fno-plt -fno-exceptions -fno-rtti -nostartfiles -O3 -march=skylake(因此 rdrand 和 rdseed 可以使用,以防它们被内联;但它们没有)。-fno-plt是多余的-static,但是很有用without消除那些混乱。

-static导致库代码实际上最终出现在 Godbolt 反汇编的链接二进制文件中. 但输出限制为500行,并且定义std::random_device::_M_getval()碰巧不在文件开头附近。

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

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

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

我觉得.text.cold or .init不幸的是,各个部分首先被链接,因此在前 500 行中不会显示任何有趣的函数。


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

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

由于有很多分支,很难遵循复杂的逻辑可能性。运行时单步执行会自动遵循actual执行路径。


Related:

  • 如何从 GCC/clang 汇编输出中消除“噪音”? https://stackoverflow.com/questions/38552116/how-to-remove-noise-from-gcc-clang-assembly-output关于使用 Matt Godbolt Compiler Explorer 来做它有用的事情。

  • Matt Godbolt CppCon 2017 演讲“我的编译器最近为我做了什么?打开编译器的盖子 https://youtu.be/bSkpMdDe4g4” 是一个很好的指南,并指出您可以克隆编译器资源管理器存储库并使用您自己选择的编译器在本地进行设置。你甚至可以破解它以允许更大的输出,但这对于this问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 godbolt 进入标准库调用 的相关文章

随机推荐