Explication. Je sais pas si tu connais GCC mais il a une option sympa qui montre les instructions assembleur qu'il génère.
Premier fichier #include <stdio.h>
int main () { char *s = "test";
puts(s); puts(s); puts(s);
return 0; }
Compiler avec gcc -S test.c il va générer test.s, ouvrir ce fichier. Il contient :
.file "test.c" .def ___main; .scl 2; .type 32; .endef .section .rdata,"dr" LC0: .ascii "test\0" .text .globl _main .def _main; .scl 2; .type 32; .endef _main: pushl %ebp movl %esp, %ebp subl $24, %esp andl $-16, %esp movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax sall $4, %eax movl %eax, -8(%ebp) movl -8(%ebp), %eax call __alloca call ___main movl $LC0, -4(%ebp) movl -4(%ebp), %eax movl %eax, (%esp) call _puts movl -4(%ebp), %eax movl %eax, (%esp) call _puts movl -4(%ebp), %eax movl %eax, (%esp) call _puts movl $0, %eax leave ret .def _puts; .scl 3; .type 32; .endef
Deuxième fichier, avec une boucle
#include <stdio.h> int main () { char *s = "test"; int n;
for (n=0; n<3; n++) puts(s);
return 0; }
re-compil:
.file "test.c" .def ___main; .scl 2; .type 32; .endef .section .rdata,"dr" LC0: .ascii "test\0" .text .globl _main .def _main; .scl 2; .type 32; .endef _main: pushl %ebp movl %esp, %ebp subl $24, %esp andl $-16, %esp movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax sall $4, %eax movl %eax, -12(%ebp) movl -12(%ebp), %eax call __alloca call ___main movl $LC0, -4(%ebp) movl $0, -8(%ebp) L2: cmpl $2, -8(%ebp) jg L3 movl -4(%ebp), %eax movl %eax, (%esp) call _puts leal -8(%ebp), %eax incl (%eax) jmp L2 L3: movl $0, %eax leave ret .def _puts; .scl 3; .type 32; .endef
Conclusion la version avec boucle crée deux labels supplémentaires, incrémente une valeur et exécute quelques instructions jump que la 1re version ne fait pas.
|