我试图通过获取用户输入的值(以改变生成的三角形的大小)并使用它来写入递减的点线来在屏幕上创建一个三角形点。
以下是代码:
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是10000000_00000000的十六进制,但除此之外我完全被卡住了,我真的很感激任何帮助!
P.S。我正在使用x84-64 linux并与YASM组装
答案 0 :(得分: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' 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点线。