Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
basalt — Le tout premier vérificateur d'aléas au monde pour NVIDIA Blackwell (sm_120), avec un assembleur et un ordonnanceur comparés octet par octet à leur propre compilateur. La vérification qu'ils n'ont jamais livrée. | Kitploit
Outils/GitHubGitHub/sunnypatell/basalt
Analyse StatiqueAnalyse des VulnérabilitésAnalyse de CodeRétro-ingénierieSécurité MatérielleAnalyse de Binaires
GitHubsunnypatell/basalt

basalt

Le tout premier vérificateur d'aléas au monde pour NVIDIA Blackwell (sm_120), avec un assembleur et un ordonnanceur comparés octet par octet à leur propre compilateur. La vérification qu'ils n'ont jamais livrée.

Voir le dépôt
3il y a 0 joursPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Site web
Partager
basalt : le premier vérificateur d'aléas pour NVIDIA Blackwell (sm_120), avec un assembleur et un ordonnanceur alignés octet pour octet avec leur propre compilateur. Le contrôle qu'ils n'ont jamais livré. sm_120 ne dispose pas d'interverrouillage matériel, donc un seul mauvais compte de stall fait lire au GPU un registre obsolète et renvoyer silencieusement une mauvaise réponse.
Architecture Python License PyPI

CI Runtime dependencies No GPU required

Controls

DOI 10.5281/zenodo.22072811 Archived on Zenodo ORCID 0009-0005-3863-7642 Cite this repository


Le problème · Quels GPU · Comment ça marche · Démarrage rapide · Mesuré, pas supposé · Résultats · API · Méthode · Feuille de route · Salle blanche


Le problème

Une instruction GPU NVIDIA fait 128 bits, et 21 d'entre eux ne sont pas du tout l'instruction. Ils constituent un mot de contrôle d'ordonnancement, de stall à reuse : combien de cycles attendre avant d'émettre l'instruction suivante, quels scoreboards signaler, lesquels attendre, et quels opérandes peuvent être servis depuis le cache de réutilisation.

Le matériel ne vérifie rien de tout cela. Sur sm_120, il n'y a pas d'interverrouillage pour les instructions à latence fixe. Le silicium fait confiance à ce qui a produit le mot de contrôle. Si un compte de stall est plus court que la latence d'une valeur consommée par l'instruction suivante, rien ne déclenche de faute, rien ne bloque, et aucun avertissement n'est émis. L'instruction lit un registre qui n'a pas encore été écrit et calcule sur des données obsolètes, à pleine vitesse, à chaque fois.

C'est un type de bug étrange. Il ne plante pas. Il n'apparaît pas dans un débogueur. Il produit des nombres simplement faux, ce qui, dans une multiplication matricielle ou un noyau d'attention, signifie un modèle qui s'entraîne légèrement mal plutôt qu'un modèle qui casse visiblement.

Cycles par instruction pour chaque encodage de stall sur sm_120 : un stall de 0 coûte 36,85 cycles et est correct, 1, 2 et 3 coûtent 4,88, 4,88 et 5,88 et renvoient silencieusement une mauvaise réponse, et 4, 8 et 15 coûtent 6,88, 10,88 et 18,02 et sont corrects.

Les trois encodages les moins chers sont ceux qui sont cassés, et rien, nulle part, ne le signale. Remarquez aussi ce que fait la barre de gauche : un stall de zéro n'est pas zéro cycle, c'est un encodage sûr distinct qui attend les résultats en cours et coûte environ neuf fois le prix d'une instruction ordonnancée. Un vérificateur qui le lirait comme zéro considérerait des programmes corrects comme cassés.

Les outils qui génèrent du code machine pour cette architecture assignent ces bits de contrôle à partir d'un modèle de latence. basalt est l'outil qui vérifie la réponse.

Le contrôle que NVIDIA n'a jamais livré

NVIDIA vous donne un compilateur qui écrit ces 21 bits. Il ne vous donne rien qui les relise et vous dise qu'ils sont sûrs, et personne d'autre non plus.

Des assembleurs pour GPU NVIDIA existent depuis une décennie, l'encodage Blackwell a déjà fait l'objet de rétro-ingénierie, des caractérisations au niveau du cycle de sm_120 sont publiées, et un assembleur public pour cette architecture assigne déjà lui-même les bits de contrôle d'ordonnancement et exécute ses propres noyaux sur une carte pour vérifier que les réponses sont correctes. Tout cela est vrai, et rien de tout cela n'est l'affirmation :

Rien d'autre ne peut recevoir un cubin qu'il n'a pas produit et se voir demander de dire si ses bits de contrôle d'ordonnancement sont sûrs.

Votre compilateur a émis ce cubin, ou une bibliothèque l'a livré, ou quelqu'un l'a écrit à la main, et jusqu'à présent il n'y avait aucun moyen de le demander. Sur une architecture sans interverrouillage matériel, c'est la différence entre « ça a tourné » et « c'est correct », et cette différence est invisible : un stall court d'un cycle lit un registre obsolète et renvoie un mauvais nombre à pleine vitesse, sans faute ni avertissement, à chaque fois.

