diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index e41196093..a5e45d84a 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -9,14 +9,16 @@ use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use wasm_common::entity::{EntityRef, PrimaryMap, SecondaryMap}; use wasm_common::Features; use wasm_common::{FuncIndex, FuncType, LocalFuncIndex, MemoryIndex, TableIndex}; -use wasmer_compiler::TrapInformation; -use wasmer_compiler::{Compilation, CompileError, CompiledFunction, Compiler}; -use wasmer_compiler::{CompilerConfig, ModuleTranslationState, Target}; -use wasmer_compiler::{FunctionBody, FunctionBodyData}; +use wasmer_compiler::{ + Compilation, CompileError, CompiledFunction, Compiler, CompilerConfig, CustomSection, + CustomSectionProtection, FunctionBody, FunctionBodyData, ModuleTranslationState, Relocation, + RelocationTarget, SectionIndex, Target, TrapInformation, +}; use wasmer_runtime::{MemoryPlan, Module, TablePlan, TrapCode}; use inkwell::targets::{InitializationConfig, Target as InkwellTarget}; +use std::collections::HashMap; use std::sync::{Arc, Mutex}; // TODO: remove /// A compiler that compiles a WebAssembly module with LLVM, translating the Wasm to LLVM IR, @@ -62,7 +64,15 @@ impl Compiler for LLVMCompiler { ) -> Result { //let data = Arc::new(Mutex::new(0)); let mut func_names = SecondaryMap::new(); - let custom_sections = PrimaryMap::new(); + + // We're going to "link" the sections by simply appending all compatible + // sections, then building the new relocations. + // TODO: merge constants. + let mut used_readonly_section = false; + let mut readonly_section = CustomSection { + protection: CustomSectionProtection::Read, + bytes: Vec::new(), + }; for (func_index, _) in &module.functions { func_names[func_index] = module @@ -71,7 +81,7 @@ impl Compiler for LLVMCompiler { .cloned() .unwrap_or_else(|| format!("fn{}", func_index.index())); } - let functions = function_body_inputs + let mut functions = function_body_inputs .into_iter() .collect::)>>() .par_iter() @@ -90,8 +100,42 @@ impl Compiler for LLVMCompiler { }) .collect::, CompileError>>()? .into_iter() + .map(|(mut function, local_relocations, custom_sections)| { + /// We collect the sections data + for (local_idx, custom_section) in custom_sections.iter().enumerate() { + let local_idx = local_idx as u32; + // TODO: these section numbers are potentially wrong, if there's + // no Read and only a ReadExecute then ReadExecute is 0. + let (ref mut section, section_num) = match &custom_section.protection { + CustomSectionProtection::Read => { + (&mut readonly_section, SectionIndex::from_u32(0)) + } + }; + let offset = section.bytes.len() as i64; + section.bytes.extend(&custom_section.bytes); + // TODO: we're needlessly rescanning the whole list. + for local_relocation in &local_relocations { + if local_relocation.local_section_index == local_idx { + used_readonly_section = true; + function.relocations.push(Relocation { + kind: local_relocation.kind, + reloc_target: RelocationTarget::CustomSection(section_num), + offset: local_relocation.offset, + addend: local_relocation.addend + offset, + }); + } + } + } + Ok(function) + }) + .collect::, CompileError>>()? + .into_iter() .collect::>(); + let mut custom_sections = PrimaryMap::new(); + if used_readonly_section { + custom_sections.push(readonly_section); + } Ok(Compilation::new(functions, custom_sections)) } diff --git a/lib/compiler-llvm/src/translator/code.rs b/lib/compiler-llvm/src/translator/code.rs index 171625f58..50a282c89 100644 --- a/lib/compiler-llvm/src/translator/code.rs +++ b/lib/compiler-llvm/src/translator/code.rs @@ -37,15 +37,14 @@ use wasm_common::{ }; use wasmer_compiler::wasmparser::{self, BinaryReader, MemoryImmediate, Operator}; use wasmer_compiler::{ - to_wasm_error, wasm_unsupported, CompileError, CompiledFunction, CompiledFunctionFrameInfo, - FunctionBody, WasmResult, -}; -use wasmer_compiler::{ - CompiledFunctionUnwindInfo, FunctionAddressMap, FunctionBodyData, Relocation, RelocationKind, - RelocationTarget, SourceLoc, + to_wasm_error, wasm_unsupported, Addend, CodeOffset, CompileError, CompiledFunction, + CompiledFunctionFrameInfo, CompiledFunctionUnwindInfo, CustomSection, CustomSectionProtection, + FunctionAddressMap, FunctionBody, FunctionBodyData, Relocation, RelocationKind, + RelocationTarget, SourceLoc, WasmResult, }; +use wasmer_runtime::libcalls::LibCall; use wasmer_runtime::Module as WasmerCompilerModule; -use wasmer_runtime::{libcalls::LibCall, MemoryPlan, MemoryStyle, TablePlan}; +use wasmer_runtime::{MemoryPlan, MemoryStyle, TablePlan}; // TODO: debugging use std::fs; @@ -83,6 +82,15 @@ fn const_zero<'ctx>(ty: BasicTypeEnum<'ctx>) -> BasicValueEnum<'ctx> { } } +// Relocation against a per-function section. +#[derive(Debug)] +pub struct LocalRelocation { + pub kind: RelocationKind, + pub local_section_index: u32, + pub offset: CodeOffset, + pub addend: Addend, +} + impl FuncTranslator { pub fn new() -> Self { Self { @@ -99,7 +107,7 @@ impl FuncTranslator { memory_plans: &PrimaryMap, table_plans: &PrimaryMap, func_names: &SecondaryMap, - ) -> Result { + ) -> Result<(CompiledFunction, Vec, Vec), CompileError> { let func_index = wasm_module.func_index(*func_index); let func_name = func_names.get(func_index).unwrap(); let module_name = match wasm_module.name.as_ref() { @@ -300,6 +308,8 @@ impl FuncTranslator { let mut bytes = vec![]; let mut relocations = vec![]; + let mut local_relocations = vec![]; + let mut required_custom_sections = vec![]; for section in object.get_sections() { match section.get_name().map(std::ffi::CStr::to_bytes) { Some(b"wasmer_function") => { @@ -334,26 +344,57 @@ impl FuncTranslator { } } } - if reloc_target.is_none() { - unimplemented!("reference to non-user function {:?}", &target); - } - let reloc_target = reloc_target.unwrap(); + if reloc_target.is_some() { + let reloc_target = reloc_target.unwrap(); - let relocation = Relocation { - kind, - reloc_target, - offset: rel.get_offset() as u32, - // TODO: it appears the LLVM C API has no way to - // retrieve the addend. - addend: 0, - }; - relocations.push(relocation); + relocations.push(Relocation { + kind, + reloc_target, + offset: rel.get_offset() as u32, + // TODO: it appears the LLVM C API has no way to + // retrieve the addend. + addend: 0, + }); + } else { + if let Some(ref target) = &target { + let local_section_index = required_custom_sections.len() as u32; + required_custom_sections.push(target.clone()); + local_relocations.push(LocalRelocation { + kind, + local_section_index, + offset: rel.get_offset() as u32, + // TODO: it appears the LLVM C API has no way to + // retrieve the addend. + addend: 0, + }); + } + } } } _ => {} }; } + // TODO: verify that we see all of them + let mut custom_sections = vec![]; + custom_sections.resize( + required_custom_sections.len(), + CustomSection { + protection: CustomSectionProtection::Read, + bytes: vec![], + }, + ); + for section in object.get_sections() { + if let Some(name) = section.get_name().map(std::ffi::CStr::to_bytes) { + if let Some(index) = required_custom_sections + .iter() + .position(|n| n.as_bytes() == name) + { + custom_sections[index].bytes.extend(section.get_contents()); + } + } + } + let address_map = FunctionAddressMap { instructions: vec![], start_srcloc: SourceLoc::default(), @@ -362,18 +403,22 @@ impl FuncTranslator { body_len: 0, // TODO }; - Ok(CompiledFunction { - body: FunctionBody { - body: bytes, - unwind_info: CompiledFunctionUnwindInfo::None, + Ok(( + CompiledFunction { + body: FunctionBody { + body: bytes, + unwind_info: CompiledFunctionUnwindInfo::None, + }, + jt_offsets: SecondaryMap::new(), + relocations, + frame_info: CompiledFunctionFrameInfo { + address_map, + traps: vec![], + }, }, - jt_offsets: SecondaryMap::new(), - relocations, - frame_info: CompiledFunctionFrameInfo { - address_map, - traps: vec![], - }, - }) + local_relocations, + custom_sections, + )) } } diff --git a/lib/compiler/src/section.rs b/lib/compiler/src/section.rs index af0fdbeff..0908f1b90 100644 --- a/lib/compiler/src/section.rs +++ b/lib/compiler/src/section.rs @@ -23,8 +23,8 @@ pub enum CustomSectionProtection { Read, // We don't include `ReadWrite` here because it would complicate freeze // and resumption of executing Modules. - /// A compiled section that is also executable. - ReadExecute, + // We also currently don't include `ReadExecute` as we don't have a way + // to represent relocations for this kind of section. } /// A Section for a `Compilation`.