Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
basalt — O primeiro verificador de hazards do mundo para NVIDIA Blackwell (sm_120), com um assembler e agendador correspondidos byte por byte ao próprio compilador deles. A verificação que eles nunca lançaram. | Kitploit
Ferramentas/GitHubGitHub/sunnypatell/basalt
Análise EstáticaAnálise de VulnerabilidadesAnálise de CódigoEngenharia ReversaSegurança de HardwareAnálise de Binários
GitHubsunnypatell/basalt

basalt

O primeiro verificador de hazards do mundo para NVIDIA Blackwell (sm_120), com um assembler e agendador correspondidos byte por byte ao próprio compilador deles. A verificação que eles nunca lançaram.

Ver Repositório
3há 0 diasAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Site
Compartilhar
basalt: o primeiro verificador de riscos do mundo para NVIDIA Blackwell (sm_120), com um montador e um escalonador comparados byte a byte com o próprio compilador. A verificação que eles nunca lançaram. sm_120 não tem intertravamento de hardware, então uma única contagem de stall errada faz a GPU ler um registrador obsoleto e retornar uma resposta errada silenciosamente.
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


O problema · Quais GPUs · Como funciona · Início rápido · Medido, não presumido · Descobertas · API · Método · Roteiro · Sala limpa


O problema

Uma instrução de GPU NVIDIA tem 128 bits, e 21 deles não são a instrução. São uma palavra de controle de escalonamento, de stall a reuse: quantos ciclos esperar antes de emitir a próxima instrução, quais scoreboards sinalizar, em quais aguardar e quais operandos podem ser servidos pelo cache de reuso.

O hardware não verifica nada disso. No sm_120 não há intertravamento em instruções de latência fixa. O silício confia em quem quer que tenha produzido a palavra de controle. Se uma contagem de stall for menor que a latência de um valor consumido pela próxima instrução, nada falha, nada trava e nenhum aviso é emitido. A instrução lê um registrador que ainda não foi escrito e calcula sobre dados obsoletos, em velocidade máxima, todas as vezes.

Esse é um tipo estranho de bug. Ele não derruba o programa. Não aparece em um depurador. Produz números apenas errados, o que em uma multiplicação de matrizes ou em um kernel de atenção significa um modelo que treina levemente mal, em vez de um que quebra visivelmente.

Ciclos por instrução para cada codificação de stall no sm_120: um stall de 0 custa 36,85 ciclos e é correto; 1, 2 e 3 custam 4,88, 4,88 e 5,88 e retornam silenciosamente a resposta errada; e 4, 8 e 15 custam 6,88, 10,88 e 18,02 e são corretos.

As três codificações mais baratas são as quebradas, e nada em lugar nenhum reporta isso. Note também o que a barra à esquerda está fazendo: um stall de zero não é zero ciclos, é uma codificação segura distinta que aguarda resultados pendentes e custa cerca de nove vezes uma instrução escalonada. Um verificador que lesse isso como zero chamaria programas corretos de quebrados.

Ferramentas que geram código de máquina para esta arquitetura atribuem esses bits de controle a partir de um modelo de latência. basalt é a coisa que verifica a resposta.

A verificação que a NVIDIA nunca lançou

A NVIDIA dá a você um compilador que escreve esses 21 bits. Ela não dá nada que os leia de volta e diga que são seguros, e ninguém mais dá.

Montadores para GPUs NVIDIA existem há uma década, a codificação Blackwell foi engenharia reversa antes, existem caracterizações publicadas em nível de ciclo do sm_120, e um montador público para esta arquitetura já atribui os bits de controle de escalonamento ele mesmo e executa seus próprios kernels em uma placa para ver se as respostas saem certas. Tudo verdade, e nada disso é a afirmação:

Nada mais pode receber um cubin que não produziu e ser instruído a dizer se seus bits de controle de escalonamento são seguros.

Seu compilador emitiu aquele cubin, ou uma biblioteca o enviou, ou alguém o escreveu à mão, e até agora não havia como perguntar. Em uma arquitetura sem intertravamento de hardware, essa é a diferença entre "rodou" e "está correto", e a diferença é invisível: um stall um ciclo curto lê um registrador obsoleto e retorna um número errado em velocidade máxima, sem falha e sem aviso, todas as vezes.

