汇编语言从0增加到100

时间:2008-08-21 06:20:08

标签: gas assembly

这有点奇怪,但今天我正在寻找GNU汇编程序(我希望能够至少阅读语法),并且试图让我的这个有点人为的例子工作。也就是说我只想从0到100,一直打印数字。几分钟后,我想出了这个:

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

我从中得到的只是一遍又一遍地打印出来。就像我说的,只是一个有点人为的例子,所以不要太担心它,这不是生死问题。

(格式有点乱,但没什么大不了的。)

6 个答案:

答案 0 :(得分:12)

你无法相信任何被调用的程序对任何寄存器的作用。 将寄存器压入堆栈并在调用printf后将其弹回,或者将增量和终点值保存在存储器中,并根据需要读/写寄存器。

我希望以下工作。我假设pushl有一个等效的popl,你可以将多个数字推到堆栈上。

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

答案 1 :(得分:6)

我对_printf不太熟悉,但可能是它修改了eax吗? Printf应返回打印的字符数,在本例中为2:'0'和'\ n'。我认为它会在eax中返回,当你递增它时,你会得到3,这就是你要打印的内容。 你可能最好为计数器使用不同的寄存器。

答案 2 :(得分:5)

您可以安全地使用“被调用者保存”的寄存器,而无需自己保存。在x86上,这些是edi,esi和ebx;其他架构有更多。

这些记录在ABI参考文献中:http://math-atlas.sourceforge.net/devel/assembly/

答案 3 :(得分:3)

编写良好的函数通常会将所有寄存器压入堆栈,然后在完成后弹出它们,以便在函数期间保持不变。例外是包含返回值的eax。像printf这样的库函数最有可能以这种方式编写,所以我不会像Wedge建议那样做:

  

您需要为您拥有的任何其他变量执行相同的操作。使用寄存器存储局部变量几乎保留给有足够寄存器来支持它的架构(例如EPIC,amd64等)

事实上,据我所知,编译器通常编译函数以完全处理这个问题。

@seanyboy,你的解决方案太过分了。所需要的只是用ecx等其他寄存器替换eax。

答案 4 :(得分:1)

内森走在正确的轨道上。在调用子例程后,您不能假设寄存器值不会被修改。事实上,最好假设它们将被修改,否则子程序将无法完成它的工作(至少对于像x86这样的低寄存器计数架构)。如果你想保留一个值,你应该将它存储在内存中(例如将其推入堆栈并跟踪它的位置)。

您需要为您拥有的任何其他变量执行相同的操作。使用寄存器存储局部变量几乎保留给有足够寄存器来支持它的架构(例如EPIC,amd64等)

答案 5 :(得分:-1)

您可以重写它,以便使用不应更改的寄存器,例如%ebp。只需确保在开始时将它们推入堆栈,然后在例程结束时将它们弹出。

# 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