susy_wasm/elements/
reloc_section.rs

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/// Relocation information.
17#[derive(Clone, Debug, PartialEq)]
18pub struct RelocSection {
19	/// Name of this section.
20	name: String,
21
22	/// ID of the section containing the relocations described in this section.
23	section_id: u32,
24
25	/// Name of the section containing the relocations described in this section. Only set if section_id is 0.
26	relocation_section_name: Option<String>,
27
28	/// Relocation entries.
29	entries: Vec<RelocationEntry>,
30}
31
32impl RelocSection {
33	/// Name of this section.
34	pub fn name(&self) -> &str {
35		&self.name
36	}
37
38	/// Name of this section (mutable).
39	pub fn name_mut(&mut self) -> &mut String {
40		&mut self.name
41	}
42
43	/// ID of the section containing the relocations described in this section.
44	pub fn section_id(&self) -> u32 {
45		self.section_id
46	}
47
48	/// ID of the section containing the relocations described in this section (mutable).
49	pub fn section_id_mut(&mut self) -> &mut u32 {
50		&mut self.section_id
51	}
52
53	/// Name of the section containing the relocations described in this section.
54	pub fn relocation_section_name(&self) -> Option<&str> {
55		self.relocation_section_name.as_ref().map(String::as_str)
56	}
57
58	/// Name of the section containing the relocations described in this section (mutable).
59	pub fn relocation_section_name_mut(&mut self) -> &mut Option<String> {
60		&mut self.relocation_section_name
61	}
62
63	/// List of relocation entries.
64	pub fn entries(&self) -> &[RelocationEntry] {
65		&self.entries
66	}
67
68	/// List of relocation entries (mutable).
69	pub fn entries_mut(&mut self) -> &mut Vec<RelocationEntry> {
70		&mut self.entries
71	}
72}
73
74impl RelocSection {
75	/// Deserialize a reloc section.
76	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/// Relocation entry.
125#[derive(Clone, Copy, Debug, PartialEq)]
126pub enum RelocationEntry {
127	/// Function index.
128	FunctionIndexLeb {
129		/// Offset of the value to rewrite.
130		offset: u32,
131
132		/// Index of the function symbol in the symbol table.
133		index: u32,
134	},
135
136	/// Function table index.
137	TableIndexSleb {
138		/// Offset of the value to rewrite.
139		offset: u32,
140
141		/// Index of the function symbol in the symbol table.
142		index: u32,
143	},
144
145	/// Function table index.
146	TableIndexI32 {
147		/// Offset of the value to rewrite.
148		offset: u32,
149
150		/// Index of the function symbol in the symbol table.
151		index: u32,
152	},
153
154	/// Linear memory index.
155	MemoryAddressLeb {
156		/// Offset of the value to rewrite.
157		offset: u32,
158
159		/// Index of the data symbol in the symbol table.
160		index: u32,
161
162		/// Addend to add to the address.
163		addend: i32,
164	},
165
166	/// Linear memory index.
167	MemoryAddressSleb {
168		/// Offset of the value to rewrite.
169		offset: u32,
170
171		/// Index of the data symbol in the symbol table.
172		index: u32,
173
174		/// Addend to add to the address.
175		addend: i32,
176	},
177
178	/// Linear memory index.
179	MemoryAddressI32 {
180		/// Offset of the value to rewrite.
181		offset: u32,
182
183		/// Index of the data symbol in the symbol table.
184		index: u32,
185
186		/// Addend to add to the address.
187		addend: i32,
188	},
189
190	/// Type table index.
191	TypeIndexLeb {
192		/// Offset of the value to rewrite.
193		offset: u32,
194
195		/// Index of the type used.
196		index: u32,
197	},
198
199	/// Global index.
200	GlobalIndexLeb {
201		/// Offset of the value to rewrite.
202		offset: u32,
203
204		/// Index of the global symbol in the symbol table.
205		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}