以下是通过装配网站找到的示例。这是C代码:
int main()
{
int a = 5;
int b = a + 6;
return 0;
}
以下是相关的汇编代码:
(gdb) disassemble
Dump of assembler code for function main:
0x0000000100000f50 <main+0>: push %rbp
0x0000000100000f51 <main+1>: mov %rsp,%rbp
0x0000000100000f54 <main+4>: mov $0x0,%eax
0x0000000100000f59 <main+9>: movl $0x0,-0x4(%rbp)
0x0000000100000f60 <main+16>: movl $0x5,-0x8(%rbp)
0x0000000100000f67 <main+23>: mov -0x8(%rbp),%ecx
0x0000000100000f6a <main+26>: add $0x6,%ecx
0x0000000100000f70 <main+32>: mov %ecx,-0xc(%rbp)
0x0000000100000f73 <main+35>: pop %rbp
0x0000000100000f74 <main+36>: retq
End of assembler dump.
我可以放心地假设这行汇编代码:
0x0000000100000f6a <main+26>: add $0x6,%ecx
与此C行相关:
int b = a + 6;
但是有没有办法提取哪些装配线与C代码的特定行相关联?
在这个小样本中,它并不太难,但在较大的程序中,当调试大量代码时,它会有点麻烦。
答案 0 :(得分:5)
但是有没有办法提取哪些汇编行与特定的C代码行相关联?
是的,原则上 - 您的编译器可能会这样做(例如GCC选项-fverbose-asm
)。或者,objdump -lSd
或类似的将使用源和行号注释反汇编程序或目标文件。
一般而言,对于大型优化程序,这可能很难遵循。
即使有完美的注释,您也会看到多次提到的相同源代码行,因为表达式和语句被拆分,交错和重新排序,以及一些与多个源表达式相关的指令。
在这种情况下,您只需要考虑源和程序集之间的关系,但需要花费一些精力。
答案 1 :(得分:1)
我发现的最好的工具之一是Matthew Godbolt的Compiler Explorer。
它具有多个编译器工具链,自动重新编译,并立即显示带有彩色线条的程序集输出,以显示相应的源代码行。
答案 2 :(得分:1)
首先,您需要通过gdwarf
或g
标记或两者来编译程序,在其目标文件中保留有关源代码的信息。接下来,如果要调试,编译器必须避免优化,否则很难看到对应代码&lt;&gt;程序集。
gcc -gdwarf -g3 -O0 prog.c -o out
接下来,告诉反汇编程序输出源代码。 source
标志包含disassemble
标志。
objdump --source out
答案 3 :(得分:0)
@Useless是对的。无论如何,知道C在机器代码中的位置的技巧是在其中注入标记;例如,
#define ASM_MARK do { asm __volatile__("nop; nop; nop;\n\t" :::); } while (0);
int main()
{
int a = 5;
ASM_MARK;
int b = a + 6;
ASM_MARK;
return 0;
}
你会看到:
main:
pushq %rbp
movq %rsp, %rbp
movl $5, -4(%rbp)
nop; nop; nop;
movl -4(%rbp), %eax
addl $6, %eax
movl %eax, -8(%rbp)
nop; nop; nop;
movl $0, %eax
popq %rbp
ret
你需要使用__volatile__
关键字或等价物来告诉编译器不要干扰,这通常是编译器特定的(注意__
),因为C没有
提供这种语法。