我想知道各种编译器如何实现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()
调用并在那里检查程序集?
答案 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-rtti
和std::__throw_bad_exception():
顺便说一句,没有std::__throw_bad_alloc():
,还有一个-fno-exceptions
定义,我认为这是一个展开处理程序。它不是您的实际功能的定义。静态二进制文件的开头附近是get_random_seed() [clone .cold]:
,我再次认为这是libstdc ++的异常处理程序代码。
不幸的是,我认为operator new(unsigned long) [clone .cold]:
或.text.cold
部分是首先链接的,因此在前500行中没有任何有趣的功能。 >
即使使用调试符号,我们也不知道正在访问哪个结构成员,仅是寄存器的数字偏移量,因为objdump不会填充这些成员。
由于存在许多分支,因此很难遵循复杂的逻辑可能性。运行时单步自动遵循 actual 的执行路径。