Lire un fichier

Auteur: Brouettelover 2024-01-03 14:18:29
Categories: > Tags:

Description

Voici comment lire un fichier text en assembleur X64 sous linux.

Code source

Voici le code que je vais détailler par la suite :

section .data
    filename db 'fichier.txt', 0

section .text
    global _start

_start:
    ; Ouvrir le fichier
    mov rdi, filename ; le nom du fichier dans RDI
    mov rsi, 0 ; syscall en mode read only
    mov rdx, 0 ; mode par défaut
    mov rax, 2  ; syscall numéro 2 pour open
    syscall
    mov r8, rax ; sauvegarder le descripteur de fichier

    ; Vérifier si l'ouverture du fichier a réussi
    cmp r8, 0 ; compare la valeur dans r8 à 0 
    jl  .error ; jump si 0 ou - que 0

    ; Lire le contenu du fichier et l'afficher
    mov rdi, r8  ; descripteur de fichier
    mov rsi, rsp ; pointeur de mémoire où stocker les données lues (utilisation de la pile)
    mov rdx, 1024 ; nombre maximal d'octets à lire
    mov rax, 0   ; syscall numéro 0 pour read
    syscall

    ; Afficher le contenu lu
    mov rdi, 1  ; file descriptor pour stdout
    mov rsi, rsp ; pointeur de mémoire où se trouve le contenu lu
    mov rdx, rax ; longueur du contenu lu
    mov rax, 1   ; syscall numéro 1 pour write
    syscall

    ; Fermer le fichier
    mov rdi, r8  ; descripteur de fichier
    mov rax, 3   ; syscall numéro 3 pour close
    syscall

    ; Terminer le programme
    mov rax, 60     ; syscall numéro 60 pour exit
    xor rdi, rdi    ; code de sortie 0
    syscall

.error:
    ; Gestion des erreurs
    mov rdi, r8     ; code d'erreur
    mov rax, 60     ; syscall numéro 60 pour exit
    syscall

Comme vu précédemment l’instruction filename db ‘fichier.txt’, 0 stocke la chaine de caractère ‘fichier.txt’ dans une variable appelé filename

1 - Ouverture du fichier

Cette section reprend l’ensemble des opérations à envoyé à l’os afin qu’il puisse ouvrir le fichier et stocker son ouverture dans un registre appelé r8.

; Ouvrir le fichier
mov rdi, filename ; le nom du fichier à ouvrir dans rdi
mov rsi, 0 ; sycall pour le mode read only
mov rdx, 0 ; prends les permissions par défaut du système
mov rax, 2  ; syscall numéro 2 pour passer en mode ouverture
syscall
mov r8, rax ; sauvegarder le descripteur de fichier

Le descripteur est utilisé pour stocké en quelque sorte le statut d’ouverture du fichier dans un registre r8 qui servira plus tard.

2 - Gestion des erreurs lors de la lecture

; Vérifier si l'ouverture du fichier a réussi
cmp r8, 0 ; compare la valeur dans r8 à 0 
jl  .error ; jump si 0 ou - que 0

l’instruction cmp r8, 0 donne l’équivalent du tableau suivant :

r8 0 Resultat
r8>0 0 n>0
0
0 0
r8<0 0 n<0

La comparaison se fait comme un “-“ mathématique ce qui revient à faire “la valeur de r8 - 0” si cette valeur est inférieur ou égale à 0 alors le bit de signe appelé SF sera mis à 0 ou moins et l’instruction “jl” se déclanchera. A noté que ce bit est “un indicateur de statut” et non pas une variable ou un registre à proprement parlé sa valeur est donc tout le temps définie et mise à jour avec cmp

jl .error : est l’équivalent de (jump if less than) soit “saute si plus petit que” 0 ou égale à 0.

3 - Lecture du fichier

; Lire le contenu du fichier et l'afficher
mov rdi, r8  ; place le descripteur du fichier dans le registre de destination
mov rsi, rsp ; pointeur de mémoire où stocker les données lues (utilisation de la pile)
mov rdx, 1024 ; nombre maximal d'octets à lire
mov rax, 0   ; syscall numéro 0 pour read
syscall

mov rsi, rsp : permet de pointer le haut de la pile afin d’y stocké le contenu

mov rdx, 1024 : Cette instruction indique au système d’exploitation de lire jusqu’à 1024 octets depuis le descripteur de fichier (rdi) et de les stocker à l’adresse mémoire pointée par rsi (c’est-à-dire au sommet de la pile).

NB : rdi est le registre utilisé courrament pour stocké la destination rsi est le registre utilisé courrament pour stocké la source donc mov rdx, 1024 revient à lire 1024 octet depuis rdi et de les stockés dans rsi.

4 - afficher le contenu sur la sortie standard

; Afficher le contenu lu
mov rdi, 1  ; sortie standard comme dans le "hello world"
mov rsi, rsp ; stock l'adresse du haut de la pile là où le fichier à été précédemment stocké
mov rdx, rax ; longueur du contenu lu
mov rax, 1   ; syscall numéro 1 pour write
syscall

rax stock la valeur de retour précédente qui dans notre cas la taille du fichier lu jusqu’à un maximum de 1024 octets.

5 - fermer le fichier

; fermer le fichier
mov rdi, r8  ; descripteur de fichier qui a été stocké précédement dans r8
mov rax, 3   ; syscall numéro 3 pour close
syscall

Ferme le fichier permet de supprimer la valeur de r8 et de libérer un descripteur de fichier.

6 - fermer le programme

; Terminer le programme
mov rax, 60     ; demande à l'os lors du syscall de sortir de l'application pour signifié qu'elle a terminé
xor rdi, rdi    ; code de sortie 0 pour dire que tout a bien fonctionné
syscall

7 - gestion des erreurs

.error:
    ; Gestion des erreurs
    mov rdi, r8     ; code d'erreur contenu dans r8 sera  présent dans le echo $?
    mov rax, 60     ; demande à l'os lors du syscall de sortir de l'application pour signifié qu'elle a terminé
    syscall