Tout le reste ici existe pour rendre cette phrase testable. L'assembleur est ce qui construit un programme avec un stall délibérément raccourci. L'ordonnanceur est ce qui force le modèle à s'engager sur une réponse plutôt que de noter celle d'un autre. Et l'audit est l'endroit où la phrase cesse d'être une absence et devient une mesure : basalt pointé sur 2 473 cubins sm_120 que NVIDIA livre dans cuBLAS, cuSOLVER, cuSPARSE, NPP et le reste.

Pourquoi cela n'existait pas, selon les propres mots du domaine. L'assembleur SASS le plus utilisé dit dans sa propre documentation que « vérifier rigoureusement l'exactitude du programme entier … [est] loin d'être possible sans support officiel. Il est donc laissé à l'utilisateur le soin de garantir l'exactitude du programme, avec une aide très limitée de l'assembleur. » SIP, à propos de l'auto-réglage des ordonnancements SASS, affirme que « la validation est impossible pour les codes d'assemblage natifs GPU car la sémantique formelle du SASS est à code source fermé. »

Les deux concernent l'exactitude sémantique : si un noyau calcule ce qu'il est censé calculer. basalt n'y répond pas, et rien ici ne prétend le faire. Il répond à une question strictement plus petite, et le fait est que cette question plus petite est décidable sans la sémantique :

Les bits de contrôle de ce programme couvrent-ils ses propres dépendances de données ?

Cela nécessite la structure de dépendances, que l'encodage révèle, et un modèle de latence, que le silicium révèle sous mesure. Ni l'un ni l'autre n'exige de savoir ce que calcule une instruction. Un noyau peut passer ce contrôle et rester le mauvais algorithme ; ce qu'il ne peut pas faire, c'est lire un registre avant que la valeur n'arrive.

Deuxièmement, rien d'autre n'est mesuré contre les octets du vendeur lui-même. La référence de basalt est la sortie de ptxas, donc un désaccord est un bug de basalt jusqu'à preuve du contraire. Son assembleur doit reproduire exactement les 128 bits du compilateur. Son ordonnanceur doit jeter tous les bits de contrôle choisis par le compilateur, en calculer de nouveaux, et faire calculer au GPU la même réponse.

Une seule norme pour tout cela : être exactement d'accord avec le vendeur, ou expliquer pourquoi.

ComposantCe qu'il faitComment il est vérifiéRésultat
AssembleurTexte SASS vers le mot de 128 bitsRéassemble chaque instruction émise par ptxas et compare les octets, sur le corpus et sur 5,2 M d'instructions de code de bibliothèque livré qu'il n'avait jamais vues59 693 des 59 760 instructions du corpus et 4 585 336 des 5 237 448 instructions livrées exactes, le reste refusé nommément, 0 erreur dans les deux
VérificateurLit un ordonnancement, signale les aléasLa sortie du vendeur lui-même doit se vérifier sans erreur, et un stall délibérément raccourci doit être détecté0 erreur sur 1 323 paires noyau/niveau d'optimisation du vendeur, 0 manqué sur 233 noyaux cassés
AuditLe même vérificateur, sur les bibliothèques livréesL'exécuter sur des noyaux sm_120 de production retenus hors de chaque table qu'il lit0 erreur sur 2 762 noyaux et 10 218 030 dépendances, les 2 762 entièrement analysés
OrdonnanceurAssigne chaque bit de contrôle à partir de zéroJeter ceux du vendeur, en calculer de nouveaux, exécuter les deux sur le GPU avec huit entrées, comparer les octets de sortie439 des 439 noyaux comparables octet pour octet identiques, aux trois niveaux d'optimisation

Et la partie sur laquelle un ordonnanceur est généralement discret : ce que coûte l'exactitude. Les ordonnancements de basalt dépensent 1.05x les cycles d'émission du vendeur, plus lents sur 111 des 1 323 paires noyau/niveau d'optimisation et moins chers sur 842, chaque noyau comparable restant octet pour octet identique sur le GPU.

Trois exécutions d'audit contre les bibliothèques sm_120 livrées par NVIDIA : 6 593 erreurs sur 250 noyaux, puis 940 après élargissement à 2 762 noyaux et 10 218 030 dépendances, puis 0 après treize corrections. Chaque erreur était celle de basalt.

La troisième ligne est celle qui a changé les trois autres. Un vérificateur calibré sur un corpus ne peut pas échouer sur ce corpus : l'écart le plus serré que le compilateur a été vu laisser est le plancher, par construction, pour exactement le code sur lequel il a été mesuré. La première fois que celui-ci a vu du code venu d'ailleurs, il a signalé vingt-six aléas par noyau dans un décodeur JPEG qui n'a jamais renvoyé un mauvais pixel, et les 6 593 étaient tous ceux de basalt. Les corriger l'a ramené à zéro, et zéro sur une bibliothèque n'était pas non plus une preuve : élargir l'ensemble retenu à trois bibliothèques et 5,2 millions d'instructions l'a ramené directement à 940, et a trouvé cinq erreurs de modèle supplémentaires en plus des huit premières. Treize corrections, aucune de NVIDIA, et l'exigence ré-extraite de 24 311 noyaux livrés a placé un prédicat de garde à 13 cycles sur 229 567 observations, soit le nombre que l'injection de fautes avait mesuré sur cette carte en cassant un programme exprès. Voir finding 32.

