Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用x86_64 sys_调用在Linux上读取单键输入(不等待返回)_Linux_Assembly_X86 64_Nasm_Tty - Fatal编程技术网

使用x86_64 sys_调用在Linux上读取单键输入(不等待返回)

使用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

我想让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/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位汇编为例)
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位汇编为例)

问题在于,终端默认处于“煮熟”模式,即行缓冲,而要获得单次击键,则需要处于原始模式;见例;顺便说一句,当您在操作系统下运行时(尤其是在保护模式下),BIOS中断不起作用。您不能在64位中使用
int 80h
assembly@JCWasmx86你可以,但结果是。问题是,终端在默认情况下处于“熟食”模式,即行缓冲,而要获得单次击键,你需要它处于原始模式;见例;顺便说一句,当您在操作系统下运行时(尤其是在保护模式下),BIOS中断不起作用。您不能在64位中使用
int 80h
assembly@JCWasmx86可以,但是结果是。所以在调用sys\u read之前,我必须先设置sys\u ioctl?系统调用的整数是80h?我是汇编linux的新手。。。我输入的字符是RAX吗?我应该把write termios结构放回哪里?顺便说一句,谢谢你的帮助@fcdt
termios
结构就像一个配置文件:您想禁用规范模式,因此必须在当前配置中读取、修改并写回。我在帖子中添加了几行关于系统调用的内容。感谢@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结构放回哪里?顺便说一句,谢谢你的帮助@fcdt
termios
结构就像一个配置文件:您想禁用规范模式,因此必须在当前配置中读取、修改并写回。我在帖子中添加了几行关于系统调用的内容。感谢@fcdt的解释。。。所以我输入的密钥是RAX。。。好的,再次感谢。我们知道有些键可能导致输入长度超过1字节,因此在这种情况下,您必须再次调用
sys\u read
。我还发现了32位linux汇编中的原始键盘输入。很抱歉在
和byte[c_cflag]上再次询问@fcdt,$FD
我在编译
键时出错。asm:81:error:symbol`FD'未定义
FD是什么意思?