Pregunta

Esto es un poco bicho raro, pero yo estaba hurgando con la GNU assembler hoy (quiero ser capaz de leer al menos la sintaxis), y estaba tratando de conseguir que este pequeño ejemplo inventado de la mina a trabajar.Es decir, sólo quiero ir de 0 a 100, la impresión de los números todo el tiempo.Así que un par de minutos más tarde me encuentro con esto:

# 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:

Todo lo que veo de esto es 3 impresa una y otra vez.Como he dicho, sólo un pequeño ejemplo inventado, así que no te preocupes demasiado acerca de él, no es de vida o muerte problema.

(El formato es un poco desordenado, pero nada importante).

¿Fue útil?

Solución

Usted no puede confiar en lo que cualquier procedimiento llamado que hace a cualquiera de los registros.De inserción de los registros en la pila y el pop de vuelta después de llamar a printf o tener el incremento y el punto final de los valores de la memoria y la lectura/escrita en los registros a medida que los necesite.

Espero que los siguientes trabajos.Estoy asumiendo que pushl tiene un equivalente de mundial y usted puede empujar un par de números en la pila.

# 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:

Otros consejos

No estoy muy familiarizado con _printf, pero podría ser que se modifica eax?Printf debe devolver el número de caracteres impresos, que en este caso son dos:'0' y ' '.Creo que se devuelve en eax, y cuando se incremente, se obtiene 3, que es lo que se proceda a imprimir.Usted puede ser mejor usando un tipo diferente de registro para el contador.

Usted puede utilizar de forma segura los registros que son "llamado-salvo" sin tener que guardar usted mismo.En x86 estos son edi, esi, y ebx;las demás arquitecturas más.

Estos están documentados en la ABI referencias: http://math-atlas.sourceforge.net/devel/assembly/

Bien escrito las funciones suelen salir todos los registros en la pila y, a continuación, el pop cuando se hayan terminado de manera que permanecen sin cambios durante la función.La excepción sería eax que contiene el valor de retorno.Biblioteca de funciones como printf es más probable escrita de esta manera, así que yo no haría como Cuña sugiere:

Tendrás que hacer lo mismo para cualquier otra variable que tiene.El uso de registros para almacenar variables locales es bastante reservado a las arquitecturas con suficientes registros de apoyo (por ejemplo,ÉPICA, amd64, etc.)

De hecho, de lo que yo sé, los compiladores suelen compilar funciones que manera de ocuparse de esta cuestión.

@seanyboy, su solución es una exageración.Todo lo que se necesita es reemplazar eax con algún otro registro como ecx.

Nathan está en el camino correcto.No se puede asumir que los valores de registro será sin modificaciones después de llamar a una subrutina.De hecho, es mejor asumir que va a ser modificado, de lo contrario la subrutina no sería capaz de hacer su trabajo (al menos para el registro bajo recuento de arquitecturas como x86).Si desea conservar un valor que se debe almacenar en la memoria (por ejemplo,empuje en la pila y mantener un seguimiento de su ubicación).

Tendrás que hacer lo mismo para cualquier otra variable que tiene.El uso de registros para almacenar variables locales es bastante reservado a las arquitecturas con suficientes registros de apoyo (por ejemplo,ÉPICA, amd64, etc.)

Usted puede reescribir de forma que el uso de los registros que no suponga para cambiar, por ejemplo %ebp.Sólo asegúrese de insertarlos en la pila al principio, y el pop en la parte final de su rutina.

# 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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top