| On utilise %ecx, et sa valeur est écrasée par call printf |
→ | %ecx est un registre scratch, donc effectivement, printf va écraser sa valeur. On aura probablement un segfault au deuxième tour de boucle. |
| On utilise %ebx, et sa valeur est écrasée par call printf |
→ | %ebx étant un registre non-scratch, printf n'écrase pas sa valeur. |
| Il manque un addl $8, %esp après le call printf |
→ | En effet, c'est nécessaire pour annuler l'effet des deux push sur le registre %esp |
| On utilise %ebx, sans faire de sauvegarde/restauration de sa valeur. |
→ | Oui, %ebx est un registre non-scratch, si on l'utilise, on doit le sauvegarder (pushl %ebx apres pushl %ebp ) et le restaurer (movl -4(%ebp), %ebx avant leave ). |
→ | Voici une version du programme qui marche :
.globl main
main:
pushl %ebp
movl %esp, %ebp
// Sauvegarde du registre non-scratch par
// l'appelé
pushl %ebx
// On fait de la place pour :
// 2 arguments du printf
// 1 sauvegarde de registres
subl $(8+4), %esp
movl $chaine, %ecx
// On n'utilise que %bl, mais on remplit
// le reste de %ebx avec des 0.
movl $0, %ebx
while:
cmpb $0, (%ecx)
je fin_while
movb (%ecx), %bl
// On empile les arguments de printf
// Sauvegarde de %ecx
pushl %ecx
pushl %ebx
pushl $fmt
call printf
// Dépilage des arguments
addl $8, %esp
// Restauration de %ecx
popl %ecx
incl %ecx // équivalent à addl $1, %ecx
jmp while
fin_while:
// Restauration de registres non-scratch.
popl %ebx
leave
ret
.data
chaine: .asciz "Hello\n"
fmt: .asciz "%c"
|