【问题标题】:How do I test to ensure only an integer is entered and ensure length of input is 5 bytes or less in Assembly?如何测试以确保只输入一个整数并确保在汇编中输入的长度为 5 个字节或更少?
【发布时间】:2016-07-17 15:44:47
【问题描述】:

如何测试以确保在以下代码中仅输入整数并确保输入长度为 5 个字节或更少?

我正在尝试了解如何正确控制输入,以便在退出程序时不会将超过 5 个字节的输入输出到终端。

另外,我将如何测试以确保只输入一个字符串,最后在最后一个场景中,只输入一个双精度数?

*** 根据 x82 和 Peter C 的指导更新了代码。我做了一些 C disas 并且能够在下面修改我的原始代码。它仍然有一些缺陷,但你们俩都是很大的帮助!我只是在输入超过 5 个整数字节时卡住了,它不会像我输入字符数据时那样重新提示,因为它继续将额外的字节数据转储到 tty。

SECTION .data                   ; initialized data section
promptInput db 'Enter Number: ', 0
lenPromptInput equ $ - promptInput
displayInput db 'Data Entered: ', 0
lenDisplayInput equ $ - lenDisplayInput

SECTION .bss                ; uninitialized data section
number resb 1024            ; allocate 1024 bytes for number variable

SECTION .text               ; code section
global _start               ; linker entry point

_start:
nop                         ; used for debugging

Read:
mov eax, 4                  ; specify sys_write call
mov ebx, 1                  ; specify stdout file descriptor
mov ecx, promptInput        ; display promptInput
mov edx, lenPromptInput     ; length of promptInput
int 0x80                    ; call sys_write

mov eax, 3                  ; specify sys_read call
mov ebx, 0                  ; specify stdin file descriptor
mov ecx, number             ; pass address of the buffer to read to
mov edx, 1024               ; specify sys_read to read 1024 bytes stdin
int 0x80                    ; call sys_read

cmp eax, 0                  ; examine sys_read return value in eax
je Exit                     ; je if end of file

cmp byte [number], 0x30     ; test input against numeric 0
jb Read                     ; jb if below 0 in ASCII chart
cmp byte [number], 0x39     ; test input against numeric 9
ja Read                     ; ja if above 9 in ASCII chart

Write:
mov eax, 4                  ; specify sys_write call
mov ebx, 1                  ; specify stdout file descriptor
mov ecx, displayInput       ; display displayInput
mov edx, lenDisplayInput    ; length of displayInput
int 0x80                    ; call sys_write    

mov eax, 4                  ; specify sys_write call
mov ebx, 1                  ; specify stdout file descriptor
mov ecx, number             ; pass address of the number to write
mov edx, 5                  ; pass number of numbers to write
int 0x80                    ; call sys_write

Exit:
mov eax, 1                  ; specific sys_exit call
mov ebx, 0                  ; return code 0 to OS
int 0x80                    ; call sys_exit

【问题讨论】:

  • 从 GOOGLE 搜索 ascii 表并检查字符、数字等的范围(和十六进制值)。作为一个小提示,您将检查 inputMsg 中的字符是否在 [a-z]-[A-Z] 范围内以进行字符串检查。对于长度检查,您应该寻找空终止符。仔细检查可能会有点困难,但我认为这不是不可能的。然后您可以根据您的特定需求微调您的算法。
  • 谢谢。这是我根据您的帮助更新的代码。我现在得到,“在 1000 次通过后找不到所有标签的有效值,可能导致递归 EQU、宏滥用”。它不会编译。
  • 查看这一行 lenDisplayInput equ $ - lenDisplayInput : 必须是 lenDisplayInput equ $ - displayInput
  • 感谢它现在可以编译,但是代码根本无法按预期工作。我试图了解如何正确控制输入,以便在退出程序时不会将超过 5 个字节的输入输出到终端,以及我将如何测试以确保只输入一个字符串,最后在最后一个场景中,只有一个 double输入了吗?
  • 为什么要一个一个地读字符?我认为最好为大约 30 个字符宽的输入分配一个缓冲区并允许用户一次输入所有内容,然后从头到尾检查缓冲区是否是整数、双精度或字符串,如果是则打印错误消息与您期望的任何格式都不匹配。无论如何,可能无法完全正常工作,但至少可以正常工作。它在第一次运行时永远不会起作用,否则你不会学到任何东西。努力吧:)

标签: linux assembly nasm tty


【解决方案1】:

(既然你接受了这个答案,我会指出这个关于在 TTY 上使用read 的问题的实际答案是my other answer on this question。)

这是对你的low-quality followup question 的回复,当你删除它时,我正要发布它。

请注意,我说的是“您可以在一个新问题中寻求调试帮助”,而不是您应该在一个问题中提出 3 个不同的问题,然后重新发布您的整个代码几乎没有改变,而没有认真尝试解决您自己的问题。将新问题设为问题仍取决于您。

如果不是我一开始就引导你发布它,我可能不会回答它。欢迎来到 StackOverflow,我很慷慨,因为您是新手,还不知道什么是好问题。


字符“0”到“9”的常用术语是“数字”,而不是“整数”。它更具体。

确保在缓冲区中只输入整数

你不能。如果检测到此类输入,您必须决定要做什么。

需要帮助创建要循环的数组

您的缓冲区是一个字节数组。

你可以用类似的东西循环它

    # eax has the return value from the read system call, which you've checked is strictly greater than 0
    mov    esi, number        ; start pointer

scan_buffer:
    movzx  edx, byte [esi]
        # do something with the character in dl / edx
        ...

    inc    esi                ; move to the next character

    dec    eax
    jnz   scan_buffer         ; loop n times, where n = number of characters read by the system call.

