Es kann von der Montage durchgeführt werden, aber es ist nicht einfach. Sie können int 21h nicht verwenden, das ist ein DOS-Systemaufruf und unter Linux nicht verfügbar.
Um unter UNIX-ähnlichen Betriebssystemen (z. B. Linux) Zeichen vom Terminal zu erhalten, lesen Sie von STDIN (Dateinummer 0). Normalerweise blockiert der Read-Systemaufruf, bis der Benutzer die Eingabetaste drückt. Dies wird als kanonischer Modus bezeichnet. Um ein einzelnes Zeichen zu lesen, ohne darauf zu warten, dass der Benutzer die Eingabetaste drückt, müssen Sie zuerst den kanonischen Modus deaktivieren. Natürlich müssen Sie es wieder aktivieren, wenn Sie später Zeileneingaben wünschen und bevor Ihr Programm beendet wird.
Um den kanonischen Modus unter Linux zu deaktivieren, senden Sie mit dem ioctl-Systemaufruf ein IOCTL (IO ControL) an STDIN. Ich nehme an, Sie wissen, wie man Linux-Systemaufrufe von Assembler aus durchführt.
Der ioctl-Systemaufruf hat drei Parameter. Die erste ist die Datei, an die der Befehl gesendet werden soll (STDIN), die zweite die IOCTL-Nummer und die dritte typischerweise ein Zeiger auf eine Datenstruktur. ioctl gibt bei Erfolg 0 oder bei Fehlschlag einen negativen Fehlercode zurück.
Das erste IOCTL, das Sie benötigen, ist TCGETS (Nummer 0x5401), das die aktuellen Terminalparameter in einer Termiosstruktur erhält. Der dritte Parameter ist ein Zeiger auf eine termios-Struktur. Aus der Kernel-Quelle ist die termios-Struktur wie folgt definiert:
struct termios {
tcflag_t c_iflag; /* input mode flags */
tcflag_t c_oflag; /* output mode flags */
tcflag_t c_cflag; /* control mode flags */
tcflag_t c_lflag; /* local mode flags */
cc_t c_line; /* line discipline */
cc_t c_cc[NCCS]; /* control characters */
};
wobei tcflag_t 32 Bit lang ist, cc_t ein Byte lang ist und NCCS derzeit als 19 definiert ist. Sehen Sie im NASM-Handbuch nach, wie Sie Platz für solche Strukturen bequem definieren und reservieren können.
Sobald Sie also die aktuellen Termios haben, müssen Sie das kanonische Flag löschen. Dieses Flag befindet sich im Feld c_lflag mit der Maske ICANON (0x00000002). Um es zu löschen, berechnen Sie c_lflag AND (NOT ICANON). und speichern Sie das Ergebnis zurück in das Feld c_lflag.
Jetzt müssen Sie den Kernel über Ihre Änderungen an der termios-Struktur informieren. Verwenden Sie das TCSETS (Nummer 0x5402) ioctl, wobei der dritte Parameter die Adresse Ihrer Termios-Struktur enthält.
Wenn alles gut geht, befindet sich das Terminal jetzt im nicht kanonischen Modus. Sie können den kanonischen Modus wiederherstellen, indem Sie das kanonische Flag setzen (durch ODER-Verknüpfung von c_lflag mit ICANON) und das TCSETS-ioctl erneut aufrufen. Vor dem Beenden immer den kanonischen Modus wiederherstellen
Wie gesagt, es ist nicht einfach.
Ich musste dies kürzlich tun und habe, inspiriert von Callums hervorragender Antwort, Folgendes geschrieben (NASM für x86-64):
DEFAULT REL
section .bss
termios: resb 36
stdin_fd: equ 0 ; STDIN_FILENO
ICANON: equ 1<<1
ECHO: equ 1<<3
section .text
canonical_off:
call read_stdin_termios
; clear canonical bit in local mode flags
and dword [termios+12], ~ICANON
call write_stdin_termios
ret
echo_off:
call read_stdin_termios
; clear echo bit in local mode flags
and dword [termios+12], ~ECHO
call write_stdin_termios
ret
canonical_on:
call read_stdin_termios
; set canonical bit in local mode flags
or dword [termios+12], ICANON
call write_stdin_termios
ret
echo_on:
call read_stdin_termios
; set echo bit in local mode flags
or dword [termios+12], ECHO
call write_stdin_termios
ret
; clobbers RAX, RCX, RDX, R8..11 (by int 0x80 in 64-bit mode)
; allowed by x86-64 System V calling convention
read_stdin_termios:
push rbx
mov eax, 36h
mov ebx, stdin_fd
mov ecx, 5401h
mov edx, termios
int 80h ; ioctl(0, 0x5401, termios)
pop rbx
ret
write_stdin_termios:
push rbx
mov eax, 36h
mov ebx, stdin_fd
mov ecx, 5402h
mov edx, termios
int 80h ; ioctl(0, 0x5402, termios)
pop rbx
ret
(Anmerkung der Redaktion:Verwenden Sie nicht int 0x80
in 64-Bit-Code:Was passiert, wenn Sie die 32-Bit-Int 0x80-Linux-ABI in 64-Bit-Code verwenden? - Es würde in einer ausführbaren PIE-Datei (wo statische Adressen nicht in den niedrigen 32 Bit liegen) oder mit dem Termios-Puffer auf dem Stapel brechen. Es funktioniert tatsächlich in einer herkömmlichen ausführbaren Nicht-PIE-Datei, und diese Version kann problemlos in den 32-Bit-Modus portiert werden.)
Sie können dann Folgendes tun:
call canonical_off
Wenn Sie eine Textzeile lesen, möchten Sie wahrscheinlich auch:
call echo_off
damit nicht jedes Zeichen während der Eingabe wiedergegeben wird.
Es gibt vielleicht bessere Möglichkeiten, dies zu tun, aber es funktioniert für mich auf einer 64-Bit-Fedora-Installation.
Weitere Informationen finden Sie in der Manpage für termios(3)
, oder im termbits.h
Quelle.