Open-source project
icedland/iced avatar
icedland/iced

iced: x86/x64 decode, disassemble and assemble across Rust, .NET, Java, Python, Lua and JavaScript

Blazing fast and correct x86/x64 disassembler, assembler, decoder, encoder for Rust, .NET, Java, Python, Lua

3,577 stars275 forksRustMIT

At a glance

What is it?
iced is a multi-language x86/x64 decoder, disassembler and assembler from icedland. It is aimed at tools that need to read machine code without allocating per instruction, and it ships bindings for six runtimes.
Who is it for?
Adopt iced if you need to decode or re-encode x86/x64 bytes inside Rust, .NET, Java, Python, Lua or JavaScript and you want one instruction to cost a fixed 40 bytes with no allocation. Do not adopt it if you need ARM or another non-x86 architecture, or if you want a ready-made interactive disassembler UI rather than a library.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What iced is for, and who actually needs it

iced is a library, not an application. It decodes x86 instructions in 16-bit, 32-bit and 64-bit modes, disassembles them to text, and assembles them back into bytes. The README describes it as a "blazing fast and correct x86 (16/32/64-bit) instruction decoder, disassembler and assembler." The audience is narrow and technical: people writing debuggers, profilers, binary analysis tools, JIT backends, emulators, or patching utilities. If you are looking for a program with a window and a hex view, iced is the wrong layer. If you are writing that program, iced is the engine you would call into.

The distinguishing claim is memory behaviour. The README states decoded instructions are "only 40 bytes and the decoder doesn't allocate any memory." For a tool walking a large code section, that changes the shape of the loop: you decode into a stack or reused buffer, format or inspect, then move on, instead of building a heap-allocated instruction object per byte offset. The second claim is breadth: "Supports all Intel and AMD instructions," with correctness checked against xed, gas, objdump, masm, dumpbin, nasm and ndisasm, plus fuzzing. That cross-checking list is the part worth weighing, because disassembler disagreements are usually found on the rare encodings, not on mov and add.

The decode, format, encode pipeline and the instruction info API

The core object is a decoder bound to a byte slice, a bitness and an IP. Decoding produces an instruction value that carries the raw bytes, the length and the parsed operands. From there you have three directions. You can format it to text through a formatter, and the README lists masm, nasm, gas (AT&T) and Intel (XED) syntaxes with "many options to customize the output." You can query it for instruction info: "read/written registers, memory and rflags bits; CPUID feature flag, control flow info, etc." Or you can hand it to the encoder, which "can be used to re-encode decoded instructions at any address."

That last point is the one that separates iced from a pure disassembler. Because the encoder takes an address, you can lift instructions, modify an operand or a branch target, and write them back at a different location, which is what a binary rewriting or instrumentation tool needs. The code assembler goes further in the other direction: the README gives `asm.mov(eax, edx)` as an example, so instructions can be constructed programmatically rather than parsed from bytes. The instruction info API is the piece that makes analysis practical, since knowing which flags and registers an instruction reads and writes is what lets you reason about a basic block without hand-maintaining a table of x86 semantics.

Installing iced and decoding your first buffer

iced is distributed through each language's own package manager, and the root README links to a separate README per language rather than documenting the APIs inline. The badges point at crates.io for the Rust crate iced-x86, NuGet for the .NET package iced, Maven Central for io.github.icedland.iced/iced-x86, and PyPI for iced-x86.

bash
cargo add iced-x86

That command adds the crate to a Rust project. The root README does not show any decoding code; it links to the Rust README at src/rust/iced-x86/README.md, and to the .NET, Java, Python, JavaScript and Lua READMEs listed in the Examples section. Follow the README for your language before writing code, because the object names differ between the ports.

For Python the PyPI package is iced-x86 and the README is at src/rust/iced-x86-py/README.md. For .NET the NuGet package is iced and the README is at src/csharp/Intel/README.md. For Java the README is at src/java/iced-x86/README.md, for JavaScript and WebAssembly it is at src/rust/iced-x86-js/README.md, and for Lua it is at src/rust/iced-x86-lua/README.md.

Where iced stops: architecture coverage and the missing root documentation

The scope is x86 and x64 only. The README says nothing about ARM, RISC-V, MIPS or any other architecture, so if your input is an ARM64 binary, iced has no decoder for it and no amount of configuration will produce one. This is a hard boundary, not a limitation to work around.

The second gap is documentation placement. The root README is a feature list plus a set of links. It does not show a single API signature, and it does not describe installation beyond pointing at four package registries. Every concrete usage detail lives in a per-language README under src/. That is reasonable for a project with six bindings, but it means the root page cannot answer "how do I decode bytes in Python" on its own, and the ports are not guaranteed to use identical names. If you are evaluating iced from the repository front page, you are evaluating a summary, not the API.