Todo o resto aqui existe para tornar essa frase testável. O montador é o que constrói um programa com um stall deliberadamente encurtado. O escalonador é o que força o modelo a se comprometer com uma resposta em vez de avaliar a de outra pessoa. E a auditoria é onde a frase deixa de ser uma ausência e se torna uma medição: basalt apontado para 2.473 cubins sm_120 que a NVIDIA distribui no cuBLAS, cuSOLVER, cuSPARSE, NPP e demais.

Por que não existia, nas próprias palavras do campo. O montador de SASS mais usado diz em sua própria documentação que "verificar o rigor da correção do programa inteiro … [está] longe de ser possível sem suporte oficial. Então, fica para o usuário garantir a correção do programa, com ajuda muito limitada do montador." SIP, sobre autotuning de escalonamentos SASS, afirma que "a validação é impossível para código assembly nativo de GPU porque a semântica formal do sass é fechada."

Ambos tratam da correção semântica: se um kernel calcula o que deveria. basalt não responde isso, e nada aqui afirma responder. Ele responde a uma pergunta estritamente menor, e o ponto é que a pergunta menor é decidível sem a semântica:

Os bits de controle deste programa cobrem suas próprias dependências de dados?

Isso exige a estrutura de dependências, que a codificação entrega, e um modelo de latência, que o silício entrega sob medição. Nenhum dos dois exige saber o que qualquer instrução calcula. Um kernel pode passar nesta verificação e ainda ser o algoritmo errado; o que não pode fazer é ler um registrador antes de o valor chegar.

Segundo, nada mais é medido contra os próprios bytes do fornecedor. A referência do basalt é a saída do ptxas, então uma discordância é bug do basalt até que se prove o contrário. Seu montador tem de reproduzir os 128 bits exatos do compilador. Seu escalonador tem de descartar cada bit de controle que o compilador escolheu, calcular novos e fazer a GPU calcular a mesma resposta.

Um padrão para tudo isso: concordar exatamente com o fornecedor, ou dizer por quê.

ComponenteO que fazComo é verificadoResultado
MontadorTexto SASS para a palavra de 128 bitsRemontar cada instrução emitida pelo ptxas e comparar bytes, no corpus e em 5,2 M de instruções de código de biblioteca distribuído que ele nunca tinha visto59.693 de 59.760 instruções do corpus e 4.585.336 de 5.237.448 distribuídas exatas, o restante recusado pelo nome, 0 erradas em ambos
VerificadorLê um escalonamento, reporta riscosA saída do próprio fornecedor precisa ser validada limpa, e um stall deliberadamente encurtado precisa ser capturado0 erros em 1.323 pares de kernel e nível de otimização do fornecedor, 0 perdidos em 233 quebrados
AuditoriaO mesmo verificador, em bibliotecas distribuídasExecutá-lo sobre kernels sm_120 de produção retidos de todas as tabelas que ele lê0 erros em 2.762 kernels e 10.218.030 dependências, todos os 2.762 totalmente analisados
EscalonadorAtribui cada bit de controle do zeroDescartar os do fornecedor, calcular novos, executar ambos na GPU contra oito entradas, comparar bytes de saída439 de 439 kernels comparáveis byte-idênticos, nos três níveis de otimização

E a parte sobre a qual um escalonador costuma ficar calado: o que a correção custa. Os escalonamentos do basalt gastam 1,05x os ciclos de emissão do fornecedor, mais lentos em 111 dos 1.323 pares de kernel e nível de otimização e mais baratos em 842, com todo kernel comparável ainda byte-idêntico na GPU.

Três execuções de auditoria contra bibliotecas sm_120 distribuídas pela NVIDIA: 6.593 erros em 250 kernels, depois 940 após ampliar para 2.762 kernels e 10.218.030 dependências, e então 0 após treze correções. Todo erro era do próprio basalt.

