如何做到这一点?
如果我想分析某些东西是如何编译的,我将如何获得发出的汇编代码?
原文由 Doug T. 发布,翻译遵循 CC BY-SA 4.0 许可协议
如何做到这一点?
如果我想分析某些东西是如何编译的,我将如何获得发出的汇编代码?
原文由 Doug T. 发布,翻译遵循 CC BY-SA 4.0 许可协议
-save-temps
在 https://stackoverflow.com/a/17083009/895245 中提到了这一点,但让我进一步举例说明。
与 -S
相比,此选项的最大优势在于它可以很容易地添加到任何构建脚本中,而不会过多地干扰构建本身。
当你这样做时:
gcc -save-temps -c -o main.o main.c
主程序
#define INC 1
int myfunc(int i) {
return i + INC;
}
现在,除了正常输出 main.o
之外,当前工作目录还包含以下文件:
main.i
是一个奖励,包含预处理文件: # 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "main.c"
int myfunc(int i) {
return i + 1;
}
main.s
包含所需的生成程序集: .file "main.c"
.text
.globl myfunc
.type myfunc, @function
myfunc:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
movl -4(%rbp), %eax
addl $1, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size myfunc, .-myfunc
.ident "GCC: (Ubuntu 8.3.0-6ubuntu1) 8.3.0"
.section .note.GNU-stack,"",@progbits
如果要对大量文件执行此操作,请考虑改用:
-save-temps=obj
它将中间文件保存到与 -o
对象输出而不是当前工作目录相同的目录中,从而避免潜在的基本名称冲突。
这个选项的另一个很酷的事情是如果你添加 -v
:
gcc -save-temps -c -o main.o -v main.c
它实际上显示了正在使用的显式文件,而不是 /tmp
下的丑陋临时文件,因此很容易确切地知道发生了什么,其中包括预处理/编译/组装步骤:
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu main.c -mtune=generic -march=x86-64 -fpch-preprocess -fstack-protector-strong -Wformat -Wformat-security -o main.i
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -fpreprocessed main.i -quiet -dumpbase main.c -mtune=generic -march=x86-64 -auxbase-strip main.o -version -fstack-protector-strong -Wformat -Wformat-security -o main.s
as -v --64 -o main.o main.s
在 Ubuntu 19.04 amd64、GCC 8.3.0 中测试。
CMake 预定义目标
CMake 自动为预处理文件提供一个目标:
make help
向我们展示了我们可以做到:
make main.s
并且该目标运行:
Compiling C source to assembly CMakeFiles/main.dir/main.c.s
/usr/bin/cc -S /home/ciro/hello/main.c -o CMakeFiles/main.dir/main.c.s
所以文件可以在 CMakeFiles/main.dir/main.c.s
在 cmake 3.16.1 上测试。
原文由 Ciro Santilli OurBigBook.com 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答3.3k 阅读
使用
-S
选项到 gcc(或 g++),可选择使用-fverbose-asm
在默认情况下效果很好-O0
将 C 名称附加到 asm 操作数作为注释。在任何优化级别上都不太好,您通常希望使用它来获得值得一看的 asm。这将在 helloworld.c 上运行预处理器 (cpp),执行初始编译,然后在运行汇编器之前停止。有关在这种情况下使用的有用编译器选项,请参阅 如何从 GCC/clang 程序集输出中删除“噪音”? (或者只是 在 Matt Godbolt 的在线编译器资源管理器 上查看您的代码, 它过滤掉指令和东西,并使用调试信息突出显示以匹配源代码行与 asm。)
默认情况下,这将输出一个文件
helloworld.s
。仍然可以使用-o
选项设置输出文件,包括-o -
写入标准输出以将管道输入less
。当然,这仅在您拥有原始来源时才有效。如果您只有生成的目标文件,另一种方法是使用
objdump
,通过设置--disassemble
选项(或-d
缩写形式)。-S
将源代码行与正常的反汇编输出交错,所以如果为目标文件启用了调试选项(编译时-g
)并且文件没有被剥离,则此选项最有效。运行
file helloworld
将为您提供一些关于使用 objdump 将获得的详细程度的指示。其他有用的
objdump
选项包括-rwC
(显示符号重定位,禁用长机器代码的换行,以及 demangle C++ 名称)。如果你不喜欢 x86 的 AT&T 语法,-Mintel
。请参阅 手册页。例如,
objdump -drwC -Mintel -S foo.o | less
。-r
.o
对于只有00 00 00 00
符号引用的占位符的 --- 非常重要,而不是链接的可执行文件。