Être moins cher que le vendeur n'est pas un motif de fierté. basalt ordonnance chaque dépendance à l'écart le plus serré que ptxas ait jamais été vu laisser pour cette paire exacte, et ptxas équilibre la pression des registres et la mémoire en plus de la latence d'émission pendant que celui-ci optimise un seul nombre. Cela n'a pas non plus été cru sur parole : la première fois que le ratio est passé sous 1.0, l'aller-retour matériel a cassé, et le nombre n'a tenu qu'une fois le bug qu'il exposait corrigé. Le ratio est verrouillé des deux côtés dans la suite de tests pour cette raison.

La colonne du milieu est le point crucial. Un vérificateur et un ordonnanceur qui partagent un modèle de latence sont d'accord entre eux tout en ayant tous deux tort, donc ni l'un ni l'autre n'est une preuve pour l'autre ; seul le silicium n'est pas partie prenante dans l'argument. Lancer l'ordonnanceur sur sept noyaux écrits à la main a passé sept sur sept pendant longtemps. Le lancer sur trois cents en a trouvé quarante et un de faux, et chaque correction dans les résultats est sortie en observant ce nombre bouger.

La même chose s'applique aux entrées. Une lecture obsolète ne change la réponse que lorsque la valeur obsolète et la valeur fraîche diffèrent, donc un motif d'octets est une seule chance de le remarquer, et l'exécution de chaque noyau contre un deuxième, un troisième et un quatrième motif a immédiatement trouvé un prédicat de retenue que le modèle d'opérandes lisait comme une source depuis le début. Il avait survécu à tous les contrôles jusqu'à ce point, y compris à l'aller-retour lui-même.

La même discipline décide de ce que l'assembleur est autorisé à faire, et il vaut la peine de séparer les deux nombres qu'il possède.

L'assembleur de basalt reproduit exactement 59 693 des 59 760 instructions du corpus et 4 585 336 des 5 237 448 instructions de bibliothèque livrées, refusant le reste nommément, et n'a assemblé aucun des 5 297 208 en de mauvais octets.

La couverture est de 99,9 % du corpus et de 87,5 % du code de bibliothèque livré. L'exactitude est de 100 %, et c'est le nombre verrouillé par un test. L'écart entre les deux est constitué d'instructions que basalt refuse, chacune nommant le champ qu'il n'a pas pu placer, car un outil qui devinerait atteindrait une couverture complète en émettant des mots qui se désassemblent en le bon texte et calculent autre chose. Il n'en a jamais émis un seul, sur 59 760 instructions du corpus et 5 237 448 instructions livrées.

Il n'y est parvenu qu'après huit séries distinctes d'erreurs commises en toute confiance :

  • écrire un numéro de registre dans l'encodage d'une forme immédiate,
  • traiter un registre uniforme comme interchangeable avec un registre ordinaire,
  • conserver la cible de branchement du noyau d'où la forme avait été extraite,
  • mettre l'entier 15 dans un champ qui contient un flottant demi-précision,
  • écrire un opérande dans des bits qui se sont révélés être un drapeau de réutilisation,
  • écrire dans un champ que le sondeur n'avait attribué que partiellement, laissant le reste encoder encore l'ancienne valeur,
  • répartir un numéro de registre sur le bit qui sélectionne dans quel fichier de registres il se trouve,
  • et lire l'index d'un chargement constant indexé par registre comme un déplacement.

Chacune de ces erreurs a produit un mot qui s'assemble, se désassemble en exactement le texte dont il provient, et calcule autre chose. C'est la même défaillance que le reste de ce dépôt existe pour attraper, et c'est pourquoi ces huit cas sont désormais refusés avec une raison nommant ce que le champ contient réellement, et pourquoi le nombre d'instructions assemblées en de mauvais octets est un test verrouillé à zéro plutôt qu'un nombre dans un tableau.

Une neuvième est apparue la première fois que l'assembleur a été pointé sur du code machine qu'il n'avait pas produit, et c'était d'un genre différent. c[0x0][UR4] indexe son décalage par un registre là où la forme enregistrée contient un nombre, et l'encodeur a levé une exception plutôt que de refuser. Un plantage sur une entrée étrangère est pire qu'un mauvais verdict, car l'appelant n'obtient ni l'un ni l'autre.

Quels GPU

NVIDIA Blackwell GeForce RTX 50 series Compute capability 12.0

sm_120 n'est pas un numéro de modèle. C'est la capacité de calcul partagée par toute la gamme grand public Blackwell, donc l'encodage des instructions, la base de données, l'assembleur et le vérificateur s'appliquent à chaque carte de cette gamme :

CarteCapacité de calculCouverte
GeForce RTX 5090, 5090D12.0 (sm_120)oui
GeForce RTX 5080, 5070 Ti, 507012.0 (sm_120)oui
GeForce RTX 5060 Ti, 5060, 505012.0 (sm_120)oui
Configurations portables GeForce RTX série 5012.0 (sm_120)oui
Cartes de poste de travail RTX PRO Blackwell12.0 (sm_120)oui
Blackwell datacentre (B100, B200, GB200)10.0 (sm_100)non, encodage différent