A terceira linha é a que mudou as outras três. Um verificador calibrado em um corpus não pode falhar nesse corpus: a folga mais apertada que o compilador foi visto deixar é o piso, por construção, exatamente para o código em que foi medido. Na primeira vez em que este viu código de outro lugar, reportou vinte e seis riscos por kernel em um decodificador JPEG que nunca retornou um pixel errado, e todos os 6.593 eram do basalt. Corrigi-los levou a zero, e zero sobre uma biblioteca também não era evidência: ampliar o conjunto retido para três bibliotecas e 5,2 milhões de instruções levou direto de volta a 940 e encontrou mais cinco erros de modelo, além dos primeiros oito. Treze correções, nenhuma da NVIDIA, e o requisito re-minerado de 24.311 kernels distribuídos colocou um predicado de guarda em 13 ciclos em 229.567 observações, que é o número que a injeção de falhas havia medido nesta placa ao quebrar um programa de propósito. Veja descoberta 32.

Ser mais barato que o fornecedor não é motivo para se vangloriar. o basalt escalona toda dependência na folga mais apertada que ptxas foi visto deixar para exatamente aquele par, e ptxas está equilibrando pressão de registradores e memória junto com latência de emissão enquanto isto otimiza um número. Também não foi acreditado à primeira vista: na primeira vez em que a razão ficou abaixo de 1,0, o round trip de hardware quebrou, e o número só se sustentou depois que o bug que expôs foi corrigido. A razão é fixada dos dois lados na suíte de testes por esse motivo.

A coluna do meio é o ponto. Um verificador e um escalonador que compartilham um modelo de latência concordam entre si enquanto ambos estão errados, então nenhum é evidência para o outro; apenas o silício não tem interesse na discussão. Executar o escalonador sobre sete kernels escritos à mão passou sete de sete por muito tempo. Executá-lo sobre trezentos encontrou quarenta e um errados, e toda correção em descobertas saiu de observar esse número se mover.

O mesmo se aplica às entradas. Uma leitura obsoleta só muda a resposta quando o valor obsoleto e o novo diferem, então um padrão de bytes é uma chance de notar, e executar cada kernel contra um segundo, terceiro e quarto padrões encontrou imediatamente um predicado de carry-out que o modelo de operandos vinha lendo como fonte desde o início. Ele tinha sobrevivido a todos os controles até aquele ponto, incluindo o próprio round trip.

A mesma disciplina decide o que o montador tem permissão de fazer, e vale separar os dois números que ele tem.

O montador do basalt reproduz 59.693 de 59.760 instruções do corpus e 4.585.336 de 5.237.448 instruções de biblioteca distribuída exatamente, recusando o restante pelo nome, e montou zero de todas as 5.297.208 para os bytes errados.

A cobertura é de 99,9% do corpus e 87,5% do código de biblioteca distribuído. A correção é de 100%, e é esse o número fixado por um teste. A lacuna entre eles é instruções que o basalt recusa, cada uma nomeando o campo que não conseguiu posicionar, porque uma ferramenta que adivinhasse alcançaria cobertura total emitindo palavras que desmontam para o texto certo e calculam outra coisa. Ele nunca emitiu uma, em 59.760 instruções do corpus e 5.237.448 distribuídas.

Ele só chegou lá após oito rodadas separadas de estar confiantemente incorreto:

  • escrever um número de registrador na codificação de uma forma imediata,
  • tratar um registrador uniforme como intercambiável com um comum,
  • manter o alvo de desvio de qualquer kernel de onde a forma foi colhida,
  • colocar o inteiro 15 em um campo que guarda um float de meia precisão,
  • escrever um operando em bits que acabaram sendo um sinalizador de reuso,
  • escrever em um campo que a sonda havia atribuído apenas parcialmente, deixando o resto ainda codificando o valor antigo,
  • espalhar um número de registrador pelo bit que seleciona em qual arquivo de registradores ele está,
  • e ler o índice de uma carga constante indexada por registrador como um deslocamento.

Cada um deles produziu uma palavra que monta, desmonta de volta exatamente para o texto de onde veio e calcula outra coisa. Essa é a mesma falha que o resto deste repositório existe para capturar, e é por isso que todos os oito agora são recusados com uma razão nomeando o que o campo realmente guarda, e por que a contagem de instruções que montam para os bytes errados é um teste fixado em zero, em vez de um número em uma tabela.

Uma nona apareceu na primeira vez em que o montador foi apontado para código de máquina que ele não havia produzido, e era de um tipo diferente. c[0x0][UR4] indexa seu deslocamento por um registrador onde a forma registrada guarda um número, e o codificador levantou uma exceção em vez de recusar. Uma falha em entrada estranha é pior do que um veredito errado, porque quem chama não recebe nenhum dos dois.

