Input e output semplici nell'assembly x86_64

Aug 29 2020

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

1 SepRoland Aug 31 2020 at 01:22

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.