LLVM-OFFLOAD-BINARY(1)
๐ llvm-offload-binary โ the LLVM Offload Binary Packager
okay so bestie, welcome to llvm-offload-binary(1), aka the LLVM Offload Binary Packager ๐ โ it's a whole little tool and honestly it's giving main character energy for people who bundle device code. let's get into it โจ
๐ NAME
llvm-offload-binary โ LLVM Offload Binary Packager. that's the whole name, icon of brevity ๐ซถ
๐ธ SYNOPSIS
llvm-offload-binary [options] [input files...]
literally that's it. options, then input files, no cap ๐
๐ DESCRIPTION
so llvm-offload-binary is a utility for bundling multiple device object files into a single binary container ๐. and then?? the resulting binary can be embedded into the host section table to form a fat binary containing offloading code for different targets. it's giving "one bag, many outfits" ๐
. and conversely โ yes we love a conversely โ it can also extract previously bundled device images from offload binaries. it does both. versatility ate ๐ฅ
when extracting images: if you don't specify any --image filters, all offload images are automatically extracted, each with descriptive filenames โจ. but the second you do provide --image filters, only the matching images get extracted. picky on purpose, as she should ๐
the tool also supports the nested OffloadBinary format โ meaning device images can be wrapped in an inner OffloadBinary container ๐ช. when extracting, the tool automatically detects and unwraps nested OffloadBinary images, making the format transparent to users. so you never have to think about it. she handles it. periodt ๐
and the binary format itself? it begins with the magic bytes 0x10FF10AD, followed by a version and size ๐ฎ. each binary contains its own header, which lets tools locate offloading sections even when they get merged by a linker โ iconic resilience honestly. each offload entry includes metadata such as the device image kind, producer kind, and key-value string metadata ๐ง. and multiple offloading images are concatenated to form a fat binary. stacking them like a charm bracelet ๐
๐ EXAMPLE
okay this part is so satisfying, watch:
# Package multiple device images into a fat binary:
$ llvm-offload-binary -o out.bin \
--image=file=input.o,triple=nvptx64,arch=sm_70
# Extract all offload images from an executable (no filters):
$ llvm-offload-binary in.bin
# Output:
# Extracted: in-nvptx64-nvidia-cuda-sm_70.0.bc
# Extracted: in-spirv64-intel-unknown.0.spv
# Extract only SPIR-V images using filters:
$ llvm-offload-binary in.bin --image=triple=spirv64-intel
# Output:
# Extracted: in-spirv64-intel-unknown.0.spv
# Extract filtered images to a specific file:
$ llvm-offload-binary in.bin --image=file=output.bc,arch=sm_70
# Extract filtered images to an archive:
$ llvm-offload-binary in.bin --image=file=output.a,triple=nvptx64 --archive
see how the last three are literally the same command with different filters? the range ๐ญ๐
โจ OPTIONS โจ
--archiveโ when extracting from an input binary, write all extracted images into a static archive instead of separate files ๐. one tidy little bag instead of a pile of loose files.--image=<<key>=<value>,...>โ specify a set of arbitrary key-value arguments describing an image ๐ธ. commonly used optional keys includearch(e.g.sm_70for CUDA) andtriple(e.g.nvptx64-nvidia-cuda).
when bundling, this option specifies images to include in the output binary ๐ซถ. when extracting, this option acts as a filter โ only images matching the specified keys are extracted. and if no --image options are provided during extraction, all images are automatically extracted with descriptive filenames โจ.
when extracting from a static archive, the member key restricts the output to a single archive member, for cases when --archive is insufficient ๐
, e.g. --image=member=foo.o,triple=nvptx64,arch=sm_70,file=out.o.
-o <file>โ write output to<file>๐. when bundling, this specifies the fat binary filename. when extracting, this specifies the archive or output file destination. one flag, two jobs, employed and thriving ๐--help,-hโ display available options ๐. use--help-hiddento show hidden options ๐ (yes there are secret ones, iykyk).--help-listโ display a list of all options ๐. use--help-list-hiddento show hidden ones ๐.--versionโ display the version of thellvm-offload-binaryexecutable โญ.@<FILE>โ read command-line options from response file<FILE>๐ฆ. put your options in a file like the organized fairy you are.
๐ฎ BINARY FORMAT
the binary format is marked by the magic bytes 0x10FF10AD, followed by a version number ๐ฅ. each created binary contains its own header, and that's what allows tools to locate offloading sections even after linker operations such as relocatable linking ๐ (linkers are chaotic, the header keeps its head). conceptually, this binary format is a serialization of a string map and an image buffer. that's the whole vibe check ๐ง
๐ OFFLOADING BINARY HEADER
okay so the original had this whole gorgeous little grid and i'm gonna give it to you field by field because every single one matters, no skipping ๐:
uint8_tโmagicโ the magic bytes for the binary format (0x10FF10AD) ๐ฎuint32_tโversionโ version of this format (currently version 1) ๐uint64_tโsizeโ size of this binary in bytes ๐uint64_tโentry offsetโ absolute offset of the offload entries in bytes ๐uint64_tโentry sizeโ size of the offload entries in bytes ๐
and each offload entry describes a bundled image along with its associated metadata ๐ธ โ like a little name tag for every image in the bag ๐ซถ
(and that's where part 1 wraps... but we're not done, bestie โ more coming ๐ )
๐ OFFLOADING ENTRY TABLE ๐
Okay bestie, this is the glow-up table that tells you what each entry is serving ๐ . Every entry has a type, an identifier, and a description โ and yes, the way that every byte is accounted for is lowkey iconic โจ.
uint16_tโ image kind โ the kind of the device image (e.g.bc,cubin) ๐ซถuint16_tโ offload kind โ the producer of the image (e.g.openmp,cuda) ๐ธuint32_tโ flags โ generic flags for the image ๐uint64_tโ string offset โ absolute offset of the string metadata table ๐uint64_tโ num strings โ number of string entries in the table โจuint64_tโ image offset โ absolute offset of the device image in bytes ๐ฆuint64_tโ image size โ size of the device image in bytes ๐
The entry table refers to both a string table and the raw device image itself. The string table provides arbitrary key-value metadata. No cap, that's the whole vibe of this little structure ๐.
๐ธ OFFLOADING STRING ENTRY ๐ธ
And here's the string-entry moment, because metadata deserves main character energy too ๐. Each string entry has two fields, both uint64_t:
uint64_tโ key offset โ absolute byte offset of the key in the string table ๐uint64_tโ value offset โ absolute byte offset of the value in the string table ๐ซ
The string table is a collection of null-terminated strings stored in the image. Offsets allow string entries to be interpreted as key-value pairs, enabling flexible metadata such as architecture or target triple. It's giving "little table, big flexibility" fr fr ๐งโจ.
๐ฆ IMAGE KIND ๐ฆ
The enumerated values for image kind and offload kind are:
Here's the IMAGE KIND name / value / description breakdown, bestie ๐:
IMG_Noneโ0x00โ no image information provided ๐IMG_Objectโ0x01โ the image is a generic object file ๐ฆIMG_Bitcodeโ0x02โ the image is an LLVM-IR bitcode file โจIMG_Cubinโ0x03โ the image is a CUDA object file ๐IMG_Fatbinaryโ0x04โ the image is a CUDA fatbinary file ๐ฅIMG_PTXโ0x05โ the image is a CUDA PTX file ๐
๐ซ OFFLOAD KIND
Okay so every offload binary carries a little "who made me" tag called the offload kind, and it's literally just a number. Here's the whole roster, no skips, bestie:
OFK_None=0x00โ no offloading info was provided at all. It's giving blank slate, nothing to see here. ๐ซฅOFK_OpenMP=0x01โ the producer was OpenMP offloading. Team OpenMP, rise. ๐ฅOFK_CUDA=0x02โ the producer was CUDA. Green team represent. ๐OFK_HIP=0x03โ the producer was HIP. AMD girlies stay winning. โค๏ธOFK_SYCL=0x04โ the producer was SYCL. One API, one vibe. ๐
That's the whole list โ if you see a value past 0x04, that's not on the guest list, iykyk. ๐
๐ COMMON WORKFLOWS
These are the six little rituals, in order, exactly as written. Screenshot them, bookmark them, tattoo them, whatever works. โจ
๐ธ Workflow 1: Explore Executable Contents
Extract all embedded offload images to see what's inside:
$ clang++ -fopenmp -fopenmp-targets=nvptx64,spirv64-intel app.cpp -o myapp
$ llvm-offload-binary myapp
# Output:
# Extracted: myapp-nvptx64-nvidia-cuda-sm_70.0.bc
# Extracted: myapp-spirv64-intel-unknown.1.spv
Literally just dump everything out and go "ohhh so that's what was hiding in there." Open the hood, no cap. ๐ต๏ธโโ๏ธ
๐ฆ Workflow 2: Extract Specific Target
Extract only images for a specific target:
$ llvm-offload-binary myapp --image=triple=spirv64-intel
# Output:
# Extracted: myapp-spirv64-intel-unknown.0.spv
Filtering? We love a selective queen. Only the spirv64-intel image gets pulled, everything else stays tucked in. ๐
๐ Workflow 3: Create Device Image Archive
Extract filtered images into a static archive:
$ llvm-offload-binary myapp --image=file=nvptx.a,triple=nvptx64 --archive
$ ar t nvptx.a
# Shows extracted CUDA images
So like โ the --archive flag means instead of loose files everywhere (chaos, we hate her), everything lands in a tidy static archive. Then ar t lists it back at you like a little server handing you your order. ๐ฆ
โญ Workflow 4: Validate SPIR-V
Extract and validate SPIR-V binaries:
$ llvm-offload-binary myapp --image=triple=spirv64-intel
$ spirv-val myapp-spirv64-intel-unknown.0.spv
$ spirv-dis myapp-spirv64-intel-unknown.0.spv -o kernel.spvasm
Validating first, disassembling second โ that's the correct order, bestie, don't @ me. spirv-val does the vibe check, spirv-dis drops the readable kernel.spvasm so you can actually look at it. ๐ฌ
๐ง Workflow 5: Bundle Multiple Targets
Create a fat binary from multiple device images:
$ clang++ -fopenmp -fopenmp-targets=nvptx64 --offload-device-only kernel.cpp -o kernel_nvptx.bc
$ clang++ -fopenmp -fopenmp-targets=spirv64-intel --offload-device-only kernel.cpp -o kernel_spirv.bc
$ llvm-offload-binary -o bundle.bin \
--image=file=kernel_nvptx.bc,triple=nvptx64,arch=sm_70 \
--image=file=kernel_spirv.bc,triple=spirv64-intel
Two separate device-only compiles, then one -o bundle.bin to rule them all. That's a fat binary and honestly? It ate. ๐ฝ๏ธ
๐ Workflow 6: Extract and Rebundle
Extract images from one binary and rebundle with modifications:
$ llvm-offload-binary old_app
$ llvm-offload-binary -o new_bundle.bin \
--image=file=old_app-nvptx64-nvidia-cuda-sm_70.0.bc,triple=nvptx64,arch=sm_70 \
--image=file=new_kernel.bc,triple=nvptx64,arch=sm_80
Out with the sm_70, in with the sm_80 โ glow-up achieved, main character energy confirmed. ๐
๐ SEE ALSO
clang(1)llvm-objdump(1)spirv-val(1)spirv-dis(1)
Go read those if you're nosy (affectionate). ๐ซถ
โ๏ธ AUTHOR
Maintained by the LLVM Team (https://llvm.org/). Shoutout to the maintainers, they're carrying the whole ecosystem on their backs fr fr. ๐ญ๐
ยฉ๏ธ COPYRIGHT
2003-2026, LLVM Project
Okay that's the whole page, bestie โ go forth and offload responsibly. ๐ โจ
Peace out from page 23 of LLVM-OFFLOAD-BINARY(1), dated 2026-10-06, brought to you by the LLVM Project. Slay, bye! ๐๐ฆ๐
๐ฆ where this page comes from
- centos-stream 9: llvm 23.1.3-1.el9 ยท Apache-2.0 WITH LLVM-exception OR NCSA
- centos-stream 9: llvm 23.1.3-1.el9 ยท Apache-2.0 WITH LLVM-exception OR NCSA
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms