在LTO模式下从GCC/Clang获取汇编输出

15
通常,可以使用GCC和Clang中的-S标志从源文件获取GCC的优化汇编输出,如下面的示例所示。
gcc -O3 -S -c -o foo.s foo.c

假设我使用-O3 -flto编译所有源文件,以启用链接时全程序优化,并想查看函数的最终编译器生成的优化汇编代码,以及查看代码如何被内联。
编译的结果是一堆.o文件,它们实际上是伪装成对象文件的IR文件。在链接可执行文件或共享库时,它们被压缩在一起,作为一个整体进行优化,然后编译成目标二进制文件。
但如果我想从这个过程中获得汇编输出呢?也就是说,在将IR编译为汇编语言期间,经过链接时优化之后,但在实际汇编和链接到最终可执行文件之前的汇编源代码。 我尝试在链接步骤中简单地添加-S标志,但那并没有真正起作用。 我知道可以对可执行文件进行反汇编,甚至与源代码交错,但有时查看实际由编译器生成的汇编代码会更好,特别是使用-fverbose-asm

你总是可以反汇编;使用 -g 选项,每个函数都有标签,并且块 -> 源代码行号调试信息允许 objdump -drwC -S -l 将反汇编与源代码交错。值得一试,不知道是否有效。虽然没有 gcc -S -fverbose-asm 那样的命名输出好看。 - Peter Cordes
反汇编是我目前所做的,但我想知道是否有任何方法可以不需要这样做(即一个大而全的汇编文件,本身可以被组装成最终的二进制文件)。 - Mona the Monad
在LLVM的情况下,将所有“对象”文件链接在一起,然后再传递“-S”是否可行? - Mona the Monad
我不知道,这就是为什么我点赞了这个问题并在评论中发布了一个解决方法! - Peter Cordes
我手头没有Clang来进行测试,但我认为它应该能够工作。不过这是针对LLVM特定的,如果可能的话,我想找到一个统一的解决方案。 - Mona the Monad
你最终解决了这个问题吗?我正在尝试在使用clang的godbolt中获取ASM输出,但是-flto会弄乱它。 - David Ledger
1个回答

5

对于GCC,只需将-save-temps添加到链接器命令中:

$ gcc -flto -save-temps ... *.o -o bin/libsortcheck.so
$ ls -1
...
libsortcheck.so.ltrans0.s

对于Clang而言,情况更加复杂。如果你使用GNU ld(默认或-fuse-ld=ld)或Gold链接器(通过-fuse-ld=gold启用),你需要使用-Wl,-plugin-opt=emit-asm来运行:
$ clang tmp.c -flto -Wl,-plugin-opt=emit-asm -o tmp.s

对于使用LLD链接器的新版本(11+)(通过-fuse-ld=lld启用),您可以使用-Wl,--lto-emit-asm生成汇编代码。


clang上似乎对我不起作用,但它似乎正在接近。添加该选项似乎会使其发出单个源的.bc.ii,但实际二进制文件还没有。我最接近的是使用-Wl,-plugin-opt = save-temps,它输出了*.{preopt,internalize,opt,precodegen}.bc文件和一个*.lto.o,但没有汇编源代码。 - Mona the Monad
1
@MonatheMonad 感谢您的反馈,由于某些原因,我以为这个问题只涉及 GCC。请查看更新后的答案。 - yugr
2
从生成的单片集成文件构建的任何最终二进制文件应该与“正常”构建的二进制文件完全相同(即没有-Wl,-plugin-opt = emit-asm),因为除了汇编和链接之外没有其他事情要做,对吧?我想将这个汇编生成作为某些调试构建的副作用,并且我想知道一个简单的clang -shared -o foo.so foo.so.s是否足够。 - Mona the Monad
2
@MonatheMonad 对于GCC来说,这绝对是正确的 - 如果你查看strace,你会发现它实际上组装了与在-save-temps下生成的完全相同的ltrans0.s文件。对于Clang来说情况不太清楚,我稍后会研究一下。 - yugr
3
从Clang的代码来看,情况似乎是一样的,但我建议进行一些验证以确保(例如,比较两种LTO流程的二进制文件)。 - yugr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接