ptxas cible aussi sm_121, une puce différente de la même famille. basalt n'a jamais tourné dessus et ne prétend pas la prendre en charge. Ce qu'il peut dire est mesuré : le compilateur émet un code octet pour octet identique, mots de contrôle compris, pour les six cibles qu'il propose ici, donc l'ordonnancement dont un noyau a besoin est une propriété de l'architecture plutôt que de la pièce (finding 28). Si ce n'était pas vrai, le compilateur de NVIDIA lui-même émettrait un ordonnancement non sûr pour l'une d'elles.

Chaque nombre mesuré sur silicium provient d'une seule carte physique, nommée précisément, car « une 5070 Ti » ne suffit pas pour reproduire une exécution :

La carteSon identité exacte
CarteGigabyte GeForce RTX 5070 Ti EAGLE OC
Signalée par le piloteNVIDIA GeForce RTX 5070 Ti
Capacité de calcul12.0
Multiprocesseurs de streaming70
Fréquence boost2542 MHz
Chaîne d'outilsCUDA 13.3.1, ptxas V13.3.73
Ce qui nécessite un GPU, et ce qui n'en nécessite pas

La plus grande partie de basalt n'a pas besoin de GPU du tout. Les deux oracles, la base de données d'instructions, l'assembleur et le vérificateur d'aléas s'exécutent contre ptxas et nvdisasm comme de simples sous-processus, c'est pourquoi ils tournent dans le CI sur une machine sans carte graphique. 237 des 252 tests font partie de ce groupe, et 200 n'ont besoin ni d'une carte ni des binaires NVIDIA.

Un GPU n'est nécessaire que pour exactement trois choses, et ce sont les trois qui transforment un outil plausible en un outil crédible :

Nécessite une cartePourquoi
measure, probe-stallsChronométrer une instruction et découvrir ce qu'une dépendance exige vraiment en la cassant
scripts/roundtrip_corpus.pyRéordonnancer chaque noyau du corpus et exécuter les deux versions pour comparer les octets de sortie
scripts/agreement_sweep.pyRaccourcir une dépendance par noyau et demander au silicium si basalt avait raison

L'overclock d'usine ne modifie pas les mesures. Chaque latence ici est en cycles, ce qui est une propriété du pipeline plutôt que de l'horloge, et la fréquence boost n'est enregistrée à côté que pour qu'une comparaison en temps d'horloge reste possible. Ce que la carte affecte, c'est la reproductibilité, et c'est pourquoi basalt measure --board l'enregistre.

Pourquoi une seule carte est une réserve et non une note de bas de page

Tout ce qui a été mesuré ici l'a été sur une seule carte, et basalt enregistre le SKU à côté de chaque mesure plutôt que de les présenter comme universelles. Une 5090 a plus de deux fois plus de SM et son propre comportement d'horloge ; l'encodage sera identique et les latences devraient être re-mesurées plutôt que supposées :```bash python -m basalt.cli measure -o my-card.json python -m basalt.cli verify kernel.cubin --latencies my-card.json

root@kitploit:~
Ce n'est pas de la modestie. Un modèle de latence partagé entre un vérificateur et un ordonnanceur est exactement
là où un mauvais nombre se cache, si bien qu'une seconde carte est la chose la plus utile que l'on puisse apporter.

</details>

## Comment ça marche

Tout repose sur deux oracles, tous deux des binaires NVIDIA standards exécutés comme processus externes. Aucun code source, en-tête ou bibliothèque NVIDIA n'est utilisé ni redistribué.

| Oracle | Invocation | Ce qu'il fournit |
| :--- | :--- | :--- |
| **Vérité terrain** | `ptxas` → cubin → `nvdisasm -c -hex` | Encodages que le compilateur du fournisseur émet réellement. Sémantique incontestable. |
| **Sonde** | `nvdisasm -b SM120a` sur des octets bruts | Décode des mots que `ptxas` n'émettra jamais, ce qui transforme l'espace d'encodage en quelque chose de recherchable plutôt qu'en quelque chose à deviner. |

L'oracle sonde est celui qui compte. Un outil limité à la sortie du compilateur ne peut que redécouvrir ce que le compilateur fait déjà. Nourrir le décodeur directement avec des mots de 128 bits synthétisés signifie que le jeu d'instructions peut être *mesuré*.

Aucun des deux oracles n'a besoin de GPU, si bien que l'intégralité de la base de données d'instructions est reconstruite en CI sur n'importe quelle machine.

### Dériver l'encodage en le modifiant

basalt ne lit une table d'opcodes nulle part. Il prend un encodage assemblé, inverse un bit, décode le résultat et enregistre ce qui a bougé. Un bit qui change le registre de destination est un bit de destination ; un bit qui change le mnémonique est un sélecteur ; un bit qui ne change rien d'observable est inerte.

