Path: blob/main/crates/environ/src/compile/module_artifacts.rs
1693 views
//! Definitions of runtime structures and metadata which are serialized into ELF1//! with `postcard` as part of a module's compilation process.23use crate::prelude::*;4use crate::{5CompiledFunctionInfo, CompiledModuleInfo, DebugInfoData, DefinedFuncIndex, FunctionLoc,6FunctionName, MemoryInitialization, Metadata, ModuleInternedTypeIndex, ModuleTranslation,7PrimaryMap, Tunables, obj,8};9use anyhow::{Result, bail};10use object::SectionKind;11use object::write::{Object, SectionId, StandardSegment, WritableBuffer};12use std::ops::Range;1314/// Helper structure to create an ELF file as a compilation artifact.15///16/// This structure exposes the process which Wasmtime will encode a core wasm17/// module into an ELF file, notably managing data sections and all that good18/// business going into the final file.19pub struct ObjectBuilder<'a> {20/// The `object`-crate-defined ELF file write we're using.21obj: Object<'a>,2223/// General compilation configuration.24tunables: &'a Tunables,2526/// The section identifier for "rodata" which is where wasm data segments27/// will go.28data: SectionId,2930/// The section identifier for function name information, or otherwise where31/// the `name` custom section of wasm is copied into.32///33/// This is optional and lazily created on demand.34names: Option<SectionId>,3536/// The section identifier for dwarf information copied from the original37/// wasm files.38///39/// This is optional and lazily created on demand.40dwarf: Option<SectionId>,41}4243impl<'a> ObjectBuilder<'a> {44/// Creates a new builder for the `obj` specified.45pub fn new(mut obj: Object<'a>, tunables: &'a Tunables) -> ObjectBuilder<'a> {46let data = obj.add_section(47obj.segment_name(StandardSegment::Data).to_vec(),48obj::ELF_WASM_DATA.as_bytes().to_vec(),49SectionKind::ReadOnlyData,50);51ObjectBuilder {52obj,53tunables,54data,55names: None,56dwarf: None,57}58}5960/// Insert the wasm raw wasm-based debuginfo into the output.61/// Note that this is distinct from the native debuginfo62/// possibly generated by the native compiler, hence these sections63/// getting wasm-specific names.64pub fn push_debuginfo(65&mut self,66dwarf: &mut Vec<(u8, Range<u64>)>,67debuginfo: &DebugInfoData<'_>,68) {69self.push_debug(dwarf, &debuginfo.dwarf.debug_abbrev);70self.push_debug(dwarf, &debuginfo.dwarf.debug_addr);71self.push_debug(dwarf, &debuginfo.dwarf.debug_aranges);72self.push_debug(dwarf, &debuginfo.dwarf.debug_info);73self.push_debug(dwarf, &debuginfo.dwarf.debug_line);74self.push_debug(dwarf, &debuginfo.dwarf.debug_line_str);75self.push_debug(dwarf, &debuginfo.dwarf.debug_str);76self.push_debug(dwarf, &debuginfo.dwarf.debug_str_offsets);77self.push_debug(dwarf, &debuginfo.debug_ranges);78self.push_debug(dwarf, &debuginfo.debug_rnglists);79self.push_debug(dwarf, &debuginfo.debug_cu_index);8081// Sort this for binary-search-lookup later in `symbolize_context`.82dwarf.sort_by_key(|(id, _)| *id);83}8485/// Completes compilation of the `translation` specified, inserting86/// everything necessary into the `Object` being built.87///88/// This function will consume the final results of compiling a wasm module89/// and finish the ELF image in-progress as part of `self.obj` by appending90/// any compiler-agnostic sections.91///92/// The auxiliary `CompiledModuleInfo` structure returned here has also been93/// serialized into the object returned, but if the caller will quickly94/// turn-around and invoke `CompiledModule::from_artifacts` after this then95/// the information can be passed to that method to avoid extra96/// deserialization. This is done to avoid a serialize-then-deserialize for97/// API calls like `Module::new` where the compiled module is immediately98/// 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 translation105/// as well as where the functions are located in the text section and any106/// associated trampolines.107///108/// * `wasm_to_array_trampolines` - list of all trampolines necessary for109/// Wasm callers calling array callees (e.g. `Func::wrap`). One for each110/// function signature in the module. Must be sorted by `SignatureIndex`.111///112/// Returns the `CompiledModuleInfo` corresponding to this core Wasm module113/// as a result of this append operation. This is then serialized into the114/// final artifact by the caller.115pub fn append(116&mut self,117translation: ModuleTranslation<'_>,118funcs: PrimaryMap<DefinedFuncIndex, CompiledFunctionInfo>,119wasm_to_array_trampolines: Vec<(ModuleInternedTypeIndex, FunctionLoc)>,120) -> Result<CompiledModuleInfo> {121let ModuleTranslation {122mut module,123debuginfo,124has_unparsed_debuginfo,125data,126data_align,127passive_data,128..129} = translation;130131// Place all data from the wasm module into a section which will the132// source of the data later at runtime. This additionally keeps track of133// the offset of134let mut total_data_len = 0;135let data_offset = self136.obj137.append_section_data(self.data, &[], data_align.unwrap_or(1));138for (i, data) in data.iter().enumerate() {139// The first data segment has its alignment specified as the alignment140// for the entire section, but everything afterwards is adjacent so it141// has alignment of 1.142let align = if i == 0 { data_align.unwrap_or(1) } else { 1 };143self.obj.append_section_data(self.data, data, align);144total_data_len += data.len();145}146for data in passive_data.iter() {147self.obj.append_section_data(self.data, data, 1);148}149150// If any names are present in the module then the `ELF_NAME_DATA` section151// is create and appended.152let mut func_names = Vec::new();153if debuginfo.name_section.func_names.len() > 0 {154let name_id = *self.names.get_or_insert_with(|| {155self.obj.add_section(156self.obj.segment_name(StandardSegment::Data).to_vec(),157obj::ELF_NAME_DATA.as_bytes().to_vec(),158SectionKind::ReadOnlyData,159)160});161let mut sorted_names = debuginfo.name_section.func_names.iter().collect::<Vec<_>>();162sorted_names.sort_by_key(|(idx, _name)| *idx);163for (idx, name) in sorted_names {164let offset = self.obj.append_section_data(name_id, name.as_bytes(), 1);165let offset = match u32::try_from(offset) {166Ok(offset) => offset,167Err(_) => bail!("name section too large (> 4gb)"),168};169let len = u32::try_from(name.len()).unwrap();170func_names.push(FunctionName {171idx: *idx,172offset,173len,174});175}176}177178// Data offsets in `MemoryInitialization` are offsets within the179// `translation.data` list concatenated which is now present in the data180// segment that's appended to the object. Increase the offsets by181// `self.data_size` to account for any previously added module.182let data_offset = u32::try_from(data_offset).unwrap();183match &mut module.memory_initialization {184MemoryInitialization::Segmented(list) => {185for segment in list {186segment.data.start = segment.data.start.checked_add(data_offset).unwrap();187segment.data.end = segment.data.end.checked_add(data_offset).unwrap();188}189}190MemoryInitialization::Static { map } => {191for (_, segment) in map {192if let Some(segment) = segment {193segment.data.start = segment.data.start.checked_add(data_offset).unwrap();194segment.data.end = segment.data.end.checked_add(data_offset).unwrap();195}196}197}198}199200// Data offsets for passive data are relative to the start of201// `translation.passive_data` which was appended to the data segment202// of this object, after active data in `translation.data`. Update the203// offsets to account prior modules added in addition to active data.204let data_offset = data_offset + u32::try_from(total_data_len).unwrap();205for (_, range) in module.passive_data_map.iter_mut() {206range.start = range.start.checked_add(data_offset).unwrap();207range.end = range.end.checked_add(data_offset).unwrap();208}209210// Insert the wasm raw wasm-based debuginfo into the output, if211// requested. Note that this is distinct from the native debuginfo212// possibly generated by the native compiler, hence these sections213// getting wasm-specific names.214let mut dwarf = Vec::new();215if self.tunables.parse_wasm_debuginfo {216self.push_debuginfo(&mut dwarf, &debuginfo);217}218219Ok(CompiledModuleInfo {220module,221funcs,222wasm_to_array_trampolines,223func_names,224meta: Metadata {225has_unparsed_debuginfo,226code_section_offset: debuginfo.wasm_file.code_section_offset,227has_wasm_debuginfo: self.tunables.parse_wasm_debuginfo,228dwarf,229},230})231}232233fn push_debug<'b, T>(&mut self, dwarf: &mut Vec<(u8, Range<u64>)>, section: &T)234where235T: gimli::Section<gimli::EndianSlice<'b, gimli::LittleEndian>>,236{237let data = section.reader().slice();238if data.is_empty() {239return;240}241let section_id = *self.dwarf.get_or_insert_with(|| {242self.obj.add_section(243self.obj.segment_name(StandardSegment::Debug).to_vec(),244obj::ELF_WASMTIME_DWARF.as_bytes().to_vec(),245SectionKind::Debug,246)247});248let offset = self.obj.append_section_data(section_id, data, 1);249dwarf.push((T::id() as u8, offset..offset + data.len() as u64));250}251252/// Creates the `ELF_WASMTIME_INFO` section from the given serializable data253/// structure.254pub fn serialize_info<T>(&mut self, info: &T)255where256T: serde::Serialize,257{258let section = self.obj.add_section(259self.obj.segment_name(StandardSegment::Data).to_vec(),260obj::ELF_WASMTIME_INFO.as_bytes().to_vec(),261SectionKind::ReadOnlyData,262);263let data = postcard::to_allocvec(info).unwrap();264self.obj.set_section_data(section, data, 1);265}266267/// Serializes `self` into a buffer. This can be used for execution as well268/// as serialization.269pub fn finish<T: WritableBuffer>(self, t: &mut T) -> Result<()> {270self.obj.emit(t).map_err(|e| e.into())271}272}273274/// A type which can be the result of serializing an object.275pub trait FinishedObject: Sized {276/// State required for `finish_object`, if any.277type State;278279/// Emit the object as `Self`.280fn finish_object(obj: ObjectBuilder<'_>, state: &Self::State) -> Result<Self>;281}282283impl FinishedObject for Vec<u8> {284type State = ();285fn finish_object(obj: ObjectBuilder<'_>, _state: &Self::State) -> Result<Self> {286let mut result = ObjectVec::default();287obj.finish(&mut result)?;288return Ok(result.0);289290#[derive(Default)]291struct ObjectVec(Vec<u8>);292293impl WritableBuffer for ObjectVec {294fn len(&self) -> usize {295self.0.len()296}297298fn reserve(&mut self, additional: usize) -> Result<(), ()> {299assert_eq!(self.0.len(), 0, "cannot reserve twice");300self.0 = Vec::with_capacity(additional);301Ok(())302}303304fn resize(&mut self, new_len: usize) {305if new_len <= self.0.len() {306self.0.truncate(new_len)307} else {308self.0.extend(vec![0; new_len - self.0.len()])309}310}311312fn write_bytes(&mut self, val: &[u8]) {313self.0.extend(val);314}315}316}317}318319320