Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
basalt — 세계 최초의 NVIDIA Blackwell(sm_120)용 해저드 검사기로, 자체 컴파일러와 바이트 단위로 일치하도록 맞춘 어셈블러와 스케줄러를 포함합니다. NVIDIA가 결코 출시하지 않았던 바로 그 검사입니다. | Kitploit
도구/GitHubGitHub/sunnypatell/basalt
Static AnalysisVulnerability AnalysisCode AnalysisReverse EngineeringHardware SecurityBinary Analysis
GitHubsunnypatell/basalt

basalt

세계 최초의 NVIDIA Blackwell(sm_120)용 해저드 검사기로, 자체 컴파일러와 바이트 단위로 일치하도록 맞춘 어셈블러와 스케줄러를 포함합니다. NVIDIA가 결코 출시하지 않았던 바로 그 검사입니다.

저장소 보기
30일 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
웹사이트
공유
basalt: 자체 컴파일러와 바이트 단위로 일치하도록 맞춰진 어셈블러와 스케줄러를 갖춘, NVIDIA Blackwell(sm_120) 최초의 위험 체커. 그들이 결코 출시하지 않은 검사. sm_120에는 하드웨어 인터록이 없으므로, 스톨 카운트가 하나만 틀려도 GPU가 스테일 레지스터를 읽고 조용히 틀린 답을 반환한다.
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


문제 · 지원 GPU · 작동 방식 · 빠른 시작 · 측정된 것, 가정된 것이 아닌 것 · 발견 사항 · API · 방법 · 로드맵 · 클린룸


문제

NVIDIA GPU 명령어는 128비트이며, 그중 21비트는 전혀 명령어가 아니다. 이들은 스케줄링 제어 워드, stall부터 reuse까지다: 다음 명령어를 발행하기 전에 몇 사이클을 기다릴지, 어떤 스코어보드에 신호를 보낼지, 어떤 것을 기다릴지, 그리고 어떤 피연산자가 재사용 캐시에서 제공될 수 있는지.

하드웨어는 그 어떤 것도 검사하지 않는다. sm_120에는 고정 레이턴시 명령어에 대한 인터록이 없다. 실리콘은 제어 워드를 만든 무엇이든 신뢰한다. 스톨 카운트가 다음 명령어가 소비하는 값의 레이턴시보다 짧으면, 아무런 폴트도 발생하지 않고, 스톨도 없으며, 경고도 출력되지 않는다. 명령어는 아직 기록되지 않은 레지스터를 읽고, 매번 전체 속도로 스테일 데이터에 대해 연산한다.

이상한 종류의 버그다. 크래시가 나지 않는다. 디버거에 나타나지 않는다. 단지 틀린 숫자를 만들어낼 뿐이며, 행렬 곱셈이나 어텐션 커널에서는 눈에 띄게 무너지는 모델이 아니라 약간 잘못 학습되는 모델을 의미한다.

sm_120의 각 스톨 인코딩에 대한 명령어당 사이클: 스톨 0은 36.85 사이클이 들고 정확하며, 1, 2, 3은 4.88, 4.88, 5.88 사이클이 들고 조용히 틀린 답을 반환하며, 4, 8, 15는 6.88, 10.88, 18.02 사이클이 들고 정확하다.

가장 저렴한 세 인코딩이 고장난 것들이며, 어디에서도 그것을 보고하지 않는다. 또한 왼쪽 막대가 무엇을 하는지 주목하라: 0 스톨은 0 사이클이 아니라, 미해결 결과를 기다리는 별개의 안전한 인코딩이며 예약된 명령어보다 약 9배의 비용이 든다. 그것을 0으로 읽는 체커는 올바른 프로그램을 고장난 것으로 판정할 것이다.

이 아키텍처용 기계어를 생성하는 도구들은 레이턴시 모델에서 그 제어 비트를 할당한다. basalt는 그 답을 검사하는 도구다.

NVIDIA가 결코 출시하지 않은 검사

NVIDIA는 그 21비트를 작성하는 컴파일러를 제공한다. 그러나 그 비트를 다시 읽어 안전하다고 말해주는 것은 제공하지 않으며, 다른 누구도 제공하지 않는다.

NVIDIA GPU용 어셈블러는 10년 동안 존재해 왔고, Blackwell 인코딩은 이전에 리버스 엔지니어링된 적이 있으며, sm_120에 대한 사이클 수준 특성화가 공개되어 있고, 이 아키텍처용 공개 어셈블러 하나는 이미 스케줄링 제어 비트를 직접 할당하고 카드에서 자체 커널을 실행해 답이 올바르게 나오는지 확인한다. 모두 사실이지만, 그중 어느 것도 다음 주장은 아니다:

다른 어떤 도구도 자신이 생성하지 않은 cubin을 건네받아 그 스케줄링 제어 비트가 안전한지 말하라고 요구받을 수 없다.

당신의 컴파일러가 그 cubin을 생성했거나, 라이브러리가 그것을 배포했거나, 누군가 손으로 작성했을 것이다. 그리고 지금까지 물어볼 방법이 없었다. 하드웨어 인터록이 없는 아키텍처에서 그것이 "실행되었다"와 "정확하다"의 차이이며, 그 차이는 보이지 않는다: 한 사이클 짧은 스톨은 스테일 레지스터를 읽고 매번 전체 속도로, 폴트도 경고도 없이 틀린 숫자를 반환한다.

