Disassembler


Introduction

LIEF Extended provides a user-friendly API for disassembling code within various parts of executable formats for the following architectures: x86/x86-64, ARM, AArch64, RISC-V, MIPS, PowerPC, and eBPF.

import lief

elf = lief.ELF.parse("/bin/hello")

inst: lief.assembly.Instruction = ...

for inst in elf.disassemble(0x400120):
    print(inst)
From a design perspective, the disassembler returns a lazy iterator, yielding a instance as it evaluates the instruction at each address.

Consequently, when calling elf.disassemble_address(0x400), no disassembly occurs until the iterator is advanced.

Instructions are represented by the object, which is extended by architecture-specific objects:

In Python, you can check the effective type of a lief.assembly.Instruction with isinstance(...):

inst: lief.assembly.Instruction = ...

if isinstance(inst, lief.assembly.riscv.Instruction):
   opcode: lief.assemble.riscv.OPCODE = inst.opcode

In C++, downcasting is performed using the function: LIEF::assembly::Instruction::as():

std::unique_ptr<LIEF::assembly::Instruction> inst = ...;

if (const auto* riscv_inst = inst->as<LIEF::assembly::riscv::Instruction>())
{
  LIEF::assembly::riscv::OPCODE opcode = riscv_inst->opcode();
}

In Rust, instructions are represented by the enum lief::assembly::Instructions. Thus, you can write:

fn check_opcode(inst: &lief::assembly::Instructions) {
  if let lief::assembly::Instructions::RiscV(riscv) = inst {
    println!("{:?}", riscv.opcode());
  }
}

Note

You can also check the assembler documentation here: Assembler

For the x86/x86-64 and AArch64 architectures, you can also iterate over an instruction’s operands:

import lief

inst: lief.assembly.aarch64.Instruction

for inst in macho.disassemble(0x400120):
    print(inst)
    # Check inst properties
    if inst.is_branch:
        print(f"Resolved: {inst.branch_target}")

    for idx, operand in enumerate(inst.operands):
        if isinstance(operand, lief.assembly.aarch64.operands.Register):
            print(f"op[{idx}]: REG - {operand.value}")
        if isinstance(operand, lief.assembly.aarch64.operands.Memory):
            print(f"op[{idx}]: MEM - {operand.base}")
        if isinstance(operand, lief.assembly.aarch64.operands.PCRelative):
            print(f"op[{idx}]: PCR - {operand.value}")
        if isinstance(operand, lief.assembly.aarch64.operands.Immediate):
            print(f"op[{idx}]: IMM - {operand.value}")

You can check the documentation of these architectures for more details about the exposed API.

Use Cases

DWARF Function

Warning

only works if the DWARF debug info is embedded in the binary. This is the default behavior for ELF binaries, but this is not the case for Mach-O .dSYM files.
import lief

elf = lief.ELF.parse("/bin/hello")

main = elf.debug_info.find_function("main")

for inst in .instructions:
    print(inst)

Dyld Shared Cache

import lief

dyld_cache: lief.dsc.DylibSharedCache = lief.dsc.load("macos-15.0.1/")

for inst in dyld_cache.disassemble(0x1886f4a44):
    print(inst)

COFF Support

For more details, please check the COFF Disassembler section

Technical Details

The disassembler is based on LLVM’s MC layer, which is known to be efficient and accurate for disassembling code. This LLVM MC layer is already used by other projects like capstone or, more recently, Nyxstone.

Compared to Capstone, LIEF uses a mainstream LLVM version with limited modifications to the MC layer. On the other hand, it does not expose a C API, supports fewer architectures than Capstone, and does not expose a standalone API.

Note

The current LLVM version is 22.x.

Unlike Nyxstone’s disassembler, LIEF hides LLVM from the public API, meaning that LLVM does not need to be installed on the system. On the other hand, it does not expose a standalone API.

The major difference between LIEF’s disassembler and other projects is that it does not expose a standalone API for disassembling arbitrary code. The disassembler is bound to the object from which the API is exposed (, , , etc.).

Python API

C++ API

Rust API: lief::assembly