web-dev-qa-db-fra.com

Pourquoi GCC déplace-t-il les variables vers un emplacement temporaire avant de les affecter?

En regardant un code C décompilé, j'ai vu ceci:

movl    -0xc(%rbp), %esi
movl    %esi, -0x8(%rbp)

Cela correspond à ce code C:

x = y;

Cela m'a fait réfléchir: comment se fait-il que gcc déplace y vers %esi puis déplacez %esi vers x au lieu de simplement déplacer y vers x directement?


Il s'agit du code C complet et décompilé, si cela est important:

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);
    }
}

Décompilé

pushq    %rbp
movq     %rsp, %rbp
subq     $0x20, %rsp
movl     $0x0, -0x4(%rbp)

movl     $0x0, -0x8(%rbp) ; x = 0
movl     $0x1, -0xc(%rbp) ; y = 1

; printf
leaq     0x56(%rip), %rdi
movl     -0x8(%rbp), %esi
movb     $0x0, %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     $0xff, -0x8(%rbp) ; x < 255
jl       0x100000f3d ; do...while(x < 255)
jmp      0x100000f2f ; while(1)
37
Charanor

La plupart des instructions x86 (autres que certaines instructions spécialisées telles que movsb) ne peuvent accéder qu'à un seul emplacement mémoire. Par conséquent, un passage de mémoire en mémoire nécessite de passer par un registre avec deux instructions mov.

L'instruction mov peut être utilisée des manières suivantes:

mov mem, reg
mov reg, mem
mov reg, reg
mov reg, imm
mov mem, imm

Il n'y a pas mov mem, mem.

Notez que si vous aviez compilé avec des optimisations, les variables seraient placées dans des registres donc ce ne serait pas un problème.

75
interjay