使用Godbolt进入标准库调用

时间:2019-05-21 19:45:04

标签: c++ assembly

我想知道各种编译器如何实现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()调用并在那里检查程序集?

1 个答案:

答案 0 :(得分:6)

您不能“介入”功能; Godbolt不是调试器,而是反汇编程序。您的程序不会运行,只会被编译。 (并且除非选择“二进制”输出选项,否则它只会编译为asm,不会编译为机器代码,并且实际上不会链接。)

但是,无论使用什么术语,不,您都无法让Godbolt向您展示正在安装的任何库版本的反汇编。

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

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


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

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

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


使用rdseed和二进制模式可以显示内容,但不能显示我们想要的内容。

I tried使用-static进行编译(因此rdrand和rdseed在可以被内联的情况下可用;但不能)。 -static -fno-plt -fno-exceptions -fno-rtti -nostartfiles -O3 -march=skylake对于-fno-plt来说是多余的,但是没有消除杂乱很有用。

-static导致库代码最终出现在Godbolt反汇编的链接二进制文件中但是输出限制为500行,-static的定义恰好不在文件开头。

std::random_device::_M_getval()避免使CRT启动文件中的-nostartfiles等二进制文件混乱。我认为Godbolt已经将这些过滤器从反汇编中过滤掉了,因为您没有在正常的二进制输出中看到它们(没有_start)。您无需运行程序,因此链接器找不到-static符号,而默认情况下只是将ELF入口点放在_start部分的开头,这无关紧要

尽管使用.text进行编译(因此不包含函数的展开处理程序),但libstdc ++函数是在启用异常处理的情况下编译的。因此,将它们链接会带来大量异常代码。静态可执行文件从-fno-exceptions -fno-rttistd::__throw_bad_exception():

之类的函数定义开始

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

不幸的是,我认为operator new(unsigned long) [clone .cold]:.text.cold部分是首先链接的,因此在前500行中没有任何有趣的功能。


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

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

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