Skip to main content

Object

Struct Object 

Source
pub struct Object { /* private fields */ }
Expand description

One object file or executable, independent of the format it is written in.

An object is a target, a kind, a list of Sections (each carrying its own Relocations), and a list of Symbols. Executables also have an entry point. The same object can be written in any format the crate supports; reading a file returns an object of the same shape.

Nothing is checked while an object is built. validate checks every rule the model has, and every writer runs it first, so a malformed object is an error value, never a malformed file.

§Examples

A relocatable object with a function that calls an external one:

use object_lang::{
    Architecture, Object, Relocation, RelocationTarget, Section, SectionKind, Symbol,
    X86_64Reloc,
};

let mut obj = Object::relocatable(Architecture::X86_64);
// call puts; ret
let text = obj.add_section(
    Section::new(".text", SectionKind::Text).with_data(vec![0xe8, 0, 0, 0, 0, 0xc3]),
);
obj.add_symbol(Symbol::function("main", text, 0, 6));
let puts = obj.add_symbol(Symbol::undefined("puts"));
obj.add_relocation(
    text,
    Relocation::new(1, X86_64Reloc::Plt32, RelocationTarget::Symbol(puts), -4),
)?;

let bytes = object_lang::elf::write(&obj)?;
let back = object_lang::elf::read(&bytes)?;
assert_eq!(back.symbols().len(), 2);
assert_eq!(back.sections()[0].relocations().len(), 1);

Implementations§

Source§

impl Object

Source

pub const fn new(kind: FileKind, arch: Architecture) -> Self

Creates an empty object of the given kind for the given architecture.

The entry point starts at zero and the stack is not executable.

§Examples
use object_lang::{Architecture, FileKind, Object};

let exe = Object::new(FileKind::Executable, Architecture::Aarch64);
assert_eq!(exe.architecture(), Architecture::Aarch64);
assert!(exe.sections().is_empty());
Source

pub const fn relocatable(arch: Architecture) -> Self

Creates an empty relocatable object: Object::new(FileKind::Relocatable, arch).

§Examples
use object_lang::{Architecture, FileKind, Object};

assert_eq!(Object::relocatable(Architecture::X86_64).kind(), FileKind::Relocatable);
Source

pub const fn executable(arch: Architecture) -> Self

Creates an empty executable: Object::new(FileKind::Executable, arch).

§Examples
use object_lang::{Architecture, FileKind, Object};

assert_eq!(Object::executable(Architecture::X86_64).kind(), FileKind::Executable);
Source

pub const fn kind(&self) -> FileKind

What the file is for.

§Examples
use object_lang::{Architecture, FileKind, Object};

assert_eq!(Object::executable(Architecture::X86_64).kind(), FileKind::Executable);
Source

pub const fn architecture(&self) -> Architecture

The instruction set the object is built for.

§Examples
use object_lang::{Architecture, Object};

assert_eq!(Object::relocatable(Architecture::Aarch64).architecture(), Architecture::Aarch64);
Source

pub const fn entry(&self) -> u64

The address execution starts at. Meaningful for executables, where it must lie inside an executable section; relocatable objects normally leave it at zero.

§Examples
use object_lang::{Architecture, Object};

let mut exe = Object::executable(Architecture::X86_64);
exe.set_entry(0x40_1000);
assert_eq!(exe.entry(), 0x40_1000);
Source

pub fn set_entry(&mut self, address: u64)

Sets the entry point address. See entry.

§Examples
use object_lang::{Architecture, Object};

let mut exe = Object::executable(Architecture::Aarch64);
exe.set_entry(0x41_0000);
assert_eq!(exe.entry(), 0x41_0000);
Source

pub const fn executable_stack(&self) -> bool

Whether the program asks for an executable stack.

Almost nothing should: it is off by default. ELF records the request as a .note.GNU-stack section in relocatable objects and a PT_GNU_STACK program header in executables; when a file read in carries neither, it is reported as true, because that is how the GNU toolchain and the Linux kernel treat a file that does not say.

§Examples
use object_lang::{Architecture, Object};

let obj = Object::relocatable(Architecture::X86_64);
assert!(!obj.executable_stack());
Source

pub fn set_executable_stack(&mut self, executable: bool)

Sets whether the program asks for an executable stack. See executable_stack.

§Examples
use object_lang::{Architecture, Object};

let mut obj = Object::relocatable(Architecture::X86_64);
obj.set_executable_stack(true);
assert!(obj.executable_stack());
Source

pub fn add_section(&mut self, section: Section) -> SectionId

Adds a section and returns its id. Sections keep the order they were added in.

§Examples
use object_lang::{Architecture, Object, Section, SectionKind};

let mut obj = Object::relocatable(Architecture::X86_64);
let bss = obj.add_section(Section::new(".bss", SectionKind::Bss).with_bss_size(64));
assert_eq!(obj.section(bss).map(|s| s.size()), Some(64));
Source

pub fn sections(&self) -> &[Section]

Every section, in the order added; a SectionId indexes this slice.

§Examples
use object_lang::{Architecture, Object, Section, SectionKind};

let mut obj = Object::relocatable(Architecture::X86_64);
obj.add_section(Section::new(".text", SectionKind::Text));
assert_eq!(obj.sections()[0].name(), ".text");
Source

pub fn section(&self, id: SectionId) -> Option<&Section>

The section with this id, or None if the object has no such section.

§Examples
use object_lang::{Architecture, Object, Section, SectionKind};

