← L'édition
DevNouveau3 min de lecture

Odin repense l'assembleur inline avec un système de modèles typés

Le langage de programmation Odin introduit une nouvelle syntaxe pour l'assembleur inline, permettant d'intégrer des instructions machine directement dans le code source. Inspirée de l'assembleur Plan 9 de Go, cette fonctionnalité apporte une vérification sémantique stricte dès la compilation pour l'architecture amd64.

Fil « Modèles d'assembleur inline dans le langage Odin »

Illustration de l'article — odin-lang.org
Image : odin-lang.org

Une syntaxe universelle pour le code bas niveau

Le langage Odin réorganise sa gestion de l'assembleur inline (injection de code en langage machine au sein d'une fonction) avec l'introduction des modèles d'assembleur (asm templates). Actuellement réservé aux cibles amd64 (l'architecture processeur 64 bits pour Linux, Windows et macOS), ce système a pour objectif de remplacer à terme certaines fonctions intrinsèques (fonctions intégrées au compilateur qui simulent une instruction processeur spécifique). Il s'appuie sur une grammaire universelle inspirée de l'assembleur de Go et du système Plan 9 (système d'exploitation créé par les Bell Labs), tout en adoptant la syntaxe d'instructions d'Intel avec l'ordre destination-source (dst, src).

Déclaration, liaisons et registres

Un modèle d'assembleur n'est pas un simple bloc de texte inséré brut : il se comporte comme une fonction obligatoirement inlinée (injectée directement sur le lieu d'appel). Dans le corps du bloc, les registres physiques de la puce sont précédés du symbole % (comme %rax), tandis que les paramètres et registres de travail restent nommés librement. Un bloc de liaisons [...] permet de configurer les liaisons de registres, la mémoire et les effets secondaires :

// Exemple d'addition de deux entiers 64 bits
add_u64 :: asm (x, y : u64) -> (r : u64) {
    mov r, x
    add r, y
}

// Incrémentation avec réutilisation du registre d'entrée
add_one :: asm (x : u64) -> (r : u64) [ x -> r ] {
    inc r
}

Le bloc de liaisons permet aussi de déclarer des registres temporaires (scratch), des vues sur des sous-largeurs de registres (width-views), ou des directives comme #clobber (qui signale l'écrasement involontaire de registres, de fanions d'état ou de la mémoire) et #volatile (qui empêche le compilateur d'éliminer ou de réordonner l'instruction).

Vérification sémantique à la compilation

La spécificité majeure de ces modèles réside dans leur analyse préalable par le compilateur. Le frontend (la phase initiale d'analyse du compilateur) vérifie chaque instruction par rapport aux tables d'encodage officielles du processeur cible au lieu de transmettre aveuglément le texte à l'assembleur. Les erreurs sont ainsi détectées immédiatement :

  • Les mnémoniques (noms d'instructions) inconnus proposent des suggestions adaptées (par exemple movss si vous écrivez movsss).
  • Le nombre et le type des opérandes (registres, valeurs immédiates, vecteurs SIMD pour le calcul parallèle) sont contrôlés.
  • Les adresses mémoires au format Intel [base + index*échelle + déplacement] sont validées selon les contraintes matérielles.

Surcharge et instanciation anonyme

Pour simplifier l'usage de ces briques bas niveau, Odin permet de regrouper des modèles d'assembleur sous un même nom pour gérer la surcharge (exécuter une variante d'instruction spécifique selon le type u32 ou u64). Enfin, il est possible de procéder à un appel d'assembleur inline anonyme directement dans une expression sans déclarer de modèle réutilisable au préalable.