如何使用NASM Assembly忽略输入中的换行符?

时间:2013-09-13 07:44:48

标签: linux ubuntu assembly nasm

学习NASM程序集,我正在尝试创建一个读取两位一位数字输入的程序。

我在.bss中声明了两个变量:

num1 resb 1
num2 resb 1

然后,我要求用户写下这样的数字:

; Get number 1
mov EAX,3
mov EBX,1
mov ECX,num1
mov EDX,1
int 0x80

; Get number 2
mov EAX,3
mov EBX,1
mov ECX,num2
mov EDX,1
int 0x80

由于我只对一位数字输入感兴趣,因此我将EDX设置为1。这样,无论用户输入什么类型,只有第一个字符存储在我的变量中(对吗?)。

问题是在第一个字符之后的所有内容都将用于将来的读取。如果您输入5,然后按ENTER5就会存储在num1中,但按ENTER生成的换行符将继续到下一个读取指令,它将存储在num2中。显然,这不是我想要的(我希望用户键入一个数字,按ENTER,键入另一个数字,然后按ENTER键。)

我不完全确定如何以最简单的方式解决这个问题。

最愚蠢的想法是在num1num2之间放置一个“虚拟”读取指令,它将捕获换行符(并且不执行任何操作)。这显然不太好。

3 个答案:

答案 0 :(得分:1)

这是一种非常基本的阅读输入方式,直到你得到你想要的数字。它会跳过任何数字而不是数字。如果它提供您想要的功能,这种方法很好。如果根据其他非数字输入需要不同的行为,则需要指定该行为。然后也可以编程这种行为。

    ; Get number 1
    mov   ECX,num1
    call  GetNumber

    ; Get number 2
    mov   ECX,num2
    call  GetNumber
    ...

GetNumber:
    pusha              ; save regs
get:
    mov   EAX,3        ; system call for reading a character
    mov   EBX,0        ; 0 is standard input
    mov   EDX,1        ; number of characters to read
    int   0x80         ; ECX has the buffer, passed into GetNumber
    cmp   byte [ecx],0x30
    jlt   get          ; Retry if the byte read is < '0'
    cmp   byte [ecx],0x39
    jgt   get          ; Retry if the byte read is > '9'

    ; At this point, if you want to just return an actual number,
    ; you could subtract '0' (0x30) off of the value read
    popa               ; restore regs
    ret

答案 1 :(得分:1)

干预stdin以禁用I_CANON将起作用,但可能是“艰难的方式”。如果讨厌的用户表现良好,使用双字节缓冲区并执行mov edx, 2将会有效 - 要么清除第二个字节,要么忽略它。

有时候讨厌的用户表现不佳。处理“垃圾输入”或其他错误条件通常需要比“做工作”更多的代码!要么处理它,要么对“通常”工作的程序感到满意。对于初学者来说,第二种选择可能就足够了。

讨厌的用户可能只是点击“输入”而不输入数字。在这种情况下,我们要么重新提示,要么打印“抱歉,你不喜欢我的程序”并退出。或者他/她可能会在点击“输入”之前输入多个字符。这有潜在危险!如果恶意用户键入“1rm -rf。”,那么您刚刚清除了整个系统! Unix功能强大,就像任何强大的工具一样,在不熟练的用户手中也是危险的。

你可能会尝试类似的事情(警告:未经测试的代码!)......

section .bss
    num1 resb 1
    num2 resb 1
    trashbin resb 1

section .text
re_prompt:
; prompt for your number
; ...
; get the number (character representing the number!)
    mov ecx, num1
reread:
    mov edx, 1
    mov ebx, 0 ; 1 will work, but 0 is stdin
    mov eax, 3 ; sys_read
    int 0x80
    cmp byte [ecx], 10 ; linefeed
    jz got_it
    mov ecx, trashbin
    jmp reread
got_it:
    cmp byte [num1], 10 ; user entered nothing?
    jz re_prompt ; or do something intelligent
; okay, we have  a character in num1
; may want to make sure it's a valid digit
; convert character to number now?
; carry on

section .bss num1 resb 1 num2 resb 1 trashbin resb 1 section .text re_prompt: ; prompt for your number ; ... ; get the number (character representing the number!) mov ecx, num1 reread: mov edx, 1 mov ebx, 0 ; 1 will work, but 0 is stdin mov eax, 3 ; sys_read int 0x80 cmp byte [ecx], 10 ; linefeed jz got_it mov ecx, trashbin jmp reread got_it: cmp byte [num1], 10 ; user entered nothing? jz re_prompt ; or do something intelligent ; okay, we have a character in num1 ; may want to make sure it's a valid digit ; convert character to number now? ; carry on

您可能需要摆弄它才能使其发挥作用。我可能不应该发布未经测试的代码(你可以这样尴尬!)。 “这样的事情”可能比摆弄更容易。迈克尔给你的第二个链接包括我用于此的代码。我对它不太满意(马虎!),但它“有点儿”。无论哪种方式,玩得开心! :)

答案 2 :(得分:0)

你将不得不处理规范的禁用原始键盘。 这就是linux如何管理输入控制台密码而不显示它。

这里很好地描述了执行此操作的程序集:

http://asm.sourceforge.net/articles/rawkb.html