1 use alloc::{string::String, vec::Vec};
2 use crate::io;
3 
4 use super::{CountedList, CountedListWriter, CountedWriter, Deserialize, Error, Serialize, VarInt32, VarUint32, VarUint7};
5 
6 const FUNCTION_INDEX_LEB: u8 = 0;
7 const TABLE_INDEX_SLEB: u8 = 1;
8 const TABLE_INDEX_I32: u8 = 2;
9 const MEMORY_ADDR_LEB: u8 = 3;
10 const MEMORY_ADDR_SLEB: u8 = 4;
11 const MEMORY_ADDR_I32: u8 = 5;
12 const TYPE_INDEX_LEB: u8 = 6;
13 const GLOBAL_INDEX_LEB: u8 = 7;
14 
15 /// Relocation information.
16 #[derive(Clone, Debug, PartialEq)]
17 pub 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 
31 impl RelocSection {
32 	/// Name of this section.
name(&self) -> &str33 	pub fn name(&self) -> &str {
34 		&self.name
35 	}
36 
37 	/// Name of this section (mutable).
name_mut(&mut self) -> &mut String38 	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.
section_id(&self) -> u3243 	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).
section_id_mut(&mut self) -> &mut u3248 	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.
relocation_section_name(&self) -> Option<&str>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).
relocation_section_name_mut(&mut self) -> &mut Option<String>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.
entries(&self) -> &[RelocationEntry]63 	pub fn entries(&self) -> &[RelocationEntry] {
64 		&self.entries
65 	}
66 
67 	/// List of relocation entries (mutable).
entries_mut(&mut self) -> &mut Vec<RelocationEntry>68 	pub fn entries_mut(&mut self) -> &mut Vec<RelocationEntry> {
69 		&mut self.entries
70 	}
71 }
72 
73 impl RelocSection {
74 	/// Deserialize a reloc section.
deserialize<R: io::Read>( name: String, rdr: &mut R, ) -> Result<Self, Error>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 
100 impl Serialize for RelocSection {
101 	type Error = Error;
102 
serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error>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)]
125 pub 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 
208 impl Deserialize for RelocationEntry {
209 	type Error = Error;
210 
deserialize<R: io::Read>(rdr: &mut R) -> Result<Self, Self::Error>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 
261 impl Serialize for RelocationEntry {
262 	type Error = Error;
263 
serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error>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)]
323 mod tests {
324 	use super::super::{Section, deserialize_file};
325 	use super::RelocationEntry;
326 
327 	#[test]
reloc_section()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 }
348