여기의 다른 모든 것은 그 문장을 테스트 가능하게 만들기 위해 존재한다. 어셈블러는 하나의 스톨을 의도적으로 줄인 프로그램을 만드는 것이다. 스케줄러는 모델이 다른 사람의 답을 평가하는 대신 답을 확정하도록 강제하는 것이다. 그리고 감사는 그 문장이 결여가 아니라 측정이 되는 지점이다: basalt는 NVIDIA가 cuBLAS, cuSOLVER, cuSPARSE, NPP 등에 포함해 배포하는 2,473개의 sm_120 cubin을 대상으로 삼았다.

왜 존재하지 않았는가, 이 분야의 말로. 가장 많이 사용되는 SASS 어셈블러는 자체 문서에서 "공식 지원 없이는 전체 프로그램의 엄격한 정확성을 검사하는 것 … [이] 거의 불가능하다. 따라서 프로그램의 정확성을 보장하는 것은 어셈블러의 매우 제한적인 도움만으로 사용자에게 맡겨진다."라고 말한다. SIP는 SASS 스케줄 자동 튜닝에 관해 "sass의 공식 의미론이 폐쇄 소스이기 때문에 GPU 네이티브 어셈블리 코드의 검증은 불가능하다."라고 말한다.

둘 다 의미론적(semantic) 정확성, 즉 커널이 의도한 대로 계산하는지에 관한 것이다. basalt는 그 질문에 답하지 않으며, 여기의 어떤 것도 그렇게 주장하지 않는다. basalt는 엄밀히 더 작은 질문에 답하며, 핵심은 그 더 작은 질문이 의미론 없이도 결정 가능하다는 것이다:

이 프로그램의 제어 비트가 자기 자신의 데이터 의존성을 모두 커버하는가?

그러려면 인코딩이 제공하는 의존성 구조와, 측정을 통해 실리콘이 내어주는 레이턴시 모델이 필요하다. 어느 쪽도 어떤 명령어가 무엇을 계산하는지 알 필요가 없다. 커널은 이 검사를 통과하면서도 여전히 잘못된 알고리즘일 수 있다. 다만 값이 도착하기 전에 레지스터를 읽는 일은 할 수 없다.

둘째, 다른 어떤 것도 벤더의 자체 바이트와 대조해 측정되지 않는다. basalt의 기준은 ptxas 출력이므로, 불일치는 반증되기 전까지 basalt의 버그다. basalt의 어셈블러는 컴파일러의 정확한 128비트를 재현해야 한다. 스케줄러는 컴파일러가 선택한 모든 제어 비트를 버리고 새 비트를 계산한 다음 GPU가 동일한 답을 계산하게 해야 한다.

그 모든 것에 적용되는 하나의 기준: 벤더와 정확히 일치하거나, 그 이유를 말하라.

구성 요소하는 일검사 방법결과
어셈블러SASS 텍스트를 128비트 워드로 변환코퍼스와 한 번도 본 적 없는 5.2M 명령어의 배포 라이브러리 코드에서 ptxas가 생성한 모든 명령어를 재조립하고 바이트를 비교코퍼스 명령어 59,760개 중 59,693개, 배포 명령어 5,237,448개 중 4,585,336개가 정확히 일치, 나머지는 이름으로 거부, 어느 쪽에서도 오류 0개
체커스케줄을 읽고 위험을 보고벤더의 자체 출력이 깨끗하게 검증되어야 하며 의도적으로 줄인 스톨이 반드시 잡혀야 함1,323개 벤더 커널·최적화 수준 쌍에서 오류 0개, 233개 고장난 것 중 놓친 것 0개
감사동일한 체커를 배포 라이브러리에 실행참조하는 모든 테이블에서 제외된 프로덕션 sm_120 커널에 대해 실행2,762개 커널과 10,218,030개 의존성에서 오류 0개, 2,762개 모두 완전히 분석됨
스케줄러모든 제어 비트를 처음부터 할당벤더의 것을 버리고 새로 계산한 뒤 GPU에서 여덟 입력에 대해 둘 다 실행하고 출력 바이트를 비교세 가지 최적화 수준 모두에서 비교 가능한 439개 중 439개 커널이 바이트 단위로 동일

그리고 스케줄러가 보통 조용히 넘어가는 부분: 정확성의 비용. basalt의 스케줄은 벤더의 발행 사이클의 1.05배를 사용하며, 1,323개의 커널 및 최적화 수준 쌍 중 111개에서 더 느리고 842개에서 더 저렴하며, 모든 비교 가능한 커널은 여전히 GPU에서 바이트 단위로 동일하다.

NVIDIA가 배포한 sm_120 라이브러리에 대한 세 차례 감사 실행: 250개 커널에서 6,593개 오류, 2,762개 커널과 10,218,030개 의존성으로 확장한 후 940개, 열세 번의 수정 후 0개. 모든 오류는 basalt 자신의 것이었다.

