有没有办法查看在 *nix 中创建可执行文件时使用了哪些编译器和标志?我编译了旧版本的代码,我想看看它是否经过优化编译。谷歌并没有太大帮助,但我不确定我使用的关键字是否正确。
7 回答
gcc 有一个-frecord-gcc-switches
选项:
-frecord-gcc-switches
This switch causes the command line that was used to invoke the compiler to
be recorded into the object file that is being created. This switch is only
implemented on some targets and the exact format of the recording is target
and binary file format dependent, but it usually takes the form of a section
containing ASCII text.
之后,ELF 可执行文件将包含包含.GCC.command.line
该信息的部分。
$ gcc -O2 -frecord-gcc-switches a.c
$ readelf -p .GCC.command.line a.out
String dump of section '.GCC.command.line':
[ 0] a.c
[ 4] -mtune=generic
[ 13] -march=x86-64
[ 21] -O2
[ 25] -frecord-gcc-switches
当然,它不适用于没有该选项编译的可执行文件。
对于简单的优化案例,如果文件是使用调试信息编译的,您可以尝试使用调试器。如果您稍微浏览一下,您可能会注意到一些变量被“优化”了。这表明进行了优化。
如果您使用该-frecord-gcc-switches
标志进行编译,那么命令行编译器选项将被写入注释部分的二进制文件中。另请参阅文档。
另一个选项是 -grecord-gcc-swtiches(注意,不是 -f 而是 -g)。根据 gcc 文档,它会将标志放入 dwarf 调试信息中。并且看起来它从 gcc 4.8 开始默认启用。
我发现 dwarfdump 程序对于提取这些 cflags 很有用。注意,字符串程序看不到它们。看起来矮人信息被压缩了。
这是需要编译器支持的东西。您没有提及您正在使用什么编译器,但是由于您标记了您的问题linux
,我将假设您正在使用 gcc - 这不会默认您询问的功能(但 -frecord-gcc-switches 是执行此操作的选项)。
如果您想检查您的二进制文件,该strings
命令将向您显示文件中似乎是可读字符串的所有内容。
只要可执行文件是由 gcc 使用-g
选项编译的,以下内容就可以解决问题:
readelf --debug-dump=info /path/to/executable | grep "DW_AT_producer"
例如:
% cat test.c
int main() {
return 42;
}
% gcc -g test.c -o test
% readelf --debug-dump=info ./test | grep "DW_AT_producer"
<c> DW_AT_producer : (indirect string, offset: 0x2a): GNU C17 10.2.0 -mtune=generic -march=x86-64 -g
可悲的是,clang 似乎并没有以类似的方式记录选项,至少在版本 10 中是这样。
当然,strings
也会出现这种情况,但是必须至少对要查找的内容有所了解,因为用肉眼检查现实世界二进制文件中的所有字符串通常是不切实际的。例如,上面示例中的二进制文件:
% strings ./test | grep march
GNU C17 10.2.0 -mtune=generic -march=x86-64 -g -O3
如果您仍然有您使用的编译器(相同版本),并且它只是您不确定的一个标志,您可以尝试再次编译您的代码,一次有和一次没有标志。然后您可以比较可执行文件。您的旧的应该与新的之一相同或非常相似。
我非常怀疑这是可能的:
int main()
{
}
编译时:
gcc -O3 -ffast-math -g main.c -o main
在生成的对象中找不到任何参数:
strings main | grep -O3
(no output)