GDB Disassembler 显示汇编代码 - 但与我预期的方式不同

GDB Disassembler shows assembly code - but in a different way than I expected

我最近开始使用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

这是反汇编结果(英特尔风格):

   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  

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

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

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

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

也许还有更多行本来可以 replaces/disregarded,但我作为初学者没有注意到它们,但我确实注意到了这一行..有什么解释吗?

通常,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