如何在 ubuntu 下使用 nasm(汇编)从键盘读取单个字符输入?

2024-11-04 08:43:00
admin
原创
217
摘要:问题描述:我在 ubuntu 下使用 nasm。顺便说一下,我需要从用户的键盘获取单个输入字符(例如当程序要求您输入 y/n ? 时),因此当按下键而不按回车键时,我需要读取输入的字符。我在 Google 上搜索了很多,但我找到的所有内容都与此行 ( int 21h) 有关,导致“分段错误”。请帮我弄清楚如何...

问题描述:

我在 ubuntu 下使用 nasm。顺便说一下,我需要从用户的键盘获取单个输入字符(例如当程序要求您输入 y/n ? 时),因此当按下键而不按回车键时,我需要读取输入的字符。我在 Google 上搜索了很多,但我找到的所有内容都与此行 ( int 21h) 有关,导致“分段错误”。请帮我弄清楚如何获取单个字符或如何克服这个分段错误。


解决方案 1:

可以用汇编语言来实现,但并不容易。您不能使用 int 21h,这是 DOS 系统调用,在 Linux 下不可用。

要在类 UNIX 操作系统(如 Linux)下从终端获取字符,您需要从 STDIN(文件编号 0)读取。通常,read 系统调用将阻塞,直到用户按下 Enter 键。这称为规范模式。要读取单个字符而不等待用户按下 Enter 键,您必须先禁用规范模式。当然,如果您稍后想要行输入,则必须在程序退出之前重新启用它。

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

ioctl 系统调用有三个参数。第一个是发送命令的文件 (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 长 1 字节,NCCS 当前定义为 19。请参阅 NASM 手册以了解如何方便地定义和保留此类结构的空间。

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

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

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

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

解决方案 2:

我最近需要这样做,并且受到 Callum 的出色回答的启发,我写了以下内容(适用于 x86-64 的 NASM):

DEFAULT REL

section .bss
termios:        resb 36

stdin_fd:       equ 0           ; STDIN_FILENO
ICANON:         equ 1<<1
ECHO:           equ 1<<3

section .text
canonical_off:
        call read_stdin_termios

        ; clear canonical bit in local mode flags
        and dword [termios+12], ~ICANON

        call write_stdin_termios
        ret

echo_off:
        call read_stdin_termios

        ; clear echo bit in local mode flags
        and dword [termios+12], ~ECHO

        call write_stdin_termios
        ret

canonical_on:
        call read_stdin_termios

        ; set canonical bit in local mode flags
        or dword [termios+12], ICANON

        call write_stdin_termios
        ret

echo_on:
        call read_stdin_termios

        ; set echo bit in local mode flags
        or dword [termios+12], ECHO

        call write_stdin_termios
        ret

; clobbers RAX, RCX, RDX, R8..11 (by int 0x80 in 64-bit mode)
; allowed by x86-64 System V calling convention    
read_stdin_termios:
        push rbx

        mov eax, 36h
        mov ebx, stdin_fd
        mov ecx, 5401h
        mov edx, termios
        int 80h            ; ioctl(0, 0x5401, termios)

        pop rbx
        ret

write_stdin_termios:
        push rbx

        mov eax, 36h
        mov ebx, stdin_fd
        mov ecx, 5402h
        mov edx, termios
        int 80h            ; ioctl(0, 0x5402, termios)

        pop rbx
        ret

(编者注:不要int 0x80在 64 位代码中使用:如果在 64 位代码中使用 32 位 int 0x80 Linux ABI 会发生什么? - 它会在 PIE 可执行文件中中断(其中静态地址不在低 32 位),或者在堆栈上使用 termios 缓冲区。它实际上在传统的非 PIE 可执行文件中工作,并且此版本可以轻松移植到 32 位模式。)

然后你可以执行以下操作:

call canonical_off

如果您正在阅读一行文本,您可能还想执行以下操作:

call echo_off

这样每个字符在输入时就不会被回显。

可能有更好的方法可以做到这一点,但它在 64 位 Fedora 安装上对我来说是有效的。

您可以在手册页termios(3)termbits.h源代码中找到更多信息。

解决方案 3:

简单的方法:对于文本模式程序,使用libncurses来访问键盘;对于图形程序,使用Gtk+。

困难的方式:假设一个文本模式的程序,你必须告诉内核你想要单字符输入,然后你必须做大量的记录和解码。这真的很复杂。没有与旧的 DOS 例程相当的东西getch()。你可以从这里开始学习如何做到这一点:终端 I/O。图形程序甚至更复杂;最低级别的 API 是Xlib。

无论哪种方式,您都会疯狂地用汇编语言编写代码;请改用 C 语言。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用