let mut obj = Object::relocatable(Architecture::X86_64);
let id = obj.add_section(Section::new(".rodata", SectionKind::ReadOnlyData));
assert_eq!(obj.section(id).map(Section::name), Some(".rodata"));
Source

pub fn section_mut(&mut self, id: SectionId) -> Option<&mut Section>

The section with this id, mutably, or None if the object has no such section.

§Examples
use object_lang::{Architecture, Object, Section, SectionKind};

let mut obj = Object::relocatable(Architecture::X86_64);
let text = obj.add_section(Section::new(".text", SectionKind::Text));
let offset = obj.section_mut(text).map(|s| s.append(&[0xc3], 16));
assert_eq!(offset, Some(Ok(0)));
Source

pub fn section_by_name(&self, name: &str) -> Option<SectionId>

The first section with this name, or None. A linear search: formats allow several sections to share a name, and this returns the earliest.

§Examples
use object_lang::{Architecture, Object, Section, SectionKind};

let mut obj = Object::relocatable(Architecture::X86_64);
let data = obj.add_section(Section::new(".data", SectionKind::Data));
assert_eq!(obj.section_by_name(".data"), Some(data));
assert_eq!(obj.section_by_name(".bss"), None);
Source

pub fn add_symbol(&mut self, symbol: Symbol) -> SymbolId

Adds a symbol and returns its id. Symbols keep the order they were added in; formats that need a different order (ELF puts local symbols first) reorder on write, so a file read back lists them in the format’s order.

§Examples
use object_lang::{Architecture, Object, Section, SectionKind, Symbol};

let mut obj = Object::relocatable(Architecture::X86_64);
let text = obj.add_section(Section::new(".text", SectionKind::Text).with_data(vec![0xc3]));
let f = obj.add_symbol(Symbol::function("f", text, 0, 1));
assert_eq!(obj.symbol(f).map(|s| s.name.as_str()), Some("f"));
Source

pub fn symbols(&self) -> &[Symbol]

Every symbol, in the order added; a SymbolId indexes this slice.

§Examples
use object_lang::{Architecture, Object, Symbol};

let mut obj = Object::relocatable(Architecture::X86_64);
obj.add_symbol(Symbol::undefined("exit"));
assert_eq!(obj.symbols()[0].name, "exit");
Source

pub fn symbol(&self, id: SymbolId) -> Option<&Symbol>

The symbol with this id, or None if the object has no such symbol.

§Examples
use object_lang::{Architecture, Object, Symbol};

let mut obj = Object::relocatable(Architecture::X86_64);
let id = obj.add_symbol(Symbol::undefined("exit"));
assert!(obj.symbol(id).is_some());
Source

pub fn symbol_mut(&mut self, id: SymbolId) -> Option<&mut Symbol>

The symbol with this id, mutably, or None if the object has no such symbol.

§Examples
use object_lang::{Architecture, Binding, Object, Symbol};

let mut obj = Object::relocatable(Architecture::X86_64);
let id = obj.add_symbol(Symbol::undefined("hook"));
if let Some(sym) = obj.symbol_mut(id) {
    sym.binding = Binding::Weak;
}
assert_eq!(obj.symbols()[0].binding, Binding::Weak);
Source

pub fn symbol_by_name(&self, name: &str) -> Option<SymbolId>

The first symbol with this name, or None. A linear search.

§Examples
use object_lang::{Architecture, Object, Symbol};

let mut obj = Object::relocatable(Architecture::X86_64);
let id = obj.add_symbol(Symbol::undefined("memcpy"));
assert_eq!(obj.symbol_by_name("memcpy"), Some(id));
Source

pub fn add_relocation( &mut self, section: SectionId, relocation: Relocation, ) -> Result<(), ModelError>

Adds a relocation to a section: shorthand for object.section_mut(section)?.add_relocation(relocation).

The relocation itself is checked by validate, like everything else.

§Errors

ModelError::UnknownSection if the object has no section section.

§Examples
use object_lang::{
    Aarch64Reloc, Architecture, Object, Relocation, RelocationTarget, Section,
    SectionKind, Symbol,
};

let mut obj = Object::relocatable(Architecture::Aarch64);
// bl <callee>
let text = obj.add_section(
    Section::new(".text", SectionKind::Text).with_data(vec![0x00, 0x00, 0x00, 0x94]),
);
let callee = obj.add_symbol(Symbol::undefined("callee"));
obj.add_relocation(
    text,
    Relocation::new(0, Aarch64Reloc::Call26, RelocationTarget::Symbol(callee), 0),
)?;
assert_eq!(obj.sections()[0].relocations().len(), 1);
Source

pub fn validate(&self) -> Result<(), ModelError>

Checks every rule of the model, returning the first violation.

Writers call this before writing anything, and readers call it on what they read, so an object that passes is one every writer can represent (barring format-specific limits, reported as WriteError). The rules are listed under ModelError, SectionProblem, SymbolProblem, and RelocationProblem.

§Errors

The first rule the object breaks, as a ModelError.

§Examples
use object_lang::{
    Architecture, ModelError, Object, Section, SectionKind, SectionProblem,
};

let mut obj = Object::relocatable(Architecture::X86_64);
let text = obj.add_section(Section::new(".text", SectionKind::Text).with_align(3));
assert_eq!(
    obj.validate(),
    Err(ModelError::Section { section: text, problem: SectionProblem::BadAlignment }),
);

Trait Implementations§

Source§

impl Clone for Object

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Object

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for Object

Source§

impl PartialEq for Object

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Object

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.