Exécuté sur `IADD R5, R5, 0x2a`, la mesure ressort comme suit :```
operand[0]  bits 16:23     flip 16 -> R4,  flip 17 -> R7      destination register
operand[1]  bits 24:31     plus bit 72, which negates it      source register
operand[2]  bits 32:63     flip 32 -> 0x2b, flip 33 -> 0x28   32-bit immediate
opcode      bits 2, 4, 12:15
inert       36 bits        no observable effect
invalid     11 bits        the decoder rejects the mutation

Champs de registre de huit bits et valeur immédiate de 32 bits, obtenus par expérimentation plutôt que par hypothèse.

Le mot de contrôle

Une instruction sm_120 est composée de 128 bits, dont les bits 105 à 125 constituent le mot de contrôle d'ordonnancement : stall sur 108:105, yield sur 109, write_barrier sur 112:110, read_barrier sur 115:113, wait_mask sur 121:116 et reuse sur 125:122.

La disposition se valide d'elle-même au contact. Dans un noyau trivial, S2R définit write_barrier=0 et l'IMAD qui consomme son résultat porte wait_mask=0x01 ; LDCU.64 définit write_barrier=1 et le STG.E dépendant porte wait_mask=0x02. Chaque paire producteur-consommateur s'aligne, et les instructions que nvdisasm annote .reuse ont le bit de réutilisation correspondant défini.

Démarrage rapide

Aucune installation CUDA et aucun GPU requis. Le script de la chaîne d'outils récupère des redistribuables épinglés, environ 45 Mo, sans droits administrateur, rien n'est ajouté à votre PATH.```bash git clone https://github.com/sunnypatell/basalt.git cd basalt python -m venv .venv && source .venv/bin/activate # Windows: ..venv\Scripts\Activate.ps1 pip install -e ".[dev]"

python scripts/fetch_toolchain.py # pinned ptxas + nvdisasm python -m basalt.cli doctor # verify both oracles end to end python scripts/verify_all.py # every control in this README, in order

root@kitploit:~
No content was provided to translate.```console
$ python -m basalt.cli doctor
ok    toolchain   V13.3.73 in third_party/cuda/13.3.1/bin
ok    ptxas       assembled sm_120a
ok    cubin oracle  16 instructions with encodings
ok    probe oracle 16/16 mnemonics round-tripped

both oracles healthy. no GPU required for anything above.

Ou comme package

pip install basalt-sass installe la CLI, la bibliothèque et les trois tables mesurées, sans dépendances d'exécution. Utilisez ceci si vous avez déjà CUDA sur la machine ; le checkout ci-dessus est ce qu'il vous faut si ce n'est pas le cas, ou si vous avez l'intention de reproduire les mesures.```bash pip install basalt-sass basalt doctor basalt verify kernel.cubin

root@kitploit:~
### Où il cherche `ptxas` et `nvdisasm`

basalt lance les deux comme processus externes et ne redistribue ni l'un ni l'autre, il doit donc en trouver une copie.
Il prend la première qui répond, et **toute installation CUDA 13 fait l'affaire** : rien ne doit être la
redistribution épinglée.

| Ordre | Emplacement |
| ---: | :--- |
| 1 | `--cuda-bin`, passé sur la ligne de commande |
| 2 | `BASALT_CUDA_BIN`, un répertoire contenant les deux binaires |
| 3 | `CUDA_PATH`, `CUDA_HOME` ou `CUDA_ROOT`, chacun plus `/bin` |
| 4 | `ptxas` dans votre `PATH` |
| 5 | `third_party/cuda/<version>/bin` dans un checkout, les plus récents d'abord |

`basalt doctor` affiche celle qui a été résolue, et quitte avec un code non nul lorsqu'il ne peut pas en trouver une, donc
il fonctionne comme une condition préalable d'étape de build plutôt que comme un simple outil à lire.

L'interrogation de la base de données d'instructions ne nécessite aucune chaîne d'outils, car la base de données est mesurée
à l'avance et est incluse dans le package :```bash
basalt isa --stats
basalt isa --opcode QMMA

Reconstruisez la base de données d’instructions à partir de zéro, ou interrogez celle qui est validée :```bash python -m basalt.cli build-isa # harvest, probe, write src/basalt/data/isa/sm_120a.json python -m basalt.cli isa --stats python -m basalt.cli isa IMAD.WIDE.U32 # one form, with its measured field layout python -m basalt.cli isa --opcode QMMA # every form of one opcode

root@kitploit:~
### Vérifiez le code machine que vous n'avez pas écrit

C'est la partie que rien d'autre ne fait, et elle ne nécessite ni GPU ni arguments. Le modèle
de latence mesuré et la table d'exigences extraite sont tous deux commités, de sorte qu'un clone frais peut être
pointé directement vers un cubin, quel que soit ce qui l'a produit :```bash
python -m basalt.cli verify kernel.cubin

Aucun contenu n'a été fourni dans le champ INPUT pour cette traduction. Merci de fournir le texte du chunk 17 à traduire.```console $ python -m basalt.cli verify nvjpeg.sm_120.cubin 25 kernels, 0 with an error 7984 instructions in 789 blocks, 11580 dependencies checked across blocks: 0 errors, 3 warnings pair data: 3957 pairings from 25634 kernels, 427 producers with enough observations to use latency model: measured on NVIDIA GeForce RTX 5070 Ti

