Linux I';我试图在集合中创建一个三角形的点,但它不是';行不通

Linux I';我试图在集合中创建一个三角形的点,但它不是';行不通,linux,assembly,x86-64,yasm,Linux,Assembly,X86 64,Yasm,我试图在屏幕上创建一个点三角形,方法是获取一个用户输入的值(改变结果三角形的大小),然后用它来写点的递减线 代码如下: section .data global _start char db ' ' prompt_text db "Enter triangle size (2-99) " prompt_length equ $-prompt_text section .bss

我试图在屏幕上创建一个点三角形,方法是获取一个用户输入的值(改变结果三角形的大小),然后用它来写点的递减线

代码如下:

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


另外,我正在使用x84-64 linux并与YASM进行组装,您的代码中有两个问题,都是在读取输入时出现的。首先,修复。然后,对当前结果进行解释

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,因此您告诉操作系统读入空缓冲区。如果您要检查系统调用的结果,您将看到一个错误代码

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

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。然后我们将第二个字符转换为一个数字,并将其添加到第一个字符中。既然两个字符都已经过测试,我们就可以将结果存储回预期位置并返回


解释 正如修复中所解释的,您正在传递一个空缓冲区,因此它返回一个错误。您的
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点线。

如果您断言您使用的是yasm,为什么要使用nasm?