使用 Godbolt 进入标准库调用
Step into standard library call with godbolt
我想知道各种编译器如何实现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()
调用并检查那里的程序集?
您不能“单步执行”函数; Godbolt 不是调试器,它是反汇编器(在“二进制”模式下,否则是编译器 asm-text 输出过滤器/查看器)。你的程序没有 运行,它只是被编译了。 (除非您选择“二进制”输出选项,否则它只会编译为 asm,不会编译为机器代码,而且实际上不会 link。)
但是不管术语如何,不,你不能让 Godbolt 向你展示它恰好安装的任何版本的库的反汇编。
Single-step 桌面上的程序。(使用 gcc -O3 -fno-plt
编译以避免必须逐步执行 PLT 惰性动态 linking。 )
(我做到了,Arch Linux 运行s cpuid
上的 libstdc++ 6.2.1 在 std::random_device
的构造函数中。如果 rdrand
可用, 它在调用 _M_getval()
时使用它。仅通过反汇编来弄清楚这一点会很棘手;函数调用和分支有多个级别,如果没有符号,就很难弄清楚是什么。我的 Skylake有 rdseed
可用,但它没有使用它。是的,正如你评论的那样,那将是一个更好的选择。)
不同的编译器可以从同一个源生成不同版本的库函数,这就是编译器资源管理器存在的要点。不,它没有由下拉列表中的每个编译器编译的单独版本的 libstdc++。
不能保证您看到的库代码与您桌面上的代码或任何东西相匹配。
它确实安装了 x86-64 Linux 库,所以理论上 Godbolt 可以为您提供查找和反汇编某些库函数的选项,但该功能不存在现在。并且仅适用于“二进制”选项可用的目标;我认为对于大多数 cross-compile 目标,它只有 headers 而没有库。或者可能有一些其他原因它不会 link 和反汇编非 x86 ISA。
使用 -static
和二进制模式显示内容,但不是我们想要的。
I tried 使用 -static -fno-plt -fno-exceptions -fno-rtti -nostartfiles -O3 -march=skylake
进行编译(因此 rdrand 和 rdseed 在它们被内联时可用;它们没有)。 -fno-plt
与 -static
是多余的,但它在 没有 的情况下很有用,可以消除混乱。
-static
导致库代码最终出现在 Godbolt 反汇编的 linked 二进制文件中 。 但是输出限制在500行,而且std::random_device::_M_getval()
的定义刚好不在文件开头附近。
-nostartfiles
避免使二进制文件与 CRT 启动文件中的 _start
等混淆。不过,我认为 Godbolt 已经从反汇编中过滤掉了这些,因为您在正常的二进制输出中看不到它们(没有 -static
)。你不会运行这个程序,所以linker找不到_start
符号并默认将ELF入口点放在.text
部分的开始。
尽管使用 -fno-exceptions -fno-rtti
进行编译(因此不包含函数的展开处理程序),但 libstdc++ 函数在编译时启用了异常处理。因此 linking 它们会引入大量异常代码。静态可执行文件以 std::__throw_bad_exception():
和 std::__throw_bad_alloc():
等函数的定义开始
顺便说一句,没有 -fno-exceptions
,还有一个 get_random_seed() [clone .cold]:
定义,我认为它是一个展开处理程序。它不是您实际功能的定义。在静态二进制文件的开头附近是 operator new(unsigned long) [clone .cold]:
,我认为它又是 libstdc++ 的 exception-handler 代码。
我认为 .text.cold
或 .init
部分首先被 link 编辑,不幸的是,所以 none 有趣的功能将是在前 500 行可见。
即使这有效,也只是 binary-mode 反汇编,而不是编译器 asm
即使使用调试符号,我们也不知道正在访问哪个结构成员,只能知道寄存器的数字偏移量,因为 objdump 不会填充这些。
并且有很多分支,很难遵循复杂的逻辑可能性。 Single-stepping run-time 自动遵循实际 执行路径。
相关:
How to remove "noise" from GCC/clang assembly output? 关于将 Matt Godbolt 的编译器资源管理器用于它擅长的事情。
Matt Godbolt 的 CppCon2017 演讲“What Has My Compiler Done for Me Lately? Unbolting the Compiler's Lid”是一个很好的指南,并指出您可以克隆 compiler-explorer 存储库并使用您自己选择的本地设置编译器。您甚至可以破解它以允许更大的输出,但这对于 这个 问题来说显然仍然是一个糟糕的方法。
我想知道各种编译器如何实现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()
调用并检查那里的程序集?
您不能“单步执行”函数; Godbolt 不是调试器,它是反汇编器(在“二进制”模式下,否则是编译器 asm-text 输出过滤器/查看器)。你的程序没有 运行,它只是被编译了。 (除非您选择“二进制”输出选项,否则它只会编译为 asm,不会编译为机器代码,而且实际上不会 link。)
但是不管术语如何,不,你不能让 Godbolt 向你展示它恰好安装的任何版本的库的反汇编。
Single-step 桌面上的程序。(使用 gcc -O3 -fno-plt
编译以避免必须逐步执行 PLT 惰性动态 linking。 )
(我做到了,Arch Linux 运行s cpuid
上的 libstdc++ 6.2.1 在 std::random_device
的构造函数中。如果 rdrand
可用, 它在调用 _M_getval()
时使用它。仅通过反汇编来弄清楚这一点会很棘手;函数调用和分支有多个级别,如果没有符号,就很难弄清楚是什么。我的 Skylake有 rdseed
可用,但它没有使用它。是的,正如你评论的那样,那将是一个更好的选择。)
不同的编译器可以从同一个源生成不同版本的库函数,这就是编译器资源管理器存在的要点。不,它没有由下拉列表中的每个编译器编译的单独版本的 libstdc++。
不能保证您看到的库代码与您桌面上的代码或任何东西相匹配。
它确实安装了 x86-64 Linux 库,所以理论上 Godbolt 可以为您提供查找和反汇编某些库函数的选项,但该功能不存在现在。并且仅适用于“二进制”选项可用的目标;我认为对于大多数 cross-compile 目标,它只有 headers 而没有库。或者可能有一些其他原因它不会 link 和反汇编非 x86 ISA。
使用 -static
和二进制模式显示内容,但不是我们想要的。
I tried 使用 -static -fno-plt -fno-exceptions -fno-rtti -nostartfiles -O3 -march=skylake
进行编译(因此 rdrand 和 rdseed 在它们被内联时可用;它们没有)。 -fno-plt
与 -static
是多余的,但它在 没有 的情况下很有用,可以消除混乱。
-static
导致库代码最终出现在 Godbolt 反汇编的 linked 二进制文件中 。 但是输出限制在500行,而且std::random_device::_M_getval()
的定义刚好不在文件开头附近。
-nostartfiles
避免使二进制文件与 CRT 启动文件中的 _start
等混淆。不过,我认为 Godbolt 已经从反汇编中过滤掉了这些,因为您在正常的二进制输出中看不到它们(没有 -static
)。你不会运行这个程序,所以linker找不到_start
符号并默认将ELF入口点放在.text
部分的开始。
尽管使用 -fno-exceptions -fno-rtti
进行编译(因此不包含函数的展开处理程序),但 libstdc++ 函数在编译时启用了异常处理。因此 linking 它们会引入大量异常代码。静态可执行文件以 std::__throw_bad_exception():
和 std::__throw_bad_alloc():
顺便说一句,没有 -fno-exceptions
,还有一个 get_random_seed() [clone .cold]:
定义,我认为它是一个展开处理程序。它不是您实际功能的定义。在静态二进制文件的开头附近是 operator new(unsigned long) [clone .cold]:
,我认为它又是 libstdc++ 的 exception-handler 代码。
我认为 .text.cold
或 .init
部分首先被 link 编辑,不幸的是,所以 none 有趣的功能将是在前 500 行可见。
即使这有效,也只是 binary-mode 反汇编,而不是编译器 asm
即使使用调试符号,我们也不知道正在访问哪个结构成员,只能知道寄存器的数字偏移量,因为 objdump 不会填充这些。
并且有很多分支,很难遵循复杂的逻辑可能性。 Single-stepping run-time 自动遵循实际 执行路径。
相关:
How to remove "noise" from GCC/clang assembly output? 关于将 Matt Godbolt 的编译器资源管理器用于它擅长的事情。
Matt Godbolt 的 CppCon2017 演讲“What Has My Compiler Done for Me Lately? Unbolting the Compiler's Lid”是一个很好的指南,并指出您可以克隆 compiler-explorer 存储库并使用您自己选择的本地设置编译器。您甚至可以破解它以允许更大的输出,但这对于 这个 问题来说显然仍然是一个糟糕的方法。