root@kitploit:~
Une bibliothèque ELF contient des centaines de kernels, et chacun est vérifié indépendamment, car les décalages repartent de zéro et rien ne se propage d'un kernel au suivant. Ajoutez `--strict` pour sortir avec un code non nul en cas de risque, ce qui est ce qu'une étape de build attend. Si vous disposez d'une carte sm_120 et souhaitez que le modèle soit mesuré sur votre propre matériel plutôt que sur celui de ce dépôt :```bash
python -m basalt.cli measure -o my-card.json   # needs a GPU, once
python -m basalt.cli verify kernel.cubin --latencies my-card.json
Chaque commande, et celles qui nécessitent une carte

Tout ce que fait la CLI est importable, et la surface de la bibliothèque avec des exemples exécutables se trouve dans docs/API.md.

Et les deux contrôles qui gardent le reste honnête. Le premier nécessite une carte ; le second nécessite les bibliothèques fournies et aucun matériel du tout :```bash python scripts/roundtrip_corpus.py # reschedule all 441 corpus kernels, run both on the GPU

python scripts/fetch_toolchain.py --libs # ~1.2 GB, no admin, nothing on PATH python scripts/audit_shipped.py --libs third_party/cuda/13.3.1/libs

root@kitploit:~
Veuillez fournir le contenu à traduire (chunk 23 de 29) — la section INPUT est vide.```console
$ python -m basalt.cli verify kernel.cubin --latencies src/basalt/data/latency/rtx-5070-ti.json
kernel.cubin
  32 instructions in 3 blocks, 23 dependencies checked: clean
  latency model: measured on NVIDIA GeForce RTX 5070 Ti

Mesuré, pas supposé

Les chiffres ici sont imprimés par l'outillage et se régénèrent à partir d'un checkout propre. Les commandes ci-dessus sont la source de vérité ; ces tableaux sont des instantanés.

Base de données d'instructions. Chaque entrée porte un encodage réellement assemblé et la version du compilateur qui l'a produit.

Base de données d'instructions

La couverture tensorielle est là où vit le matériel basse précision : HMMA et IMMA, QMMA à travers les types FP8, FP6 et FP4, y compris les paires d'opérandes asymétriques, les formes à facteur d'échelle QMMA.SF et OMMA.SF qui portent un exposant par bloc, le IMMA.SP sparse, et les instructions de mouvement matriciel LDSM, STSM et MOVM dans toutes les formes, y compris les variantes de transposition.

Latence, sur une RTX 5070 Ti. 70 SMs, chaque ajustement R² ≥ 0,9998. Mesuré en chronométrant des chaînes dépendantes et en prenant la pente, la longueur de chaîne étant relue dans le SASS compilé plutôt que supposée.

Trois d'entre elles contredisent le modèle supposé avec lequel basalt a été livré : DADD était supposé être de 48, POPC était supposé être de 4, et chaque conversion était supposée être de 6, contre 24 mesurés pour l'aller-retour.

Trois latences que basalt supposait avant de les mesurer par rapport à ce que le silicium rapportait : addition fp64 supposée à 48 et mesurée à 64, POPC supposé à 4 et mesuré à 18, et l'aller-retour de conversion I2FP plus F2I supposé à 12 et mesuré à 24.

Un modèle de latence supposé n'est pas une petite approximation d'un modèle mesuré, ce qui est tout l'argument en faveur de la mesure.

Et un stall de zéro n'est pas zéro cycle. C'est un encodage sûr distinct qui attend les résultats en attente, coûtant environ 37 cycles là où une instruction planifiée en coûte 4. C'est pourquoi ptxas -O0 émet un mot de contrôle entièrement mis à zéro et que le code calcule quand même correctement, environ neuf fois plus lentement.

Il concorde avec le compilateur du fabricant sur chaque kernel du corpus. Chaque kernel que ptxas construit à partir du corpus est vérifié par rapport à son propre ordonnancement, à chaque niveau d'optimisation qui ordonnance : 30 421 dépendances, zéro erreur. Ce balayage s'exécute en CI à chaque push, et chaque erreur de modélisation que ce projet a commise a été attrapée par lui plutôt que par le raisonnement.

Les verdicts correspondent au silicium. Pour chaque stall encodable sur un producteur dépendant, la réponse statique de basalt et ce que le matériel calcule réellement concordent, y compris le cas zéro. Cela est maintenu comme un test, pas affirmé ici. La preuve complète, y compris trois méthodes indépendantes pour le stall requis et les corrections apportées en cours de route, se trouve dans les constatations.

Et quand il dit qu'un ordonnancement est non sûr, le silicium est d'accord. Prenez le propre ordonnancement fonctionnel du fabricant pour 233 kernels, raccourcissez une vraie dépendance dans chacun, et comparez le verdict de basalt à ce que le GPU calcule : 79 qu'il a déclarés cassés l'étaient bien, et rien de ce qu'il a déclaré sûr n'a calculé une mauvaise réponse. Ce nombre a commencé à 34 manqués plutôt qu'à zéro, et les constatations disent quelle en était la cause et ce que sa correction a coûté en fausses alertes, parce qu'un balayage qui n'aurait jamais rapporté que son chiffre final vaudrait moins que celui qui a rapporté son premier.

Il peut aussi assigner les bits de contrôle

