Cal*_*lum 11
它可以通过装配来完成,但这并不容易.你不能使用int 21h,这是一个DOS系统调用,它在Linux下不可用.
要在类UNIX操作系统(如Linux)下从终端获取字符,请从STDIN(文件号0)读取.通常,读取系统调用将阻塞,直到用户按下回车键.这称为规范模式.要在不等待用户按Enter的情况下读取单个字符,必须先禁用规范模式.当然,如果您希望稍后输入行,并且在程序退出之前,则必须重新启用它.
要在Linux上禁用规范模式,请使用ioctl系统调用将IOCTL(IO ControL)发送到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 */
};
Run Code Online (Sandbox Code Playgroud)
其中tcflag_t为32位长,cc_t为一个字节长,NCCS当前定义为19.有关如何方便地为此类结构定义和保留空间的信息,请参阅NASM手册.
所以,一旦你有了当前的termios,你需要清除规范的旗帜.该标志位于c_lflag字段中,带有掩码ICANON(0x00000002).要清除它,请计算c_lflag AND(NOT ICANON).并将结果存储回c_lflag字段.
现在您需要通知内核您对termios结构的更改.使用TCSETS(编号0x5402)ioctl,第三个参数设置termios结构的地址.
如果一切顺利,终端现在处于非规范模式.您可以通过设置规范标志(通过ORing c_lflag与ICANON)并再次调用TCSETS ioctl来恢复规范模式.在退出之前始终恢复规范模式
正如我所说,这并不容易.
我最近需要这样做,并且受到Callum的出色答案的启发,我写了以下内容:
termios: times 36 db 0
stdin: equ 0
ICANON: equ 1<<1
ECHO: equ 1<<3
canonical_off:
call read_stdin_termios
; clear canonical bit in local mode flags
push rax
mov eax, ICANON
not eax
and [termios+12], eax
pop rax
call write_stdin_termios
ret
echo_off:
call read_stdin_termios
; clear echo bit in local mode flags
push rax
mov eax, ECHO
not eax
and [termios+12], eax
pop rax
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
read_stdin_termios:
push rax
push rbx
push rcx
push rdx
mov eax, 36h
mov ebx, stdin
mov ecx, 5401h
mov edx, termios
int 80h
pop rdx
pop rcx
pop rbx
pop rax
ret
write_stdin_termios:
push rax
push rbx
push rcx
push rdx
mov eax, 36h
mov ebx, stdin
mov ecx, 5402h
mov edx, termios
int 80h
pop rdx
pop rcx
pop rbx
pop rax
ret
Run Code Online (Sandbox Code Playgroud)
然后你可以这样做:
call canonical_off
Run Code Online (Sandbox Code Playgroud)
如果您正在阅读一行文字,您可能还想这样做:
call echo_off
Run Code Online (Sandbox Code Playgroud)
这样每个字符都不会被键入.
可能有更好的方法,但它适用于64位Fedora安装.
更多信息可以在手册页中找到termios(3)
,或在termbits.h
源.
归档时间: |
|
查看次数: |
8153 次 |
最近记录: |