Input e output semplici nell'assembly x86_64
Sono un nuovo programmatore di assembly in Linux (x86_64) e voglio assicurarmi di programmare in modo corretto. Ho scritto un programma che prende solo un input dall'utente e quindi scrive il suo input su stdout
SYS_WRITE equ 1 ; write text to stdout
SYS_READ equ 0 ; read text from stdin
SYS_EXIT equ 60 ; terminate the program
STDOUT equ 1 ; stdout
section .bss
uinput resb 24 ; 24 bytes for user string
uinput_len equ $ - uinput ; get length of user input section .data text db "You wroted: " text_len equ $ - text
section .text
global _start
_start:
mov rax, SYS_READ
mov rdi, STDOUT
mov rsi, uinput
mov rdx, uinput_len
syscall
mov rax, SYS_WRITE
mov rdi, STDOUT
mov rsi, text
mov rdx, text_len
syscall
mov rax, SYS_WRITE
mov rdi, STDOUT
mov rsi, uinput
mov rdx, uinput_len
syscall
mov rax, SYS_EXIT
mov rsi, 0 ; successful exit
syscall
Sto facendo correttamente questo esperimento? Quali suggerimenti trovi per migliorare questo codice? Potresti fornire alcune risorse per approfondire le buone pratiche (e se possibile più funzionalità o tecniche efficaci)?
Grazie.
Risposte
Tre piccoli errori
section .data text db "You wroted: " text_len equ $ - text
Un piccolo errore di ortografia (errore di battitura). Esatto è: "Hai scritto:" senza la d .
mov rax, SYS_READ mov rdi, STDOUT mov rsi, uinput mov rdx, uinput_len syscall
Per SYS_READ è necessario utilizzare STDIN invece di STDOUT .
mov rax, SYS_EXIT mov rsi, 0 ; successful exit syscall
Il primo parametro va nel RDIregistro invece di RSI.
Tre piccoli miglioramenti
section .bss uinput resb 24 ; 24 bytes for user string uinput_len equ $ - uinput ; get length of user input
È strano vedere un calcolo per la variabile uinput_len dato che la lunghezza è un 24 hardcoded. Quello che puoi scrivere è:
section .bss
uinput_len equ 24 ; 24 bytes for user input
uinput resb uinput_len
Sii gentile con la persona che usa il tuo programma e mostra un messaggio di qualche tipo prima di aspettarti un input.
Per il risultato finale attualmente mostri l'intero buffer di input. E se l'utente non avesse inserito così tanti caratteri? Meglio mostrare solo i personaggi che sono stati effettivamente inseriti. Ottieni questo conteggio nel RAXregistro al ritorno da SYS_READ . Ad esempio, se l'utente inserisce 5 caratteri, RAXne manterrà 6. Quei 5 caratteri più il carattere di fine riga (0Ah).
Stesso codice, stile diverso
Dovresti compensare i commenti in coda in modo che inizino tutti nella stessa colonna. Ciò migliorerà la leggibilità.
E poiché la leggibilità è molto molto importante , ho applicato la stessa regola a etichette, mnemonici e operandi.
SYS_READ equ 0 ; read text from stdin
SYS_WRITE equ 1 ; write text to stdout
SYS_EXIT equ 60 ; terminate the program
STDIN equ 0 ; standard input
STDOUT equ 1 ; standard output
; --------------------------------
section .bss
uinput_len equ 24 ; 24 bytes for user input
uinput resb uinput_len ; buffer for user input
; --------------------------------
section .data
prompt db "Please input some text: "
prompt_len equ $ - prompt text db 10, "You wrote: " text_len equ $ - text
; --------------------------------
section .text
global _start
_start:
mov rdx, prompt_len
mov rsi, prompt
mov rdi, STDOUT
mov rax, SYS_WRITE
syscall
mov rdx, uinput_len
mov rsi, uinput
mov rdi, STDIN
mov rax, SYS_READ
syscall ; -> RAX
push rax ; (1)
mov rdx, text_len
mov rsi, text
mov rdi, STDOUT
mov rax, SYS_WRITE
syscall
pop rdx ; (1)
mov rsi, uinput
mov rdi, STDOUT
mov rax, SYS_WRITE
syscall
xor edi, edi ; successful exit
mov rax, SYS_EXIT
syscall
Invece di mov rdi, 0, ho usato xor edi, ediche è più breve e più veloce e lascia lo stesso risultato (0) nel RDIregistro.
Preferisco sempre scrivere il numero della funzione direttamente sopra l' syscallistruzione. Lo trovo più chiaro. Di conseguenza ho anche invertito l'ordine degli altri parametri, sempre per chiarezza.
Puoi imparare molto sulla programmazione Linux a 64 bit dal .PDF che puoi scaricare qui
Fornisce buoni esempi che si occupano di input e output della console e altro ancora.