Pergunta

Isso é meio estranho, mas eu estava mexendo no montador GNU hoje (quero poder pelo menos ler a sintaxe) e estava tentando fazer esse meu pequeno exemplo inventado funcionar.Ou seja, eu só quero ir de 0 a 100, imprimindo números o tempo todo.Então, alguns minutos depois, eu penso nisso:

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

Tudo o que obtenho com isso são 3 impressos repetidamente.Como eu disse, apenas um pequeno exemplo inventado, então não se preocupe muito com isso, não é um problema de vida ou morte.

(A formatação está um pouco confusa, mas nada grave).

Foi útil?

Solução

Você não pode confiar no que qualquer procedimento chamado faz em qualquer um dos registros.Empurre os registros para a pilha e retire-os após chamar printf ou mantenha os valores de incremento e ponto final na memória e leia/escreva nos registros conforme necessário.

Espero que o seguinte funcione.Estou assumindo que pushl tem um popl equivalente e você pode colocar alguns números extras na pilha.

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

Outras dicas

Não estou muito familiarizado com _printf, mas será que ele modifica o eax?Printf deve retornar o número de caracteres impressos, que neste caso é dois:'0' e ' '.Acho que ele retorna isso em eax, e quando você incrementa, você obtém 3, que é o que você imprime.Talvez seja melhor usar um registro diferente para o contador.

Você pode usar com segurança registros "salvos por callee" sem precisar salvá-los você mesmo.No x86 são edi, esi e ebx;outras arquiteturas têm mais.

Eles estão documentados nas referências da ABI: http://math-atlas.sourceforge.net/devel/assembly/

Funções bem escritas geralmente colocam todos os registros na pilha e os colocam quando terminam, para que permaneçam inalterados durante a função.A exceção seria eax que contém o valor de retorno.Funções de biblioteca como printf provavelmente são escritas desta forma, então eu não faria o que Wedge sugere:

Você precisará fazer o mesmo para qualquer outra variável que tiver.O uso de registros para armazenar variáveis ​​locais é praticamente reservado a arquiteturas com registros suficientes para suportá-lo (por exemplo,ÉPICO, amd64, etc.)

Na verdade, pelo que sei, os compiladores costumam compilar funções dessa forma para lidar exatamente com esse problema.

@seanyboy, sua solução é um exagero.Tudo o que é necessário é substituir eax por algum outro registro como ecx.

Nathan está no caminho certo.Você não pode presumir que os valores do registro não serão modificados após a chamada de uma sub-rotina.Na verdade, é melhor assumir que eles serão modificados, caso contrário a sub-rotina não seria capaz de funcionar (pelo menos para arquiteturas com baixa contagem de registros, como x86).Se você quiser preservar um valor, você deve armazená-lo na memória (por exemplo,coloque-o na pilha e acompanhe sua localização).

Você precisará fazer o mesmo para qualquer outra variável que tiver.O uso de registros para armazenar variáveis ​​locais é praticamente reservado a arquiteturas com registros suficientes para suportá-lo (por exemplo,ÉPICO, amd64, etc.)

Você poderia reescrevê-lo para usar registros que não deveriam mudar, por exemplo %ebp.Apenas certifique-se de colocá-los na pilha no início e retirá-los no final de sua rotina.

# 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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top