Path: blob/main/crates/environ/src/compile/module_artifacts.rs
3071 views
//! Definitions of runtime structures and metadata which are serialized into ELF1//! with `postcard` as part of a module's compilation process.23use crate::error::{Result, bail};4use crate::prelude::*;5use crate::{6CompiledModuleInfo, DebugInfoData, FunctionName, MemoryInitialization, Metadata,7ModuleTranslation, Tunables, obj,8};9use object::SectionKind;10use object::write::{Object, SectionId, StandardSegment, WritableBuffer};11use std::ops::Range;1213/// Helper structure to create an ELF file as a compilation artifact.14///15/// This structure exposes the process which Wasmtime will encode a core wasm16/// module into an ELF file, notably managing data sections and all that good17/// business going into the final file.18pub struct ObjectBuilder<'a> {19/// The `object`-crate-defined ELF file write we're using.20obj: Object<'a>,2122/// General compilation configuration.23tunables: &'a Tunables,2425/// The section identifier for "rodata" which is where wasm data segments26/// will go.27data: SectionId,2829/// The section identifier for function name information, or otherwise where30/// the `name` custom section of wasm is copied into.31///32/// This is optional and lazily created on demand.33names: Option<SectionId>,3435/// The section identifier for dwarf information copied from the original36/// wasm files.37///38/// This is optional and lazily created on demand.39dwarf: Option<SectionId>,40}4142impl<'a> ObjectBuilder<'a> {43/// Creates a new builder for the `obj` specified.44pub fn new(mut obj: Object<'a>, tunables: &'a Tunables) -> ObjectBuilder<'a> {45let data = obj.add_section(46obj.segment_name(StandardSegment::Data).to_vec(),47obj::ELF_WASM_DATA.as_bytes().to_vec(),48SectionKind::ReadOnlyData,49);50ObjectBuilder {51obj,52tunables,53data,54names: None,55dwarf: None,56}57}5859/// Insert the wasm raw wasm-based debuginfo into the output.60/// Note that this is distinct from the native debuginfo61/// possibly generated by the native compiler, hence these sections62/// getting wasm-specific names.63pub fn push_debuginfo(64&mut self,65dwarf: &mut Vec<(u8, Range<u64>)>,66debuginfo: &DebugInfoData<'_>,67) {68self.push_debug(dwarf, &debuginfo.dwarf.debug_abbrev);69self.push_debug(dwarf, &debuginfo.dwarf.debug_addr);70self.push_debug(dwarf, &debuginfo.dwarf.debug_aranges);71self.push_debug(dwarf, &debuginfo.dwarf.debug_info);72self.push_debug(dwarf, &debuginfo.dwarf.debug_line);73self.push_debug(dwarf, &debuginfo.dwarf.debug_line_str);74self.push_debug(dwarf, &debuginfo.dwarf.debug_str);75self.push_debug(dwarf, &debuginfo.dwarf.debug_str_offsets);76self.push_debug(dwarf, &debuginfo.debug_ranges);77self.push_debug(dwarf, &debuginfo.debug_rnglists);78self.push_debug(dwarf, &debuginfo.debug_cu_index);7980// Sort this for binary-search-lookup later in `symbolize_context`.81dwarf.sort_by_key(|(id, _)| *id);82}8384/// Completes compilation of the `translation` specified, inserting85/// everything necessary into the `Object` being built.86///87/// This function will consume the final results of compiling a wasm module88/// and finish the ELF image in-progress as part of `self.obj` by appending89/// any compiler-agnostic sections.90///91/// The auxiliary `CompiledModuleInfo` structure returned here has also been92/// serialized into the object returned, but if the caller will quickly93/// turn-around and invoke `CompiledModule::from_artifacts` after this then94/// the information can be passed to that method to avoid extra95/// deserialization. This is done to avoid a serialize-then-deserialize for96/// API calls like `Module::new` where the compiled module is immediately97/// going to be used.98///99/// The various arguments here are:100///101/// * `translation` - the core wasm translation that's being completed.102///103/// * `funcs` - compilation metadata about functions within the translation104/// as well as where the functions are located in the text section and any105/// associated trampolines.106///107/// * `wasm_to_array_trampolines` - list of all trampolines necessary for108/// Wasm callers calling array callees (e.g. `Func::wrap`). One for each109/// function signature in the module. Must be sorted by `SignatureIndex`.110///111/// Returns the `CompiledModuleInfo` corresponding to this core Wasm module112/// as a result of this append operation. This is then serialized into the113/// final artifact by the caller.114pub fn append(&mut self, translation: ModuleTranslation<'_>) -> Result<CompiledModuleInfo> {115let ModuleTranslation {116mut module,117debuginfo,118has_unparsed_debuginfo,119data,120data_align,121passive_data,122..123} = translation;124125// Place all data from the wasm module into a section which will the126// source of the data later at runtime. This additionally keeps track of127// the offset of128let mut total_data_len = 0;129let data_offset = self130.obj131.append_section_data(self.data, &[], data_align.unwrap_or(1));132for (i, data) in data.iter().enumerate() {133// The first data segment has its alignment specified as the alignment134// for the entire section, but everything afterwards is adjacent so it135// has alignment of 1.136let align = if i == 0 { data_align.unwrap_or(1) } else { 1 };137self.obj.append_section_data(self.data, data, align);138total_data_len += data.len();139}140for data in passive_data.iter() {141self.obj.append_section_data(self.data, data, 1);142}143144// If any names are present in the module then the `ELF_NAME_DATA` section145// is create and appended.146let mut func_names = Vec::new();147if debuginfo.name_section.func_names.len() > 0 {148let name_id = *self.names.get_or_insert_with(|| {149self.obj.add_section(150self.obj.segment_name(StandardSegment::Data).to_vec(),151obj::ELF_NAME_DATA.as_bytes().to_vec(),152SectionKind::ReadOnlyData,153)154});155let mut sorted_names = debuginfo.name_section.func_names.iter().collect::<Vec<_>>();156sorted_names.sort_by_key(|(idx, _name)| *idx);157for (idx, name) in sorted_names {158let offset = self.obj.append_section_data(name_id, name.as_bytes(), 1);159let offset = match u32::try_from(offset) {160Ok(offset) => offset,161Err(_) => bail!("name section too large (> 4gb)"),162};163let len = u32::try_from(name.len()).unwrap();164func_names.push(FunctionName {165idx: *idx,166offset,167len,168});169}170}171172// Data offsets in `MemoryInitialization` are offsets within the173// `translation.data` list concatenated which is now present in the data174// segment that's appended to the object. Increase the offsets by175// `self.data_size` to account for any previously added module.176let data_offset = u32::try_from(data_offset).unwrap();177match &mut module.memory_initialization {178MemoryInitialization::Segmented(list) => {179for segment in list {180segment.data.start = segment.data.start.checked_add(data_offset).unwrap();181segment.data.end = segment.data.end.checked_add(data_offset).unwrap();182}183}184MemoryInitialization::Static { map } => {185for (_, segment) in map {186if let Some(segment) = segment {187segment.data.start = segment.data.start.checked_add(data_offset).unwrap();188segment.data.end = segment.data.end.checked_add(data_offset).unwrap();189}190}191}192}193194// Data offsets for passive data are relative to the start of195// `translation.passive_data` which was appended to the data segment196// of this object, after active data in `translation.data`. Update the197// offsets to account prior modules added in addition to active data.198let data_offset = data_offset + u32::try_from(total_data_len).unwrap();199for (_, range) in module.passive_data_map.iter_mut() {200range.start = range.start.checked_add(data_offset).unwrap();201range.end = range.end.checked_add(data_offset).unwrap();202}203204// Insert the wasm raw wasm-based debuginfo into the output, if205// requested. Note that this is distinct from the native debuginfo206// possibly generated by the native compiler, hence these sections207// getting wasm-specific names.208let mut dwarf = Vec::new();209if self.tunables.parse_wasm_debuginfo {210self.push_debuginfo(&mut dwarf, &debuginfo);211}212213Ok(CompiledModuleInfo {214module,215func_names,216meta: Metadata {217has_unparsed_debuginfo,218code_section_offset: debuginfo.wasm_file.code_section_offset,219has_wasm_debuginfo: self.tunables.parse_wasm_debuginfo,220dwarf,221},222})223}224225fn push_debug<'b, T>(&mut self, dwarf: &mut Vec<(u8, Range<u64>)>, section: &T)226where227T: gimli::Section<gimli::EndianSlice<'b, gimli::LittleEndian>>,228{229let data = section.reader().slice();230if data.is_empty() {231return;232}233let section_id = *self.dwarf.get_or_insert_with(|| {234self.obj.add_section(235self.obj.segment_name(StandardSegment::Debug).to_vec(),236obj::ELF_WASMTIME_DWARF.as_bytes().to_vec(),237SectionKind::Debug,238)239});240let offset = self.obj.append_section_data(section_id, data, 1);241dwarf.push((T::id() as u8, offset..offset + data.len() as u64));242}243244/// Creates the `ELF_WASMTIME_INFO` section from the given serializable data245/// structure.246pub fn serialize_info<T>(&mut self, info: &T)247where248T: serde::Serialize,249{250let section = self.obj.add_section(251self.obj.segment_name(StandardSegment::Data).to_vec(),252obj::ELF_WASMTIME_INFO.as_bytes().to_vec(),253SectionKind::ReadOnlyData,254);255let data = postcard::to_allocvec(info).unwrap();256self.obj.set_section_data(section, data, 1);257}258259/// Serializes `self` into a buffer. This can be used for execution as well260/// as serialization.261pub fn finish<T: WritableBuffer>(self, t: &mut T) -> Result<()> {262self.obj.emit(t).map_err(|e| e.into())263}264}265266/// A type which can be the result of serializing an object.267pub trait FinishedObject: Sized {268/// State required for `finish_object`, if any.269type State;270271/// Emit the object as `Self`.272fn finish_object(obj: ObjectBuilder<'_>, state: &Self::State) -> Result<Self>;273}274275impl FinishedObject for Vec<u8> {276type State = ();277fn finish_object(obj: ObjectBuilder<'_>, _state: &Self::State) -> Result<Self> {278let mut result = ObjectVec::default();279obj.finish(&mut result)?;280return Ok(result.0);281282#[derive(Default)]283struct ObjectVec(Vec<u8>);284285impl WritableBuffer for ObjectVec {286fn len(&self) -> usize {287self.0.len()288}289290fn reserve(&mut self, additional: usize) -> Result<(), ()> {291assert_eq!(self.0.len(), 0, "cannot reserve twice");292self.0 = Vec::with_capacity(additional);293Ok(())294}295296fn resize(&mut self, new_len: usize) {297if new_len <= self.0.len() {298self.0.truncate(new_len)299} else {300self.0.extend(vec![0; new_len - self.0.len()])301}302}303304fn write_bytes(&mut self, val: &[u8]) {305self.0.extend(val);306}307}308}309}310311312