· 4 min de lecture

Les appels système (syscalls) sous Linux en assembleur x86-64

Convention de registres System V ABI, tableau des numéros et Hello World autonome sans libc en assembleur x86-64.

Écrire en assembleur x86-64 sur GNU/Linux implique de dialoguer directement avec le noyau via des appels système (syscalls), sans passer par la bibliothèque C standard (libc).

Chaque appel système possède un numéro unique placé dans le registre rax, des arguments transmis dans un ordre strict via des registres dédiés, puis l'instruction syscall déclenche la transition vers l'espace noyau.

La convention d'appel System V AMD64 ABI

Sous Linux 64 bits (x86-64), la convention de passage des registres pour un appel système est la suivante :

RôleRegistreDescription
Numéro du syscallraxIdentifiant de la fonction noyau à exécuter
Argument 1rdiPremier argument
Argument 2rsiDeuxième argument
Argument 3rdxTroisième argument
Argument 4r10Quatrième argument (attention : rcx en fonction standard C, mais r10 pour syscall)
Argument 5r8Cinquième argument
Argument 6r9Sixième argument
Valeur de retourraxRésultat de l'opération (si négatif entre -1 et -4095, il s'agit de -errno)

Attention aux registres écrasés : L'instruction processeur syscall modifie systématiquement les registres rcx (qui sauvegarde l'adresse de retour RIP) et r11 (qui sauvegarde les drapeaux RFLAGS).

Tableau des principaux appels système x86-64

%raxNom du Syscall%rdi (arg1)%rsi (arg2)%rdx (arg3)%r10 (arg4)%r8 (arg5)Description
0sys_readfdbufcount--Lit des octets depuis un descripteur de fichier
1sys_writefdbufcount--Écrit des octets vers un descripteur de fichier
2sys_openfilenameflagsmode--Ouvre un fichier et retourne un descripteur
3sys_closefd----Ferme un descripteur de fichier ouvert
4sys_statfilenamestatbuf---Récupère les métadonnées d'un fichier par son chemin
5sys_fstatfdstatbuf---Récupère les métadonnées d'un fichier par son fd
8sys_lseekfdoffsetwhence--Déplace le curseur de lecture/écriture
9sys_mmapaddrlengthprotflagsfdMappe des fichiers ou de la mémoire anonyme
10sys_mprotectaddrlengthprot--Modifie les permissions d'une zone mémoire
11sys_munmapaddrlength---Libère une zone mémoire mappée
12sys_brkbrk----Ajuste la fin du segment de données (heap)
39sys_getpid-----Retourne le PID du processus courant
41sys_socketfamilytypeprotocol--Crée un point de communication réseau
42sys_connectfduservaddraddrlen--Établit une connexion vers une adresse distante
43sys_acceptfdupeer_sockaddrupeer_addrlen--Accepte une connexion réseau entrante
57sys_fork-----Crée un nouveau processus fils
59sys_execvefilenameargvenvp--Exécute un nouveau programme
60sys_exiterror_code----Termine immédiatement le processus
62sys_killpidsig---Envoie un signal à un processus

Exemple complet : Hello World sans libc en NASM

Voici un exemple minimaliste et autonome qui n'utilise aucune bibliothèque externe :

section .data
    msg db "Bonjour le monde en assembleur x86-64 !", 0x0A
    len equ $ - msg

section .text
    global _start

_start:
    ; 1. Appel sys_write (rax = 1, rdi = 1 (stdout), rsi = msg, rdx = len)
    mov rax, 1          ; Numéro du syscall sys_write
    mov rdi, 1          ; Descripteur de fichier : 1 = stdout
    mov rsi, msg        ; Pointeur vers la chaîne
    mov rdx, len        ; Longueur du message
    syscall             ; Déclenche l'appel système

    ; 2. Appel sys_exit (rax = 60, rdi = 0 (code de retour succès))
    mov rax, 60         ; Numéro du syscall sys_exit
    xor rdi, rdi        ; Code de retour 0
    syscall

Compilation et exécution :

# Assembler le fichier objet en 64 bits ELF
nasm -f elf64 hello.asm -o hello.o

# Lier le binaire sans libc
ld hello.o -o hello

# Exécuter
./hello

En résumé

  • Sous Linux x86-64, le numéro de syscall va toujours dans rax et l'exécution se déclenche avec syscall.
  • La convention passe les arguments dans l'ordre : rdi, rsi, rdx, r10, r8, r9.
  • La valeur de retour est renvoyée dans rax (les codes d'erreurs étant négatifs entre -1 et -4095) ;)