为什么 GCC 在分配变量之前将变量移动到临时位置?
Why does GCC move variables to a temporary location before assigning them?
在查看一些反编译的 C 代码时,我看到了这个:
movl -0xc(%rbp), %esi
movl %esi, -0x8(%rbp)
这对应于这个C代码:
x = y;
这让我开始思考:gcc 为什么将 y
移动到 %esi
,然后将 %esi
移动到 x
而不是仅仅将 y
移动到 x
直接?
这是完整的 C 和反编译代码,如果重要的话:
C
int main(void) {
int x, y, z;
while(1) {
x = 0;
y = 1;
do {
printf("%d\n", x);
z = x + y;
x = y;
y = z;
} while(x < 255);
}
}
反编译
pushq %rbp
movq %rsp, %rbp
subq [=13=]x20, %rsp
movl [=13=]x0, -0x4(%rbp)
movl [=13=]x0, -0x8(%rbp) ; x = 0
movl [=13=]x1, -0xc(%rbp) ; y = 1
; printf
leaq 0x56(%rip), %rdi
movl -0x8(%rbp), %esi
movb [=13=]x0, %al
callq 0x100000f78
; z = x + y
movl -0x8(%rbp), %esi ; x -> esi
addl -0xc(%rbp), %esi ; y + esi
movl %esi, -0x10(%rbp) ; z = esi
; x = y
movl -0xc(%rbp), %esi
movl %esi, -0x8(%rbp)
; y = z
movl -0x10(%rbp), %esi
movl %esi, -0xc(%rbp)
movl %eax, -0x14(%rbp) ; not sure... I believe printf return value?
cmpl [=13=]xff, -0x8(%rbp) ; x < 255
jl 0x100000f3d ; do...while(x < 255)
jmp 0x100000f2f ; while(1)
大多数 x86 指令(除了一些专用指令,例如 movsb
)只能访问一个内存位置。因此,从内存到内存的移动需要通过带有两个 mov
指令的寄存器。
mov
指令可以通过以下方式使用:
mov mem, reg
mov reg, mem
mov reg, reg
mov reg, imm
mov mem, imm
没有mov mem, mem
.
请注意,如果您使用优化进行编译,变量将被放置在寄存器中,因此这不会成为问题。
在查看一些反编译的 C 代码时,我看到了这个:
movl -0xc(%rbp), %esi
movl %esi, -0x8(%rbp)
这对应于这个C代码:
x = y;
这让我开始思考:gcc 为什么将 y
移动到 %esi
,然后将 %esi
移动到 x
而不是仅仅将 y
移动到 x
直接?
这是完整的 C 和反编译代码,如果重要的话:
C
int main(void) {
int x, y, z;
while(1) {
x = 0;
y = 1;
do {
printf("%d\n", x);
z = x + y;
x = y;
y = z;
} while(x < 255);
}
}
反编译
pushq %rbp
movq %rsp, %rbp
subq [=13=]x20, %rsp
movl [=13=]x0, -0x4(%rbp)
movl [=13=]x0, -0x8(%rbp) ; x = 0
movl [=13=]x1, -0xc(%rbp) ; y = 1
; printf
leaq 0x56(%rip), %rdi
movl -0x8(%rbp), %esi
movb [=13=]x0, %al
callq 0x100000f78
; z = x + y
movl -0x8(%rbp), %esi ; x -> esi
addl -0xc(%rbp), %esi ; y + esi
movl %esi, -0x10(%rbp) ; z = esi
; x = y
movl -0xc(%rbp), %esi
movl %esi, -0x8(%rbp)
; y = z
movl -0x10(%rbp), %esi
movl %esi, -0xc(%rbp)
movl %eax, -0x14(%rbp) ; not sure... I believe printf return value?
cmpl [=13=]xff, -0x8(%rbp) ; x < 255
jl 0x100000f3d ; do...while(x < 255)
jmp 0x100000f2f ; while(1)
大多数 x86 指令(除了一些专用指令,例如 movsb
)只能访问一个内存位置。因此,从内存到内存的移动需要通过带有两个 mov
指令的寄存器。
mov
指令可以通过以下方式使用:
mov mem, reg
mov reg, mem
mov reg, reg
mov reg, imm
mov mem, imm
没有mov mem, mem
.
请注意,如果您使用优化进行编译,变量将被放置在寄存器中,因此这不会成为问题。