使用x86_64 sys_调用在Linux上读取单键输入(不等待返回)
我想让Linux只需使用sys\u read从键盘上按一次键,但sys\u read只需等待,直到我按下enter键。如何读取1次击键?这是我的代码:使用x86_64 sys_调用在Linux上读取单键输入(不等待返回),linux,assembly,x86-64,nasm,tty,Linux,Assembly,X86 64,Nasm,Tty,我想让Linux只需使用sys\u read从键盘上按一次键,但sys\u read只需等待,直到我按下enter键。如何读取1次击键?这是我的代码: Mov EAX,3 Mov EBX,0 Mov ECX,Nada Mov EDX,1 Int 80h Cmp ECX,49 Je Do_C Jmp Error 我已经尝试过使用BIOS中断,但失败了(分段错误),我想从键盘捕获1到8号输入。64位linux中的系统调用 man syscall中的表格在这里提供了一个很好的概述: arch/AB
Mov EAX,3
Mov EBX,0
Mov ECX,Nada
Mov EDX,1
Int 80h
Cmp ECX,49
Je Do_C
Jmp Error
我已经尝试过使用BIOS中断,但失败了(分段错误),我想从键盘捕获1到8号输入。64位linux中的系统调用
man syscall
中的表格在这里提供了一个很好的概述:
arch/ABI instruction syscall # retval Notes
──────────────────────────────────────────────────────────────────
i386 int $0x80 eax eax
x86_64 syscall rax rax See below
arch/ABI arg1 arg2 arg3 arg4 arg5 arg6 arg7 Notes
──────────────────────────────────────────────────────────────────
i386 ebx ecx edx esi edi ebp -
x86_64 rdi rsi rdx r10 r8 r9 -
我省略了这里不相关的行。在32位模式下,参数在eax
、ecx
等模式下传输,系统调用号在eax
模式下。在64位模式下,它有点不同:所有寄存器现在都是64位宽的,因此具有不同的名称。系统调用号仍在eax
中,现在变成rax
。但是参数现在在rdi
、rsi
等中传递。此外,这里使用指令syscall
而不是int 0x80
来触发系统调用
参数的顺序也可以在手册页中读取,这里是man 2 ioctl
和man 2 read
:
int ioctl(int fd, unsigned long request, ...);
ssize_t read(int fd, void *buf, size_t count);
因此,intfd
的值在rdi
中,是rsi
中的第二个参数
如何摆脱等待换行的习惯
首先在内存中创建一个termios
结构(在.bss
部分):
然后获取当前终端设置并禁用规范模式:
; Get current settings
mov eax, 16 ; syscall number: SYS_ioctl
mov edi, 0 ; fd: STDIN_FILENO
mov esi, 0x5401 ; request: TCGETS
mov rdx, termios ; request data
syscall
; Modify flags
and byte [c_cflag], $FD ; Clear ICANON to disable canonical mode
; Write termios structure back
mov eax, 16 ; syscall number: SYS_ioctl
mov edi, 0 ; fd: STDIN_FILENO
mov esi, 0x5402 ; request: TCSETS
mov rdx, termios ; request data
syscall
现在,您可以使用sys\u read
来读取击键:
mov eax, 0 ; syscall number: SYS_read
mov edi, 0 ; int fd: STDIN_FILENO
mov rsi, buf ; void* buf
mov rdx, len ; size_t count
syscall
然后检查rax
中的返回值:它包含读取的字符数
参考文献:
- (外部站点,以32位汇编为例)
man syscall
中的表格在这里提供了一个很好的概述:
arch/ABI instruction syscall # retval Notes
──────────────────────────────────────────────────────────────────
i386 int $0x80 eax eax
x86_64 syscall rax rax See below
arch/ABI arg1 arg2 arg3 arg4 arg5 arg6 arg7 Notes
──────────────────────────────────────────────────────────────────
i386 ebx ecx edx esi edi ebp -
x86_64 rdi rsi rdx r10 r8 r9 -
我省略了这里不相关的行。在32位模式下,参数在eax
、ecx
等模式下传输,系统调用号在eax
模式下。在64位模式下,它有点不同:所有寄存器现在都是64位宽的,因此具有不同的名称。系统调用号仍在eax
中,现在变成rax
。但是参数现在在rdi
、rsi
等中传递。此外,这里使用指令syscall
而不是int 0x80
来触发系统调用
参数的顺序也可以在手册页中读取,这里是man 2 ioctl
和man 2 read
:
int ioctl(int fd, unsigned long request, ...);
ssize_t read(int fd, void *buf, size_t count);
因此,intfd
的值在rdi
中,是rsi
中的第二个参数
如何摆脱等待换行的习惯
首先在内存中创建一个termios
结构(在.bss
部分):
然后获取当前终端设置并禁用规范模式:
; Get current settings
mov eax, 16 ; syscall number: SYS_ioctl
mov edi, 0 ; fd: STDIN_FILENO
mov esi, 0x5401 ; request: TCGETS
mov rdx, termios ; request data
syscall
; Modify flags
and byte [c_cflag], $FD ; Clear ICANON to disable canonical mode
; Write termios structure back
mov eax, 16 ; syscall number: SYS_ioctl
mov edi, 0 ; fd: STDIN_FILENO
mov esi, 0x5402 ; request: TCSETS
mov rdx, termios ; request data
syscall
现在,您可以使用sys\u read
来读取击键:
mov eax, 0 ; syscall number: SYS_read
mov edi, 0 ; int fd: STDIN_FILENO
mov rsi, buf ; void* buf
mov rdx, len ; size_t count
syscall
然后检查rax
中的返回值:它包含读取的字符数
参考文献:
- (外部站点,以32位汇编为例)
int 80h
assembly@JCWasmx86你可以,但结果是。问题是,终端在默认情况下处于“熟食”模式,即行缓冲,而要获得单次击键,你需要它处于原始模式;见例;顺便说一句,当您在操作系统下运行时(尤其是在保护模式下),BIOS中断不起作用。您不能在64位中使用int 80h
assembly@JCWasmx86可以,但是结果是。所以在调用sys\u read之前,我必须先设置sys\u ioctl?系统调用的整数是80h?我是汇编linux的新手。。。我输入的字符是RAX吗?我应该把write termios结构放回哪里?顺便说一句,谢谢你的帮助@fcdttermios
结构就像一个配置文件:您想禁用规范模式,因此必须在当前配置中读取、修改并写回。我在帖子中添加了几行关于系统调用的内容。感谢@fcdt的解释。。。所以我输入的密钥是RAX。。。好的,再次感谢。我们知道有些键可能导致输入长度超过1字节,因此在这种情况下,您必须再次调用sys\u read
。我还发现了32位linux汇编中的原始键盘输入。很抱歉在和byte[c_cflag]上再次询问@fcdt,$FD
我在编译键时出错。asm:81:error:symbol`FD'未定义
FD是什么意思?所以在调用sys_read之前,我必须先设置sys_ioctl?系统调用的整数是80h?我是汇编linux的新手。。。我输入的字符是RAX吗?我应该把write termios结构放回哪里?顺便说一句,谢谢你的帮助@fcdttermios
结构就像一个配置文件:您想禁用规范模式,因此必须在当前配置中读取、修改并写回。我在帖子中添加了几行关于系统调用的内容。感谢@fcdt的解释。。。所以我输入的密钥是RAX。。。好的,再次感谢。我们知道有些键可能导致输入长度超过1字节,因此在这种情况下,您必须再次调用sys\u read
。我还发现了32位linux汇编中的原始键盘输入。很抱歉在和byte[c_cflag]上再次询问@fcdt,$FD
我在编译键时出错。asm:81:error:symbol`FD'未定义
FD是什么意思?