1use alloc::{string::String, vec::Vec};
2use crate::io;
3
4use super::{CountedList, CountedListWriter, CountedWriter, Deserialize, Error, Serialize, VarInt32, VarUint32, VarUint7};
5
6const FUNCTION_INDEX_LEB: u8 = 0;
7const TABLE_INDEX_SLEB: u8 = 1;
8const TABLE_INDEX_I32: u8 = 2;
9const MEMORY_ADDR_LEB: u8 = 3;
10const MEMORY_ADDR_SLEB: u8 = 4;
11const MEMORY_ADDR_I32: u8 = 5;
12const TYPE_INDEX_LEB: u8 = 6;
13const GLOBAL_INDEX_LEB: u8 = 7;
14
15#[derive(Clone, Debug, PartialEq)]
17pub struct RelocSection {
18 name: String,
20
21 section_id: u32,
23
24 relocation_section_name: Option<String>,
26
27 entries: Vec<RelocationEntry>,
29}
30
31impl RelocSection {
32 pub fn name(&self) -> &str {
34 &self.name
35 }
36
37 pub fn name_mut(&mut self) -> &mut String {
39 &mut self.name
40 }
41
42 pub fn section_id(&self) -> u32 {
44 self.section_id
45 }
46
47 pub fn section_id_mut(&mut self) -> &mut u32 {
49 &mut self.section_id
50 }
51
52 pub fn relocation_section_name(&self) -> Option<&str> {
54 self.relocation_section_name.as_ref().map(String::as_str)
55 }
56
57 pub fn relocation_section_name_mut(&mut self) -> &mut Option<String> {
59 &mut self.relocation_section_name
60 }
61
62 pub fn entries(&self) -> &[RelocationEntry] {
64 &self.entries
65 }
66
67 pub fn entries_mut(&mut self) -> &mut Vec<RelocationEntry> {
69 &mut self.entries
70 }
71}
72
73impl RelocSection {
74 pub fn deserialize<R: io::Read>(
76 name: String,
77 rdr: &mut R,
78 ) -> Result<Self, Error> {
79 let section_id = VarUint32::deserialize(rdr)?.into();
80
81 let relocation_section_name =
82 if section_id == 0 {
83 Some(String::deserialize(rdr)?)
84 }
85 else {
86 None
87 };
88
89 let entries = CountedList::deserialize(rdr)?.into_inner();
90
91 Ok(RelocSection {
92 name,
93 section_id,
94 relocation_section_name,
95 entries,
96 })
97 }
98}
99
100impl Serialize for RelocSection {
101 type Error = Error;
102
103 fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
104 let mut counted_writer = CountedWriter::new(wtr);
105
106 self.name.serialize(&mut counted_writer)?;
107
108 VarUint32::from(self.section_id).serialize(&mut counted_writer)?;
109
110 if let Some(relocation_section_name) = self.relocation_section_name {
111 relocation_section_name.serialize(&mut counted_writer)?;
112 }
113
114 let counted_list = CountedListWriter(self.entries.len(), self.entries.into_iter());
115 counted_list.serialize(&mut counted_writer)?;
116
117 counted_writer.done()?;
118
119 Ok(())
120 }
121}
122
123#[derive(Clone, Copy, Debug, PartialEq)]
125pub enum RelocationEntry {
126 FunctionIndexLeb {
128 offset: u32,
130
131 index: u32,
133 },
134
135 TableIndexSleb {
137 offset: u32,
139
140 index: u32,
142 },
143
144 TableIndexI32 {
146 offset: u32,
148
149 index: u32,
151 },
152
153 MemoryAddressLeb {
155 offset: u32,
157
158 index: u32,
160
161 addend: i32,
163 },
164
165 MemoryAddressSleb {
167 offset: u32,
169
170 index: u32,
172
173 addend: i32,
175 },
176
177 MemoryAddressI32 {
179 offset: u32,
181
182 index: u32,
184
185 addend: i32,
187 },
188
189 TypeIndexLeb {
191 offset: u32,
193
194 index: u32,
196 },
197
198 GlobalIndexLeb {
200 offset: u32,
202
203 index: u32,
205 },
206}
207
208impl Deserialize for RelocationEntry {
209 type Error = Error;
210
211 fn deserialize<R: io::Read>(rdr: &mut R) -> Result<Self, Self::Error> {
212 match VarUint7::deserialize(rdr)?.into() {
213 FUNCTION_INDEX_LEB => Ok(RelocationEntry::FunctionIndexLeb {
214 offset: VarUint32::deserialize(rdr)?.into(),
215 index: VarUint32::deserialize(rdr)?.into(),
216 }),
217
218 TABLE_INDEX_SLEB => Ok(RelocationEntry::TableIndexSleb {
219 offset: VarUint32::deserialize(rdr)?.into(),
220 index: VarUint32::deserialize(rdr)?.into(),
221 }),
222
223 TABLE_INDEX_I32 => Ok(RelocationEntry::TableIndexI32 {
224 offset: VarUint32::deserialize(rdr)?.into(),
225 index: VarUint32::deserialize(rdr)?.into(),
226 }),
227
228 MEMORY_ADDR_LEB => Ok(RelocationEntry::MemoryAddressLeb {
229 offset: VarUint32::deserialize(rdr)?.into(),
230 index: VarUint32::deserialize(rdr)?.into(),
231 addend: VarInt32::deserialize(rdr)?.into(),
232 }),
233
234 MEMORY_ADDR_SLEB => Ok(RelocationEntry::MemoryAddressSleb {
235 offset: VarUint32::deserialize(rdr)?.into(),
236 index: VarUint32::deserialize(rdr)?.into(),
237 addend: VarInt32::deserialize(rdr)?.into(),
238 }),
239
240 MEMORY_ADDR_I32 => Ok(RelocationEntry::MemoryAddressI32 {
241 offset: VarUint32::deserialize(rdr)?.into(),
242 index: VarUint32::deserialize(rdr)?.into(),
243 addend: VarInt32::deserialize(rdr)?.into(),
244 }),
245
246 TYPE_INDEX_LEB => Ok(RelocationEntry::TypeIndexLeb {
247 offset: VarUint32::deserialize(rdr)?.into(),
248 index: VarUint32::deserialize(rdr)?.into(),
249 }),
250
251 GLOBAL_INDEX_LEB => Ok(RelocationEntry::GlobalIndexLeb {
252 offset: VarUint32::deserialize(rdr)?.into(),
253 index: VarUint32::deserialize(rdr)?.into(),
254 }),
255
256 entry_type => Err(Error::UnknownValueType(entry_type as i8)),
257 }
258 }
259}
260
261impl Serialize for RelocationEntry {
262 type Error = Error;
263
264 fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
265 match self {
266 RelocationEntry::FunctionIndexLeb { offset, index } => {
267 VarUint7::from(FUNCTION_INDEX_LEB).serialize(wtr)?;
268 VarUint32::from(offset).serialize(wtr)?;
269 VarUint32::from(index).serialize(wtr)?;
270 },
271
272 RelocationEntry::TableIndexSleb { offset, index } => {
273 VarUint7::from(TABLE_INDEX_SLEB).serialize(wtr)?;
274 VarUint32::from(offset).serialize(wtr)?;
275 VarUint32::from(index).serialize(wtr)?;
276 },
277
278 RelocationEntry::TableIndexI32 { offset, index } => {
279 VarUint7::from(TABLE_INDEX_I32).serialize(wtr)?;
280 VarUint32::from(offset).serialize(wtr)?;
281 VarUint32::from(index).serialize(wtr)?;
282 },
283
284 RelocationEntry::MemoryAddressLeb { offset, index, addend } => {
285 VarUint7::from(MEMORY_ADDR_LEB).serialize(wtr)?;
286 VarUint32::from(offset).serialize(wtr)?;
287 VarUint32::from(index).serialize(wtr)?;
288 VarInt32::from(addend).serialize(wtr)?;
289 },
290
291 RelocationEntry::MemoryAddressSleb { offset, index, addend } => {
292 VarUint7::from(MEMORY_ADDR_SLEB).serialize(wtr)?;
293 VarUint32::from(offset).serialize(wtr)?;
294 VarUint32::from(index).serialize(wtr)?;
295 VarInt32::from(addend).serialize(wtr)?;
296 },
297
298 RelocationEntry::MemoryAddressI32 { offset, index, addend } => {
299 VarUint7::from(MEMORY_ADDR_I32).serialize(wtr)?;
300 VarUint32::from(offset).serialize(wtr)?;
301 VarUint32::from(index).serialize(wtr)?;
302 VarInt32::from(addend).serialize(wtr)?;
303 },
304
305 RelocationEntry::TypeIndexLeb { offset, index } => {
306 VarUint7::from(TYPE_INDEX_LEB).serialize(wtr)?;
307 VarUint32::from(offset).serialize(wtr)?;
308 VarUint32::from(index).serialize(wtr)?;
309 },
310
311 RelocationEntry::GlobalIndexLeb { offset, index } => {
312 VarUint7::from(GLOBAL_INDEX_LEB).serialize(wtr)?;
313 VarUint32::from(offset).serialize(wtr)?;
314 VarUint32::from(index).serialize(wtr)?;
315 },
316 }
317
318 Ok(())
319 }
320}
321
322#[cfg(test)]
323mod tests {
324 use super::super::{Section, deserialize_file};
325 use super::RelocationEntry;
326
327 #[test]
328 fn reloc_section() {
329 let module =
330 deserialize_file("./res/cases/v1/relocatable.wasm").expect("Module should be deserialized")
331 .parse_reloc().expect("Reloc section should be deserialized");
332 let mut found = false;
333 for section in module.sections() {
334 match *section {
335 Section::Reloc(ref reloc_section) => {
336 assert_eq!(vec![
337 RelocationEntry::MemoryAddressSleb { offset: 4, index: 0, addend: 0 },
338 RelocationEntry::FunctionIndexLeb { offset: 12, index: 0 },
339 ], reloc_section.entries());
340 found = true
341 },
342 _ => { }
343 }
344 }
345 assert!(found, "There should be a reloc section in relocatable.wasm");
346 }
347}