세 번째 행이 나머지 세 개를 바꾼 것이다. 코퍼스로 보정된 체커는 그 코퍼스에서는 실패할 수 없다: 컴파일러가 남기는 것이 관찰된 가장 좁은 간격은, 구성상, 측정된 바로 그 코드에 대한 바닥이다. 이 체커가 처음으로 다른 곳의 코드를 본 순간, 잘못된 픽셀을 한 번도 반환한 적 없는 JPEG 디코더에서 커널당 스물여섯 개의 위험을 보고했고, 6,593개 모두 basalt의 것이었다. 그것들을 고치자 0이 되었지만, 하나의 라이브러리에서의 0도 증거가 아니었다: 제외 집합을 세 개의 라이브러리와 520만 개의 명령어로 넓히자 곧바로 940으로 되돌아갔고, 처음 여덟 개에 더해 모델 오류 다섯 개를 더 찾아냈다. 열세 번의 수정, 그중 어느 것도 NVIDIA의 것이 아니었다. 그리고 24,311개의 배포 커널에서 다시 채굴한 요구사항은 229,567개의 관측치에 걸쳐 가드 프레디킷을 13 사이클에 두었는데, 이는 이 카드에서 프로그램을 의도적으로 깨뜨려 폴트 주입이 측정한 숫자다. 발견 32를 참조하라.

벤더보다 저렴하다는 것은 자랑할 만한 주장이 아니다. basalt는 모든 의존성을 해당 정확한 쌍에 대해 ptxas가 지금까지 남긴 것으로 관찰된 가장 좁은 간격으로 스케줄링하며, ptxas는 발행 레이턴시와 함께 레지스터 압박과 메모리를 균형 잡는 반면, 이것은 하나의 숫자만 최적화한다. 그것은 또한 눈으로 보고 곧바로 믿어지지 않았다: 비율이 처음 1.0 아래로 내려갔을 때 하드웨어 라운드 트립이 깨졌고, 그 숫자는 그것이 드러낸 버그가 고쳐진 뒤에야 유지되었다. 그 이유로 테스트 스위트에서는 그 비율이 양쪽에서 고정되어 있다.

중간 열이 핵심이다. 레이턴시 모델을 공유하는 체커와 스케줄러는 둘 다 틀린 상태에서도 서로 동의하므로, 어느 쪽도 상대방에 대한 증거가 될 수 없다. 오직 실리콘만이 그 논쟁에서 이해관계가 없다. 스케줄러를 손으로 작성한 커널 일곱 개에 실행했을 때 오랫동안 일곱 개 중 일곱 개가 통과했다. 그것을 삼백 개에 실행하자 마흔하나 개가 틀린 것으로 드러났고, 발견 사항의 모든 수정은 그 숫자가 움직이는 것을 지켜보는 데서 나왔다.

입력에도 같은 원칙이 적용된다. 스테일 읽기는 스테일 값과 새 값이 다를 때만 답을 바꾸므로, 하나의 바이트 패턴은 발견할 기회 한 번일 뿐이다. 모든 커널을 두 번째, 세 번째, 네 번째 패턴에 대해 실행하자 피연산자 모델이 처음부터 소스로 읽고 있던 캐리-아웃 조건자가 즉시 발견되었다. 그것은 그 시점까지 모든 검증을 통과했으며, 라운드 트립 자체도 포함했다.

동일한 원칙이 어셈블러가 무엇을 할 수 있는지를 결정하며, 어셈블러가 가진 두 숫자를 구분할 가치가 있다.

basalt의 어셈블러는 59,760개의 코퍼스 명령어 중 59,693개와 5,237,448개의 배포 라이브러리 명령어 중 4,585,336개를 정확히 재현하며, 나머지는 이름으로 거부하고, 전체 5,297,208개 중 0개를 잘못된 바이트로 어셈블했다.

커버리지는 코퍼스의 99.9%와 배포 라이브러리 코드의 87.5%다. 정확성은 100%이며, 그것이 테스트로 고정되는 숫자다. 둘 사이의 차이는 basalt가 거부하는 명령어들로, 각각은 배치하지 못한 필드를 이름으로 밝힌다. 추측하는 도구는 올바른 텍스트로 역어셈블되면서 다른 것을 계산하는 워드를 생성함으로써 완전한 커버리지에 도달할 수 있기 때문이다. basalt는 59,760개의 코퍼스 명령어와 5,237,448개의 배포 명령어에 걸쳐 단 하나도 생성한 적이 없다.

그것은 확신에 차서 틀린 여덟 차례의 별도 시행 끝에야 그 지점에 도달했다:

  • 즉치 형식의 인코딩에 레지스터 번호를 쓴 것,
  • 유니폼 레지스터를 일반 레지스터와 상호 교환 가능한 것으로 취급한 것,
  • 해당 형식을 수집해 온 커널의 분기 대상을 유지한 것,
  • 반정밀도 부동소수점을 담는 필드에 정수 15를 넣은 것,
  • 재사용 플래그로 밝혀진 비트에 피연산자를 쓴 것,
  • 프로버가 부분적으로만 귀속시킨 필드에 써서 나머지가 여전히 이전 값을 인코딩하게 한 것,
  • 레지스터 번호를 어느 레지스터 파일에 속하는지 선택하는 비트에 걸쳐 분산시킨 것,
  • 레지스터 인덱스 상수 로드의 인덱스를 변위(displacement)로 읽은 것.

