在 Linux 上使用 x86 汇编和 at&t 打印计数器 0 --> 4

Print counter 0 --> 4 using x86 assembly and at&t on Linux

我想打印一个循环的计数器 (0 --> 4)。在下面的代码中,diff 是 '0' 字符的 ASCII 数,最大循环重复次数,计数计数器和 p 是包含该字符的变量。

.data

.text

.global main

diff    =   48
max     =   5   

count:  .byte   0
p:      .long   0

main:

compare:
    cmpb    $max,count    # if counter is equal or above max
    jae     end           # jump to end

    movl    ,%eax       # write
    movl    ,%ebx       # stdout
    xor     %ecx,%ecx     # reset ecx
    addb    $diff,%cl     # add ASCII number of '0'
    addb    count,%cl     # add value of counter
    movb    %cl,p         # move ASCII value of the counter
    movl    $p,%ecx       # move the number to third argument of write
    movl    ,%edx       # size of long
    int     [=11=]x80         # interrupt

    movb    count,%al     # move value of the counter to al
    inc     %al           # increment al
    movb    %al,count     # move value of al to counter
    jmp     compare       # always jump to compare

end:
    movl    ,%eax       # exit
    movl    [=11=],%ebx       # exit(0)
    int     [=11=]x80         # interrupt

没用。 gcc 不会给我错误,但执行它会给出核心转储。为什么?

您的变量 countp 是在 .text 指令之后定义的,这意味着它们在 text 部分中。此部分应该用于代码并且是只读的。因此,尝试写入这些位置会导致段错误。

您可能想按照 .data 指令定义它们。

修复这个问题后,看起来程序可以运行,但实际上还有另一个错误。在每次循环迭代中,您使用 4 个字节调用 write,整个 long。高位字节为 0。因此,不是写入一个字节,ascii 0 (0x30),而是写入 4 个字节 (0x30 0x00 0x00 0x00)。您的程序总共输出 20 个字节而不是 5 个。

您可能只想写入一个字节。在这种情况下,您可能希望在调用 write 时将 %edx 设置为 1。在这种情况下,p 可以只是 .byte 而不是 .long.

顺便说一下,如果您 运行 在调试器(例如 gdb)下执行此操作,您将立即看到哪个指令出错。如果你没有这样做,你应该!知道如何使用调试器对于任何语言的程序员来说都是必不可少的,尤其是汇编语言。

如果你这样做了,最好在你的问题中包含这些信息。