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