【问题标题】:GDB Disassembler shows assembly code - but in a different way than I expectedGDB Disassembler 显示汇编代码 - 但方式与我预期的不同
【发布时间】:2021-01-13 18:27:16
【问题描述】:

我最近开始使用 gdb 反汇编器,想看看它如何真正显示汇编代码,是否合乎逻辑(尝试调试 C 程序,一个计算链表长度的函数)。

这是 C 代码(不是我的,必须感谢 this site):

int length() {
   int length = 0;
   struct node *current;
    
   for(current = head; current != NULL; current = current->next) {
      length++;
   }
    
   return length;
}

编译:

gcc linkedlist.c -o linkedlist

这是产生的反汇编(intel-flavored):

   0x00000000000012a8 <+0>: endbr64 
   0x00000000000012ac <+4>: push   rbp
   0x00000000000012ad <+5>: mov    rbp,rsp
   0x00000000000012b0 <+8>: mov    DWORD PTR [rbp-0xc],0x0
   0x00000000000012b7 <+15>:    mov    rax,QWORD PTR [rip+0x2d5a]        # 0x4018 <head>
   0x00000000000012be <+22>:    mov    QWORD PTR [rbp-0x8],rax
   0x00000000000012c2 <+26>:    jmp    0x12d4 <length+44>
   0x00000000000012c4 <+28>:    add    DWORD PTR [rbp-0xc],0x1
   0x00000000000012c8 <+32>:    mov    rax,QWORD PTR [rbp-0x8]
   0x00000000000012cc <+36>:    mov    rax,QWORD PTR [rax+0x8]
   0x00000000000012d0 <+40>:    mov    QWORD PTR [rbp-0x8],rax
   0x00000000000012d4 <+44>:    cmp    QWORD PTR [rbp-0x8],0x0
   0x00000000000012d9 <+49>:    jne    0x12c4 <length+28>
   0x00000000000012db <+51>:    mov    eax,DWORD PTR [rbp-0xc]
   0x00000000000012de <+54>:    pop    rbp
   0x00000000000012df <+55>:    ret  

真正困扰我的一点是,我注意到的一件小事,也许你注意到的更多,是它不是我所学的汇编代码类型。我记得老师/教授一遍又一遍地说:“不要使用 mov ,0x0,只需 xor ,”

但在这里,它的内部是: DWORD PTR [rbp-0xc],0x0

我假设是变量int length = 0;的初始化

我的问题是,为什么它没有显示最有效的代码?如果它不能做到这一点(可能一切都不完美) - 那么为什么它不知道检测数字 0 的初始化并执行 xor 操作而不是 mov (自动),这真的很重要性能吗(如果它是什么因素?)

也许有更多的行可以被替换/忽略,但我作为一个初学者并没有注意到它们,但我做了这个具体的..有什么解释吗?

【问题讨论】:

  • 你是如何编译代码的?您是否添加了优化标志,例如 -O2
  • @ssbssa 不,我认为我将更新我如何编译 C 程序的问题并不重要
  • 好吧,如果你想让生成的可执行文件有良好的性能,你需要添加一个优化标志。
  • xor 作为归零习惯用法仅适用于寄存器,因为它本身需要 xor。显式内存操作数不能是xor 的两个操作数。 (但是,与 mov 相比,带有 0 的 and 是一种更短的零初始化内存方式。)
  • GDB 向您展示了那里的代码。您的措辞很奇怪,就像您希望 GDB 向您展示优化的代码,即使那不是您告诉 GCC 要做的。我想这不是你的意思。如果您只想查看编译器输出,有更简单的方法,例如How to remove "noise" from GCC/clang assembly output? 使用 gcc -O2 -Sgodbolt.org

标签: c assembly gdb nasm


【解决方案1】:

通常,gcc 编译时默认启用-O0 选项。它完全按照源文件中的内容生成代码,没有任何优化。编译器可以优化具有许多可能选项的代码,如下例所示:

struct node
{
    struct node *next;
};

int length(struct node *head) {
   int length = 0;
   struct node *current;
    
   for(current = head; current != NULL; current = current->next) {
      length++;
   }
    
   return length;
}

int __attribute__((optimize("-O3"))) length1(struct node *head) {
   int length = 0;
   struct node *current;
    
   for(current = head; current != NULL; current = current->next) {
      length++;
   }
    
   return length;
}

int __attribute__((optimize("-Os"))) length2(struct node *head) {
   int length = 0;
   struct node *current;
    
   for(current = head; current != NULL; current = current->next) {
      length++;
   }
    
   return length;
}

int __attribute__((optimize("-Og"))) length3(struct node *head) {
   int length = 0;
   struct node *current;
    
   for(current = head; current != NULL; current = current->next) {
      length++;
   }
    
   return length;
}

和代码

length:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-24], rdi
        mov     DWORD PTR [rbp-4], 0
        mov     rax, QWORD PTR [rbp-24]
        mov     QWORD PTR [rbp-16], rax
        jmp     .L2
.L3:
        add     DWORD PTR [rbp-4], 1
        mov     rax, QWORD PTR [rbp-16]
        mov     rax, QWORD PTR [rax]
        mov     QWORD PTR [rbp-16], rax
.L2:
        cmp     QWORD PTR [rbp-16], 0
        jne     .L3
        mov     eax, DWORD PTR [rbp-4]
        pop     rbp
        ret
length1:
        xor     eax, eax
        test    rdi, rdi
        je      .L8
.L7:
        mov     rdi, QWORD PTR [rdi]
        add     eax, 1
        test    rdi, rdi
        jne     .L7
        ret
.L8:
        ret
length2:
        xor     eax, eax
.L12:
        test    rdi, rdi
        je      .L14
        mov     rdi, QWORD PTR [rdi]
        inc     eax
        jmp     .L12
.L14:
        ret
length3:
        mov     eax, 0
        jmp     .L16
.L17:
        add     eax, 1
        mov     rdi, QWORD PTR [rdi]
.L16:
        test    rdi, rdi
        jne     .L17
        ret

【讨论】:

    猜你喜欢
    • 2020-12-10
    • 1970-01-01
    • 1970-01-01
    • 2015-12-22
    • 1970-01-01
    • 2020-10-05
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    相关资源
    最近更新 更多