【问题标题】:Linux temios non-canonical sys_call getch() doesn't workLinux temios 非规范 sys_call getch() 不起作用
【发布时间】:2020-07-22 05:02:30
【问题描述】:

我最近使用 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 !!

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

【问题讨论】:

标签: linux assembly x86-64 nasm system-calls


【解决方案1】:

...我得到了这段代码,我最终尝试了一下,代码不像我预期的那样工作...

   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 的地址)作为参数的系统调用。

您可以将代码组装和链接为 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”,而是使用另一个汇编程序;所以也许我错了。但据我所知,上面的指令会被“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

【讨论】:

  • 感谢@Martin Rosenau 的帮助,但我不明白c_lflag 的意思...为了清楚起见,我必须And 两次?
  • 对于read(),我必须在清除termios结构之前或清除它之后放置它?
  • @felixmontalfu 不,您只需执行一次AND。但是,有两种不同的变体,您选择了两种变体之一。
  • @felixmontalfu 通常(在 C 中编程时)我使用以下顺序:阅读 termios;写termios;使用read();写入 termios 的旧值。如果您不将 termios 恢复为旧值,则在您的程序完成后,shell 会出现问题。
  • 啊,所以顺序已经对了?只是一些参数错误? @Martin Rosenau
猜你喜欢
  • 1970-01-01
  • 2020-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-24
相关资源
最近更新 更多