elouann.dev
EN — English version

ProjetsBas-niveau & embarqué

Libasm

Des fonctions de la libc en assembleuren cours

Période
juin 2025 – aujourd’hui
Cadre
cursus 42
Équipe
solo
Note
pas encore évaluée
  • C
  • Assembleur
  • NASM x86-64 Intel
  • Bas-niveau
  • Programmation impérative
  • Testeur

Voir le code

Réécrire des fonctions de la libc directement en assembleur x86-64, en respectant les conventions d’appel pour qu’un programme C puisse les utiliser sans voir la différence. Le tout guidé par les tests.

test en CASSERT_SAME(ft_strlen,strlen,"héllo")ft_strlen.sxor rax, rax.loop:cmp byte [rdi+rax], 0je .done ; inc rax.done: retrdi = srax = longueurABI System Vle cycle TDDécrire le testil échoueécrire l’asmil passefonction suivante
SchémaUn appel depuis le C : les arguments arrivent dans des registres, le résultat repart dans rax. Le testeur compare chaque fonction à celle de la libc.

Le contrat

Pour qu’une fonction écrite en NASM soit appelable depuis le C, elle doit respecter l’ABI System V : le premier argument arrive dans rdi, le deuxième dans rsi, le troisième dans rdx, et la valeur de retour repart dans rax. Certains registres doivent être rendus intacts à l’appelant.

Au programme : strlen, strcpy, strcmp, strdup, read, write, et en bonus des listes chaînées et un atoi_base. Pour read et write, il faut aussi renseigner errno comme le ferait la libc.

Tester d’abord

J’ai fait ce projet en TDD : j’écris d’abord les tests, puis la fonction. Le testeur est un petit framework en C. Une macro ASSERT_SAME appelle ma fonction et celle de la libc avec les mêmes entrées, et compare les résultats.

Les cas sont choisis pour piéger l’assembleur : chaîne vide, octets supérieurs à 127, UTF-8, octet nul au milieu, chaîne de 10 000 caractères, ou pointeur non aligné. Le testeur compile et lie la bibliothèque, lance les tests dans un sous-processus, puis repasse tout sous Valgrind.

Où j’en suis

Le projet est encore en cours : le testeur est en place et les fonctions arrivent les unes après les autres.

Ce que j’en retiens

  • L’ABI, c’est le contrat qui permet à deux langages de se parler.
  • En assembleur, rien n’est implicite : chaque registre utilisé est une décision.
  • Écrire les tests en premier évite de croire qu’une fonction marche parce qu’elle « a l’air » de marcher.