Quais GPUs

NVIDIA Blackwell GeForce RTX 50 series Compute capability 12.0

sm_120 não é um número de modelo. É a capacidade de computação compartilhada por toda a linha Blackwell de consumo, então a codificação de instruções, o banco de dados, o montador e o verificador se aplicam a todas as placas dela:

PlacaCapacidade de computaçãoCoberta
GeForce RTX 5090, 5090D12.0 (sm_120)sim
GeForce RTX 5080, 5070 Ti, 507012.0 (sm_120)sim
GeForce RTX 5060 Ti, 5060, 505012.0 (sm_120)sim
Modelos laptop da série GeForce RTX 5012.0 (sm_120)sim
Placas de estação RTX PRO Blackwell12.0 (sm_120)sim
Blackwell de datacenter (B100, B200, GB200)10.0 (sm_100)não, codificação diferente

ptxas também tem como alvo sm_121, um chip diferente da mesma família. o basalt nunca rodou em um e não afirma suportá-lo. O que pode dizer é medido: o compilador emite código byte-idêntico, palavras de controle incluídas, para todos os seis alvos que oferece aqui, então o escalonamento de que um kernel precisa é uma propriedade da arquitetura, em vez da peça (descoberta 28). Se isso não fosse verdade, o próprio compilador da NVIDIA estaria emitindo um escalonamento inseguro para um deles.

Todo número medido em silício vem de uma placa física, nomeada exatamente, porque "uma 5070 Ti" não é suficiente para reproduzir uma execução:

A placaO que é exatamente
PlacaGigabyte GeForce RTX 5070 Ti EAGLE OC
Reportada pelo driverNVIDIA GeForce RTX 5070 Ti
Capacidade de computação12.0
Multiprocessadores de streaming70
Clock de boost2542 MHz
ToolchainCUDA 13.3.1, ptxas V13.3.73
O que precisa de GPU, e o que não precisa

A maior parte do basalt não precisa de GPU alguma. Ambos os oráculos, o banco de dados de instruções, o montador e o verificador de riscos funcionam contra ptxas e nvdisasm como subprocessos comuns, e é por isso que rodam em CI em uma máquina sem placa gráfica. 237 dos 252 testes estão nesse grupo, e 200 não precisam nem de placa nem dos binários da NVIDIA.

Uma GPU é necessária para exatamente três coisas, e são as três que transformam uma ferramenta plausível em uma crível:

Precisa de placaPor quê
measure, probe-stallsMedir o tempo de uma instrução e descobrir o que uma dependência realmente exige quebrando-a
scripts/roundtrip_corpus.pyRe-escalonar cada kernel do corpus e executar ambas as versões para comparar bytes de saída
scripts/agreement_sweep.pyEncurtar uma dependência por kernel e perguntar ao silício se o basalt estava certo

O overclock de fábrica não move as medições. Toda latência aqui está em ciclos, que é uma propriedade do pipeline, em vez do clock, e o valor de boost é registrado ao lado delas apenas para que uma comparação de tempo de parede continue possível. O que a placa afeta é a reprodutibilidade, e é por isso que basalt measure --board a registra.

Por que uma placa é uma ressalva, e não uma nota de rodapé

