Skip to content

encounter/objdiff

Repository files navigation

objdiff Build Status

A local diffing tool for decompilation projects. Inspired by decomp.me and asm-differ.

Features:

  • Compare entire object files: functions and data
  • Built-in C++ symbol demangling (GCC, MSVC, CodeWarrior, Itanium)
  • Automatic rebuild on source file changes
  • Project integration via configuration file
  • Search and filter objects with quick switching
  • Click-to-highlight values and registers
  • Detailed progress reporting (powers decomp.dev)
  • WebAssembly API, web interface and Visual Studio Code extension (WIP)

Supports:

  • ARM (GBA, DS, 3DS)
  • ARM64 (Switch)
  • MIPS (N64, PS1, PS2, PSP)
  • PowerPC (GameCube, Wii, PS3, Xbox 360)
  • SuperH (Saturn, Dreamcast)
  • x86, x86_64 (PC)

See Usage for more information.

Downloads

To build from source, see Building.

GUI

For Linux and macOS, run chmod +x objdiff-* to make the binary executable.

CLI

CLI binaries are available on the releases page.

Screenshots

Symbol Screenshot Diff Screenshot

Usage

objdiff compares two relocatable object files (.o). Here's how it works:

  1. Create an objdiff.json configuration file in your project root (or generate it with your build script).
    This file lists all objects in the project with their target ("expected") and base ("current") paths.

  2. Load the project in objdiff.

  3. Select an object from the sidebar to begin diffing.

  4. objdiff automatically:

    • Executes the build system to compile the base object (from current source code)
    • Compares the two objects and displays the differences
    • Watches for source file changes and rebuilds when detected

The configuration file allows complete flexibility in project structure - your build directories can have any layout as long as the paths are specified correctly.

See Configuration for setup details.

Configuration

Projects can add an objdiff.json file to configure the tool automatically. The configuration file must be located in the root project directory.

If your project has a generator script (e.g. configure.py), it's highly recommended to generate the objdiff configuration file as well. You can then add objdiff.json to your .gitignore to prevent it from being committed.

{
  "$schema": "https://raw.githubusercontent.com/encounter/objdiff/main/config.schema.json",
  "custom_make": "ninja",
  "custom_args": [
    "-d",
    "keeprsp"
  ],
  "build_target": false,
  "build_base": true,
  "watch_patterns": [
    "*.c",
    "*.cc",
    "*.cp",
    "*.cpp",
    "*.cxx",
    "*.c++",
    "*.h",
    "*.hh",
    "*.hp",
    "*.hpp",
    "*.hxx",
    "*.h++",
    "*.pch",
    "*.pch++",
    "*.inc",
    "*.s",
    "*.S",
    "*.asm",
    "*.py",
    "*.yml",
    "*.txt",
    "*.json"
  ],
  "ignore_patterns": [
    "build/**/*"
  ],
  "units": [
    {
      "name": "main/MetroTRK/mslsupp",
      "target_path": "build/asm/MetroTRK/mslsupp.o",
      "base_path": "build/src/MetroTRK/mslsupp.o",
      "metadata": {}
    }
  ]
}

Schema

Note

View config.schema.json for all available options. Below is a summary of the most important options.

Build Configuration

custom_make (optional, default: "make")
If the project uses a different build system (e.g. ninja), specify it here. The build command will be [custom_make] [custom_args] path/to/object.o.

custom_args (optional)
Additional arguments to pass to the build command prior to the object path.

build_target (default: false)
If true, objdiff will build the target objects before diffing (e.g. make path/to/target.o). Useful if target objects are not built by default or can change based on project configuration. Requires proper build system configuration.

build_base (default: true)
If true, objdiff will build the base objects before diffing (e.g. make path/to/base.o). It's unlikely you'll want to disable this unless using an external tool to rebuild the base object.

File Watching

watch_patterns (optional, default: listed above)
A list of glob patterns to watch for changes (supported syntax). When these files change, objdiff automatically rebuilds and re-compares objects.

ignore_patterns (optional, default: listed above)
A list of glob patterns to explicitly ignore when watching for changes (supported syntax).

Units (Objects)

units (optional)
If specified, objdiff displays a list of objects in the sidebar for easy navigation. Each unit contains:

  • name (optional) - The display name in the UI. Defaults to the object's path.
  • target_path (optional) - Path to the "target" or "expected" object (the intended result).
  • base_path (optional) - Path to the "base" or "current" object (built from current source code). Omit if there is no source object yet.
  • metadata.auto_generated (optional) - Hides the object from the sidebar but includes it in progress reports.
  • metadata.complete (optional) - Marks the object as "complete" (linked) when true or "incomplete" when false.

Building

Install Rust via rustup.

git clone https://github.com/encounter/objdiff.git
cd objdiff
cargo run --release

Or install directly with cargo:

cargo install --locked --git https://github.com/encounter/objdiff.git objdiff-gui objdiff-cli

Binaries will be installed to ~/.cargo/bin as objdiff and objdiff-cli.

Contributing

Install pre-commit to run linting and formatting automatically:

rustup toolchain install nightly  # Required for cargo fmt/clippy
cargo install --locked cargo-deny # https://github.com/EmbarkStudios/cargo-deny
uv tool install pre-commit        # https://docs.astral.sh/uv, or use pipx or pip
pre-commit install

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.