1

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

这是代码:

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 的十六进制,但除此之外我完全被卡住了,我真的很感激任何帮助!

PS我正在使用x84-​​64 linux并使用YASM组装

4

1 回答 1

2

当您阅读输入时,您的代码中有两个问题。首先,修复。然后,对当前结果的解释。

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 点。

有趣的是,如果你的内部循环测试 ifbx等于 0 而不是大于,你会简单地得到一个从 65536 点到 0 的三角形,在它之前没有 1 点线。

于 2013-11-10T03:28:35.800 回答