Question

C'est un peu excentrique, mais j'ai été farfouillé avec l'assembleur GNU aujourd'hui (je veux pouvoir au moins lire la syntaxe), et a essayé de faire ce peu artificiel exemple de la mine de travailler.À savoir, je veux juste passer de 0 à 100, de l'impression des numéros de tous les temps.Ainsi, quelques minutes plus tard, j'arrive à ceci:

# count.s: print the numbers from 0 to 100. 
    .text
string: .asciz "%d\n"
    .globl _main

_main:
    movl    $0, %eax # The starting point/current value.
    movl    $100,   %ebx # The ending point.

_loop:
    # Display the current value.
    pushl   %eax
    pushl   $string
    call     _printf
    addl     $8, %esp

    # Check against the ending value.
    cmpl    %eax, %ebx
    je    _end

    # Increment the current value.
    incl    %eax
    jmp _loop   

_end:

Tout ce que j'obtiens, c'est 3 imprimé, encore et encore.Comme je l'ai dit, juste un peu artificiel exemple, donc ne vous inquiétez pas trop à ce sujet, c'est pas une vie ou la mort de problème.

(La mise en forme est un peu foiré, mais rien de majeur).

Était-ce utile?

La solution

Vous ne pouvez pas faire confiance à ce que toute procédure d'appel fait à l'un des registres.Soit pousser les registres sur la pile et de la pop de retour off après l'appel de printf ou ont l'incrément et le point final des valeurs dans la mémoire et la lecture/écriture dans les registres que vous en avez besoin.

J'espère que les œuvres suivantes.Je suis en supposant que pushl a un équivalent de popl et vous pouvez pousser un couple supplémentaire de numéros sur la pile.

# count.s: print the numbers from 0 to 100. 
    .text
string: .asciz "%d\n"
    .globl _main

_main:
    movl    $0, %eax # The starting point/current value.
    movl    $100,       %ebx # The ending point.

_loop:
    # Remember your registers.
    pushl   %eax
    pushl   %ebx

    # Display the current value.
    pushl   %eax
    pushl   $string
    call     _printf
    addl     $8, %esp

    # reinstate registers.
    popl   %ebx
    popl   %eax

    # Check against the ending value.
    cmpl    %eax, %ebx
    je    _end

    # Increment the current value.
    incl    %eax
    jmp _loop   

_end:

Autres conseils

Je ne suis pas trop familier avec _printf, mais se pourrait-il qu'il modifie eax?Printf doit renvoyer le nombre de caractères imprimés, ce qui dans ce cas est de deux:'0' et ' '.Je pense qu'il est de retour cette eax, et quand vous l'incrémenter, vous obtenez 3, qui est ce que vous procédez à l'impression.Vous feriez mieux d'utiliser un registre différent pour le compteur.

Vous pouvez utiliser en toute sécurité les registres qui sont "callee-saved" sans avoir à les enregistrer vous-même.Sur x86, ce sont edi, esi, et ebx;d'autres architectures ont plus.

Ceux-ci sont documentés dans l'ABI références: http://math-atlas.sourceforge.net/devel/assembly/

Bien écrit, les fonctions seront généralement pousser tous les registres sur la pile puis de la pop quand ils sont fait pour qu'ils restent inchangées lors de la fonction.L'exception serait eax qui contient la valeur de retour.Bibliothèque de fonctions comme printf sont les plus susceptibles écrit de cette manière, donc je ne ferais pas comme Coin suggère:

Vous aurez besoin de faire la même chose pour n'importe quelle autre variable que vous avez.L'utilisation des registres pour stocker les variables locales est à peu près réservées aux architectures avec assez de registres à l'appui (p. ex.ÉPIQUE, amd64, etc.)

En fait, de ce que je sais, les compilateurs généralement de compiler les fonctions que la façon de traiter exactement avec ce problème.

@seanyboy, votre solution est exagéré.Tout ce qui est nécessaire est de remplacer eax avec certains autre registre comme ecx.

Nathan est sur la bonne voie.Vous ne pouvez pas supposer que les valeurs de registre ne sera pas modifié après l'appel d'une sous-routine.En fait, il est préférable de supposer qu'ils seront modifiés, le reste de la sous-routine ne serait pas en mesure de le faire fonctionner (au moins pour le bas registre de comptage des architectures comme x86).Si vous souhaitez conserver une valeur, vous devez les stocker dans la mémoire (par ex.push sur la pile et de garder une trace de l'emplacement).

Vous aurez besoin de faire la même chose pour n'importe quelle autre variable que vous avez.L'utilisation des registres pour stocker les variables locales est à peu près réservées aux architectures avec assez de registres à l'appui (p. ex.ÉPIQUE, amd64, etc.)

Vous pouvez réécrire de façon que vous utilisez les registres qui ne sont pas censés changer, par exemple %ebp.Assurez-vous juste de les pousser sur la pile au début, et de la pop à la fin de votre routine.

# count.s: print the numbers from 0 to 100. 
    .text
string: .asciz "%d\n"
    .globl _main

_main:
    push    %ecx
    push    %ebp
    movl    $0, %ecx # The starting point/current value.
    movl    $100,       %ebp # The ending point.

_loop:
    # Display the current value.
    pushl   %ecx
    pushl   $string
    call     _printf
    addl     $8, %esp

    # Check against the ending value.
    cmpl    %ecx, %ebp
    je    _end

    # Increment the current value.
    incl    %ecx
    jmp _loop   

_end:
    pop     %ebp
    pop     %ecx
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top