装配移动指令似乎没用
Assembly move instruction seems to be useless
我正在努力学习汇编。我反汇编了一个简单的C程序并用gdb调试了它。但我注意到的一件事是值的移动非常频繁。
0x0000555555555231 <+0>: push rbp
0x0000555555555232 <+1>: mov rbp,rsp
0x0000555555555235 <+4>: sub rsp,0x20
0x0000555555555239 <+8>: mov QWORD PTR [rbp-0x18],rdi
0x000055555555523d <+12>: mov QWORD PTR [rbp-0x20],rsi
0x0000555555555241 <+16>: mov rax,QWORD PTR [rbp-0x18]
0x0000555555555245 <+20>: mov rdi,rax
0x0000555555555248 <+23>: call 0x5555555551d9 <get_file_size>
rdi 的值移到 rbp-0x18(<+8>)处的堆栈,rsi 的值移到 rbp-0x20(+12)处的堆栈。然后 rbp-0x18 的值被移动到 rax(+16),它会再次被移动到 rdi(+20)。为什么这样做?为什么不直接使用 rdi 或者至少将 rbp-0x18 直接移动到 rdi 而不是通过 rax (at <+16>)?这可以将指令保存在 +20
如果你想从中学习一些汇编程序,没有启用任何优化的编译没有多大意义。
这里有一个优化如何更改生成的代码的示例。
char *foo(char *dest, const char *src, size_t len)
{
char *savedDest = dest;
size_t index = 0;
if(len)
{
while(--len && (dest[index] = src[index]));
index++;
*dest = 0;
}
return savedDest;
}
无优化
foo:
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-24], rdi
mov QWORD PTR [rbp-32], rsi
mov QWORD PTR [rbp-40], rdx
mov rax, QWORD PTR [rbp-24]
mov QWORD PTR [rbp-8], rax
mov QWORD PTR [rbp-16], 0
cmp QWORD PTR [rbp-40], 0
je .L2
.L4:
sub QWORD PTR [rbp-40], 1
cmp QWORD PTR [rbp-40], 0
je .L3
mov rdx, QWORD PTR [rbp-32]
mov rax, QWORD PTR [rbp-16]
add rdx, rax
mov rcx, QWORD PTR [rbp-24]
mov rax, QWORD PTR [rbp-16]
add rax, rcx
movzx edx, BYTE PTR [rdx]
mov BYTE PTR [rax], dl
movzx eax, BYTE PTR [rax]
test al, al
jne .L4
.L3:
add QWORD PTR [rbp-16], 1
mov rax, QWORD PTR [rbp-24]
mov BYTE PTR [rax], 0
.L2:
mov rax, QWORD PTR [rbp-8]
pop rbp
ret
并优化尺寸
foo:
mov rax, rdi
test rdx, rdx
je .L2
.L4:
dec rdx
je .L3
mov cl, BYTE PTR [rsi]
mov BYTE PTR [rax], cl
test cl, cl
jne .L4
.L3:
mov BYTE PTR [rax], 0
.L2:
ret
我正在努力学习汇编。我反汇编了一个简单的C程序并用gdb调试了它。但我注意到的一件事是值的移动非常频繁。
0x0000555555555231 <+0>: push rbp
0x0000555555555232 <+1>: mov rbp,rsp
0x0000555555555235 <+4>: sub rsp,0x20
0x0000555555555239 <+8>: mov QWORD PTR [rbp-0x18],rdi
0x000055555555523d <+12>: mov QWORD PTR [rbp-0x20],rsi
0x0000555555555241 <+16>: mov rax,QWORD PTR [rbp-0x18]
0x0000555555555245 <+20>: mov rdi,rax
0x0000555555555248 <+23>: call 0x5555555551d9 <get_file_size>
rdi 的值移到 rbp-0x18(<+8>)处的堆栈,rsi 的值移到 rbp-0x20(+12)处的堆栈。然后 rbp-0x18 的值被移动到 rax(+16),它会再次被移动到 rdi(+20)。为什么这样做?为什么不直接使用 rdi 或者至少将 rbp-0x18 直接移动到 rdi 而不是通过 rax (at <+16>)?这可以将指令保存在 +20
如果你想从中学习一些汇编程序,没有启用任何优化的编译没有多大意义。
这里有一个优化如何更改生成的代码的示例。
char *foo(char *dest, const char *src, size_t len)
{
char *savedDest = dest;
size_t index = 0;
if(len)
{
while(--len && (dest[index] = src[index]));
index++;
*dest = 0;
}
return savedDest;
}
无优化
foo:
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-24], rdi
mov QWORD PTR [rbp-32], rsi
mov QWORD PTR [rbp-40], rdx
mov rax, QWORD PTR [rbp-24]
mov QWORD PTR [rbp-8], rax
mov QWORD PTR [rbp-16], 0
cmp QWORD PTR [rbp-40], 0
je .L2
.L4:
sub QWORD PTR [rbp-40], 1
cmp QWORD PTR [rbp-40], 0
je .L3
mov rdx, QWORD PTR [rbp-32]
mov rax, QWORD PTR [rbp-16]
add rdx, rax
mov rcx, QWORD PTR [rbp-24]
mov rax, QWORD PTR [rbp-16]
add rax, rcx
movzx edx, BYTE PTR [rdx]
mov BYTE PTR [rax], dl
movzx eax, BYTE PTR [rax]
test al, al
jne .L4
.L3:
add QWORD PTR [rbp-16], 1
mov rax, QWORD PTR [rbp-24]
mov BYTE PTR [rax], 0
.L2:
mov rax, QWORD PTR [rbp-8]
pop rbp
ret
并优化尺寸
foo:
mov rax, rdi
test rdx, rdx
je .L2
.L4:
dec rdx
je .L3
mov cl, BYTE PTR [rsi]
mov BYTE PTR [rax], cl
test cl, cl
jne .L4
.L3:
mov BYTE PTR [rax], 0
.L2:
ret