object: one Rust API for ELF, PE, Mach-O and everything else
A unified interface for reading and writing object file formats
At a glance
- What is it?
- The object crate gives Rust programs a single interface for reading and writing object files across platforms, with three levels of access from raw structs to a unified view of sections and symbols. Its security section is unusually candid: it is meant for trusted inputs, it does not try to stop algorithmic complexity attacks, and it does not claim to agree with a platform loader.
- Who is it for?
- Use object when your Rust program has to read or produce binaries in more than one format, because the unified API saves you from writing three parsers and the raw layer is there when you need the bytes. Do not point it at untrusted input, since the crate says it is intended for trusted inputs and is not suitable for malware analysis or for a service exposed to arbitrary inputs.
- Can I use it commercially?
- Yes. Apache-2.0 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 received new commits within the last day.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the crate covers
The object crate provides a unified interface to working with object files across platforms. It supports reading relocatable object files and executable files, and writing COFF, ELF, Mach-O and XCOFF relocatable object files and ELF and PE executable files. The formats it can read are broader than the formats it can write: ELF, Mach-O, Windows PE and COFF, Wasm, XCOFF and Unix archive. That asymmetry is the shape of most such libraries, since the reading side is a parsing problem and the writing side is a generation problem with a much smaller common core. The crate lives at docs.rs/object, the repository is under the gimli-rs organisation, and the version in the package metadata is 0.40.0 on edition 2024.
Three levels of access, and choosing one
For reading, the crate offers multiple levels of support. There are raw struct definitions suitable for zero copy access, which is how you read a header without copying it. There are low level APIs for accessing those raw structs. And there is a higher level unified API for the common features of object files, such as sections and symbols. The unified layer looks like this.
use object::{Object, ObjectSection};
use std::error::Error;
use std::fs;
/// Reads a file and displays the name of each section.
fn main() -> Result<(), Box<dyn Error>> {
let binary_data = fs::read("path/to/binary")?;
let file = object::File::parse(&*binary_data)?;
for section in file.sections() {
println!("{}", section.name()?);
}
Ok(())
}The choice between the layers is a real decision rather than a preference. The zero copy layer is what you want in a tool that inspects thousands of binaries, because copying each header is the difference between a scan that takes a second and one that takes a minute, and the unified layer is what you want when you are writing a small tool and do not want to think about the format.
Writing is a smaller surface than reading
For writing, the crate provides low level writers for ELF, PE and COFF, a higher level builder for ELF, and a unified API for writing relocatable object files in ELF, Mach-O, COFF and XCOFF. So there is no unified executable writer and no Mach-O or XCOFF low level writer. The asymmetry is deliberate and follows from where the difficulty lies: producing a relocatable object file is a well-defined problem that the unified API can solve across formats, whereas producing a working executable requires matching what a loader expects, and each platform's loader has its own rules. The examples referenced in the README are a rewrite example, a simple write example and an objdump example, which suggests the intended uses are tooling rather than a compiler back end.
The security section says what the crate will not do
This is the part of the README worth reading twice, because it is specific rather than boilerplate. The crate is intended to be used with trusted inputs: it is suitable as part of a compiler toolchain, but not for malware analysis or for a service exposed to arbitrary inputs. The crate aims to be reliable, providing memory safety with some use of unsafe for performance, and malformed input is expected to result in an error rather than a panic or incorrect parsing. Then there are two stated limitations. There is little effort to mitigate denial of service attacks, such as algorithmic complexity attacks due to overlapping structures. And the crate does not aim to replicate the behaviour of platform loaders such as the Windows loader or dynamic linkers, so data returned by the parser may not match the data used by a loader. Non-intrusive fixes for these are welcome but are not a focus of development.
Feature flags per format, and why they matter
The feature list in the package metadata is organised around what you actually need to enable. The read feature pulls in read_core plus archive, coff, elf, macho, pe and xcoff, so one flag gives you every supported read format. The write feature is structured the same way around write_core, which itself pulls in crc32fast, indexmap and hashbrown, and there is a write_std variant that adds the standard library features to those. The optional dependencies line up with that design: flate2, ruzstd, wasmparser, indexmap, hashbrown and crc32fast appear as optional dependencies, matching the split between the read and write feature sets. The crate also has two internal features, core and alloc, which are documented as only used when building as part of libstd and not part of the stable interface, which is how a parser can be used in a no_std or freestanding context.
MSRV, edition and the dual licence
The minimum supported Rust version is handled carefully. Changes to MSRV are not considered breaking changes, the project says it is conservative about changing the MSRV but sometimes it is required due to dependencies, and the MSRV with all features enabled is 1.87.0 while the MSRV with some features disabled is 1.85.0. The package metadata agrees with the lower of those, setting rust-version to 1.85 with edition 2024. The licence is a choice rather than a single grant: the crate is licensed under either the Apache License version 2.0 or the MIT license, at your option, with both files in the repository and the metadata recording it as Apache-2.0 OR MIT. The contribution section makes the same arrangement explicit, saying that unless you explicitly state otherwise any contribution is dual licensed on those terms.
The repository layout
The top-level listing shows a crate with more structure than a typical library. There is a src directory for the main crate, a crates directory holding the examples and the rewrite example, a tests directory and a testfiles directory holding the binaries the tests parse, an xtask directory which is the usual Rust convention for build and release automation, a scripts directory, and a Cargo.lock together with a CHANGELOG.md. There is a .cargo directory for cargo configuration and a .gitmodules file, which suggests some test inputs or tooling come from other repositories. The separate testfiles directory is a detail that matters for anyone extending the crate: a parser project needs a corpus of real and malformed binaries to test against, and shipping that corpus is how the reliability claim about malformed input being an error rather than a panic gets checked.
Where object is the wrong choice
Four limits apply. It is not a loader, so if your tool needs to know what the operating system will actually do with the file, this crate will not tell you, and the README is explicit that its output may differ from what a loader uses. It is not hardened against hostile input, so anything parsing untrusted binaries needs a sandbox and a resource limit around it, and the crate says so plainly. Its write support is narrower than its read support, so a tool that must emit a Mach-O or PE executable is not covered by the unified writer. And the design deliberately trades away the low-level control that a format-specific library would give you: the unified API is easier, and when you need to do something the unified layer does not model you drop to the raw structs, which is where the effort you saved comes back.
Editorial conclusion
Use object when your Rust program has to read or produce binaries in more than one format, because the unified API saves you from writing three parsers and the raw layer is there when you need the bytes. Do not point it at untrusted input, since the crate says it is intended for trusted inputs and is not suitable for malware analysis or for a service exposed to arbitrary inputs. Verify first which features you need, since read and write support is split per format and the feature list is long, that your Rust version satisfies the MSRV, which is 1.87.0 with all features enabled and 1.85.0 with some disabled, and whether the licence choice of Apache or MIT at your option fits how you distribute it.
Frequently asked questions
What formats can the object crate read and write?
It reads ELF, Mach-O, Windows PE and COFF, Wasm, XCOFF and Unix archive. It writes COFF, ELF, Mach-O and XCOFF relocatable object files and ELF and PE executable files, with low level writers for ELF, PE and COFF and a higher level builder for ELF.
Is the object crate safe for untrusted binaries?
No. The README states the crate is intended to be used with trusted inputs, suitable as part of a compiler toolchain but not for malware analysis or a service exposed to arbitrary inputs. It also notes there is little effort to mitigate denial of service attacks such as algorithmic complexity attacks from overlapping structures.
What is the minimum Rust version for object?
The MSRV with all features enabled is 1.87.0, and 1.85.0 with some features disabled, with the package metadata setting rust-version to 1.85. The project says changes to MSRV are not considered breaking changes but that it is sometimes required due to dependencies.
What licence does the object crate use?
Either the Apache License version 2.0 or the MIT license, at your option, with the package metadata recording it as Apache-2.0 OR MIT. Contributions are dual licensed on the same terms unless you explicitly state otherwise.
What does object do with malformed input?
The crate aims to be reliable, providing memory safety with some use of unsafe for performance, and malformed input is expected to result in an error rather than a panic or incorrect parsing. It does not aim to replicate the behaviour of platform loaders, so parsed data may not match what a loader would use.
Official sources
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.
[](https://hysenlabs.com/projects/gimli-rs-object)Was this useful?