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