tetsy_wasm/elements/
reloc_section.rs

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