Skip to content

Commit

Permalink
read: add ObjectSection::relocation_map (#654)
Browse files Browse the repository at this point in the history
This is intended to handle relocations for DWARF.
  • Loading branch information
philipc authored Mar 28, 2024
1 parent ff176cc commit d65bc75
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 16 deletions.
10 changes: 7 additions & 3 deletions src/read/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ use crate::read::xcoff;
use crate::read::{
self, Architecture, BinaryFormat, CodeView, ComdatKind, CompressedData, CompressedFileRange,
Error, Export, FileFlags, FileKind, Import, Object, ObjectComdat, ObjectKind, ObjectMap,
ObjectSection, ObjectSegment, ObjectSymbol, ObjectSymbolTable, ReadRef, Relocation, Result,
SectionFlags, SectionIndex, SectionKind, SegmentFlags, SubArchitecture, SymbolFlags,
SymbolIndex, SymbolKind, SymbolMap, SymbolMapName, SymbolScope, SymbolSection,
ObjectSection, ObjectSegment, ObjectSymbol, ObjectSymbolTable, ReadRef, Relocation,
RelocationMap, Result, SectionFlags, SectionIndex, SectionKind, SegmentFlags, SubArchitecture,
SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolMapName, SymbolScope, SymbolSection,
};

/// Evaluate an expression on the contents of a file format enum.
Expand Down Expand Up @@ -787,6 +787,10 @@ impl<'data, 'file, R: ReadRef<'data>> ObjectSection<'data> for Section<'data, 'f
}
}

fn relocation_map(&self) -> Result<RelocationMap> {
with_inner!(self.inner, SectionInternal, |x| x.relocation_map())
}

fn flags(&self) -> SectionFlags {
with_inner!(self.inner, SectionInternal, |x| x.flags())
}
Expand Down
6 changes: 5 additions & 1 deletion src/read/coff/section.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::pe;
use crate::read::util::StringTable;
use crate::read::{
self, CompressedData, CompressedFileRange, Error, ObjectSection, ObjectSegment, ReadError,
ReadRef, Result, SectionFlags, SectionIndex, SectionKind, SegmentFlags,
ReadRef, RelocationMap, Result, SectionFlags, SectionIndex, SectionKind, SegmentFlags,
};

use super::{CoffFile, CoffHeader, CoffRelocationIterator};
Expand Down Expand Up @@ -384,6 +384,10 @@ impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectSection<'data>
}
}

fn relocation_map(&self) -> read::Result<RelocationMap> {
RelocationMap::new(self.file, self)
}