There is also a release cadence question. The most recent release listed is v1.21.0 from 2024-01-20, following v1.20.0 in 2023-07-19 and v1.19.0 in 2023-06-04. The default branch has seen commits more recently than that (the last push was on 2026-09-16), so the master branch and the tagged releases are not in lockstep. If you pin to a published version, you are not getting whatever has landed on master since January 2024.

iced against Capstone and the LLVM disassembler

The obvious alternative for most readers is Capstone, which also disassembles x86 and additionally covers ARM, ARM64, MIPS, PowerPC and others. The difference in approach is the axis of coverage. Capstone optimises for breadth of instruction sets behind one API; iced optimises for depth within x86, and adds two things Capstone's disassembly side does not offer in the same library: an assembler and an encoder. If you need to turn modified instructions back into bytes, or build instructions programmatically with an API like `asm.mov(eax, edx)`, that is iced's territory. If your codebase has to handle ARM and x86 in the same tool, Capstone gets you one dependency instead of two, and iced cannot cover the ARM half at all.

A second reference point is the LLVM disassembler, which is what objdump-style tooling builds on. It is extremely broad and is maintained alongside the compiler backends, but it is not packaged as a small embeddable library with per-instruction memory guarantees, and pulling it into a Rust or Python tool means a much larger dependency. iced's pitch is the opposite: a fixed 40-byte instruction and a decoder that does not allocate, in a package you can add with one line in six different ecosystems. The README's own correctness claim leans on comparing against these tools, which is an argument for using iced as the primary decoder and the others as the oracle, not the reverse.

Licence, upgrade cost and what to check before you depend on it

iced is MIT licensed, stated in the README and shipped as LICENSE.txt at the repository root. MIT is permissive: it allows use in closed-source products with attribution and the licence text retained. That matters here because binary analysis tooling often ships inside commercial products. This is a description of the licence text, not legal advice; if your organisation has a policy on permissive licences, run it through that process.

The upgrade cost splits by language. On the Rust side the crate is iced-x86 and version bumps follow semver, so a minor release can add API. On the .NET side the package is iced, on the Java side it is io.github.icedland.iced/iced-x86, and on the Python side it is iced-x86. Because the ports are generated from a shared core, a formatter option or an instruction-info field added upstream tends to appear across all of them, but not necessarily in the same release window. If you use more than one binding in the same organisation, pin them together and test the upgrade as one change rather than six.

The practical warning is the release gap. With v1.21.0 published on 2024-01-20 and master moving since, the version you install from a registry may be well behind the code you can read on GitHub. Decide deliberately which one you are targeting, and if you need a fix that only exists on master, plan to depend on a git revision rather than a published version until the next tag.

Editorial conclusion

Adopt iced if you need to decode or re-encode x86/x64 bytes inside Rust, .NET, Java, Python, Lua or JavaScript and you want one instruction to cost a fixed 40 bytes with no allocation. Do not adopt it if you need ARM or another non-x86 architecture, or if you want a ready-made interactive disassembler UI rather than a library. Before committing, verify the version your package manager resolves against the crates.io, NuGet, Maven Central or PyPI listing, and check the per-language README under src/ for the exact API surface, because the root README only links to those documents.

Frequently asked questions

Does iced support ARM or only x86 and x64?

Only x86 and x64. The README describes it as an x86 (16/32/64-bit) instruction decoder, disassembler and assembler, and no other architecture is mentioned anywhere in the documentation.

Which package managers does iced publish to?

The README badges point to crates.io for the Rust crate iced-x86, NuGet for the .NET package iced, Maven Central for io.github.icedland.iced/iced-x86, and PyPI for iced-x86. JavaScript is supported through a WebAssembly build and Lua through a separate binding, both documented in their own READMEs under src/.

How much memory does an iced decoded instruction use?

The README states decoded instructions are only 40 bytes and that the decoder does not allocate any memory. That is the property that makes it practical to walk a large code section without building a heap object per instruction.

Can iced assemble instructions as well as disassemble them?

Yes. The README lists a code assembler, with `asm.mov(eax, edx)` as the example, and an encoder that can re-encode decoded instructions at any address.

What syntaxes can iced format disassembly into?

The README lists masm, nasm, gas (AT&T) and Intel (XED), and notes there are many options to customize the output.

What licence is iced released under?

MIT. The README states it and the repository root contains LICENSE.txt.

Official sources

  1. icedland/iced on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/icedland-iced.svg)](https://hysenlabs.com/projects/icedland-iced)