确保 1024 缓冲区上的字符不会向 tty 发送数据

如果您担心 1024 对这个玩具程序来说不够大,那么使用 select(2)poll(2) 检查是否有更多输入可以读取,如果没有则不阻塞。

【讨论】:

  • 谢谢@petercordes 我根据你的建议更新了代码,并花了一天时间通过 GDB 进行测试,但希望能得到最后一点帮助。
  • @KevinM.Thomas:您的问题仍然没有说明您想要它做什么。它充满了像pass address of number to ecx 这样的无用cmets,我们已经可以从mov ecx, number 中看到。更有用的评论是,这是 *buf arg 到 read(2)
  • 问题:如何保证只输入一个整数值才能jmp退出,这样当非整数值达到1024字节时,程序会提示输入重新提示'输入数字的问题?
  • @KevinM.Thomas:您一直在说“确保”有关输入的内容。至少你最终描述了当你看到有效输入与看到无效输入时你想要发生的事情。你应该用它来编辑你的问题,而不是仅仅离开 cmets。
【解决方案2】:

我只是回答问题的 POSIX 系统编程部分,一旦你知道你想让你的程序做什么,就让你来做正确的系统调用。使用 gdb 对其进行调试(有关调试提示,请参见 标签 wiki 底部),并使用 strace 跟踪系统调用。

您可能希望用 C 编写程序,而不是尝试同时学习 asm 和 Unix 系统调用 API。用 C 写一些东西来测试这个想法,然后在 asm 中实现它。 (然后你可以在卡住的时候看看编译器的输出,看看编译器是怎么做的。只要你仔细阅读并理解编译器生成的代码是如何工作的,你还是在学习。我建议以-O2-O3 作为asm 实现的起点进行编译。至少-O1,绝对不是-O0。)。


我正在尝试了解如何正确控制输入,以便在退出程序时不会将超过 5 个字节的输入输出到终端。

这只是一个 POSIX 语义问题,与 asm 无关。如果您在 C 中进行系统编程,调用 read(2) system call 也是一样的。您在 asm 中使用 mov eax,3 / int 0x80 调用它,而不是像 C 编译器输出那样使用 glibc 包装器 call,但它是相同的系统调用。

如果程序退出时the terminal (tty) 上有未读数据,shell 会在检查输入时读取它。

在 tty 上运行的交互式 shell 中,您运行的程序(如 ./a.out/bin/cat)将其标准输入连接到 shell 从中获取交互式输入的同一 tty 设备。因此,程序标准输入上的未读数据与 shell 将看到的未读数据相同。

如果您从文件中重定向程序的输入,情况会有所不同。 (./a.out < my_file.txt)。那么您的程序将不会以 tty 的已打开文件描述符开始。它仍然可以open("/dev/tty")(这是一个始终指向控制 tty 的“神奇”符号链接)并清除运行时键入的任何内容。


确保在以下代码中只输入一个整数并确保输入的长度为 5 个字节或更少?

您无法控制输入的内容。您可以检测您不喜欢的输入,并打印错误消息或您想做的任何其他事情。

如果您希望输入字符在 5 个字节后停止回显到屏幕,您需要 put the tty into raw mode(而不是默认的行缓冲“熟”模式)并手动执行回显,或者在之后禁用回显5 个字节。 (不过,后者并不可靠。在禁用回显和用户输入第 6 个字节(例如,作为粘贴的一部分)之间存在竞争条件。


回复:编辑

当输入超过 5 个整数字节时,它不会像我输入字符数据时那样重新提示,因为它会继续将额外的字节数据转储到 tty。

你破坏了你的程序,因为如果你不喜欢你读到的数字,逻辑仍然是围绕 re-read()ing 一个字符设计的。但是您的 read 调用最多读取 5 个字节。

正常的做法是一个大的read,然后通过遍历缓冲区中的字节来解析整行。所以在.bss 部分使用一个大缓冲区(如1024 字节),并进行read 系统调用。

除非您想提示用户输入另一行文本,否则不要进行另一个 read 系统调用。

【讨论】:

  • 谢谢你们!我更新了我的代码并根据您的所有建议取得了进展它运行良好,除非输入超过 5 个整数字节,它不会像我输入字符数据时那样重新提示,因为它继续将额外的字节数据转储到tty.
  • @KevinM.Thomas:听起来它在你不想要的时候就退出了。顺便说一句,如果您仍在一次读取一个字节,则应该更改 cmets 中建议的内容。 tty 上的read() 将在 tty 上返回换行符或 EOF (ctrl-d),即使这意味着它在填充缓冲区之前返回。 (检查返回值以查看您读取了多少个字符。)
  • @KevinM.Thomas:顺便说一句,如果您认为该答案回答了主要问题或足够多,您可以将此答案标记为“已接受”(投票箭头下方的复选框)。不要对问题进行过多编辑,以免变成新问题。
  • 嗨@PeterCordes 我不确定如何使用 read() ,因为我目前使用的是 sys_read 。使用上面的代码,你能建议我如何实现 read() 来解决这个问题吗?
  • @KevinM.Thomas:sys_read 系统调用与我正在谈论的 POSIX C read(2) 函数相同。 (从技术上讲,C 函数调用 glibc 中的包装器,而不是编译为内联系统调用,正如您在查看 gcc -S -fverbose-asm -O3 输出时可能注意到的那样。如果您反汇编 libc,您会看到 __read() 基本上就是这样一个 sys_read 并在需要时设置 errno。read__read 的弱别名。)系统调用的手册页记录了原始系统调用和 libc 包装器之间的任何差异(如果有)。
猜你喜欢
  • 2015-02-08
  • 2021-08-12
  • 1970-01-01
  • 1970-01-01
  • 2014-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多