Skip to content

Commit cbd87b7

Browse files
jbmsandylizi
andauthored
wasmparser: add RelocSectionReader (#1511)
Co-authored-by: Andy Li <andylizi666@gmail.com>
1 parent c4a37fb commit cbd87b7

2 files changed

Lines changed: 304 additions & 0 deletions

File tree

crates/wasmparser/src/readers/core.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mod memories;
1515
mod names;
1616
mod operators;
1717
mod producers;
18+
mod reloc;
1819
mod tables;
1920
mod tags;
2021
mod types;
@@ -36,6 +37,7 @@ pub use self::memories::*;
3637
pub use self::names::*;
3738
pub use self::operators::*;
3839
pub use self::producers::*;
40+
pub use self::reloc::*;
3941
pub use self::tables::*;
4042
pub use self::tags::*;
4143
pub use self::types::*;
Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
use std::ops::Range;
2+
3+
use crate::{BinaryReader, FromReader, Result, SectionLimited};
4+
5+
/// Reader for relocation entries within a `reloc.*` section.
6+
pub type RelocationEntryReader<'a> = SectionLimited<'a, RelocationEntry>;
7+
8+
/// Reader for reloc.* sections as defined by
9+
/// https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md#relocation-sections.
10+
#[derive(Debug, Clone)]
11+
pub struct RelocSectionReader<'a> {
12+
section: u32,
13+
range: Range<usize>,
14+
entries: SectionLimited<'a, RelocationEntry>,
15+
}
16+
17+
impl<'a> RelocSectionReader<'a> {
18+
/// Creates a new reader for a `reloc.*` section starting at
19+
/// `original_position` within the wasm file.
20+
pub fn new(data: &'a [u8], original_position: usize) -> Result<Self> {
21+
let mut reader = BinaryReader::new_with_offset(data, original_position);
22+
let range = reader.range().clone();
23+
let section = reader.read_var_u32()?;
24+
Ok(Self {
25+
section,
26+
range,
27+
entries: SectionLimited::new(reader.remaining_buffer(), reader.original_position())?,
28+
})
29+
}
30+
31+
/// Index of section to which the relocations apply.
32+
pub fn section_index(&self) -> u32 {
33+
self.section
34+
}
35+
36+
/// The byte range of the entire section.
37+
pub fn range(&self) -> Range<usize> {
38+
self.range.clone()
39+
}
40+
41+
/// The relocation entries.
42+
pub fn entries(&self) -> SectionLimited<'a, RelocationEntry> {
43+
self.entries.clone()
44+
}
45+
}
46+
47+
macro_rules! back_to_enum {
48+
($(#[$meta:meta])+ $vis:vis enum $name:ident {
49+
$($(#[$vmeta:meta])* $vname:ident $(= $val:expr)?,)*
50+
}) => {
51+
$(#[$meta])*
52+
$vis enum $name {
53+
$($(#[$vmeta])* $vname $(= $val)?,)*
54+
}
55+
56+
impl std::convert::TryFrom<u8> for $name {
57+
type Error = ();
58+
59+
fn try_from(v: u8) -> Result<Self, Self::Error> {
60+
match v {
61+
$(x if x == $name::$vname as u8 => Ok($name::$vname),)*
62+
_ => Err(()),
63+
}
64+
}
65+
}
66+
}
67+
}
68+
69+
back_to_enum! {
70+
71+
/// Relocation entry type. Each entry type corresponds to one of the
72+
/// `R_WASM_*` constants defined at
73+
/// https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/BinaryFormat/WasmRelocs.def
74+
/// and
75+
/// https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md#relocation-sections.
76+
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
77+
#[repr(u8)]
78+
pub enum RelocationType {
79+
/// A function index encoded as a 5-byte varuint32. Used for the
80+
/// immediate argument of a call instruction. (since LLVM 10.0)
81+
FunctionIndexLeb = 0,
82+
83+
/// A function table index encoded as a 5-byte varint32. Used to refer
84+
/// to the immediate argument of a i32.const instruction, e.g. taking
85+
/// the address of a function. (since LLVM 10.0)
86+
TableIndexSleb = 1,
87+
88+
/// A function table index encoded as a uint32, e.g. taking the address
89+
/// of a function in a static data initializer. (since LLVM 10.0)
90+
TableIndexI32 = 2,
91+
92+
/// A linear memory index encoded as a 5-byte varuint32. Used for the
93+
/// immediate argument of a load or store instruction, e.g. directly
94+
/// loading from or storing to a C++ global. (since LLVM 10.0)
95+
MemoryAddrLeb = 3,
96+
97+
/// A linear memory index encoded as a 5-byte varint32. Used for the
98+
/// immediate argument of a i32.const instruction, e.g. taking the
99+
/// address of a C++ global. (since LLVM 10.0)
100+
MemoryAddrSleb = 4,
101+
102+
/// A linear memory index encoded as a uint32, e.g. taking the address
103+
/// of a C++ global in a static data initializer. (since LLVM 10.0)
104+
MemoryAddrI32 = 5,
105+
106+
/// A type index encoded as a 5-byte varuint32, e.g. the type immediate
107+
/// in a call_indirect. (since LLVM 10.0)
108+
TypeIndexLeb = 6,
109+
110+
/// A global index encoded as a 5-byte varuint32, e.g. the index
111+
/// immediate in a get_global. (since LLVM 10.0)
112+
GlobalIndexLeb = 7,
113+
114+
/// A byte offset within code section for the specific function encoded
115+
/// as a uint32. The offsets start at the actual function code excluding
116+
/// its size field. (since LLVM 10.0)
117+
FunctionOffsetI32 = 8,
118+
119+
/// A byte offset from start of the specified section encoded as a
120+
/// uint32. (since LLVM 10.0)
121+
SectionOffsetI32 = 9,
122+
123+
/// An event index encoded as a 5-byte varuint32. Used for the immediate
124+
/// argument of a throw and if_except instruction. (since LLVM 10.0)
125+
EventIndexLeb = 10,
126+
127+
/// A memory address relative to the __memory_base wasm global. Used in
128+
/// position independent code (-fPIC) where absolute memory addresses
129+
/// are not known at link time.
130+
MemoryAddrRelSleb = 11,
131+
132+
/// A function address (table index) relative to the __table_base wasm
133+
/// global. Used in position indepenent code (-fPIC) where absolute
134+
/// function addresses are not known at link time.
135+
TableIndexRelSleb = 12,
136+
137+
/// A global index encoded as uint32. (since LLVM 11.0)
138+
GlobalIndexI32 = 13,
139+
140+
/// The 64-bit counterpart of `MemoryAddrLeb`. A 64-bit linear memory
141+
/// index encoded as a 10-byte varuint64, Used for the immediate
142+
/// argument of a load or store instruction on a 64-bit linear memory
143+
/// array. (since LLVM 11.0)
144+
MemoryAddrLeb64 = 14,
145+
146+
/// The 64-bit counterpart of `MemoryAddrSleb`. A 64-bit linear memory
147+
/// index encoded as a 10-byte varint64. Used for the immediate argument
148+
/// of a i64.const instruction. (since LLVM 11.0)
149+
MemoryAddrSleb64 = 15,
150+
151+
/// The 64-bit counterpart of `MemoryAddrI32`. A 64-bit linear memory
152+
/// index encoded as a uint64, e.g. taking the 64-bit address of a C++
153+
/// global in a static data initializer. (since LLVM 11.0)
154+
MemoryAddrI64 = 16,
155+
156+
/// The 64-bit counterpart of `MemoryAddrRelSleb`.
157+
MemoryAddrRelSleb64 = 17,
158+
159+
/// The 64-bit counterpart of `TableIndexSleb`. A function table index
160+
/// encoded as a 10-byte varint64. Used to refer to the immediate
161+
/// argument of a i64.const instruction, e.g. taking the address of a
162+
/// function in Wasm64. (in LLVM 12.0)
163+
TableIndexSleb64 = 18,
164+
165+
/// The 64-bit counterpart of `TableIndexI32`. A function table index
166+
/// encoded as a uint64, e.g. taking the address of a function in a
167+
/// static data initializer. (in LLVM 12.0)
168+
TableIndexI64 = 19,
169+
170+
/// A table number encoded as a 5-byte varuint32. Used for the table
171+
/// immediate argument in the table.* instructions. (in LLVM 12.0)
172+
TableNumberLeb = 20,
173+
174+
/// An offset from the __tls_base symbol encoded as a 5-byte [varint32].
175+
/// Used for PIC case to avoid absolute relocation. (in LLVM 12.0)
176+
MemoryAddrTlsSleb = 21,
177+
178+
/// The 64-bit counterpart of `FunctionOffsetI32`. A byte offset within
179+
/// code section for the specific function encoded as a uint64. (in LLVM
180+
/// 12.0)
181+
FunctionOffsetI64 = 22,
182+
183+
/// A byte offset between the relocating address and a linear memory
184+
/// index encoded as a uint32. Used for pointer-relative addressing. (in
185+
/// LLVM 13.0)
186+
MemoryAddrLocrelI32 = 23,
187+
188+
/// The 64-bit counterpart of `TableIndexRelSleb`. A function table
189+
/// index encoded as a 10-byte varint64. (in LLVM 13.0)
190+
TableIndexRelSleb64 = 24,
191+
192+
/// The 64-bit counterpart of `MemoryAddrTlsSleb`. (in LLVM 13.0)
193+
MemoryAddrTlsSleb64 = 25,
194+
195+
/// A function index encoded as a uint32. Used in custom sections for
196+
/// function annotations (__attribute__((annotate(<name>))) (in LLVM
197+
/// 17.0)
198+
FunctionIndexI32 = 26,
199+
}
200+
201+
}
202+
203+
impl<'a> FromReader<'a> for RelocationType {
204+
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
205+
let num = reader.read_u8()?;
206+
num.try_into().or_else(|_| {
207+
Err(BinaryReader::invalid_leading_byte_error(
208+
num,
209+
"RelocEntryType",
210+
reader.original_position() - 1,
211+
))
212+
})
213+
}
214+
}
215+
216+
/// Indicates the kind of addend that applies to a relocation entry.
217+
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
218+
pub enum RelocAddendKind {
219+
/// Relocation entry does not include an addend.
220+
None,
221+
/// Relocation entry includes a 32-bit addend.
222+
Addend32,
223+
/// Relocation entry includes a 64-bit addend.
224+
Addend64,
225+
}
226+
227+
/// Single relocation entry within a `reloc.*` section, as defined at
228+
/// https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md#relocation-sections.
229+
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
230+
pub struct RelocationEntry {
231+
/// Relocation entry type.
232+
pub ty: RelocationType,
233+
/// Offset in bytes from the start of the section indicated by
234+
/// `RelocSectionReader::section` targetted by this relocation.
235+
pub offset: u32,
236+
/// Index in the symbol table contained in the linking section that
237+
/// corresponds to the value at `offset`.
238+
pub index: u32,
239+
/// Addend to add to the address, or `0` if not applicable. The value must
240+
/// be consistent with the `self.ty.addend_kind()`.
241+
pub addend: i64,
242+
}
243+
244+
impl RelocationEntry {
245+
/// Byte range relative to the start of the section indicated by
246+
/// `RelocSectionReader::section` targetted by this relocation.
247+
pub fn relocation_range(&self) -> Range<usize> {
248+
(self.offset as usize)..(self.offset as usize + self.ty.extent())
249+
}
250+
}
251+
252+
impl RelocationType {
253+
/// Indicates if this relocation type has an associated `RelocEntry::addend`.
254+
pub const fn addend_kind(self: Self) -> RelocAddendKind {
255+
use RelocationType::*;
256+
match self {
257+
MemoryAddrLeb | MemoryAddrSleb | MemoryAddrI32 | FunctionOffsetI32
258+
| SectionOffsetI32 | MemoryAddrLocrelI32 | MemoryAddrRelSleb | MemoryAddrTlsSleb => {
259+
RelocAddendKind::Addend32
260+
}
261+
MemoryAddrRelSleb64 | MemoryAddrTlsSleb64 | MemoryAddrLeb64 | MemoryAddrSleb64
262+
| MemoryAddrI64 | FunctionOffsetI64 => RelocAddendKind::Addend64,
263+
_ => RelocAddendKind::None,
264+
}
265+
}
266+
267+
/// Indicates the number of bytes that this relocation type targets.
268+
pub const fn extent(self) -> usize {
269+
use RelocationType::*;
270+
match self {
271+
FunctionIndexLeb | TableIndexSleb | MemoryAddrLeb | MemoryAddrSleb | TypeIndexLeb
272+
| GlobalIndexLeb | EventIndexLeb | MemoryAddrRelSleb | TableIndexRelSleb
273+
| TableNumberLeb | MemoryAddrTlsSleb => 5,
274+
MemoryAddrLeb64 | MemoryAddrSleb64 | TableIndexSleb64 | TableIndexRelSleb64
275+
| MemoryAddrRelSleb64 | MemoryAddrTlsSleb64 => 10,
276+
277+
TableIndexI32 | MemoryAddrI32 | FunctionOffsetI32 | SectionOffsetI32
278+
| GlobalIndexI32 | MemoryAddrLocrelI32 | FunctionIndexI32 => 4,
279+
280+
MemoryAddrI64 | TableIndexI64 | FunctionOffsetI64 => 8,
281+
}
282+
}
283+
}
284+
285+
impl<'a> FromReader<'a> for RelocationEntry {
286+
fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
287+
let ty = RelocationType::from_reader(reader)?;
288+
let offset = reader.read_var_u32()?;
289+
let index = reader.read_var_u32()?;
290+
let addend = match ty.addend_kind() {
291+
RelocAddendKind::None => 0,
292+
RelocAddendKind::Addend32 => reader.read_var_i32()? as i64,
293+
RelocAddendKind::Addend64 => reader.read_var_i64()?,
294+
};
295+
Ok(RelocationEntry {
296+
ty,
297+
offset,
298+
index,
299+
addend,
300+
})
301+
}
302+
}

0 commit comments

Comments
 (0)