use alloc::vec::Vec;
use crate::error::ModelError;
use crate::reloc::Relocation;
use crate::section::Section;
use crate::symbol::Symbol;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[non_exhaustive]
pub enum Architecture {
X86_64,
Aarch64,
}
impl Architecture {
#[must_use]
pub const fn page_size(self) -> u64 {
match self {
Architecture::X86_64 => 0x1000,
Architecture::Aarch64 => 0x1_0000,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[non_exhaustive]
pub enum FileKind {
Relocatable,
Executable,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct SectionId(pub(crate) u32);
impl SectionId {
#[must_use]
pub const fn new(index: u32) -> Self {
SectionId(index)
}
#[must_use]
pub const fn index(self) -> usize {
self.0 as usize
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct SymbolId(pub(crate) u32);
impl SymbolId {
#[must_use]
pub const fn new(index: u32) -> Self {
SymbolId(index)
}
#[must_use]
pub const fn index(self) -> usize {
self.0 as usize
}
}
pub(crate) const MAX_ITEMS: usize = 0x7fff_ffff;
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Object {
kind: FileKind,
arch: Architecture,
entry: u64,
executable_stack: bool,
sections: Vec<Section>,
symbols: Vec<Symbol>,
}
impl Object {
#[must_use]
pub const fn new(kind: FileKind, arch: Architecture) -> Self {
Object {
kind,
arch,
entry: 0,
executable_stack: false,
sections: Vec::new(),
symbols: Vec::new(),
}
}
#[must_use]
pub const fn relocatable(arch: Architecture) -> Self {
Object::new(FileKind::Relocatable, arch)
}
#[must_use]
pub const fn executable(arch: Architecture) -> Self {
Object::new(FileKind::Executable, arch)
}
#[must_use]
pub const fn kind(&self) -> FileKind {
self.kind
}
#[must_use]
pub const fn architecture(&self) -> Architecture {
self.arch
}
#[must_use]
pub const fn entry(&self) -> u64 {
self.entry
}
pub fn set_entry(&mut self, address: u64) {
self.entry = address;
}
#[must_use]
pub const fn executable_stack(&self) -> bool {
self.executable_stack
}
pub fn set_executable_stack(&mut self, executable: bool) {
self.executable_stack = executable;
}
pub fn add_section(&mut self, section: Section) -> SectionId {
let id = SectionId(u32::try_from(self.sections.len()).unwrap_or(u32::MAX));
self.sections.push(section);
id
}
#[must_use]
pub fn sections(&self) -> &[Section] {
&self.sections
}
#[must_use]
pub fn section(&self, id: SectionId) -> Option<&Section> {
self.sections.get(id.index())
}
#[must_use]
pub fn section_mut(&mut self, id: SectionId) -> Option<&mut Section> {
self.sections.get_mut(id.index())
}
#[must_use]
pub fn section_by_name(&self, name: &str) -> Option<SectionId> {
self.sections
.iter()
.position(|s| s.name() == name)
.and_then(|i| u32::try_from(i).ok())
.map(SectionId)
}
pub fn add_symbol(&mut self, symbol: Symbol) -> SymbolId {
let id = SymbolId(u32::try_from(self.symbols.len()).unwrap_or(u32::MAX));
self.symbols.push(symbol);
id
}
#[must_use]
pub fn symbols(&self) -> &[Symbol] {
&self.symbols
}
#[must_use]
pub fn symbol(&self, id: SymbolId) -> Option<&Symbol> {
self.symbols.get(id.index())
}
#[must_use]
pub fn symbol_mut(&mut self, id: SymbolId) -> Option<&mut Symbol> {
self.symbols.get_mut(id.index())
}
#[must_use]
pub fn symbol_by_name(&self, name: &str) -> Option<SymbolId> {
self.symbols
.iter()
.position(|s| s.name == name)
.and_then(|i| u32::try_from(i).ok())
.map(SymbolId)
}
pub fn add_relocation(
&mut self,
section: SectionId,
relocation: Relocation,
) -> Result<(), ModelError> {
match self.sections.get_mut(section.index()) {
Some(s) => {
s.add_relocation(relocation);
Ok(())
}
None => Err(ModelError::UnknownSection { section }),
}
}
pub fn validate(&self) -> Result<(), ModelError> {
crate::validate::validate(self)
}
pub(crate) fn from_parts(
kind: FileKind,
arch: Architecture,
entry: u64,
executable_stack: bool,
sections: Vec<Section>,
symbols: Vec<Symbol>,
) -> Self {
Object {
kind,
arch,
entry,
executable_stack,
sections,
symbols,
}
}
}