Contexte historique
Avant l’introduction officielle de ud2, les programmeurs exploitaient deux séquences d’octets qui provoquaient une exception d’opcode invalide : 0F FF et 0F B9. Intel a rétroactivement nommé ces séquences ud0 et ud1. Lorsque les processeurs de nouvelle génération ont commencé à donner un comportement différent à 0F FF, certains logiciels se sont arrêtés, illustrant la loi de Hyrum : un comportement observé finit par être exploité.
Fonctionnement de l’instruction ud2
Le code machine officiel de ud2 est
0F 0B. Il s’agit d’une instruction de deux octets sans opérande. Au moment du décodage, le processeur reconnaît immédiatement l’opcode comme « undefined » et déclenche l’interruption #UD (invalid opcode). Aucun registre ou adresse mémoire n’est lu, ce qui évite les effets de bord liés à la décodage partiel d’une instruction.Contrairement à ud0 (0F FF) et ud1 (0F B9), qui étaient décodés comme des instructions à deux paramètres (destination registre, source registre ou mémoire), ud2 ne possède aucun paramètre. Cette caractéristique élimine le risque d’une faute d’accès si la partie décodée dépasse la page mémoire active ; les processeurs plus anciens pouvaient générer une violation d’accès au lieu d’une exception #UD lorsqu’une instruction incomplète traversait une page non présente.
Utilisation par les compilateurs
Les compilateurs modernes insèrent ud2 pour marquer du code déclaré « unreachable ». Par exemple, une fonction annotée [[noreturn]] qui retournerait accidentellement verra un ud2 placé immédiatement après l’appel. Ainsi, si le flux d’exécution atteint ce point, le processus se termine immédiatement avec une exception #UD, évitant l’exécution de données aléatoires.
Le même mécanisme est utilisé dans les implémentations de __builtin_unreachable() ou des macros d’assertion qui doivent interrompre le programme en cas d’erreur logique détectée à la compilation.
Implications et limites
Sur les processeurs antérieurs à l’introduction officielle de ud2, l’opcode 0F 0B reste inconnu et déclenche également #UD, car tout opcode non répertorié entraîne cette exception. La garantie d’Intel consiste à ne jamais réassigner ces deux octets dans les futures micro‑architectures, assurant ainsi une compatibilité ascendante.
Le principal avantage de ud2 réside dans sa prévisibilité : le comportement est défini par l’architecture, indépendamment de la version du processeur ou du mode d’exécution (real mode, protected mode, long mode). Aucun scénario connu ne permet de contourner l’exception, ce qui en fait un repère fiable pour les outils de diagnostic et les mécanismes de sécurité qui souhaitent provoquer une interruption contrôlée.