【问题标题】:I'm trying to create a triangle of dots in assembly but it isn't working我正在尝试在汇编中创建一个三角形的点,但它不起作用
【发布时间】:2013-11-10 00:35:12
【问题描述】:

我正在尝试通过获取用户输入的值(以改变生成的三角形的大小)并使用它来编写递减的点线来在屏幕上创建一个点三角形。

代码如下:

section .data
        global  _start

        char    db      ' '

        prompt_text     db      "Enter triangle size (2-99) "
        prompt_length   equ     $-prompt_text

section .bss
        tri_size        resb    3
        tri_size_length equ     $-tri_size

section .text
_start:
        call    prompt
        call    insert_size

        mov     rax,    [tri_size]

outer_loop:
        mov     rbx,    [tri_size]

inner_loop:
        call    dot
        dec     bx
        cmp     bx,     0
        jg      inner_loop

        call    linefeed

        call    dec_length

        dec     ax
        cmp     ax,     0
        jne     outer_loop

        call    linefeed
        call    exit

prompt:
        mov     rax,    4
        mov     rbx,    1
        mov     rcx,    prompt_text
        mov     rdx,    prompt_length
        int     80h
        ret

insert_size:
        mov     rax,    3
        mov     rbx,    0
        mov     rcx,    [tri_size]
        mov     rdx,    tri_size_length
        int     80h
        ret

dot:
        mov     [char], byte '.'
        call    print_char
        ret

linefeed:
        mov     [char], byte 10
        call    print_char
        ret

print_char:

        push    rax
        push    rbx
        push    rcx
        push    rdx


        mov     rax,    4
        mov     rbx,    1
        mov     rcx,    char
        mov     rdx,    1
        int     80h

        pop     rdx
        pop     rcx
        pop     rbx
        pop     rax
        ret

dec_length:

        push    rax
        push    rbx
        push    rcx
        push    rdx

        mov     rax,    [tri_size]
        dec     ax
        mov     [tri_size],     rax

        pop     rdx
        pop     rcx
        pop     rbx
        pop     rax
        ret

exit:
        mov     rax,    1
        mov     rbx,    0
        int     80h

问题:

  • 在运行程序时,我希望用户输入的数字用于第一行的点数。但是,当我输入任何数字时,会打印出大量的行,每行都带有一个点,然后大约一秒钟后,会打印出包含 32768 个点的行。接下来是一行 32767 个点等。每行上的点数继续减少,直到有 1 个点的行。

我注意到 32768 是 10000000_00000000 的十六进制,但除此之外,我完全陷入困境,非常感谢任何帮助!

附:我正在使用 x84-64 linux 并使用 YASM 进行组装

【问题讨论】:

  • 如果你断言你仍然在使用 yasm,为什么还要使用 nasm?

标签: linux assembly x86-64 yasm


【解决方案1】:

您的代码中有两个问题,都是在您读取输入时。首先,修复。然后,解释一下目前的结果。

insert_size:
    mov     rax,    3
    mov     rbx,    0
    mov     rcx,    [tri_size]          ; issue 1
    mov     rdx,    tri_size_length
    int     80h
    ret                                 ; issue 2 (sort of)

修复

首先,rcx 应该包含一个缓冲区的地址,但你得到的是tri_size 的内容,而不是它的地址。由于tri_size 在 bss 部分中,它被初始化为 0,所以你告诉操作系统读入一个 NULL 缓冲区。如果你要检查系统调用的结果,你会看到一个错误代码。

其次,当你读取输入时,你读取的是一个字符串,而不是一个数字。如果要将其用作数字,则需要先将其转换。这是修复了这两个问题的代码:

insert_size:
    mov     rax,    3
    mov     rbx,    0
    mov     rcx,    tri_size           ; 1
    mov     rdx,    tri_size_length
    int     80h
    mov     dh,     0                  ; 2
    mov     ah,     0
    mov     dl,     [tri_size]         ; 3
    mov     ah,     [tri_size+1]
    sub     dl,     '0'                ; 4
    cmp     al,     '0'                ; 5
    jb      done
    cmp     al,     '9'                ; 6
    ja      done
    imul    dx,     10                 ; 7
    sub     al,     '0'                ; 8
    add     dx,     ax                 ; 9
done:
    mov     [tri_size], dx             ; 10
    ret

第一个问题很容易解决,只需删除括号即可获取地址而不是内容。第二个更复杂。首先,我们将使用 16 位寄存器,但只读取 8 位,因此步骤 2 将 0 放在每个寄存器的高字节中。然后,我们读取字符串的前两个字节。接下来,我们将第一个字符从字符转换为数字。由于 ASCII 中的数字是连续的,我们可以通过减去字符“0”来做到这一点。请注意,这假定第一个字符是有效数字。

我们不能假设第二个字符是有效数字,因为可能只输入了一个。因此,第 5 步和第 6 步分别检查它是否小于“0”和大于“9”,如果其中一个为真,则跳转到末尾。如果我们都过去了,那么第二个字符就是一个数字。这意味着第一个数字应该在 10 的位置,所以我们将它乘以 10。然后我们将第二个字符转换为一个数字并将其添加到第一个字符。现在两个字符都已经测试过了,我们可以将结果存储回预期的位置并返回。


解释

正如修复中所解释的,您传递的是 NULL 缓冲区,因此它会返回错误。你的 tri_size 变量永远不会改变,所以它仍然包含 0。这意味着你的两个计数器都从 0 开始。由于你不检查这个,第一个点被打印出来,bx 被递减,导致 -1 .由于 -1 不大于 0,内部循环退出,打印换行符,您的计数器和 ax 递减,导致 -1。这不是零,所以它循环回到外循环。这发生了 32768 次,直到您的计数器变为 -32768。

此时当你递减bx 时,它变为-32769,但这个数字不能用16 位2 的补码表示。相反,它溢出了,你得到的数字是 32767。这大于 0,所以你继续内循环直到它到达 0,总共打印 32768 个点。内部循环退出并打印换行符后,计数器和ax 都递减,结果为 32767。从这一点开始,您的程序就像输入为 32767 一样工作,这意味着您从那里得到一个三角形到 0 点.

有趣的是,如果您的内部循环测试 bx 是否等于 0 而不是大于,您将简单地得到一个从 65536 点到 0 的三角形,其前面没有 1 点线。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-03
    • 2020-06-14
    • 2021-05-27
    • 2020-07-25
    • 2020-10-26
    • 1970-01-01
    • 1970-01-01
    • 2022-11-22
    相关资源
    最近更新 更多