Tudo medido aqui foi medido em uma placa, e o basalt registra o SKU junto com cada medição, em vez de apresentá-las como universais. Uma 5090 tem mais que o dobro de SMs e seu próprio comportamento de clock; a codificação será idêntica e as latências devem ser remedidas em vez de presumidas:```bash python -m basalt.cli measure -o my-card.json python -m basalt.cli verify kernel.cubin --latencies my-card.json

root@kitploit:~
Isso não é modéstia. Um modelo de latência compartilhado entre um verificador e um agendador é exatamente
onde um número errado se esconde, então um segundo cartão é a coisa mais útil que alguém pode contribuir.

</details>

## Como funciona

Tudo depende de dois oráculos, ambos binários NVIDIA padrão executados como processos externos. Nenhum código-fonte, cabeçalho ou biblioteca da NVIDIA é usado ou redistribuído.

| Oráculo | Invocação | O que fornece |
| :--- | :--- | :--- |
| **Verdade de base** | `ptxas` → cubin → `nvdisasm -c -hex` | Codificações que o compilador do fabricante realmente emite. Semântica indiscutível. |
| **Sonda** | `nvdisasm -b SM120a` sobre bytes brutos | Decodifica palavras que o `ptxas` nunca emitirá, o que transforma o espaço de codificação em algo pesquisável em vez de algo para adivinhar. |

O oráculo de sondagem é o que importa. Uma ferramenta limitada à saída do compilador só pode redescobrir o que o compilador já faz. Alimentar palavras sintetizadas de 128 bits diretamente no decodificador significa que o conjunto de instruções pode ser *medido*.

Nenhum dos oráculos precisa de GPU, portanto todo o banco de dados de instruções é reconstruído no CI em qualquer máquina.

### Derivando a codificação ao alterá-la

O basalt não lê uma tabela de opcodes de lugar nenhum. Ele pega uma codificação que foi montada, inverte um bit, decodifica o resultado e registra o que mudou. Um bit que altera o registrador de destino é um bit de destino; um bit que altera o mnemônico é um seletor; um bit que não altera nada observável é inerte.

Executado contra `IADD R5, R5, 0x2a`, a medição resulta em:```
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

Campos de registradores de oito bits e um imediato de 32 bits, obtidos por experimentação em vez de suposição.

A palavra de controle

Uma instrução sm_120 tem 128 bits, dos quais os bits 105 a 125 são a palavra de controle de agendamento: stall em 108:105, yield em 109, write_barrier em 112:110, read_barrier em 115:113, wait_mask em 121:116 e reuse em 125:122.

O layout se valida por si só no contato. Em um kernel trivial, S2R define write_barrier=0 e o IMAD que consome seu resultado carrega wait_mask=0x01; LDCU.64 define write_barrier=1 e o STG.E dependente carrega wait_mask=0x02. Cada par produtor-consumidor se alinha, e as instruções que o nvdisasm anota com .reuse têm o bit de reutilização correspondente definido.

Início rápido

Sem instalação do CUDA e sem GPU. O script da toolchain busca redistribuíveis fixados, aproximadamente 45 MB, sem direitos de administrador, sem nada adicionado ao seu 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 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 como pacote

pip install basalt-sass instala a CLI, a biblioteca e as três tabelas medidas, sem dependências de tempo de execução. Use isto se você já tiver CUDA na máquina; o checkout acima é o que você quer se não tiver, ou se pretende reproduzir as medições.```bash pip install basalt-sass basalt doctor basalt verify kernel.cubin

root@kitploit:~
### Onde procura por `ptxas` e `nvdisasm`

O basalt executa ambos como processos externos e não redistribui nenhum deles, então precisa encontrar uma cópia.
Ele usa o primeiro que responder, e **qualquer instalação do CUDA 13 serve**: nada precisa ser o
redistribuível fixado.

| Ordem | Onde |
| ---: | :--- |
| 1 | `--cuda-bin`, passado na linha de comando |
| 2 | `BASALT_CUDA_BIN`, um diretório contendo ambos os binários |
| 3 | `CUDA_PATH`, `CUDA_HOME` ou `CUDA_ROOT`, cada um mais `/bin` |
| 4 | `ptxas` no seu `PATH` |
| 5 | `third_party/cuda/<version>/bin` em um checkout, do mais recente para o mais antigo |

`basalt doctor` mostra qual foi resolvido e sai com código não zero quando não consegue encontrar um; assim,
funciona como pré-condição de etapa de build, e não apenas como algo para ler.

Consultar o banco de dados de instruções não precisa de nenhuma toolchain, porque o banco de dados é medido
antecipadamente e vem incluso no pacote:```bash
basalt isa --stats
basalt isa --opcode QMMA

Reconstrua o banco de dados de instruções do zero ou consulte o que foi commitado:```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:~
### Verifique o código de máquina que você não escreveu

Esta é a parte que nada mais faz, e não precisa de GPU nem de argumentos. O modelo
de latência medido e a tabela de requisitos minerada estão ambos commitados, então um clone novo pode ser
apontado diretamente para um cubin, não importa o que o tenha produzido:```bash
python -m basalt.cli verify kernel.cubin

