Anatomy of a CUDA Binary NVIDIA's CUDA binary format (cubin) is an ELF64 file with undocumented NVIDIA-specific sections that encode kernel machine code, parameter layout, and metadata. A reverse-engineering analysis reveals the section layout, EIATTR metadata encoding, and constant bank conventions for sm_100 (B200) hardware, based on validation against ptxas output. The findings are critical for developers building custom cubin emitters or understanding CUDA driver requirements. Anatomy of a CUDA Binary When you compile a CUDA kernel, the final artifact is a cubin — a CUDA binary. It is a standard ELF64 file with NVIDIA-specific sections that encode everything the CUDA driver needs to load and launch a kernel: the machine code, the parameter layout, register allocation metadata, and a collection of attributes that have no public documentation. This post walks through the section layout of a cubin, explains the .nv.info metadata format that makes a kernel self-describing, and shows how these pieces connect at the byte level. The material is drawn from building a from-scratch cubin emitter and validating it against ptxas output on B200 silicon. A note on methodology:Everything in this article is based on my analysis of cubins produced by ptxas and validated on real hardware. Nvidia does not publish a specification for the cubin section layout, the .nv.info EIATTR encoding, or the constant bank parameter conventions described here. The structures and semantics are reverse-engineered from compiled binaries. Readers should verify against their own cubins and toolkit versions. The ELF Container A cubin is an ELF64 executable. The header identifies it: 1 2 3 4 5 e ident EI OSABI = 0x41 CUDA ABI, not the older 0x33 e ident EI ABIVERSION = 8 e type = ET EXEC loadable, not relocatable e machine = EM CUDA 0xBE e flags = 0x06006402 for sm 100, 64-bit addressing The e flags field encodes the SM architecture in bits 8–15. For sm 100 B200 , that is 0x64 = 100 decimal. Bit 1 marks 64-bit addressing. Bits 24–26 carry a format version that the driver checks. Older cubins used ELFOSABI CUDA = 0x33 with ABI version 0. The CUDA 13 driver rejects these — cuModuleGetFunction returns CUDA ERROR NOT SUPPORTED . If you are emitting cubins from scratch, the ABI version matters. Section Layout A single-kernel cubin contains roughly twelve sections. We will use a minimal kernel as the running example — an integer add, written in LLVM IR: 1 2 3 4 define i32 @add i32 %a, i32 %b { %c = add i32 %a, %b ret i32 %c } Compiling this with llc -march=sass -filetype=obj produces a relocatable CUDA ELF. After finalization, the cubin contains these sections: | | Section | Type | Purpose | |---|---|---|---| | 0 | null | SHT NULL | ELF convention | | 1 | .text.add | SHT PROGBITS | SASS machine code 128-bit instructions | | 2 | .nv.constant0.add | SHT PROGBITS | Constant bank 0 parameter region | | 3 | .nv.info | SHT LOPROC | Module-level metadata EIATTR stream | | 4 | .nv.info.add | SHT LOPROC | Per-kernel metadata EIATTR stream | | 5 | .note.nv.cuver | SHT NOTE | CUDA version note | | 6 | .note.nv.tkinfo | SHT NOTE | Toolkit release note | | 7 | .nv.compat | 0x70000086 | SM compatibility descriptor | | 8 | .nv.callgraph | 0x70000001 | Intra-module call graph | | 9 | .symtab | SHT SYMTAB | Symbol table | | 10 | .strtab | SHT STRTAB | String table | | 11 | .shstrtab | SHT STRTAB | Section-name string table | The sections fall into four categories: the executable code, the kernel ABI metadata, driver compatibility notes, and the standard ELF bookkeeping. This is the minimal set. A real cubin produced by ptxas for a production kernel is larger — typically ~22 sections, 8 symbols, and 5 program headers. One notable addition is .nv.shared.reserved.0 , a SHT NOBITS section 64 bytes that reserves shared memory space. It comes with two weak symbols .nv.reservedSmem.offset0 and nv reservedSMEM offset 0 alias and its own PT LOAD program header. Other additional sections include .nv.shared.