mirror of
https://github.com/encounter/object.git
synced 2026-03-30 11:32:22 -07:00
read: add ObjectSection::relocation_map (#654)
This is intended to handle relocations for DWARF.
This commit is contained in:
+7
-3
@@ -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.
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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};
|
||||
@@ -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),
|
||||
|
||||
@@ -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::{
|
||||
@@ -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(),
|
||||
|
||||
@@ -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};
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
@@ -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]
|
||||
|
||||
@@ -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};
|
||||
@@ -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),
|
||||
|
||||
+6
-3
@@ -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.
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+7
-3
@@ -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)]
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(),
|
||||
|
||||
Reference in New Issue
Block a user