程序集从 STDIN 直接读取字节到寄存器
Assembly read byte from STDIN directly into register
在 x64 NASM 中,如果我想从 STDIN 读取一个字符到 8 位寄存器,我知道的唯一方法是:
xor rax, rax
xor rdi, rdi
mov rsi, buffer
mov rdx, 1
syscall
mov al, byte [buffer]
是否可以不使用缓冲区直接将字符读入寄存器? (我正在使用 Ubuntu 18.04)
您要记住的一件事是,一次按键不一定等于一个字节。例如,功能键可以 return 最多 5 个字节。此方法不需要专门分配的缓冲区,但从概念上讲,堆栈上的 space 可以视为缓冲区。
See comment below edi, 8 should be edx, 8
mov edi, 8 ; Size of one QWORD
push rax ; Could be any register, we just need 8 bytes
mov rsi, rsp
xor edi, edi ; Essentially STDIN
mov eax, edi ; SYS_READ
syscall
pop rax ; Bytes
如果您按下从 space (20H) 到波形符 (7FH) 的 96 个键中的一个,那么您的结果将在 AL 中 returned。但是,如果 AL = 27 (1BH),则其余位 (08-3F) 将具有其他相关数据。
我使用这个程序来接受没有回声的单个击键并且需要按 return 来接受输入。
; =============================================================================
; Accept a single key press from operator and return the result that may be
; up to 5 bytes in length.
; LEAVE: RAX = Byte[s] returned by SYS_READ
; -----------------------------------------------------------------------------
%define c_lflag rdx + 12
%define keys rbp + 8
%define MASK ICANON | ECHO
STK_SIZE equ 56 ; Room for 36 byte termios structure
QueryKey:
xor eax, eax
push rax ; This is where result will be stored.
push rbp
mov rbp, rsp
sub rsp, STK_SIZE
push r11 ; Modified by SYSCALL
push rbx
push rdx
push rcx
push rdi
push rsi ; With size of 56, stack is now QWORD aligned
mov edi, eax ; Equivalent to setting EDI to STDOUT
mov esi, TCGETS
lea rdx, [rbp-STK_SIZE] ; Points to TERMIOS buffer on stack
mov al, sys_ioctl
syscall
lea rbx, [c_lflag]
and byte [rbx], ~(MASK)
inc esi ; RSI = TCPUTS
push rsi
mov al, sys_ioctl
push rax
syscall
; Wait for keypress from operator.
lea rsi, [keys] ; Set buffer for input
push rdx
mov edx, 8 ; Read QWORD bytes max
mov al, sys_read
syscall
pop rdx ; Points back to TERMIOS
pop rax
pop rsi ; TCPUTS again
or byte [rbx], MASK
syscall
pop rsi
pop rdi
pop rcx
pop rdx
pop rbx
pop r11
leave
pop rax ; Return up to 8 characters
ret
在 x64 NASM 中,如果我想从 STDIN 读取一个字符到 8 位寄存器,我知道的唯一方法是:
xor rax, rax
xor rdi, rdi
mov rsi, buffer
mov rdx, 1
syscall
mov al, byte [buffer]
是否可以不使用缓冲区直接将字符读入寄存器? (我正在使用 Ubuntu 18.04)
您要记住的一件事是,一次按键不一定等于一个字节。例如,功能键可以 return 最多 5 个字节。此方法不需要专门分配的缓冲区,但从概念上讲,堆栈上的 space 可以视为缓冲区。
See comment below edi, 8 should be edx, 8
mov edi, 8 ; Size of one QWORD
push rax ; Could be any register, we just need 8 bytes
mov rsi, rsp
xor edi, edi ; Essentially STDIN
mov eax, edi ; SYS_READ
syscall
pop rax ; Bytes
如果您按下从 space (20H) 到波形符 (7FH) 的 96 个键中的一个,那么您的结果将在 AL 中 returned。但是,如果 AL = 27 (1BH),则其余位 (08-3F) 将具有其他相关数据。
我使用这个程序来接受没有回声的单个击键并且需要按 return 来接受输入。
; ============================================================================= ; Accept a single key press from operator and return the result that may be ; up to 5 bytes in length. ; LEAVE: RAX = Byte[s] returned by SYS_READ ; ----------------------------------------------------------------------------- %define c_lflag rdx + 12 %define keys rbp + 8 %define MASK ICANON | ECHO STK_SIZE equ 56 ; Room for 36 byte termios structure QueryKey: xor eax, eax push rax ; This is where result will be stored. push rbp mov rbp, rsp sub rsp, STK_SIZE push r11 ; Modified by SYSCALL push rbx push rdx push rcx push rdi push rsi ; With size of 56, stack is now QWORD aligned mov edi, eax ; Equivalent to setting EDI to STDOUT mov esi, TCGETS lea rdx, [rbp-STK_SIZE] ; Points to TERMIOS buffer on stack mov al, sys_ioctl syscall lea rbx, [c_lflag] and byte [rbx], ~(MASK) inc esi ; RSI = TCPUTS push rsi mov al, sys_ioctl push rax syscall ; Wait for keypress from operator. lea rsi, [keys] ; Set buffer for input push rdx mov edx, 8 ; Read QWORD bytes max mov al, sys_read syscall pop rdx ; Points back to TERMIOS pop rax pop rsi ; TCPUTS again or byte [rbx], MASK syscall pop rsi pop rdi pop rcx pop rdx pop rbx pop r11 leave pop rax ; Return up to 8 characters ret