그 각각은 어셈블되고, 원래의 텍스트로 정확히 역어셈블되며, 다른 것을 계산하는 워드를 만들어냈다. 이 저장소의 나머지가 잡아내기 위해 존재하는 바로 그 실패다. 그래서 여덟 가지 모두 이제 필드가 실제로 무엇을 담는지 이름을 밝히는 사유와 함께 거부되며, 잘못된 바이트로 어셈블되는 명령어 수가 테이블의 숫자가 아니라 0으로 고정된 테스트인 이유다.

아홉 번째는 어셈블러가 자신이 생성하지 않은 기계어를 처음 가리켰을 때 나타났으며, 종류가 달랐다. c[0x0][UR4]는 기록된 형식이 숫자를 담는 곳에서 오프셋을 레지스터로 인덱싱하며, 인코더는 거부하는 대신 예외를 발생시켰다. 외부 입력에서의 크래시는 잘못된 판정보다 더 나쁘다. 호출자가 둘 다 얻지 못하기 때문이다.

지원 GPU

NVIDIA Blackwell GeForce RTX 50 series Compute capability 12.0

sm_120은 모델 번호가 아니다. 이것은 컨슈머 Blackwell 제품군 전체가 공유하는 컴퓨트 능력이며, 따라서 명령어 인코딩, 데이터베이스, 어셈블러, 체커는 그 안의 모든 카드에 적용된다:

카드컴퓨트 능력지원 여부
GeForce RTX 5090, 5090D12.0 (sm_120)예
GeForce RTX 5080, 5070 Ti, 507012.0 (sm_120)예
GeForce RTX 5060 Ti, 5060, 505012.0 (sm_120)예
GeForce RTX 50 시리즈 노트북용 모델12.0 (sm_120)예
RTX PRO Blackwell 워크스테이션 카드12.0 (sm_120)예
데이터센터 Blackwell (B100, B200, GB200)10.0 (sm_100)아니요, 다른 인코딩

ptxas는 또한 같은 제품군의 다른 칩인 sm_121을 대상으로 한다. basalt는 그 칩에서 실행된 적이 없으며 지원한다고 주장하지도 않는다. basalt가 말할 수 있는 것은 측정된 것이다: 컴파일러는 여기서 제공하는 여섯 가지 대상 모두에 대해 제어 워드를 포함해 바이트 단위로 동일한 코드를 생성하므로, 커널에 필요한 스케줄은 개별 부품의 속성이 아니라 아키텍처의 속성이다 (발견 28). 그것이 사실이 아니라면, NVIDIA 자신의 컴파일러가 그중 하나에 대해 안전하지 않은 스케줄을 생성하고 있을 것이다.

실리콘에서 측정된 모든 숫자는 단 하나의 물리적 카드에서 나온 것이며, 정확히 이름이 명시된다. "5070 Ti"만으로는 실행을 재현하기에 충분하지 않기 때문이다:

카드정확한 사양
보드Gigabyte GeForce RTX 5070 Ti EAGLE OC
드라이버가 보고한 명칭NVIDIA GeForce RTX 5070 Ti
컴퓨트 능력12.0
스트리밍 멀티프로세서70
부스트 클록2542 MHz
툴체인CUDA 13.3.1, ptxas V13.3.73
GPU가 필요한 것과 그렇지 않은 것

basalt의 대부분은 GPU가 전혀 필요 없다. 두 오라클 모두, 명령어 데이터베이스, 어셈블러, 위험 체커는 일반적인 하위 프로세스로 ptxas와 nvdisasm을 실행하므로, 그래픽 카드가 없는 머신의 CI에서도 실행된다. 252개의 테스트 중 237개가 그 그룹에 속하며, 200개는 카드도 NVIDIA 바이너리도 필요로 하지 않는다.

GPU가 필요한 일은 정확히 세 가지이며, 그 세 가지가 그럴듯한 도구를 믿을 만한 도구로 바꾼다:

카드 필요이유
measure, probe-stalls명령어의 타이밍을 재고, 의존성을 깨뜨려 실제로 무엇을 요구하는지 알아내기
scripts/roundtrip_corpus.py모든 코퍼스 커널을 재스케줄링하고 두 버전을 실행해 출력 바이트를 비교하기
scripts/agreement_sweep.py커널당 하나의 의존성을 줄이고 실리콘에 basalt가 옳았는지 묻기

공장 오버클록은 측정값을 움직이지 않는다. 여기의 모든 레이턴시는 사이클 단위이며, 이는 클록이 아니라 파이프라인의 속성이다. 부스트 수치는 벽시계 시간 비교가 가능하도록 옆에 함께 기록될 뿐이다. 보드가 실제로 영향을 주는 것은 재현성이며, 그래서 basalt measure --board가 이를 기록한다.

왜 카드 한 장이 각주가 아니라 주의사항인가