fn flags(&self) -> SectionFlags {
SectionFlags::Coff {
characteristics: self.section.characteristics.get(LE),
Expand Down
6 changes: 5 additions & 1 deletion src/read/elf/section.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::endian::{self, Endianness, U32Bytes};
use crate::pod::Pod;
use crate::read::{
self, Bytes, CompressedData, CompressedFileRange, CompressionFormat, Error, ObjectSection,
ReadError, ReadRef, SectionFlags, SectionIndex, SectionKind, StringTable,
ReadError, ReadRef, RelocationMap, SectionFlags, SectionIndex, SectionKind, StringTable,
};

use super::{
Expand Down Expand Up @@ -593,6 +593,10 @@ where
}
}

fn relocation_map(&self) -> read::Result<RelocationMap> {
RelocationMap::new(self.file, self)
}

fn flags(&self) -> SectionFlags {
SectionFlags::Elf {
sh_flags: self.section.sh_flags(self.file.endian).into(),
Expand Down
8 changes: 6 additions & 2 deletions src/read/macho/section.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::endian::{self, Endianness};
use crate::macho;
use crate::pod::Pod;
use crate::read::{
self, CompressedData, CompressedFileRange, ObjectSection, ReadError, ReadRef, Result,
SectionFlags, SectionIndex, SectionKind,
self, CompressedData, CompressedFileRange, ObjectSection, ReadError, ReadRef, RelocationMap,
Result, SectionFlags, SectionIndex, SectionKind,
};

use super::{MachHeader, MachOFile, MachORelocationIterator};
Expand Down Expand Up @@ -199,6 +199,10 @@ where
}
}

fn relocation_map(&self) -> read::Result<RelocationMap> {
RelocationMap::new(self.file, self)
}

fn flags(&self) -> SectionFlags {
SectionFlags::MachO {
flags: self.internal.section.flags(self.file.endian),
Expand Down
89 changes: 89 additions & 0 deletions src/read/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ use alloc::borrow::Cow;
use alloc::vec::Vec;
use core::{fmt, result};

#[cfg(not(feature = "std"))]
use alloc::collections::btree_map::BTreeMap as Map;
#[cfg(feature = "std")]
use std::collections::hash_map::HashMap as Map;

pub use crate::common::*;

mod read_ref;
Expand Down Expand Up @@ -727,6 +732,90 @@ impl Relocation {
}
}

/// A map from section offsets to relocation information.
///
/// This can be used to apply relocations to a value at a given section offset.
/// This is intended for use with DWARF in relocatable object files, and only
/// supports relocations that are used in DWARF.
///
/// Returned by [`ObjectSection::relocation_map`].
#[derive(Debug, Default)]
pub struct RelocationMap(Map<u64, RelocationMapEntry>);

impl RelocationMap {
/// Construct a new relocation map for a section.
///
/// Fails if any relocation cannot be added to the map.
/// You can manually use `add` if you need different error handling,
/// such as to list all errors or to ignore them.
pub fn new<'data, 'file, T>(file: &'file T, section: &T::Section) -> Result<Self>
where
T: Object<'data, 'file>,
{
let mut map = RelocationMap(Map::new());
for (offset, relocation) in section.relocations() {
map.add(file, offset, relocation)?;
}
Ok(map)
}

/// Add a single relocation to the map.
pub fn add<'data: 'file, 'file, T>(
&mut self,
file: &'file T,
offset: u64,
relocation: Relocation,
) -> Result<()>
where
T: Object<'data, 'file>,
{
let mut entry = RelocationMapEntry {
implicit_addend: relocation.has_implicit_addend(),
addend: relocation.addend() as u64,
};
match relocation.kind() {
RelocationKind::Absolute => match relocation.target() {
RelocationTarget::Symbol(symbol_idx) => {
let symbol = file
.symbol_by_index(symbol_idx)
.read_error("Relocation with invalid symbol")?;
entry.addend = symbol.address().wrapping_add(entry.addend);
}
_ => {
return Err(Error("Unsupported relocation target"));
}
},
_ => {
return Err(Error("Unsupported relocation type"));
}
}
if self.0.insert(offset, entry).is_some() {
return Err(Error("Multiple relocations for offset"));
}
Ok(())
}

/// Relocate a value that was read from the section at the given offset.
pub fn relocate(&self, offset: u64, value: u64) -> u64 {
if let Some(relocation) = self.0.get(&offset) {
if relocation.implicit_addend {
// Use the explicit addend too, because it may have the symbol value.
value.wrapping_add(relocation.addend)
} else {
relocation.addend
}
} else {
value
}
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
struct RelocationMapEntry {
implicit_addend: bool,
addend: u64,
}

/// A data compression format.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
Expand Down
6 changes: 5 additions & 1 deletion src/read/pe/section.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::pe;
use crate::pe::ImageSectionHeader;
use crate::read::{
self, CompressedData, CompressedFileRange, ObjectSection, ObjectSegment, ReadError, ReadRef,
Relocation, Result, SectionFlags, SectionIndex, SectionKind, SegmentFlags,
Relocation, RelocationMap, Result, SectionFlags, SectionIndex, SectionKind, SegmentFlags,
};

use super::{ImageNtHeaders, PeFile, SectionTable};
Expand Down Expand Up @@ -288,6 +288,10 @@ where
PeRelocationIterator(PhantomData)
}

fn relocation_map(&self) -> read::Result<RelocationMap> {
RelocationMap::new(self.file, self)
}

fn flags(&self) -> SectionFlags {
SectionFlags::Coff {
characteristics: self.section.characteristics.get(LE),
Expand Down
9 changes: 6 additions & 3 deletions src/read/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use alloc::vec::Vec;
use crate::endian::Endianness;
use crate::read::{
self, Architecture, CodeView, ComdatKind, CompressedData, CompressedFileRange, Export,
FileFlags, Import, ObjectKind, ObjectMap, Relocation, Result, SectionFlags, SectionIndex,
SectionKind, SegmentFlags, SubArchitecture, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap,
SymbolMapName, SymbolScope, SymbolSection,
FileFlags, Import, ObjectKind, ObjectMap, Relocation, RelocationMap, Result, SectionFlags,
SectionIndex, SectionKind, SegmentFlags, SubArchitecture, SymbolFlags, SymbolIndex, SymbolKind,
SymbolMap, SymbolMapName, SymbolScope, SymbolSection,
};

/// An object file.
Expand Down Expand Up @@ -419,6 +419,9 @@ pub trait ObjectSection<'data>: read::private::Sealed {
/// Get the relocations for this section.
fn relocations(&self) -> Self::RelocationIterator;

/// Construct a relocation map for this section.
fn relocation_map(&self) -> Result<RelocationMap>;

/// Section flags that are specific to each file format.
fn flags(&self) -> SectionFlags;
}
Expand Down
10 changes: 7 additions & 3 deletions src/read/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ use wasmparser as wp;
use crate::read::{
self, Architecture, ComdatKind, CompressedData, CompressedFileRange, Error, Export, FileFlags,
Import, NoDynamicRelocationIterator, Object, ObjectComdat, ObjectKind, ObjectSection,
ObjectSegment, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, Relocation, Result,
SectionFlags, SectionIndex, SectionKind, SegmentFlags, SymbolFlags, SymbolIndex, SymbolKind,
SymbolScope, SymbolSection,
ObjectSegment, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, Relocation, RelocationMap,
Result, SectionFlags, SectionIndex, SectionKind, SegmentFlags, SymbolFlags, SymbolIndex,
SymbolKind, SymbolScope, SymbolSection,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -737,6 +737,10 @@ impl<'data, 'file, R: ReadRef<'data>> ObjectSection<'data> for WasmSection<'data
WasmRelocationIterator(PhantomData)
}

fn relocation_map(&self) -> read::Result<RelocationMap> {
RelocationMap::new(self.file, self)
}

#[inline]
fn flags(&self) -> SectionFlags {
SectionFlags::None
Expand Down
8 changes: 6 additions & 2 deletions src/read/xcoff/section.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use core::{iter, result, slice, str};
use crate::endian::BigEndian as BE;
use crate::pod::Pod;
use crate::read::{
self, CompressedData, CompressedFileRange, Error, ObjectSection, ReadError, ReadRef, Result,
SectionFlags, SectionIndex, SectionKind,
self, CompressedData, CompressedFileRange, Error, ObjectSection, ReadError, ReadRef,
RelocationMap, Result, SectionFlags, SectionIndex, SectionKind,
};
use crate::xcoff;

Expand Down Expand Up @@ -191,6 +191,10 @@ where
}
}

fn relocation_map(&self) -> read::Result<RelocationMap> {
RelocationMap::new(self.file, self)
}

fn flags(&self) -> SectionFlags {
SectionFlags::Xcoff {
s_flags: self.section.s_flags(),
Expand Down

0 comments on commit d65bc75

Please sign in to comment.