I'm ready to translate the chunk, but the input content appears to be missing—the message ends with "INPUT:" and no actual Markdown content follows.

Since I must not fabricate content or ask questions, and there is no text to translate, I will output nothing. Please provide the chunk text and I'll translate it immediately.```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:~
Uma biblioteca ELF contém centenas de kernels e cada um é verificado individualmente, porque os offsets recomeçam em zero e nada passa de um para o próximo. Adicione `--strict` para sair com código de status não zero em caso de perigo, que é o que uma etapa de build espera. Se você tiver uma placa sm_120 e quiser medir o modelo no seu próprio silício em vez de no que está neste repositório:```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
Todos os comandos e quais precisam de uma placa

Tudo o que a CLI faz é importável, e a superfície da biblioteca com exemplos executáveis está em docs/API.md.

E os dois controles que mantêm o restante confiável. O primeiro precisa de uma placa; o segundo precisa das bibliotecas fornecidas e nenhum hardware:```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:~
O conteúdo de entrada está vazio — não há texto para traduzir neste chunk.```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

Medido, não presumido

Os números aqui são impressos pela ferramenta e regenerados a partir de um checkout limpo. Os comandos acima são a fonte da verdade; estas tabelas são instantâneos.

Banco de dados de instruções. Cada entrada carrega uma codificação que foi realmente montada e a build do compilador que a produziu.

Banco de dados de instruções

A cobertura de tensor é onde vive o hardware de baixa precisão: HMMA e IMMA, QMMA nos tipos FP8, FP6 e FP4, incluindo pares de operandos assimétricos, as formas de fator de escala QMMA.SF e OMMA.SF que carregam um expoente por bloco, IMMA.SP esparso, e as instruções de movimentação de matriz LDSM, STSM e MOVM em todas as formas, incluindo as variantes de transposição.

Latência, em uma RTX 5070 Ti. 70 SMs, todos os ajustes com R² ≥ 0,9998. Medida cronometrando cadeias dependentes e tomando a inclinação, com o comprimento da cadeia lido do SASS compilado em vez de presumido.

Três delas contradizem o modelo presumido com o qual o basalt foi lançado: DADD foi presumido como 48, POPC foi presumido como 4, e cada conversão foi presumida como 6, contra 24 medidos para a ida e volta.

Três latências que o basalt presumiu antes de medi-las contra o que o silício reportou: adição fp64 presumida em 48 e medida em 64, POPC presumida em 4 e medida em 18, e a ida e volta da conversão I2FP + F2I presumida em 12 e medida em 24.

Um modelo de latência presumido não é uma pequena aproximação de um medido, o que é todo o argumento para medir.

E um stall de zero não é zero ciclos. É uma codificação segura distinta que espera por resultados pendentes, custando cerca de 37 ciclos onde uma instrução agendada custa 4. É por isso que ptxas -O0 emite uma palavra de controle totalmente zerada e o código ainda assim computa corretamente, aproximadamente nove vezes mais devagar.

Ele concorda com o compilador do fornecedor em todo kernel do corpus. Todo kernel que o ptxas compila a partir do corpus é verificado contra o seu próprio agendamento, em todo nível de otimização que agenda: 30.421 dependências, zero erros. Essa varredura roda na CI a cada push, e todo erro de modelagem que este projeto cometeu foi capturado por ela em vez de por raciocínio.

Os veredictos correspondem ao silício. Para todo stall codificável em um produtor dependente, a resposta estática do basalt e o que o hardware realmente computa concordam, incluindo o caso do zero. Isso é mantido como um teste, não afirmado aqui. A evidência completa, incluindo três métodos independentes para o stall necessário e as correções feitas ao longo do caminho, está em descobertas.

E quando ele diz que um agendamento é inseguro, o silício concorda. Pegue o próprio agendamento funcional do fornecedor para 233 kernels, encurte uma dependência real em cada um e compare o veredicto do basalt com o que a GPU computa: 79 que ele chamou de quebrados estavam quebrados, e nada que ele chamou de seguro computou uma resposta errada. Esse número começou em 34 não detectados em vez de zero, e descobertas diz qual foi a causa e o que custou corrigi-la em falsos alarmes, porque uma varredura que só relatasse seu número final valeria menos do que uma que relatou o primeiro.

Ele também pode atribuir os bits de controle

O verificador responde se um agendamento é seguro. O agendador responde como seria um agendamento seguro, a partir das mesmas medições: ele descarta todo bit de controle que o ptxas produziu, computa os seus próprios, entrega o resultado de volta ao verificador e então o executa na GPU ao lado da versão do fornecedor do mesmo kernel.

Executado sobre todo o corpus na placa, em todo nível de otimização que produz um agendamento, todos os 439 kernels comparáveis produzem resultados byte-idênticos ao agendamento do fornecedor, a partir de bits de controle que o basalt calculou sozinho. Os 2 que são excluídos leem o clock e o id da grade, então também não concordam consigo mesmos, e descobertas diz isso em vez de incluí-los em uma porcentagem.

Esse controle é a razão pela qual todo o resto é confiável. O verificador e o agendador leem o mesmo modelo de latência, então uma entrada errada nele satisfaz ambos ao mesmo tempo, e eles concordam entre si enquanto ambos estão errados. Apenas o silício não tem nada em jogo nessa discussão. Executar o agendador sobre sete kernels escritos à mão passou sete de sete por muito tempo; executá-lo sobre trezentos encontrou quarenta e um errados, e toda correção de modelo desde então veio de observar esse número se mover.

Esse ciclo é de onde vieram os bugs reais. Stall gasto fora da janela entre um produtor e seu consumidor não conta nada, e gastá-lo ali encerra a busca com um programa que ainda está curto. Um stall fixado na codificação segura estava sendo sobrescrito por uma passagem posterior, substituindo uma garantia por um número pequeno. Operandos fp64 ocupam pares de registradores sem nada no mnemônico que o indique, então metade de toda dependência fp64 era invisível tanto para o verificador quanto para o agendador. Um predicado usado como guarda de uma instrução precisa de treze ciclos, onde o mesmo predicado lido como dado precisa de cinco, porque uma guarda precisa ser resolvida antes mesmo que a instrução seja emitida. E esperar por um scoreboard não resolve uma dependência completamente: o produtor ainda deve um pequeno stall próprio, dois ciclos para adição fp64, e um ciclo a menos é silenciosamente errado. Nenhum desses foi encontrado por raciocínio; cada um foi encontrado executando a saída e obtendo o número errado.

[!NOTE] 1.0, e específico sobre o que isso significa. O que está feito: ambos os oráculos, o banco de dados de instruções com seus campos comprovadamente graváveis, o verificador de hazards sobre um grafo de fluxo de controle real, a latência medida em um SKU por três métodos independentes, um agendador que percorre todo kernel comparável do corpus pelo hardware byte por byte, e uma auditoria de 2.762 kernels distribuídos, mantidos fora de toda tabela que o verificador lê. O que não está: 12 kernels do corpus que não são executáveis por construção e 2 cuja saída do fornecedor não é determinística, todos nomeados nas descobertas; dez opcodes ainda carregam uma latência presumida em vez de medida, nenhum deles jamais um produtor em nenhum dos dois corpos de código; e apenas uma GPU foi medida, o que a descoberta 28 mostra importar menos do que parece. Onde algo é inferido em vez de medido, a ferramenta diz isso em vez de tratá-lo como um fato. Veja o roadmap e o método.

Estrutura do repositório

Onde tudo está


``` 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>