여기서 측정된 모든 것은 한 장의 카드에서 측정되었으며, basalt는 측정값을 보편적인 것으로 제시하지 않고 모든 측정과 함께 SKU를 기록한다. 5090은 두 배 이상의 SM과 고유한 클록 동작을 가진다. 인코딩은 동일하겠지만 레이턴시는 가정하지 말고 다시 측정해야 한다:```bash python -m basalt.cli measure -o my-card.json python -m basalt.cli verify kernel.cubin --latencies my-card.json

root@kitploit:~
그것은 겸손이 아니다. 체커와 스케줄러가 공유하는 지연 시간 모델은 정확히 잘못된 숫자가 숨어 있는 지점이므로, 누구나 기여할 수 있는 가장 유용한 것은 두 번째 카드다.

</details>

## 작동 방식

모든 것은 두 개의 오라클에 의존하는데, 둘 다 외부 프로세스로 구동되는 순정 NVIDIA 바이너리다. NVIDIA 소스, 헤더, 라이브러리는 사용되거나 재배포되지 않는다.

| 오라클 | 호출 | 제공 내용 |
| :--- | :--- | :--- |
| **참값** | `ptxas` → cubin → `nvdisasm -c -hex` | 공급업체 컴파일러가 실제로 생성하는 인코딩. 논란의 여지가 없는 의미론. |
| **프로브** | `nvdisasm -b SM120a`를 원시 바이트에 대해 실행 | `ptxas`가 결코 생성하지 않을 워드를 디코딩하여, 인코딩 공간을 추측 대상이 아니라 탐색 가능한 대상으로 만든다. |

중요한 것은 프로브 오라클이다. 컴파일러 출력에만 한정된 도구는 컴파일러가 이미 하는 일을 재발견할 수밖에 없다. 합성된 128비트 워드를 디코더에 직접 공급한다는 것은 명령어 세트가 *측정*될 수 있음을 뜻한다.

어느 오라클도 GPU가 필요 없으므로, 전체 명령어 데이터베이스는 어떤 머신에서든 CI에서 다시 빌드된다.

### 인코딩을 변경하여 도출하기

basalt는 어디에서도 opcode 테이블을 읽지 않는다. 어셈블된 인코딩 하나를 가져와 한 비트를 뒤집고, 결과를 디코딩한 다음, 무엇이 바뀌었는지 기록한다. 대상 레지스터를 변경하는 비트는 대상 비트이고, 니모닉을 변경하는 비트는 셀렉터이며, 관찰 가능한 어떤 것도 변경하지 않는 비트는 불활성이다.

`IADD R5, R5, 0x2a`에 대해 실행하면 측정 결과는 다음과 같이 나온다:```
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

8비트 레지스터 필드와 32비트 즉시값은 추측이 아닌 실험을 통해 도출되었습니다.

제어 워드

sm_120 명령어는 128비트이며, 그중 105~125비트가 스케줄링 제어 워드입니다. stall은 108:105, yield는 109, write_barrier는 112:110, read_barrier는 115:113, wait_mask는 121:116, reuse는 125:122입니다.

레이아웃은 실제 명령어와 맞닿는 순간 스스로 검증됩니다. 간단한 커널에서 S2R은 write_barrier=0을 설정하고, 그 결과를 소비하는 IMAD는 wait_mask=0x01을 갖습니다. LDCU.64는 write_barrier=1을 설정하고 의존하는 STG.E는 wait_mask=0x02를 갖습니다. 모든 생산자-소비자 쌍이 정렬되며, nvdisasm이 .reuse로 주석을 다는 명령어에는 일치하는 재사용 비트가 설정되어 있습니다.

빠른 시작

CUDA 설치도 GPU도 필요 없습니다. 툴체인 스크립트가 고정된 재배포 패키지를 내려받습니다. 약 45MB이며, 관리자 권한이 필요 없고 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:~
The input content for chunk 7 is empty. No text was provided after "INPUT:", so there is nothing to translate. Please provide the actual chunk content to proceed.```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.

또는 패키지로 설치

pip install basalt-sass는 CLI, 라이브러리 및 세 가지 측정 테이블을 모두 설치하며, 런타임 종속성이 없습니다. 이미 머신에 CUDA가 있다면 이 방법을 사용하세요. 위의 체크아웃 방식은 CUDA가 없거나 측정 결과를 재현하려는 경우에 적합합니다.```bash pip install basalt-sass basalt doctor basalt verify kernel.cubin

root@kitploit:~
### `ptxas` 및 `nvdisasm`을 찾는 위치

basalt는 둘 다 외부 프로세스로 구동하며 재배포하지 않으므로, 해당 도구의 복사본을 찾아야 합니다.
첫 번째로 응답하는 것을 사용하며, **CUDA 13 설치본이면 무엇이든 됩니다**: 고정된 재배포판일 필요는 없습니다.

| 순서 | 위치 |
| ---: | :--- |
| 1 | `--cuda-bin`, 명령줄에서 전달 |
| 2 | `BASALT_CUDA_BIN`, 두 바이너리를 모두 보관하는 디렉터리 |
| 3 | `CUDA_PATH`, `CUDA_HOME` 또는 `CUDA_ROOT`, 각각에 `/bin` 추가 |
| 4 | `PATH`에 있는 `ptxas` |
| 5 | 체크아웃 내 `third_party/cuda/<version>/bin`, 최신순 |

`basalt doctor`는 어떤 것을 선택했는지 출력하며, 찾지 못하면 0이 아닌 종료 코드로 종료되므로
단순히 읽을 수 있는 도구가 아니라 빌드 단계의 선행 조건으로 작동합니다.

