如何将汇编代码与C程序中的确切行相关联?

时间:2017-06-21 11:35:12

标签: c debugging assembly gdb

以下是通过装配网站找到的示例。这是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代码的特定行相关联?
在这个小样本中,它并不太难,但在较大的程序中,当调试大量代码时,它会有点麻烦。

4 个答案:

答案 0 :(得分:5)

  

但是有没有办法提取哪些汇编行与特定的C代码行相关联?

是的,原则上 - 您的编译器可能会这样做(例如GCC选项-fverbose-asm)。或者,objdump -lSd或类似的将使用源和行号注释反汇编程序或目标文件。

一般而言,对于大型优化程序,这可能很难遵循。

即使有完美的注释,您也会看到多次提到的相同源代码行,因为表达式和语句被拆分,交错和重新排序,以及一些与多个源表达式相关的指令。

在这种情况下,您只需要考虑源和程序集之间的关系,但需要花费一些精力。

答案 1 :(得分:1)

我发现的最好的工具之一是Matthew Godbolt的Compiler Explorer

它具有多个编译器工具链,自动重新编译,并立即显示带有彩色线条的程序集输出,以显示相应的源代码行。

答案 2 :(得分:1)

首先,您需要通过gdwarfg标记或两者来编译程序,在其目标文件中保留有关源代码的信息。接下来,如果要调试,编译器必须避免优化,否则很难看到对应代码&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没有 提供这种语法。