Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions ostool/src/artifact/elf_metadata.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
use anyhow::{Context, bail};
use object::{
Object, ObjectSegment, ObjectSymbol,
read::elf::{ElfFile, FileHeader, ProgramHeader},
Object, ObjectSection, ObjectSegment, ObjectSymbol,
read::elf::{ElfFile, FileHeader, ProgramHeader, SectionHeader},
};

pub(crate) struct ElfMetadata {
pub(crate) arch: object::Architecture,
pub(crate) entry: u64,
pub(crate) load_segments: Vec<LoadSegment>,
/// Allocated sections with file bytes that can appear in a raw binary image.
pub(crate) load_sections: Vec<LoadSection>,
pub(crate) executable_start: Option<u64>,
}

#[derive(Debug, PartialEq, Eq)]
pub(crate) struct LoadSegment {
pub(crate) virtual_address: u64,
pub(crate) physical_address: u64,
Expand All @@ -21,6 +24,14 @@ pub(crate) struct LoadSegment {
pub(crate) flags: u32,
}

/// A file-backed allocated section, represented in both ELF address spaces.
#[derive(Debug, PartialEq, Eq)]
pub(crate) struct LoadSection {
pub(crate) virtual_address: u64,
pub(crate) file_offset: u64,
pub(crate) size: u64,
}

impl ElfMetadata {
pub(crate) fn parse(data: &[u8]) -> anyhow::Result<Self> {
let file = object::File::parse(data).context("failed to parse ELF")?;
Expand Down Expand Up @@ -53,6 +64,26 @@ impl ElfMetadata {
})
.collect();

let load_sections = file
.sections()
.filter_map(|section| {
let header = section.elf_section_header();
let flags: u64 = header.sh_flags(endian).into();
if flags & u64::from(object::elf::SHF_ALLOC) == 0
|| header.sh_type(endian) == object::elf::SHT_NOBITS
{
return None;
}

let (file_offset, size) = section.file_range()?;
(size != 0).then_some(LoadSection {
virtual_address: section.address(),
file_offset,
size,
})
})
.collect();

let mut executable_start = None;
for symbol in file.symbols() {
if symbol.name()? == "__executable_start" && symbol.is_definition() {
Expand All @@ -65,6 +96,7 @@ impl ElfMetadata {
arch: file.architecture(),
entry: file.entry(),
load_segments,
load_sections,
executable_start,
})
}
Expand Down
18 changes: 18 additions & 0 deletions ostool/src/artifact/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,24 @@ impl PreparedRuntimeArtifacts {
pub(crate) fn arch(&self) -> Option<Architecture> {
self.arch
}

#[cfg(test)]
pub(crate) fn for_test(source_elf: PathBuf, elf: PathBuf) -> Self {
let source_artifact_dir = source_elf
.parent()
.map(Path::to_path_buf)
.unwrap_or_default();
let runtime_artifact_dir = elf.parent().map(Path::to_path_buf);
Self {
source_elf,
elf,
bin: None,
source_artifact_dir,
cargo_artifact_dir: None,
runtime_artifact_dir,
arch: None,
}
}
}

/// Prepares runtime ELF/BIN artifacts from a Cargo or custom-build ELF.
Expand Down
Loading
Loading