명령어 데이터베이스를 조회하는 데는 도구 체인이 전혀 필요 없습니다. 데이터베이스는 미리 측정되어
패키지 안에 포함되어 있기 때문입니다.```bash
basalt isa --stats
basalt isa --opcode QMMA

명령 데이터베이스를 처음부터 다시 구축하거나 커밋된 데이터베이스를 조회하세요:```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:~
### 작성하지 않은 기계 코드 확인

이 부분은 다른 도구가 하지 못하는 부분이며, GPU나 인수가 필요 없습니다. 측정된
지연 시간 모델과 채굴된 요구 사항 테이블이 모두 커밋되어 있으므로, 새 클론은
그것이 무엇으로 생성되었든 cubin을 직접 가리킬 수 있습니다:```bash
python -m basalt.cli verify kernel.cubin

The input chunk is empty — there is no text provided to translate. Please supply chunk 17 of 29 so I can translate it into Korean.```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:~
라이브러리 ELF에는 수백 개의 커널이 들어 있으며, 오프셋이 0부터 다시 시작하고 한 커널에서 다음 커널로 넘어가는 일이 없기 때문에 각 커널은 개별적으로 검사됩니다. 위험(hazard) 발생 시 0이 아닌 종료 코드로 종료하려면 `--strict`를 추가하세요. 이는 빌드 단계에서 원하는 동작입니다. sm_120 카드가 있고 이 저장소에 있는 실리콘 대신 자신의 실리콘에서 모델을 측정하려면:```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
모든 명령과 카드가 필요한 명령

CLI가 수행하는 모든 것은 임포트 가능하며, 실행 가능한 예제가 포함된 라이브러리 표면은 docs/API.md에 있습니다.

그리고 나머지를 정확하게 유지하는 두 가지 제어 기능이 있습니다. 첫 번째는 카드가 필요하고, 두 번째는 제공된 라이브러리가 필요하며 하드웨어가 전혀 필요 없습니다:```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:~
No content was provided for translation.```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

측정된 것이지 추정된 것이 아니다

여기 있는 숫자는 도구가 출력한 것이며, 깨끗한 체크아웃에서 재생성된다. 위의 명령이 진실의 원천이고, 이 표들은 스냅샷이다.

명령어 데이터베이스. 모든 항목은 실제로 어셈블된 인코딩과 그것을 생성한 컴파일러 빌드를 담고 있다.

명령어 데이터베이스개수
명령어 폼

텐서 커버리지는 저정밀 하드웨어가 존재하는 곳이다: HMMA와 IMMA, FP8, FP6, FP4 유형 전반의 QMMA(비대칭 피연산자 쌍 포함), 블록별 지수를 운반하는 스케일 팩터 폼 QMMA.SF와 OMMA.SF, 희소 IMMA.SP, 그리고 전치 변형을 포함한 모든 형태의 행렬 이동 명령어 LDSM, STSM, MOVM이다.

레이턴시, RTX 5070 Ti 기준. 70 SMs, 모든 핏 R² ≥ 0.9998. 종속 체인의 시간을 측정하고 기울기를 취해 측정했으며, 체인 길이는 추정이 아니라 컴파일된 SASS에서 다시 읽어 왔다.

이 중 세 가지는 basalt가 기본 제공한 추정 모델과 모순된다: DADD는 48로 추정됐고, POPC는 4로 추정됐으며, 각 변환은 왕복에 대해 측정된 24와 대비해 6으로 추정됐다.

basalt가 실리콘이 보고한 값과 비교하기 전에 추정한 세 가지 레이턴시: fp64 add는 48로 추정하고 64로 측정, POPC는 4로 추정하고 18로 측정, I2FP 및 F2I 변환 왕복은 12로 추정하고 24로 측정.

추정된 레이턴시 모델은 측정된 모델의 작은 근사가 아니다. 이것이 측정을 하는 이유의 전부다.

그리고 0의 스톨은 0사이클이 아니다. 그것은 미해결 결과를 기다리는 별개의 안전한 인코딩으로, 스케줄된 명령어가 4사이클인 데 비해 약 37사이클이 든다. 그래서 ptxas -O0은 완전히 0으로 채워진 제어 워드를 생성하고도 코드는 여전히 올바르게 계산하며, 대략 9배 느리다.

코퍼스의 모든 커널에서 벤더 컴파일러와 일치한다. ptxas가 코퍼스에서 빌드하는 모든 커널은 스케줄하는 모든 최적화 수준에서 자체 스케줄링과 대조 검증된다: 30,421개 종속성, 오류 0건. 이 스윕은 모든 푸시에서 CI로 실행되며, 이 프로젝트가 만든 모든 모델링 오류는 추론이 아니라 스윕에 의해 잡혔다.

판정은 실리콘과 일치한다. 종속 프로듀서의 모든 인코딩 가능한 스톨에 대해, basalt의 정적 답과 하드웨어가 실제로 계산하는 결과는 0의 경우를 포함해 일치한다. 이것은 여기서 주장이 아니라 테스트로 유지된다. 필요한 스톨에 대한 세 가지 독립적 방법과 과정에서 수정된 사항을 포함한 전체 증거는 발견 사항에 있다.

그리고 어떤 스케줄이 안전하지 않다고 말할 때, 실리콘도 동의한다. 233개 커널에 대한 벤더 자체의 작동 스케줄을 가져와 각 커널의 실제 종속성 하나를 단축하고 basalt의 판정을 GPU가 계산한 결과와 비교하라: 그것이 깨졌다고 판정한 79개는 실제로 깨졌고, 안전하다고 판정한 것 중 잘못된 답을 계산한 것은 하나도 없었다. 그 숫자는 0이 아니라 34개의 놓침으로 시작했으며, 발견 사항은 원인이 무엇이었고 그것을 고치는 데 오탐이 얼마나 들었는지 말해 준다. 최종 수치만 보고하는 스윕은 첫 수치를 보고하는 스윕보다 가치가 낮기 때문이다.

제어 비트도 할당할 수 있다

검증기(verifier)는 스케줄이 안전한지 답한다. 스케줄러(scheduler)는 동일한 측정에서 안전한 스케줄이 무엇일지 답한다: ptxas가 생성한 모든 제어 비트를 버리고 자신의 것을 계산한 다음 결과를 검증기에 넘기고, 같은 커널의 벤더 버전과 나란히 GPU에서 실행한다.

카드에서 전체 코퍼스에 대해, 스케줄을 생성하는 모든 최적화 수준에서 실행하면, 비교 가능한 439개 커널 전체가 basalt가 스스로 알아낸 제어 비트로 벤더 스케줄과 바이트 단위로 동일한 결과를 계산한다. 제외된 2개는 클록과 그리드 id를 읽으므로 자기 자신과도 일치하지 않으며, 발견 사항은 그것을 백분율에 포함하는 대신 그렇게 명시한다.

그 제어가 나머지가 모두 신뢰할 수 있는 이유다. 검사기와 스케줄러는 동일한 레이턴시 모델을 읽으므로, 모델의 잘못된 항목은 둘을 동시에 만족시키고 둘 다 틀린 상태에서 서로 일치하게 된다. 오직 실리콘만이 논쟁에 이해관계가 없다. 손으로 작성한 7개 커널로 스케줄러를 실행했을 때는 오랫동안 7개 중 7개를 통과했다. 300개로 실행했을 때는 41개의 잘못된 커널을 찾았고, 그 이후의 모든 모델 수정은 그 숫자가 움직이는 것을 관찰해서 나왔다.

그 루프에서 실제 버그들이 나왔다. 프로듀서와 컨슈머 사이의 윈도우 밖에서 보낸 스톨은 아무 효과가 없으며, 거기에 스톨을 쓰면 여전히 부족한 프로그램으로 탐색이 끝난다. 안전한 인코딩에 고정된 스톨 값은 이후 패스에 의해 덮여 쓰였고, 보장이 작은 숫자로 대체됐다. fp64 피연산자는 니모닉에 그 사실을 알려 주는 것이 없는 레지스터 쌍을 차지하므로, 각 fp64 종속성의 절반은 검사기와 스케줄러 둘 다에게 보이지 않았다. 명령어의 가드로 사용되는 프레디킷은 13사이클이 필요한 반면, 데이터로 읽히는 같은 프레디킷은 5사이클이 필요하다. 가드는 명령어가 아예 발행되기 전에 해소되어야 하기 때문이다. 그리고 스코어보드를 기다리는 것은 종속성을 완전히 해소하지 못한다: 프로듀서는 여전히 자신의 작은 스톨을 지불해야 하는데, fp64 add는 2사이클이고, 1사이클이 적으면 조용히 틀리게 된다. 이러한 것 중 어느 것도 추론으로 발견되지 않았다. 모두 출력을 실행하고 잘못된 숫자를 얻어서 발견됐다.

[!NOTE] 1.0, 그리고 그것이 의미하는 바를 구체적으로 명시한다. 완료된 것: 두 오라클, 필드가 쓰기 가능함이 입증된 명령어 데이터베이스, 실제 제어 흐름 그래프에 대한 해저드 검사기, 세 가지 독립적 방법으로 하나의 SKU에서 측정된 레이턴시, 모든 비교 가능한 코퍼스 커널을 하드웨어를 통해 바이트 단위로 왕복시키는 스케줄러, 그리고 검사기가 읽는 모든 테이블에서 보류된 2,762개 출시 커널에 대한 감사. 완료되지 않은 것: 구조상 실행 불가능한 12개 코퍼스 커널과 벤더 출력이 결정적이지 않은 2개(모두 발견 사항에 명명됨), 여전히 측정이 아닌 추정 레이턴시를 지닌 10개 opcode(그중 어느 것도 두 코드 본문에서 프로듀서가 된 적 없음), 그리고 단 하나의 GPU만 측정되었으며, 발견 28은 이것이 듣기보다 중요도가 낮음을 보여 준다. 측정이 아닌 추론으로 얻어진 것이 있으면 도구는 그것을 사실로 둥글려 말하는 대신 그렇게 명시한다. 로드맵과 방법을 참조하라.

저장소 구조

모든 것이 어디에 있는지


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

## 클린룸 입장

basalt는 상호운용성을 위한 독립적인 클린룸 작업입니다. NVIDIA 소스 코드, 헤더, 라이브러리 또는 문서를 포함하지 않으며 어떤 것도 재배포하지 않습니다. 공개적으로 배포된 실행 파일의 동작을 관찰하고 이를 기록하며, 이는 지난 10년 이상 이와 같은 작업이 의존해 온 기반입니다.

NVIDIA, CUDA 및 Blackwell은 NVIDIA Corporation의 상표입니다. 이 프로젝트는 NVIDIA와 제휴, 보증 또는 후원 관계가 아닙니다.

[Apache-2.0](https://github.com/sunnypatell/basalt/blob/main/LICENSE)에 따라 라이선스가 부여됩니다. 의도적으로 제한적인 라이선스 대신 Apache를 선택했습니다. 아무도 기반으로 삼을 수 없는 정확성 도구는 아무도 실행하지 않는 정확성 도구이며, 하드웨어에 이렇게 가까운 작업에는 특허 부여가 중요합니다.

## 기여하기

가장 가치 있는 기여는 basalt가 잘못 처리하는 인코딩입니다. [`CONTRIBUTING.md`](https://github.com/sunnypatell/basalt/blob/main/CONTRIBUTING.md)와 [ISA 격차 템플릿](https://github.com/sunnypatell/basalt/blob/main/.github/ISSUE_TEMPLATE/isa_gap.yml)을 참조하세요. 이 템플릿은 여러분의 머신 없이도 재현할 수 있는 충분한 정보를 수집합니다.

[`SUPPORT.md`](https://github.com/sunnypatell/basalt/blob/main/SUPPORT.md)는 질문을 어디에 올려야 하는지를, [`GOVERNANCE.md`](https://github.com/sunnypatell/basalt/blob/main/GOVERNANCE.md)는 변경 사항이 통과해야 하는 절차를, [`RELEASING.md`](https://github.com/sunnypatell/basalt/blob/main/RELEASING.md)는 릴리스가 어떻게 만들어지고 검증되는지를, [`SECURITY.md`](https://github.com/sunnypatell/basalt/blob/main/SECURITY.md)는 비공개로 보고하는 방법을 설명합니다.

## basalt 인용하기

basalt를 논문, 도구, 모델 또는 버그 보고서에 활용한다면 인용해 주세요. GitHub는
[`CITATION.cff`](https://github.com/sunnypatell/basalt/blob/main/CITATION.cff)를 기본적으로 읽으므로, 사이드바의 **이 저장소 인용**을 누르면
수동 입력 없이 APA와 BibTeX를 얻을 수 있습니다. 같은 파일은 Zenodo와 인용 관리자들이
파싱하는 대상이며, 저자 정보의 공식 기록입니다.

아래 키는 GitHub가 생성한 것이므로, 여기에서 복사하든 사이드바에서 복사하든
서로 다른 작업처럼 보이는 두 항목이 아닌 동일한 항목이 생성됩니다:```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}
}
도구 다운로드
필드비트의미
stall108:105다음 명령어를 발행하기 전에 대기할 사이클
yield109워프 스케줄러가 워프를 전환할 수 있음을 나타내는 힌트
write_barrier112:110쓰기 완료 시 신호를 보낼 스코어보드 (7 = 없음)
read_barrier115:113피연산자 읽기 시 신호를 보낼 스코어보드 (7 = 없음)
wait_mask121:116발행 전에 비어 있어야 하는 스코어보드
reuse125:122소스 슬롯마다 하나씩 있는 피연산자 재사용 캐시 플래그
명령기능GPU 필요
doctor두 오라클을 종단 간 확인아니요
build-isa수집 및 프로빙, 명령어 데이터베이스 작성아니요
isa폼, opcode 또는 커버리지 조회아니요
validate-isa측정된 필드가 통과하여 기록될 수 있음을 입증아니요
mine-stalls컴파일러가 스케줄링하는 것으로부터 쌍별 요구 사항 학습아니요
verifycubin의 제어 비트에서 데이터 위험 확인아니요
schedulecubin의 제어 비트를 처음부터 할당하고 결과 확인아니요
assembleSASS 텍스트 또는 전체 cubin을 인코딩하고 다시 읽어 증명아니요
measure실제 실리콘에서 명령어 지연 시간 측정예
probe-stalls프로그램을 의도적으로 깨뜨려 필요한 스톨 찾기예
345
고유 opcode90
전체 피연산자 맵을 갖는 폼339
텐서 코어 폼46
빌드에 사용된ptxas V13.3.73
명령어사이클
IMAD IADD3 FFMA FADD FMUL LOP3 SHF4
POPC18
I2FP + F2I 함께24
MUFU44
DADD DFMA64
stall명령어당 사이클결과
036.85정확함
14.88틀림
24.88틀림
35.88틀림
46.88정확함

Cite the concept DOI, 10.5281/zenodo.22072811, rather than a version DOI or this URL. It resolves to the newest release, so it stays correct without ever being edited again. CITATION.cff carries it, so it is already in both forms above.

If you reuse the measured tables (src/basalt/data/) or reproduce a figure, cite the release they came from rather than main: the numbers are regenerated by scripts/verify_all.py at a specific commit, and a tag is what makes that reproducible.

Attribution is a licence term, not a courtesy. Apache-2.0 §4 requires that LICENSE and NOTICE travel with any redistribution or derivative work, and NOTICE carries the authorship and the clean-room statement. Forks, vendored copies and repackaged wheels all keep both files.

Author

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