Le vérificateur détermine si un ordonnancement est sûr. L'ordonnanceur détermine ce que serait un ordonnancement sûr, à partir des mêmes mesures : il jette chaque bit de contrôle produit par ptxas, calcule les siens, redonne le résultat au vérificateur, puis l'exécute sur le GPU à côté de la version du fabricant du même kernel.

Exécutés sur la carte, sur l'ensemble du corpus, à chaque niveau d'optimisation qui produit un ordonnancement, les 439 kernels comparables ressortent avec des résultats identiques octet pour octet à ceux de l'ordonnancement du fabricant, à partir de bits de contrôle que basalt a déterminés lui-même. Les 2 qui sont exclus lisent l'horloge et l'identifiant de grille, donc ils ne concordent pas non plus avec eux-mêmes, et les constatations le disent plutôt que de les fondre dans un pourcentage.

Ce contrôle est la raison pour laquelle tout le reste est digne de confiance. Le vérificateur et l'ordonnanceur lisent le même modèle de latence, donc une entrée erronée dans celui-ci les satisfait tous les deux à la fois et ils s'accordent entre eux tout en ayant tous les deux tort. Seul le silicium n'a aucun intérêt dans le débat. Exécuter l'ordonnanceur sur sept kernels écrits à la main a passé sept sur sept pendant longtemps ; l'exécuter sur trois cents en a trouvé quarante et un erronés, et depuis, chaque correction du modèle est venue en observant ce nombre évoluer.

C'est de cette boucle que viennent les vrais bugs. Un stall passé en dehors de la fenêtre entre un producteur et son consommateur ne compte pour rien, et le passer là met fin à la recherche avec un programme encore trop court. Un stall épinglé à l'encodage sûr était écrasé par une passe ultérieure, remplaçant une garantie par un petit nombre. Les opérandes fp64 occupent des paires de registres sans que rien dans le mnémonique ne le dise, donc la moitié de chaque dépendance fp64 était invisible pour le vérificateur comme pour l'ordonnanceur. Un prédicat utilisé comme garde d'une instruction a besoin de treize cycles là où le même prédicat lu comme donnée en demande cinq, parce qu'une garde doit être résolue avant même que l'instruction ne soit émise. Et attendre un scoreboard ne règle pas complètement une dépendance : le producteur doit encore un petit stall qui lui est propre, deux cycles pour l'addition fp64, et un cycle de moins est silencieusement incorrect. Aucun de ces bugs n'a été trouvé par le raisonnement ; chacun a été trouvé en exécutant la sortie et en obtenant un mauvais résultat.

[!NOTE] 1.0, et précis sur ce que cela signifie. Ce qui est fait : les deux oracles, la base de données d'instructions dont les champs sont prouvés écrivables, le vérificateur d'aléas sur un vrai graphe de flux de contrôle, la latence mesurée sur un seul SKU par trois méthodes indépendantes, un ordonnanceur qui fait faire un aller-retour à chaque kernel comparable du corpus à travers le matériel, octet pour octet, et un audit de 2 762 kernels livrés tenus à l'écart de chaque tableau que le vérificateur lit. Ce qui ne l'est pas : 12 kernels du corpus qui ne sont pas exécutables par construction et 2 dont la sortie du fabricant n'est pas déterministe, tous nommés dans les constatations ; dix opcodes portent encore une latence supposée plutôt que mesurée, aucun d'eux n'étant jamais un producteur dans l'un ou l'autre code ; et un seul GPU a été mesuré, ce que la constatation 28 montre comme moins important que cela n'en a l'air. Quand quelque chose est inféré plutôt que mesuré, l'outillage le signale plutôt que de le faire passer pour un fait. Voir la feuille de route et la méthode.

Structure du dépôt

Où tout se trouve


