我在ubuntu下使用nasm。顺便说一句,我需要从用户键盘上获取单个输入字符(例如,当程序要求您输入y/n?时),这样就可以按下键,而无需按下Enter键,我需要读取输入的字符。我在Google上进行了很多搜索,但是发现的所有内容都与此行(int 21h)相关,从而导致“分段错误”。请帮助我弄清楚如何获得单个字符或如何克服这种分割错误。

最佳答案

可以通过组装完成,但这并不容易。您不能使用int 21h,这是DOS系统调用,在Linux下不可用。

要在类似UNIX的操作系统(例如Linux)下从终端获取字符,请从STDIN(文件号0)中读取。通常,读取的系统调用将一直阻塞,直到用户按下Enter键为止。这称为规范模式。要在不等待用户按Enter的情况下读取单个字符,必须首先禁用规范模式。当然,如果以后要在程序退出之前进行行输入,则必须重新启用它。

要在Linux上禁用规范模式,请使用ioctl syscall将IOCTL(IO ControL)发送到STDIN。我假设您知道如何从汇编程序进行Linux系统调用。

ioctl syscall具有三个参数。第一个是将命令发送到(STDIN)的文件,第二个是IOCTL号,第三个通常是指向数据结构的指针。 ioctl成功返回0,失败则返回负错误代码。

您需要的第一个IOCTL是TCGETS(编号0x5401),它可以在termios结构中获取当前的终端参数。第三个参数是指向termios结构的指针。从内核源来看,termios结构定义为:

struct termios {
    tcflag_t c_iflag;               /* input mode flags */
    tcflag_t c_oflag;               /* output mode flags */
    tcflag_t c_cflag;               /* control mode flags */
    tcflag_t c_lflag;               /* local mode flags */
    cc_t c_line;                    /* line discipline */
    cc_t c_cc[NCCS];                /* control characters */
};

其中tcflag_t为32位长,cc_t为一字节长,NCCS当前定义为19。有关如何方便地为此类结构定义和保留空间的信息,请参阅NASM手册。

因此,一旦获得了当前的termios,就需要清除规范标志。此标志位于c_lflag字段中,其掩码为ICANON(0x00000002)。要清除它,请计算c_lflag AND(非ICANON)。并将结果存储回c_lflag字段。

现在,您需要将对termios结构所​​做的更改通知内核。使用TCSETS(数字0x5402)ioctl,第三个参数设置termios结构的地址。

如果一切顺利,则终端现在处于非规范模式。您可以通过设置规范标志(通过将c_lflag与ICANON进行或运算)并再次调用TCSETS ioctl来恢复规范模式。 始终在退出之前恢复规范模式

正如我所说,这并不容易。

07-24 09:38
查看更多