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#[derive(Clone, Debug, PartialEq)]
20pub struct RelocSection {
21 name: String,
23
24 section_id: u32,
26
27 relocation_section_name: Option<String>,
29
30 entries: Vec<RelocationEntry>,
32}
33
34impl RelocSection {
35 pub fn name(&self) -> &str {
37 &self.name
38 }
39
40 pub fn name_mut(&mut self) -> &mut String {
42 &mut self.name
43 }
44
45 pub fn section_id(&self) -> u32 {
47 self.section_id
48 }
49
50 pub fn section_id_mut(&mut self) -> &mut u32 {
52 &mut self.section_id
53 }
54
55 pub fn relocation_section_name(&self) -> Option<&str> {
57 self.relocation_section_name.as_deref()
58 }
59
60 pub fn relocation_section_name_mut(&mut self) -> &mut Option<String> {
62 &mut self.relocation_section_name
63 }
64
65 pub fn entries(&self) -> &[RelocationEntry] {
67 &self.entries
68 }
69
70 pub fn entries_mut(&mut self) -> &mut Vec<RelocationEntry> {
72 &mut self.entries
73 }
74}
75
76impl RelocSection {
77 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#[derive(Clone, Copy, Debug, PartialEq)]
115pub enum RelocationEntry {
116 FunctionIndexLeb {
118 offset: u32,
120
121 index: u32,
123 },
124
125 TableIndexSleb {
127 offset: u32,
129
130 index: u32,
132 },
133
134 TableIndexI32 {
136 offset: u32,
138
139 index: u32,
141 },
142
143 MemoryAddressLeb {
145 offset: u32,
147
148 index: u32,
150
151 addend: i32,
153 },
154
155 MemoryAddressSleb {
157 offset: u32,
159
160 index: u32,
162
163 addend: i32,
165 },
166
167 MemoryAddressI32 {
169 offset: u32,
171
172 index: u32,
174
175 addend: i32,
177 },
178
179 TypeIndexLeb {
181 offset: u32,
183
184 index: u32,
186 },
187
188 GlobalIndexLeb {
190 offset: u32,
192
193 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}