``` src/basalt/ toolchain.py Locating and driving ptxas / nvdisasm encoding.py The 128-bit instruction word and its control fields disasm.py Both oracles: cubin ground truth and raw-word probe harvest/ PTX corpus generation and encoding extraction probe/ Differential bit probing and field inference isa/ The generated instruction database and its builder asm/ The assembler, and the ELF reader that rewrites words in place sched/ Assigning the control bits, and costing the result verify/ Register def-use analysis, hazard model, latency checking gpu/ Driver-API bindings and the latency measurement harness src/basalt/data/ The measured tables, inside the package so an installed copy has them: the ISA database, the latency model and the mined stall requirement docs/ Findings, method, the Python API, roadmap, artwork sources scripts/ Toolchain fetch, asset rendering, drift check, and the two hardware controls: the corpus round trip and the agreement sweep tests/ Unit tests, plus toolchain- and GPU-marked suites

root@kitploit:~
</details>

## Position clean-room

basalt est un travail indépendant et clean-room, réalisé pour l'interopérabilité. Il ne contient aucun code source, en-tête, bibliothèque ou documentation NVIDIA, et n'en redistribue aucun. Il observe le comportement d'exécutables distribués publiquement et l'enregistre, ce qui est le fondement sur lequel ce type de travail repose depuis plus d'une décennie.

NVIDIA, CUDA et Blackwell sont des marques déposées de NVIDIA Corporation. Ce projet n'est ni affilié à NVIDIA, ni approuvé ou sponsorisé par NVIDIA.

Sous licence [Apache-2.0](https://github.com/sunnypatell/basalt/blob/main/LICENSE). Apache plutôt qu'une licence restrictive, à dessein : un outil de correction que personne n'est autorisé à utiliser comme base n'est un outil de correction que personne n'utilise, et la concession de brevets compte pour un travail aussi proche du matériel.

## Contribuer

La contribution la plus précieuse est un encodage que basalt traite incorrectement. Voir [`CONTRIBUTING.md`](https://github.com/sunnypatell/basalt/blob/main/CONTRIBUTING.md) et le [modèle d'écart ISA](https://github.com/sunnypatell/basalt/blob/main/.github/ISSUE_TEMPLATE/isa_gap.yml), qui recueille suffisamment d'informations pour reproduire le problème sans votre machine.

[`SUPPORT.md`](https://github.com/sunnypatell/basalt/blob/main/SUPPORT.md) indique où poser une question, [`GOVERNANCE.md`](https://github.com/sunnypatell/basalt/blob/main/GOVERNANCE.md) ce qu'une modification doit satisfaire, [`RELEASING.md`](https://github.com/sunnypatell/basalt/blob/main/RELEASING.md) comment une version est préparée et vérifiée, et [`SECURITY.md`](https://github.com/sunnypatell/basalt/blob/main/SECURITY.md) comment signaler un problème de manière privée.

## Citer basalt

Si basalt éclaire un article, un outil, un modèle ou un rapport de bug, veuillez le citer. GitHub lit
[`CITATION.cff`](https://github.com/sunnypatell/basalt/blob/main/CITATION.cff) nativement, donc **Cite this repository** dans la barre latérale vous fournit
APA et BibTeX sans transcription. Ce même fichier est ce que Zenodo et les gestionnaires de citations
analysent, et il constitue le registre faisant autorité de la paternité.

La clé ci-dessous est celle que GitHub génère, donc copier d'ici et copier depuis la barre latérale
donnent la même entrée plutôt que deux qui semblent être des travaux différents :```bibtex
@software{Patel_basalt_a_hazard_2026,
  author = {Patel, Sunny},
  license = {Apache-2.0},
  month = aug,
  title = {{basalt: a hazard checker, assembler and scheduler for NVIDIA consumer Blackwell (sm\_120)}},
  doi = {10.5281/zenodo.22072811},
  url = {https://github.com/sunnypatell/basalt},
  version = {1.0.0},
  year = {2026}
}
Télécharger l’outil
FieldBitsMeaning
stall108:105Cycles à attendre avant d'émettre l'instruction suivante
yield109Indication que l'ordonnanceur de warps peut permuter les warps
write_barrier112:110Scoreboard à signaler lors du write-back (7 = aucun)
read_barrier115:113Scoreboard à signaler lors de la lecture d'opérande (7 = aucun)
wait_mask121:116Scoreboards qui doivent être libres avant l'émission
reuse125:122Drapeaux de cache de réutilisation d'opérande, un par emplacement source
CommandeCe qu'elle faitNécessite un GPU
doctorVérifier les deux oracles de bout en boutnon
build-isaRécolter et sonder, écrire la base de données d'instructionsnon
isaInterroger une forme, un opcode ou la couverturenon
validate-isaProuver que les champs mesurés peuvent être écritsnon
mine-stallsApprendre les exigences par paire à partir de ce que le compilateur ordonnancenon
verifyVérifier les bits de contrôle d'un cubin pour détecter les aléas de donnéesnon
scheduleAttribuer les bits de contrôle d'un cubin à partir de zéro et vérifier le résultatnon
assembleEncoder du texte SASS, ou un cubin entier, et le relire pour le prouvernon
measureMesurer la latence des instructions sur du silicium réeloui
probe-stallsTrouver le stall requis en cassant volontairement des programmesoui
Nombre
Formes d'instructions345
Opcodes distincts90
Formes avec une carte d'opérandes complète339
Formes tensor-core46
Compilé avecptxas V13.3.73
InstructionsCycles
IMAD IADD3 FFMA FADD FMUL LOP3 SHF4
POPC18
I2FP + F2I ensemble24
MUFU44
DADD DFMA64
stallcycles/instructionrésultat
036,85correct
14,88incorrect
24,88incorrect
35,88incorrect
46,88correct

Citez le DOI de concept, 10.5281/zenodo.22072811, plutôt qu'un DOI de version ou cette URL. Il pointe vers la version la plus récente, il reste donc correct sans jamais avoir besoin d'être modifié. CITATION.cff le contient, il est donc déjà présent sous les deux formes ci-dessus.

Si vous réutilisez les tableaux mesurés (src/basalt/data/) ou reproduisez une figure, citez la version dont ils proviennent plutôt que main : les valeurs sont régénérées par scripts/verify_all.py à un commit spécifique, et un tag est ce qui rend cela reproductible.

L'attribution est une condition de licence, pas une courtoisie. Apache-2.0 §4 exige que LICENSE et NOTICE accompagnent toute redistribution ou œuvre dérivée, et NOTICE contient la mention de paternité et la déclaration de clean-room. Les forks, les copies intégrées et les wheels reconstruits conservent tous les deux fichiers.

Auteur

Sunny Patel · sunnypatel.net · github.com/sunnypatell