## Posição de clean-room

basalt é um trabalho independente, em clean-room, para interoperabilidade. Não contém código-fonte, cabeçalhos, bibliotecas ou documentação da NVIDIA, e não redistribui nada disso. Ele observa o comportamento de executáveis distribuídos publicamente e o registra, que é a base sobre a qual esse tipo de trabalho se sustenta há mais de uma década.

NVIDIA, CUDA e Blackwell são marcas comerciais da NVIDIA Corporation. Este projeto não é afiliado, endossado ou patrocinado pela NVIDIA.

Licenciado sob [Apache-2.0](https://github.com/sunnypatell/basalt/blob/main/LICENSE). Apache de propósito, em vez de algo restritivo: uma ferramenta de correção que ninguém pode usar como base é uma ferramenta de correção que ninguém executa, e a concessão de patentes importa para um trabalho tão próximo do hardware.

## Contribuindo

A contribuição de maior valor é uma codificação que o basalt erra. Consulte [`CONTRIBUTING.md`](https://github.com/sunnypatell/basalt/blob/main/CONTRIBUTING.md) e o [modelo de lacuna de ISA](https://github.com/sunnypatell/basalt/blob/main/.github/ISSUE_TEMPLATE/isa_gap.yml), que coleta informações suficientes para reproduzir sem a sua máquina.

[`SUPPORT.md`](https://github.com/sunnypatell/basalt/blob/main/SUPPORT.md) indica para onde enviar uma pergunta, [`GOVERNANCE.md`](https://github.com/sunnypatell/basalt/blob/main/GOVERNANCE.md) o que uma alteração precisa cumprir, [`RELEASING.md`](https://github.com/sunnypatell/basalt/blob/main/RELEASING.md) como um lançamento é criado e verificado, e [`SECURITY.md`](https://github.com/sunnypatell/basalt/blob/main/SECURITY.md) como reportar de forma privada.

## Citando o basalt

Se o basalt fundamenta um artigo, uma ferramenta, um modelo ou um relatório de bug, cite-o. O GitHub lê
[`CITATION.cff`](https://github.com/sunnypatell/basalt/blob/main/CITATION.cff) nativamente; portanto, **Citar este repositório** na barra lateral fornece
APA e BibTeX sem transcrição. Esse mesmo arquivo é o que o Zenodo e os gerenciadores de citação
interpretam, e é o registro autoritativo de autoria.

A chave abaixo é a que o GitHub gera, portanto copiar daqui e copiar da barra lateral
produz a mesma entrada, em vez de duas que parecem trabalhos diferentes:```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}
}
Baixar ferramenta
CampoBitsSignificado
stall108:105Ciclos de espera antes de emitir a próxima instrução
yield109Dica de que o escalonador de warps pode alternar warps
write_barrier112:110Scoreboard para sinalizar no write-back (7 = nenhum)
read_barrier115:113Scoreboard para sinalizar na leitura de operando (7 = nenhum)
wait_mask121:116Scoreboards que devem estar limpos antes da emissão
reuse125:122Flags de cache de reutilização de operandos, uma por slot de origem
ComandoO que fazPrecisa de GPU
doctorVerifica ambos os oráculos de ponta a pontanão
build-isaColeta e testa, escreve o banco de dados de instruçõesnão
isaConsulta um formulário, um opcode ou a coberturanão
validate-isaProva que os campos medidos podem ser escritosnão
mine-stallsAprende requisitos por par a partir do que o compilador agendanão
verifyVerifica os bits de controle de um cubin quanto a riscos de dadosnão
scheduleAtribui os bits de controle de um cubin do zero e verifica o resultadonão
assembleCodifica texto SASS, ou um cubin inteiro, e o lê de volta para provarnão
measureCronometra a latência de instruções em silício realsim
probe-stallsEncontra a parada necessária quebrando programas de propósitosim
Contagem
Formas de instrução345
Opcodes distintos90
Formas com mapa completo de operandos339
Formas de tensor-core46
Construído comptxas V13.3.73
InstruçõesCiclos
IMAD IADD3 FFMA FADD FMUL LOP3 SHF4
POPC18
I2FP + F2I juntos24
MUFU44
DADD DFMA64
stallciclos/instruçãoresultado
036,85correto
14,88errado
24,88errado
35,88errado
46,88correto

Cite o DOI do conceito, 10.5281/zenodo.22072811, em vez de um DOI de versão ou desta URL. Ele resolve para o lançamento mais recente, então permanece correto sem nunca precisar ser editado novamente. O CITATION.cff o contém, portanto já está em ambas as formas acima.

Se você reutilizar as tabelas medidas (src/basalt/data/) ou reproduzir uma figura, cite o lançamento de onde elas vieram em vez de main: os números são regenerados por scripts/verify_all.py em um commit específico, e uma tag é o que torna isso reproduzível.

A atribuição é um termo de licença, não uma cortesia. A Apache-2.0 §4 exige que LICENSE e NOTICE acompanhem qualquer redistribuição ou trabalho derivado, e o NOTICE carrega a autoria e a declaração de clean-room. Forks, cópias vendorizadas e wheels reempacotados mantêm ambos os arquivos.

Autor

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