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个点的线为止
另外,我正在使用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?