Linux temios 非规范 sys_call getch() 不工作

Linux temios non-canonical sys_call getch() doesn't work

我最近使用 Linux 程序集 (x86_64) 进行输入,我得到了这段代码并尝试了它,最终代码并不像我预期的那样工作,我应该等待击键但是它从任何地方自动输入,我怀疑 termios 标志...代码在下面:

 ;Get current settings
    Mov  EAX, 16             ; SYS_ioctl
    Mov  EDI, 0              ; STDIN_FILENO
    Mov  ESI, 0x5401         ; TCGETS
    Mov  RDX, termios
    Int 80h

    And dword [c_cflag], 0xFD  ; Clear ICANON to disable canonical mode

    ; Write termios structure back
    Mov  EAX, 16             ; SYS_ioctl
    Mov  EDI, 0              ; STDIN_FILENO
    Mov  ESI, 0x5402         ; TCSETS
    Mov  RDX, termios
    Int 80h

    Mov EAX,0   ;sys_read kernel call
    Mov EBX,0   ;stdin trap (standart input)
    Mov ECX,Nada    ;Masukkan offset/jumlah byte yang akan di baca
    Mov EDX,1   ;Jumlah byte yang dibaca
    Int 80h     ;Call Kernel

对于 termios 结构:

SECTION .bss    ;deklarasi untuk variable yang belum terdefinisi

Enter: Resb 1   ;Pesan 1 byte untuk Enter
Nada: Resb 1
termios: 
    c_iflag Resd 1    ; input mode flags
    c_oflag Resd 1    ; output mode flags
    c_cflag Resd 1    ; control mode flags
    c_lflag Resd 1    ; local mode flags
    c_line Resb 1     ; line discipline
    c_cc Resb 64      ; control characters

对于输出:

nasm -f elf64 -g -F stabs key.asm
ld -o KeyPress key.o
./KeyPress
Untuk memulai tekan tombol enter: 
Tekan tombol untuk memainkan satu not: (1,2,3,4,5,6,7,8)
//this part are the error occur,i have to check if user inputed right value 
if not it will jump to error label and printed below message//
Error note not found please contact the app developer !!

参考:, My Github Repo
PS:对于我已经推送到我的存储库的最新代码,我使用 ubuntu 20.04 和 Intel i7(64 位),感谢您的帮助

... i got this code and i try it eventually the code are doesn't work like what i expected ...

   Mov  ESI, 0x5401
   Mov  RDX, termios
   Int  80h

这行不通:

Int 80h是32位程序中使用的32位系统调用。前三个参数在EBXECXEDX中传递,在ESI中肯定是而不是

并且 Int 80h 所需的 EAX 的值与 64 位程序中使用的方法不同:read() 将是 EAX=3,而不是 EAX=0.

Int 80h 似乎也适用于 64 位程序,但是,传递 64 位值将不起作用;因此您不能将 Int 80h 用于以地址(在示例中:termios 的地址)作为参数的系统调用。

要么你 assemble 和 link 你的代码作为 32 位程序,使用 int 80h,传递 EBXECXEDX 并使用 32 位程序所需的 EAX 中的值(例如:EAX=3 用于 read()):

mov eax, 54      ; sys_ioctl when using "int 80h"
mov ebx, 0       ; stdin
mov ecx, 0x5402  ; TCSETS
mov edx, termios
int 80h

或者您构建一个 64 位程序并使用 syscall 指令调用系统调用(参见 this question):

mov eax, 0    ; sys_read when using "syscall"
              ; note that this instruction will actually set RAX to 0
mov edi, 0    ; set RDI to stdin (implicitly sets rdi)
mov rsi, Nada ; Address of the buffer (see below)
              ; we explicitly have to use "rsi" here!
mov edx, 1    ; number of bytes
syscall
mov ecx, Nada

我不使用“nasm”而是另一个assembler;所以也许我错了。但据我所知,上面的指令将被“nasm”解释为:

读取存储在 RAM 地址 Nada 的值,并将该值写入 ecx 寄存器。

但是,您希望将Nada的地址写入ecx寄存器。

据我所知,这条指令应该写成:mov ecx, offset Nada in "masm".

如果这是真的,我上面例子中对应的行必须是:mov rsi, offset Nada.

And dword [c_cflag], 0xFD  ; Clear ICANON to disable canonical mode

这一行包含两个错误:

ICANON 位于 C_LFLAG,而不是 C_CFLAG

此指令与 C/C++ 指令相同:c_cflag &= ~0xFFFFFF02,但您要执行的操作是:c_cflag &= ~2.

要仅清除位 1,您有两种可能性:

And byte [c_lflag], 0xFD
; OR:
And dword [c_lflag], 0xFFFFFFFD