【发布时间】: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 -S或 godbolt.org