read/wasm: Implement reloc.* section reading (#895)

This commit is contained in:
lapla
2026-05-11 12:14:57 +09:00
committed by GitHub
parent 8cf8be5c51
commit 5b53725e35
3 changed files with 93 additions and 9 deletions
@@ -22,6 +22,14 @@ Symbols
4: Symbol { name: "main", address: 5e, size: f, kind: Text, section: Section(SectionIndex(a)), scope: Linkage, weak: false, flags: None }
5: Symbol { name: "__main_void", address: 2, size: 5b, kind: Text, section: Section(SectionIndex(a)), scope: Dynamic, weak: false, flags: None }
<code> relocations
(6, Relocation { kind: Unknown, encoding: Generic, size: 28, target: Symbol(SymbolIndex(1)), addend: 0, implicit_addend: false, flags: Wasm { r_type: 7 } })
(1b, Relocation { kind: Unknown, encoding: Generic, size: 28, target: Symbol(SymbolIndex(1)), addend: 0, implicit_addend: false, flags: Wasm { r_type: 7 } })
(2c, Relocation { kind: Unknown, encoding: Generic, size: 28, target: Symbol(SymbolIndex(2)), addend: 0, implicit_addend: false, flags: Wasm { r_type: 4 } })
(3c, Relocation { kind: Unknown, encoding: Generic, size: 28, target: Symbol(SymbolIndex(3)), addend: 0, implicit_addend: false, flags: Wasm { r_type: 0 } })
(54, Relocation { kind: Unknown, encoding: Generic, size: 28, target: Symbol(SymbolIndex(1)), addend: 0, implicit_addend: false, flags: Wasm { r_type: 7 } })
(62, Relocation { kind: Unknown, encoding: Generic, size: 28, target: Symbol(SymbolIndex(0)), addend: 0, implicit_addend: false, flags: Wasm { r_type: 0 } })
Dynamic symbols
Symbol map
+6
View File
@@ -764,6 +764,12 @@ pub enum RelocationFlags {
/// `r_rsize` field in the XCOFF relocation.
r_rsize: u8,
},
/// Wasm relocation fields.
#[cfg(feature = "wasm")]
Wasm {
/// Relocation type (the `R_WASM_*` constant).
r_type: u8,
},
}
/// Wrapper to print as `[..]` without a manual `Debug` implementation, rather than dumping an
+79 -9
View File
@@ -16,6 +16,7 @@ use crate::read::{
RelocationMap, Result, SectionFlags, SectionIndex, SectionKind, SegmentFlags, SymbolFlags,
SymbolIndex, SymbolKind, SymbolScope, SymbolSection,
};
use crate::{RelocationEncoding, RelocationFlags, RelocationKind, RelocationTarget};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(usize)]
@@ -47,6 +48,8 @@ pub struct WasmFile<'data, R = &'data [u8]> {
sections: Vec<SectionHeader<'data>>,
// Indices into `sections` of sections with a non-zero id.
id_sections: Box<[Option<usize>; MAX_SECTION_ID + 1]>,
// Parsed `reloc.*` custom sections, keyed by the binary index of the target section.
relocations: Vec<RelocSection>,
// Whether the file has DWARF information.
has_debug_symbols: bool,
// Symbols collected from imports, exports, code and name sections.
@@ -56,11 +59,18 @@ pub struct WasmFile<'data, R = &'data [u8]> {
marker: PhantomData<R>,
}
#[derive(Debug)]
struct RelocSection {
target: u32,
entries: Vec<wp::RelocationEntry>,
}
#[derive(Debug)]
struct SectionHeader<'data> {
id: SectionId,
range: Range<usize>,
name: &'data str,
binary_index: u32,
}
#[derive(Clone)]
@@ -87,6 +97,7 @@ impl<'data, R: ReadRef<'data>> WasmFile<'data, R> {
has_memory64: false,
sections: Vec::new(),
id_sections: Default::default(),
relocations: Vec::new(),
has_debug_symbols: false,
symbols: Vec::new(),
entry: 0,
@@ -213,6 +224,18 @@ impl<'data, R: ReadRef<'data>> WasmFile<'data, R> {
symbols = Some(s);
}
}
} else if name.strip_prefix("reloc.").is_some() {
// https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md#relocation-sections
let reader = wp::BinaryReader::new(section.data(), section.data_offset());
let reloc = wp::RelocSectionReader::new(reader)
.read_error("Invalid Wasm reloc section")?;
let target = reloc.section_index();
let mut entries = Vec::new();
for entry in reloc.entries() {
let entry = entry.read_error("Invalid Wasm reloc entry")?;
entries.push(entry);
}
file.relocations.push(RelocSection { target, entries });
} else if name.starts_with(".debug_") {
file.has_debug_symbols = true;
}
@@ -509,7 +532,13 @@ impl<'data, R: ReadRef<'data>> WasmFile<'data, R> {
}
fn add_section(&mut self, id: SectionId, range: Range<usize>, name: &'data str) {
let section = SectionHeader { id, range, name };
let binary_index = self.sections.len() as u32;
let section = SectionHeader {
id,
range,
name,
binary_index,
};
self.id_sections[id as usize] = Some(self.sections.len());
self.sections.push(section);
}
@@ -920,7 +949,12 @@ impl<'data, 'file, R: ReadRef<'data>> ObjectSection<'data> for WasmSection<'data
#[inline]
fn relocations(&self) -> WasmRelocationIterator<'data, 'file, R> {
WasmRelocationIterator(PhantomData)
WasmRelocationIterator {
target: self.section.binary_index,
sections: self.file.relocations.iter(),
entries: [].iter(),
marker: PhantomData,
}
}
fn relocation_map(&self) -> read::Result<RelocationMap> {
@@ -1154,18 +1188,54 @@ impl<'data, 'file> ObjectSymbol<'data> for WasmSymbol<'data, 'file> {
}
/// An iterator for the relocations for a [`WasmSection`].
///
/// This is a stub that doesn't implement any functionality.
#[derive(Debug)]
pub struct WasmRelocationIterator<'data, 'file, R = &'data [u8]>(
PhantomData<(&'data (), &'file (), R)>,
);
pub struct WasmRelocationIterator<'data, 'file, R = &'data [u8]> {
/// Binary index of the wasm section we are iterating relocations for.
target: u32,
/// Remaining `reloc.*` sections that may target this section.
sections: slice::Iter<'file, RelocSection>,
/// Remaining entries from the current matching `reloc.*` section.
entries: slice::Iter<'file, wp::RelocationEntry>,
marker: PhantomData<(&'data (), R)>,
}
impl<'data, 'file, R> Iterator for WasmRelocationIterator<'data, 'file, R> {
type Item = (u64, Relocation);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
None
let entry = loop {
if let Some(entry) = self.entries.next() {
break *entry;
}
let next = self.sections.find(|r| r.target == self.target)?;
self.entries = next.entries.iter();
};
let r_type = entry.ty as u8;
// Number of bits the relocation patches in the target section.
let size = (entry.ty.extent() * 8) as u8;
// For `R_WASM_TYPE_INDEX_LEB`, the `index` field refers to the type section, not the symbol table.
let (target, addend) = if entry.ty == wp::RelocationType::TypeIndexLeb {
(
RelocationTarget::Section(SectionIndex(SectionId::Type as usize)),
entry.index as i64,
)
} else {
(
RelocationTarget::Symbol(SymbolIndex(entry.index as usize)),
entry.addend,
)
};
let relocation = Relocation {
kind: RelocationKind::Unknown,
encoding: RelocationEncoding::Generic,
size,
target,
subtractor: None,
// Wasm relocation entries always carry an explicit addend.
implicit_addend: false,
addend,
flags: RelocationFlags::Wasm { r_type },
};
Some((entry.offset as u64, relocation))
}
}