我想知道如何在我的C源文件上使用GCC来转储机器码的助记符版本,以便可以看到我的代码被编译成什么。您可以使用Java来做到这一点,但我无法通过GCC找到一种方法。
我试图在汇编中重新编写C方法,看看GCC如何做到这一点会有很大帮助。
我想知道如何在我的C源文件上使用GCC来转储机器码的助记符版本,以便可以看到我的代码被编译成什么。您可以使用Java来做到这一点,但我无法通过GCC找到一种方法。
我试图在汇编中重新编写C方法,看看GCC如何做到这一点会有很大帮助。
Answers:
如果使用调试符号进行编译,则可以objdump
用来产生更具可读性的反汇编。
>objdump --help
[...]
-S, --source Intermix source code with disassembly
-l, --line-numbers Include line numbers and filenames in output
objdump -drwC -Mintel
很好:
-r
在重定位上显示符号名称(因此您将puts
在call
下面的说明中看到)-R
显示动态链接重定位/符号名称(在共享库上有用)-C
分解C ++符号名称-w
为“宽”模式:它不会换行机器码字节-Mintel
:使用类似于GAS / binutils MASM的.intel_syntax noprefix
语法,而不是AT&T-S
:交叉插入源代码行和反汇编。你可以alias disas="objdump -drwCS -Mintel"
在你的东西~/.bashrc
例:
> gcc -g -c test.c
> objdump -d -M intel -S test.o
test.o: file format elf32-i386
Disassembly of section .text:
00000000 <main>:
#include <stdio.h>
int main(void)
{
0: 55 push ebp
1: 89 e5 mov ebp,esp
3: 83 e4 f0 and esp,0xfffffff0
6: 83 ec 10 sub esp,0x10
puts("test");
9: c7 04 24 00 00 00 00 mov DWORD PTR [esp],0x0
10: e8 fc ff ff ff call 11 <main+0x11>
return 0;
15: b8 00 00 00 00 mov eax,0x0
}
1a: c9 leave
1b: c3 ret
-Wa,-adhln -g to gcc
。这假设组装者是气体,并且并非总是如此。
-Mintel
。
如果给GCC标记-fverbose-asm
,它将
在生成的汇编代码中添加额外的注释信息,以使其更具可读性。
[...]添加的评论包括:
- 有关编译器版本和命令行选项的信息,
- 与汇编指令相关的源代码行,格式为FILENAME:LINENUMBER:CONTENT OF LINE,
- 提示哪些高级表达式对应于各种汇编指令操作数。
objdump
- 的开关objdump -drwCS -Mintel
,那么如何使用verbose
with objdump
呢?这样我就可以像-fverbose-asm
在gcc中一样在asm代码中添加注释了?
-fverbose-asm
以输出的asm语法中的注释形式出现,而不是会在.o
文件中添加任何多余内容的指令。在组装时将其全部丢弃。查看编译器的汇编输出而不是反汇编,例如在godbolt.org上,您可以通过鼠标悬停和相应的源/ asm行的颜色突出显示轻松地将其与源行进行匹配。 如何从GCC / c装配件输出中消除“噪音”?
使用-S(注意:大写S)开关切换到GCC,它将把汇编代码发送到扩展名为.s的文件中。例如,以下命令:
gcc -O2 -S foo.c
将生成的汇编代码保留在文件foo.s中。
直接从http://www.delorie.com/djgpp/v2faq/faq8_20.html翻录(但删除了错误的-c
)
gcc -march=native -O3 -save-temps
。您仍然可以-c
在不尝试链接或任何其他操作的情况下停止创建目标文件。
-save-temps
有趣的是,它一次转储完全由代码生成的代码,而另一种调用编译器的选项-S
意味着编译两次,并且可能使用不同的选项。但是 -save-temps
将所有内容转储到当前目录中,这有点混乱。看起来它更适合作为GCC的调试选项,而不是用于检查代码的工具。
-S
默认情况下,在基于x86的系统上使用切换到GCC会产生AT&T语法的转储,可以使用该-masm=att
开关指定它,如下所示:
gcc -S -masm=att code.c
而如果您想使用Intel语法生成转储,则可以使用该-masm=intel
开关,如下所示:
gcc -S -masm=intel code.c
(两者都将转储code.c
成不同的语法,code.s
分别生成到文件中)
为了使用objdump产生类似的效果,您需要使用--disassembler-options=
intel
/ att
开关(一个示例)(带有代码转储以说明语法上的差异):
$ objdump -d --disassembler-options=att code.c
080483c4 <main>:
80483c4: 8d 4c 24 04 lea 0x4(%esp),%ecx
80483c8: 83 e4 f0 and $0xfffffff0,%esp
80483cb: ff 71 fc pushl -0x4(%ecx)
80483ce: 55 push %ebp
80483cf: 89 e5 mov %esp,%ebp
80483d1: 51 push %ecx
80483d2: 83 ec 04 sub $0x4,%esp
80483d5: c7 04 24 b0 84 04 08 movl $0x80484b0,(%esp)
80483dc: e8 13 ff ff ff call 80482f4 <puts@plt>
80483e1: b8 00 00 00 00 mov $0x0,%eax
80483e6: 83 c4 04 add $0x4,%esp
80483e9: 59 pop %ecx
80483ea: 5d pop %ebp
80483eb: 8d 61 fc lea -0x4(%ecx),%esp
80483ee: c3 ret
80483ef: 90 nop
和
$ objdump -d --disassembler-options=intel code.c
080483c4 <main>:
80483c4: 8d 4c 24 04 lea ecx,[esp+0x4]
80483c8: 83 e4 f0 and esp,0xfffffff0
80483cb: ff 71 fc push DWORD PTR [ecx-0x4]
80483ce: 55 push ebp
80483cf: 89 e5 mov ebp,esp
80483d1: 51 push ecx
80483d2: 83 ec 04 sub esp,0x4
80483d5: c7 04 24 b0 84 04 08 mov DWORD PTR [esp],0x80484b0
80483dc: e8 13 ff ff ff call 80482f4 <puts@plt>
80483e1: b8 00 00 00 00 mov eax,0x0
80483e6: 83 c4 04 add esp,0x4
80483e9: 59 pop ecx
80483ea: 5d pop ebp
80483eb: 8d 61 fc lea esp,[ecx-0x4]
80483ee: c3 ret
80483ef: 90 nop
gcc -S -masm=intel test.c
对我而言并不完全有效,我得到了Intel和AT&T语法的一些杂种,例如:mov %rax, QWORD PTR -24[%rbp]
,而不是:movq -24(%rbp), %rax
。
.o
和ASM文件的并行输出时,也可以使用该方法,即通过-Wa,-ahls -o yourfile.o yourfile.cpp>yourfile.asm
-M
选项,它与选项相同,--disassembler-options
但要短得多,例如objdump -d -M intel a.out | less -N
godbolt是一个非常有用的工具,它们只列出了C ++编译器,但是您可以使用-x c
flag来将其视为C。它将随后为您的代码并排生成汇编列表,您可以使用该Colourise
选项生成彩色条以可视方式指示哪些源代码映射到生成的程序集。例如下面的代码:
#include <stdio.h>
void func()
{
printf( "hello world\n" ) ;
}
使用以下命令行:
-x c -std=c99 -O3
并Colourise
生成以下内容:
-masm=intel
但是其余的呢?
-x c
您是否尝试过gcc -S -fverbose-asm -O source.c
查看生成的source.s
汇编文件?
生成的汇编代码进入source.s
(您可以使用-o
assembler-filename覆盖它);该-fverbose-asm
选项要求编译器发出一些汇编注释,以“解释”生成的汇编代码。该-O
选项要求编译器优化一点(它可以使用-O2
或优化更多-O3
)。
如果您想了解gcc
正在执行的操作,请尝试传递-fdump-tree-all
但要小心:您将获得数百个转储文件。
source.s
,因为很多人希望在控制台上打印输出。
-S -o-
转储到标准输出。 -masm=intel
如果要使用NASM / YASM语法,则很有帮助。(但它使用qword ptr [mem]
,而不是qword
,因此更像是Intel / MASM而不是NASM / YASM)。 gcc.godbolt.org很好地整理了转储:可选地剥离仅注释行,未使用的标签和汇编程序指令。
-Og
它甚至比更好-O1
。这意味着“针对调试进行优化”,并且使asm没有太多棘手的/难以遵循的优化,而该优化无法完成消息来源所说的一切。它从gcc4.8开始可用,但是clang 3.7仍然没有。IDK是否决定反对还是采取其他措施。
您可以像objdump这样使用gdb。
此摘录摘自http://sources.redhat.com/gdb/current/onlinedocs/gdb_9.html#SEC64
这是一个显示Intel x86的混合源代码+程序集的示例:
(gdb)disas / m main 函数main的汇编代码转储: 5 { 0x08048330:推送%ebp 0x08048331:mov%esp,%ebp 0x08048333:子$ 0x8,%esp 0x08048336:和$ 0xfffffff0,%esp 0x08048339:子$ 0x10,%esp 6 printf(“ Hello。\ n”); 0x0804833c:movl $ 0x8048440,(%esp) 0x08048343:致电0x8048284 7返回0; 8} 0x08048348:mov $ 0x0,%eax 0x0804834d:离开 0x0804834e:重新 汇编器转储结束。
set disassembly-flavor intel
命令。
我还没有尝试过gcc,但是在使用g ++的情况下。下面的命令对我有用。-g用于调试构建,-Wa,-adhln传递给汇编器以列出源代码
g ++ -g -Wa,-adhln src.cpp