parity_wasm/elements/
reloc_section.rs

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