1 //! Definitions of runtime structures and metadata which are serialized into ELF 2 //! with `postcard` as part of a module's compilation process. 3 4 use crate::prelude::*; 5 use crate::{ 6 CompiledModuleInfo, DebugInfoData, FunctionName, MemoryInitialization, Metadata, 7 ModuleTranslation, Tunables, obj, 8 }; 9 use anyhow::{Result, bail}; 10 use object::SectionKind; 11 use object::write::{Object, SectionId, StandardSegment, WritableBuffer}; 12 use std::ops::Range; 13 14 /// Helper structure to create an ELF file as a compilation artifact. 15 /// 16 /// This structure exposes the process which Wasmtime will encode a core wasm 17 /// module into an ELF file, notably managing data sections and all that good 18 /// business going into the final file. 19 pub struct ObjectBuilder<'a> { 20 /// The `object`-crate-defined ELF file write we're using. 21 obj: Object<'a>, 22 23 /// General compilation configuration. 24 tunables: &'a Tunables, 25 26 /// The section identifier for "rodata" which is where wasm data segments 27 /// will go. 28 data: SectionId, 29 30 /// The section identifier for function name information, or otherwise where 31 /// the `name` custom section of wasm is copied into. 32 /// 33 /// This is optional and lazily created on demand. 34 names: Option<SectionId>, 35 36 /// The section identifier for dwarf information copied from the original 37 /// wasm files. 38 /// 39 /// This is optional and lazily created on demand. 40 dwarf: Option<SectionId>, 41 } 42 43 impl<'a> ObjectBuilder<'a> { 44 /// Creates a new builder for the `obj` specified. 45 pub fn new(mut obj: Object<'a>, tunables: &'a Tunables) -> ObjectBuilder<'a> { 46 let data = obj.add_section( 47 obj.segment_name(StandardSegment::Data).to_vec(), 48 obj::ELF_WASM_DATA.as_bytes().to_vec(), 49 SectionKind::ReadOnlyData, 50 ); 51 ObjectBuilder { 52 obj, 53 tunables, 54 data, 55 names: None, 56 dwarf: None, 57 } 58 } 59 60 /// Insert the wasm raw wasm-based debuginfo into the output. 61 /// Note that this is distinct from the native debuginfo 62 /// possibly generated by the native compiler, hence these sections 63 /// getting wasm-specific names. 64 pub fn push_debuginfo( 65 &mut self, 66 dwarf: &mut Vec<(u8, Range<u64>)>, 67 debuginfo: &DebugInfoData<'_>, 68 ) { 69 self.push_debug(dwarf, &debuginfo.dwarf.debug_abbrev); 70 self.push_debug(dwarf, &debuginfo.dwarf.debug_addr); 71 self.push_debug(dwarf, &debuginfo.dwarf.debug_aranges); 72 self.push_debug(dwarf, &debuginfo.dwarf.debug_info); 73 self.push_debug(dwarf, &debuginfo.dwarf.debug_line); 74 self.push_debug(dwarf, &debuginfo.dwarf.debug_line_str); 75 self.push_debug(dwarf, &debuginfo.dwarf.debug_str); 76 self.push_debug(dwarf, &debuginfo.dwarf.debug_str_offsets); 77 self.push_debug(dwarf, &debuginfo.debug_ranges); 78 self.push_debug(dwarf, &debuginfo.debug_rnglists); 79 self.push_debug(dwarf, &debuginfo.debug_cu_index); 80 81 // Sort this for binary-search-lookup later in `symbolize_context`. 82 dwarf.sort_by_key(|(id, _)| *id); 83 } 84 85 /// Completes compilation of the `translation` specified, inserting 86 /// everything necessary into the `Object` being built. 87 /// 88 /// This function will consume the final results of compiling a wasm module 89 /// and finish the ELF image in-progress as part of `self.obj` by appending 90 /// any compiler-agnostic sections. 91 /// 92 /// The auxiliary `CompiledModuleInfo` structure returned here has also been 93 /// serialized into the object returned, but if the caller will quickly 94 /// turn-around and invoke `CompiledModule::from_artifacts` after this then 95 /// the information can be passed to that method to avoid extra 96 /// deserialization. This is done to avoid a serialize-then-deserialize for 97 /// API calls like `Module::new` where the compiled module is immediately 98 /// going to be used. 99 /// 100 /// The various arguments here are: 101 /// 102 /// * `translation` - the core wasm translation that's being completed. 103 /// 104 /// * `funcs` - compilation metadata about functions within the translation 105 /// as well as where the functions are located in the text section and any 106 /// associated trampolines. 107 /// 108 /// * `wasm_to_array_trampolines` - list of all trampolines necessary for 109 /// Wasm callers calling array callees (e.g. `Func::wrap`). One for each 110 /// function signature in the module. Must be sorted by `SignatureIndex`. 111 /// 112 /// Returns the `CompiledModuleInfo` corresponding to this core Wasm module 113 /// as a result of this append operation. This is then serialized into the 114 /// final artifact by the caller. 115 pub fn append(&mut self, translation: ModuleTranslation<'_>) -> Result<CompiledModuleInfo> { 116 let ModuleTranslation { 117 mut module, 118 debuginfo, 119 has_unparsed_debuginfo, 120 data, 121 data_align, 122 passive_data, 123 .. 124 } = translation; 125 126 // Place all data from the wasm module into a section which will the 127 // source of the data later at runtime. This additionally keeps track of 128 // the offset of 129 let mut total_data_len = 0; 130 let data_offset = self 131 .obj 132 .append_section_data(self.data, &[], data_align.unwrap_or(1)); 133 for (i, data) in data.iter().enumerate() { 134 // The first data segment has its alignment specified as the alignment 135 // for the entire section, but everything afterwards is adjacent so it 136 // has alignment of 1. 137 let align = if i == 0 { data_align.unwrap_or(1) } else { 1 }; 138 self.obj.append_section_data(self.data, data, align); 139 total_data_len += data.len(); 140 } 141 for data in passive_data.iter() { 142 self.obj.append_section_data(self.data, data, 1); 143 } 144 145 // If any names are present in the module then the `ELF_NAME_DATA` section 146 // is create and appended. 147 let mut func_names = Vec::new(); 148 if debuginfo.name_section.func_names.len() > 0 { 149 let name_id = *self.names.get_or_insert_with(|| { 150 self.obj.add_section( 151 self.obj.segment_name(StandardSegment::Data).to_vec(), 152 obj::ELF_NAME_DATA.as_bytes().to_vec(), 153 SectionKind::ReadOnlyData, 154 ) 155 }); 156 let mut sorted_names = debuginfo.name_section.func_names.iter().collect::<Vec<_>>(); 157 sorted_names.sort_by_key(|(idx, _name)| *idx); 158 for (idx, name) in sorted_names { 159 let offset = self.obj.append_section_data(name_id, name.as_bytes(), 1); 160 let offset = match u32::try_from(offset) { 161 Ok(offset) => offset, 162 Err(_) => bail!("name section too large (> 4gb)"), 163 }; 164 let len = u32::try_from(name.len()).unwrap(); 165 func_names.push(FunctionName { 166 idx: *idx, 167 offset, 168 len, 169 }); 170 } 171 } 172 173 // Data offsets in `MemoryInitialization` are offsets within the 174 // `translation.data` list concatenated which is now present in the data 175 // segment that's appended to the object. Increase the offsets by 176 // `self.data_size` to account for any previously added module. 177 let data_offset = u32::try_from(data_offset).unwrap(); 178 match &mut module.memory_initialization { 179 MemoryInitialization::Segmented(list) => { 180 for segment in list { 181 segment.data.start = segment.data.start.checked_add(data_offset).unwrap(); 182 segment.data.end = segment.data.end.checked_add(data_offset).unwrap(); 183 } 184 } 185 MemoryInitialization::Static { map } => { 186 for (_, segment) in map { 187 if let Some(segment) = segment { 188 segment.data.start = segment.data.start.checked_add(data_offset).unwrap(); 189 segment.data.end = segment.data.end.checked_add(data_offset).unwrap(); 190 } 191 } 192 } 193 } 194 195 // Data offsets for passive data are relative to the start of 196 // `translation.passive_data` which was appended to the data segment 197 // of this object, after active data in `translation.data`. Update the 198 // offsets to account prior modules added in addition to active data. 199 let data_offset = data_offset + u32::try_from(total_data_len).unwrap(); 200 for (_, range) in module.passive_data_map.iter_mut() { 201 range.start = range.start.checked_add(data_offset).unwrap(); 202 range.end = range.end.checked_add(data_offset).unwrap(); 203 } 204 205 // Insert the wasm raw wasm-based debuginfo into the output, if 206 // requested. Note that this is distinct from the native debuginfo 207 // possibly generated by the native compiler, hence these sections 208 // getting wasm-specific names. 209 let mut dwarf = Vec::new(); 210 if self.tunables.parse_wasm_debuginfo { 211 self.push_debuginfo(&mut dwarf, &debuginfo); 212 } 213 214 Ok(CompiledModuleInfo { 215 module, 216 func_names, 217 meta: Metadata { 218 has_unparsed_debuginfo, 219 code_section_offset: debuginfo.wasm_file.code_section_offset, 220 has_wasm_debuginfo: self.tunables.parse_wasm_debuginfo, 221 dwarf, 222 }, 223 }) 224 } 225 226 fn push_debug<'b, T>(&mut self, dwarf: &mut Vec<(u8, Range<u64>)>, section: &T) 227 where 228 T: gimli::Section<gimli::EndianSlice<'b, gimli::LittleEndian>>, 229 { 230 let data = section.reader().slice(); 231 if data.is_empty() { 232 return; 233 } 234 let section_id = *self.dwarf.get_or_insert_with(|| { 235 self.obj.add_section( 236 self.obj.segment_name(StandardSegment::Debug).to_vec(), 237 obj::ELF_WASMTIME_DWARF.as_bytes().to_vec(), 238 SectionKind::Debug, 239 ) 240 }); 241 let offset = self.obj.append_section_data(section_id, data, 1); 242 dwarf.push((T::id() as u8, offset..offset + data.len() as u64)); 243 } 244 245 /// Creates the `ELF_WASMTIME_INFO` section from the given serializable data 246 /// structure. 247 pub fn serialize_info<T>(&mut self, info: &T) 248 where 249 T: serde::Serialize, 250 { 251 let section = self.obj.add_section( 252 self.obj.segment_name(StandardSegment::Data).to_vec(), 253 obj::ELF_WASMTIME_INFO.as_bytes().to_vec(), 254 SectionKind::ReadOnlyData, 255 ); 256 let data = postcard::to_allocvec(info).unwrap(); 257 self.obj.set_section_data(section, data, 1); 258 } 259 260 /// Serializes `self` into a buffer. This can be used for execution as well 261 /// as serialization. 262 pub fn finish<T: WritableBuffer>(self, t: &mut T) -> Result<()> { 263 self.obj.emit(t).map_err(|e| e.into()) 264 } 265 } 266 267 /// A type which can be the result of serializing an object. 268 pub trait FinishedObject: Sized { 269 /// State required for `finish_object`, if any. 270 type State; 271 272 /// Emit the object as `Self`. 273 fn finish_object(obj: ObjectBuilder<'_>, state: &Self::State) -> Result<Self>; 274 } 275 276 impl FinishedObject for Vec<u8> { 277 type State = (); 278 fn finish_object(obj: ObjectBuilder<'_>, _state: &Self::State) -> Result<Self> { 279 let mut result = ObjectVec::default(); 280 obj.finish(&mut result)?; 281 return Ok(result.0); 282 283 #[derive(Default)] 284 struct ObjectVec(Vec<u8>); 285 286 impl WritableBuffer for ObjectVec { 287 fn len(&self) -> usize { 288 self.0.len() 289 } 290 291 fn reserve(&mut self, additional: usize) -> Result<(), ()> { 292 assert_eq!(self.0.len(), 0, "cannot reserve twice"); 293 self.0 = Vec::with_capacity(additional); 294 Ok(()) 295 } 296 297 fn resize(&mut self, new_len: usize) { 298 if new_len <= self.0.len() { 299 self.0.truncate(new_len) 300 } else { 301 self.0.extend(vec![0; new_len - self.0.len()]) 302 } 303 } 304 305 fn write_bytes(&mut self, val: &[u8]) { 306 self.0.extend(val); 307 } 308 } 309 } 310 } 311