程序集从 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