Start work on object loader using llvm's RuntimeDyld api.

This commit is contained in:
Lachlan Sneff 2019-02-25 18:07:22 -08:00
parent 2a913f5663
commit 4f833876e0
9 changed files with 579 additions and 122 deletions

30
Cargo.lock generated
View File

@ -262,6 +262,28 @@ dependencies = [
"generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dlopen"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"dlopen_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dlopen_derive"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "either"
version = "1.5.1"
@ -469,10 +491,16 @@ dependencies = [
name = "llvm-backend"
version = "0.1.0"
dependencies = [
"cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
"dlopen 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"goblin 0.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
"hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"inkwell 0.1.0 (git+https://github.com/TheDan64/inkwell?branch=llvm7-0)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmer-runtime-core 0.1.2",
"wasmparser 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1362,6 +1390,8 @@ dependencies = [
"checksum cranelift-native 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "474bee81d620a473bf43411a3d6f10ffbf7965141dc5e5b76d8d2151dde3285d"
"checksum cranelift-wasm 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49723365dab9a48b354bdc24cb6d9d5719bc1d3b858ffd2ea179d0d7d885804a"
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
"checksum dlopen 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8c301a18a3404a48d5d078e86b011ac834a6c4c742217e9aa8ceadd8a7e09e0"
"checksum dlopen_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6e16e4e343d6090ba47113c55bf6aa94e9b1eb5ab0c5abc9510d4c15074f30e9"
"checksum either 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c67353c641dc847124ea1902d69bd753dee9bb3beff9aa3662ecf86c971d1fac"
"checksum enum-methods 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7798e7da2d4cb0d6d6fc467e8d6b5bf247e9e989f786dde1732d79899c32bb10"
"checksum env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afb070faf94c85d17d50ca44f6ad076bce18ae92f0037d350947240a36e9d42e"

View File

@ -11,6 +11,14 @@ inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "llvm7-0" }
hashbrown = "0.1.8"
smallvec = "0.6.8"
goblin = "0.0.20"
dlopen = "0.1.6"
tempfile = "3.0.7"
[build-dependencies]
cc = "1.0"
lazy_static = "1.2.0"
regex = "1.1.0"
semver = "0.9"
[dev-dependencies]
wabt = "0.7.4"

213
lib/llvm-backend/build.rs Normal file
View File

@ -0,0 +1,213 @@
//! This file was mostly taken from the llvm-sys crate.
//! (https://bitbucket.org/tari/llvm-sys.rs/src/21ab524ec4df1450035df895209c3f8fbeb8775f/build.rs?at=default&fileviewer=file-view-default)
use lazy_static::lazy_static;
use regex::Regex;
use semver::Version;
use std::env;
use std::ffi::OsStr;
use std::io::{self, ErrorKind};
use std::path::PathBuf;
use std::process::Command;
lazy_static! {
/// LLVM version used by this version of the crate.
static ref CRATE_VERSION: Version = {
let crate_version = Version::parse(env!("CARGO_PKG_VERSION"))
.expect("Crate version is somehow not valid semver");
Version {
major: crate_version.major / 10,
minor: crate_version.major % 10,
.. crate_version
}
};
static ref LLVM_CONFIG_BINARY_NAMES: Vec<String> = {
vec![
"llvm-config".into(),
// format!("llvm-config-{}", CRATE_VERSION.major),
// format!("llvm-config-{}.{}", CRATE_VERSION.major, CRATE_VERSION.minor),
]
};
/// Filesystem path to an llvm-config binary for the correct version.
static ref LLVM_CONFIG_PATH: PathBuf = {
// Try llvm-config via PATH first.
if let Some(name) = locate_system_llvm_config() {
return name.into();
} else {
println!("Didn't find usable system-wide LLVM.");
}
// Did the user give us a binary path to use? If yes, try
// to use that and fail if it doesn't work.
let binary_prefix_var = "LLVM_SYS_70_PREFIX";
let path = if let Some(path) = env::var_os(&binary_prefix_var) {
Some(path.to_str().unwrap().to_owned())
} else if let Ok(mut file) = std::fs::File::open(".llvmenv") {
use std::io::Read;
let mut s = String::new();
file.read_to_string(&mut s).unwrap();
Some(s)
} else {
None
};
if let Some(path) = path {
for binary_name in LLVM_CONFIG_BINARY_NAMES.iter() {
let mut pb: PathBuf = path.clone().into();
pb.push("bin");
pb.push(binary_name);
let ver = llvm_version(&pb)
.expect(&format!("Failed to execute {:?}", &pb));
if is_compatible_llvm(&ver) {
return pb;
} else {
println!("LLVM binaries specified by {} are the wrong version.
(Found {}, need {}.)", binary_prefix_var, ver, *CRATE_VERSION);
}
}
}
println!("No suitable version of LLVM was found system-wide or pointed
to by {}.
Consider using `llvmenv` to compile an appropriate copy of LLVM, and
refer to the llvm-sys documentation for more information.
llvm-sys: https://crates.io/crates/llvm-sys
llvmenv: https://crates.io/crates/llvmenv", binary_prefix_var);
panic!("Could not find a compatible version of LLVM");
};
}
/// Try to find a system-wide version of llvm-config that is compatible with
/// this crate.
///
/// Returns None on failure.
fn locate_system_llvm_config() -> Option<&'static str> {
for binary_name in LLVM_CONFIG_BINARY_NAMES.iter() {
match llvm_version(binary_name) {
Ok(ref version) if is_compatible_llvm(version) => {
// Compatible version found. Nice.
return Some(binary_name);
}
Ok(version) => {
// Version mismatch. Will try further searches, but warn that
// we're not using the system one.
println!(
"Found LLVM version {} on PATH, but need {}.",
version, *CRATE_VERSION
);
}
Err(ref e) if e.kind() == ErrorKind::NotFound => {
// Looks like we failed to execute any llvm-config. Keep
// searching.
}
// Some other error, probably a weird failure. Give up.
Err(e) => panic!("Failed to search PATH for llvm-config: {}", e),
}
}
None
}
/// Check whether the given LLVM version is compatible with this version of
/// the crate.
fn is_compatible_llvm(llvm_version: &Version) -> bool {
let strict = env::var_os(format!(
"LLVM_SYS_{}_STRICT_VERSIONING",
env!("CARGO_PKG_VERSION_MAJOR")
))
.is_some()
|| cfg!(feature = "strict-versioning");
if strict {
llvm_version.major == CRATE_VERSION.major && llvm_version.minor == CRATE_VERSION.minor
} else {
llvm_version.major >= CRATE_VERSION.major
|| (llvm_version.major == CRATE_VERSION.major
&& llvm_version.minor >= CRATE_VERSION.minor)
}
}
/// Get the output from running `llvm-config` with the given argument.
///
/// Lazily searches for or compiles LLVM as configured by the environment
/// variables.
fn llvm_config(arg: &str) -> String {
llvm_config_ex(&*LLVM_CONFIG_PATH, arg).expect("Surprising failure from llvm-config")
}
/// Invoke the specified binary as llvm-config.
///
/// Explicit version of the `llvm_config` function that bubbles errors
/// up.
fn llvm_config_ex<S: AsRef<OsStr>>(binary: S, arg: &str) -> io::Result<String> {
Command::new(binary)
.arg(arg)
.arg("--link-static") // Don't use dylib for >= 3.9
.output()
.map(|output| {
String::from_utf8(output.stdout).expect("Output from llvm-config was not valid UTF-8")
})
}
/// Get the LLVM version using llvm-config.
fn llvm_version<S: AsRef<OsStr>>(binary: S) -> io::Result<Version> {
let version_str = llvm_config_ex(binary.as_ref(), "--version")?;
// LLVM isn't really semver and uses version suffixes to build
// version strings like '3.8.0svn', so limit what we try to parse
// to only the numeric bits.
let re = Regex::new(r"^(?P<major>\d+)\.(?P<minor>\d+)(?:\.(?P<patch>\d+))??").unwrap();
let c = re
.captures(&version_str)
.expect("Could not determine LLVM version from llvm-config.");
// some systems don't have a patch number but Version wants it so we just append .0 if it isn't
// there
let s = match c.name("patch") {
None => format!("{}.0", &c[0]),
Some(_) => c[0].to_string(),
};
Ok(Version::parse(&s).unwrap())
}
fn get_llvm_cxxflags() -> String {
let output = llvm_config("--cxxflags");
// llvm-config includes cflags from its own compilation with --cflags that
// may not be relevant to us. In particularly annoying cases, these might
// include flags that aren't understood by the default compiler we're
// using. Unless requested otherwise, clean CFLAGS of options that are
// known to be possibly-harmful.
let no_clean = env::var_os(format!(
"LLVM_SYS_{}_NO_CLEAN_CFLAGS",
env!("CARGO_PKG_VERSION_MAJOR")
))
.is_some();
if no_clean || cfg!(target_env = "msvc") {
// MSVC doesn't accept -W... options, so don't try to strip them and
// possibly strip something that should be retained. Also do nothing if
// the user requests it.
return output;
}
output
.split(&[' ', '\n'][..])
.filter(|word| !word.starts_with("-W"))
.collect::<Vec<_>>()
.join(" ")
}
fn main() {
std::env::set_var("CXXFLAGS", get_llvm_cxxflags());
cc::Build::new()
.cpp(true)
.file("cpp/object_loader.cpp")
.compile("llvm-backend");
println!("cargo:rustc-link-lib=static=llvm-backend");
}

View File

@ -0,0 +1,96 @@
#include "object_loader.hh"
#include <llvm/ExecutionEngine/RuntimeDyld.h>
#include <iostream>
class MemoryManager : llvm::RuntimeDyld::MemoryManager {
public:
MemoryManager() {}
virtual ~MemoryManager() {}
virtual uint8_t* allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, llvm::StringRef SectionName) override {
return nullptr;
}
virtual uint8_t* allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, llvm::StringRef SectionName, bool isReadOnly) override {
return nullptr;
}
virtual void reserveAllocationSpace(
uintptr_t code_size,
uint32_t code_align,
uintptr_t read_data_size,
uint32_t read_data_align,
uintptr_t read_write_data_size,
uint32_t read_write_data_align
) override {
}
/* Turn on the `reserveAllocationSpace` callback. */
virtual bool needsToReserveAllocationSpace() override {
return true;
}
virtual void registerEHFrames(uint8_t* Addr, uint64_t LoadAddr, size_t Size) override {
}
virtual void deregisterEHFrames() override {
}
virtual bool finalizeMemory(std::string *ErrMsg = nullptr) override {
return false;
}
virtual void notifyObjectLoaded(llvm::RuntimeDyld &RTDyld, const llvm::object::ObjectFile &Obj) override {
}
private:
struct Section {
uint8_t* base;
size_t num_pages;
size_t num_commited_bytes;
};
uint8_t *image_base;
size_t num_allocated_pages;
Section code_section, read_section, readwrite_section;
};
class SymbolLookup : llvm::JITSymbolResolver {
public:
virtual llvm::Expected<LookupResult> lookup(const LookupSet& symbols) override {
LookupResult result;
for (auto symbol : symbols) {
result.emplace(symbol, symbol_lookup(symbol));
}
return result;
}
virtual llvm::Expected<LookupFlagsResult> lookupFlags(const LookupSet& symbols) override {
LookupFlagsResult result;
for (auto symbol : symbols) {
result.emplace(symbol, symbol_lookup(symbol).getFlags());
}
return result;
}
private:
llvm::JITEvaluatedSymbol symbol_lookup(llvm::StringRef name) {
std::cout << "symbol name: " << (std::string)name << std::endl;
uint64_t addr = 0;
return llvm::JITEvaluatedSymbol(addr, llvm::JITSymbolFlags::None);
}
};

View File

@ -0,0 +1,40 @@
#include <cstddef>
#include <cstdint>
typedef enum {
PROTECT_NONE,
PROTECT_READ,
PROTECT_READ_WRITE,
PROTECT_READ_EXECUTE,
} mem_protect_t;
typedef enum {
RESULT_OK,
RESULT_ALLOCATE_FAILURE,
RESULT_PROTECT_FAILURE,
RESULT_DEALLOC_FAILURE,
RESULT_OBJECT_LOAD_FAILURE,
} result_t;
typedef result_t (*alloc_memory_t)(size_t size, mem_protect_t protect, uint8_t** ptr_out, size_t* size_out);
typedef result_t (*protect_memory_t)(uint8_t* ptr, size_t size, mem_protect_t protect);
typedef result_t (*dealloc_memory_t)(uint8_t* ptr, size_t size);
typedef uintptr_t (*lookup_vm_symbol_t)(char* name_ptr, size_t name_size);
typedef struct {
/* Memory management. */
alloc_memory_t alloc_memory;
protect_memory_t protect_memory;
dealloc_memory_t dealloc_memory;
lookup_vm_symbol_t lookup_vm_symbol;
} callbacks_t;
extern "C" {
result_t object_load(uint8_t* mem_ptr, size_t mem_size, callbacks_t* callbacks) {
return RESULT_OK;
}
void test_cpp() {
}
}

View File

@ -1,45 +1,76 @@
use crate::intrinsics::Intrinsics;
use dlopen::symbor::Library;
use inkwell::{
module::Module,
execution_engine::{ExecutionEngine, JitFunction},
targets::{CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine},
OptimizationLevel,
};
use crate::intrinsics::Intrinsics;
use std::ptr::NonNull;
use std::{io::Write, ptr::NonNull};
use tempfile::NamedTempFile;
use wasmer_runtime_core::{
module::ModuleInner,
types::LocalFuncIndex,
structures::TypedIndex,
backend::{FuncResolver, vm},
backend::FuncResolver, module::ModuleInner, structures::TypedIndex, types::LocalFuncIndex, vm,
};
pub struct LLVMBackend {
exec_engine: ExecutionEngine,
tempfile: NamedTempFile,
library: Library,
}
impl LLVMBackend {
pub fn new(module: Module, intrinsics: Intrinsics) -> Self {
let exec_engine = module.create_jit_execution_engine(OptimizationLevel::Default).unwrap();
Target::initialize_x86(&InitializationConfig {
asm_parser: true,
asm_printer: true,
base: true,
disassembler: true,
info: true,
machine_code: true,
});
let triple = TargetMachine::get_default_triple().to_string();
let target = Target::from_triple(&triple).unwrap();
let target_machine = target
.create_target_machine(
&triple,
&TargetMachine::get_host_cpu_name().to_string(),
&TargetMachine::get_host_cpu_features().to_string(),
OptimizationLevel::Default,
RelocMode::PIC,
CodeModel::Default,
)
.unwrap();
exec_engine.add_global_mapping(&intrinsics.memory_grow_dynamic_local, vmcalls::local_dynamic_memory_grow as usize);
exec_engine.add_global_mapping(&intrinsics.memory_grow_static_local, vmcalls::local_static_memory_grow as usize);
exec_engine.add_global_mapping(&intrinsics.memory_grow_dynamic_import, vmcalls::imported_dynamic_memory_grow as usize);
exec_engine.add_global_mapping(&intrinsics.memory_grow_static_import, vmcalls::imported_static_memory_grow as usize);
exec_engine.add_global_mapping(&intrinsics.memory_size_dynamic_local, vmcalls::local_dynamic_memory_size as usize);
exec_engine.add_global_mapping(&intrinsics.memory_size_static_local, vmcalls::local_static_memory_size as usize);
exec_engine.add_global_mapping(&intrinsics.memory_size_dynamic_import, vmcalls::imported_dynamic_memory_size as usize);
exec_engine.add_global_mapping(&intrinsics.memory_size_static_import, vmcalls::imported_static_memory_size as usize);
let memory_buffer = target_machine
.write_to_memory_buffer(&module, FileType::Object)
.unwrap();
Self { exec_engine }
let mut tempfile = NamedTempFile::new().unwrap();
tempfile.write_all(memory_buffer.as_slice()).unwrap();
tempfile.flush().unwrap();
let library = Library::open(tempfile.path()).unwrap();
Self { tempfile, library }
}
}
impl FuncResolver for LLVMBackend {
fn get(&self, module: &ModuleInner, local_func_index: LocalFuncIndex) -> Option<NonNull<vm::Func>> {
fn get(
&self,
module: &ModuleInner,
local_func_index: LocalFuncIndex,
) -> Option<NonNull<vm::Func>> {
let index = module.info.imported_functions.len() + local_func_index.index();
let name = format!("fn{}", index);
let name = if cfg!(macos) {
format!("_fn{}", index)
} else {
format!("fn{}", index)
};
unsafe {
let func: JitFunction<unsafe extern fn()> = self.exec_engine.get_function(&name).ok()?;
self.library
.symbol::<NonNull<vm::Func>>(&name)
.ok()
.map(|symbol| *symbol)
}
}
}
}

View File

@ -481,6 +481,7 @@ fn parse_function(
// Emit an unreachable instruction.
// If llvm cannot prove that this is never touched,
// it will emit a `ud2` instruction on x86_64 arches.
ctx.build_trap();
builder.build_unreachable();
state.reachable = false;
}
@ -623,7 +624,8 @@ fn parse_function(
}
}
Operator::CallIndirect { index, table_index } => {
let expected_dynamic_sigindex = ctx.dynamic_sigindex(SigIndex::new(index as usize));
let sig_index = SigIndex::new(index as usize);
let expected_dynamic_sigindex = ctx.dynamic_sigindex(sig_index);
let (table_base, table_bound) = ctx.table(TableIndex::new(table_index as usize));
let func_index = state.pop1()?.into_int_value();
@ -651,12 +653,10 @@ fn parse_function(
"func_ptr",
)
.into_pointer_value(),
builder
.build_load(
builder.build_struct_gep(anyfunc_struct_ptr, 1, "ctx_ptr_ptr"),
"ctx_ptr",
)
.into_pointer_value(),
builder.build_load(
builder.build_struct_gep(anyfunc_struct_ptr, 1, "ctx_ptr_ptr"),
"ctx_ptr",
),
builder
.build_load(
builder.build_struct_gep(anyfunc_struct_ptr, 2, "sigindex_ptr"),
@ -685,21 +685,49 @@ fn parse_function(
)
.try_as_basic_value()
.left()
.unwrap();
.unwrap()
.into_int_value();
let continue_block = context.append_basic_block(&function, "continue_block");
let sigindices_notequal_block =
context.append_basic_block(&function, "sigindices_notequal_block");
builder.build_conditional_branch(
sigindices_equal,
&continue_block,
&sigindices_notequal_block,
);
builder.position_at_end(&sigindices_notequal_block);
ctx.build_trap();
builder.build_unreachable();
builder.position_at_end(&continue_block);
println!("func ptr: {:#?}", func_ptr);
println!("ctx ptr: {:#?}", ctx_ptr);
println!("found dynamic sigindex: {:#?}", found_dynamic_sigindex);
let wasmer_fn_sig = &info.signatures[sig_index];
let fn_ty = signatures[sig_index];
unimplemented!("{}, {}", index, table_index);
let pushed_args = state.popn_save(wasmer_fn_sig.params().len())?;
let args: Vec<_> = std::iter::once(ctx_ptr)
.chain(pushed_args.into_iter())
.collect();
println!("args: {:?}", args);
let typed_func_ptr = builder.build_pointer_cast(
func_ptr,
fn_ty.ptr_type(AddressSpace::Generic),
"typed_func_ptr",
);
let call_site = builder.build_call(typed_func_ptr, &args, "indirect_call");
match wasmer_fn_sig.returns() {
[] => {}
[_] => {
let value = call_site.try_as_basic_value().left().unwrap();
state.push1(value);
}
returns @ _ => unimplemented!("multi-value returns"),
}
}
/***************************

View File

@ -64,6 +64,7 @@ pub struct Intrinsics {
pub copysign_f64: FunctionValue,
pub expect_i1: FunctionValue,
pub trap: FunctionValue,
pub void_ty: VoidType,
pub i1_ty: IntType,
@ -255,6 +256,7 @@ impl Intrinsics {
copysign_f64: module.add_function("llvm.copysign.f64", ret_f64_take_f64_f64, None),
expect_i1: module.add_function("llvm.expect.i1", ret_i1_take_i1_i1, None),
trap: module.add_function("llvm.trap", void_ty.fn_type(&[], false), None),
void_ty,
i1_ty,
@ -695,7 +697,9 @@ impl<'a> CtxType<'a> {
(imported_func_cache.func_ptr, imported_func_cache.ctx_ptr)
}
// pub fn table(&mut self, table_index: TableIndex, elem_index: IntValue) ->
pub fn build_trap(&self) {
self.builder.build_call(self.intrinsics.trap, &[], "trap");
}
}
// pub struct Ctx {

View File

@ -10,11 +10,11 @@ use wasmer_runtime_core::{
module::ModuleInner,
};
mod backend;
mod code;
mod intrinsics;
mod read_info;
mod state;
// mod backend;
pub struct LLVMCompiler {
_private: (),
@ -28,13 +28,61 @@ impl LLVMCompiler {
impl Compiler for LLVMCompiler {
fn compile(&self, wasm: &[u8], _: Token) -> Result<ModuleInner, CompileError> {
let (_info, _code_reader) = read_info::read_module(wasm).unwrap();
let (info, code_reader) = read_info::read_module(wasm).unwrap();
let (module, intrinsics) = code::parse_function_bodies(&info, code_reader).unwrap();
unimplemented!()
let backend = backend::LLVMBackend::new(module, intrinsics);
// Create placeholder values here.
let (protected_caller, cache_gen) = {
use wasmer_runtime_core::backend::{
sys::Memory, CacheGen, ProtectedCaller, UserTrapper,
};
use wasmer_runtime_core::cache::Error as CacheError;
use wasmer_runtime_core::error::RuntimeResult;
use wasmer_runtime_core::module::ModuleInfo;
use wasmer_runtime_core::types::{FuncIndex, Value};
use wasmer_runtime_core::vm;
struct Placeholder;
impl ProtectedCaller for Placeholder {
fn call(
&self,
_module: &ModuleInner,
_func_index: FuncIndex,
_params: &[Value],
_import_backing: &vm::ImportBacking,
_vmctx: *mut vm::Ctx,
_: Token,
) -> RuntimeResult<Vec<Value>> {
Ok(vec![])
}
fn get_early_trapper(&self) -> Box<dyn UserTrapper> {
unimplemented!()
}
}
impl CacheGen for Placeholder {
fn generate_cache(
&self,
module: &ModuleInner,
) -> Result<(Box<ModuleInfo>, Box<[u8]>, Memory), CacheError> {
unimplemented!()
}
}
(Box::new(Placeholder), Box::new(Placeholder))
};
Ok(ModuleInner {
func_resolver: Box::new(backend),
protected_caller,
cache_gen,
info,
})
}
unsafe fn from_cache(&self, _artifact: Artifact, _: Token) -> Result<ModuleInner, CacheError> {
unimplemented!()
unimplemented!("the llvm backend doesn't support caching yet")
}
}
@ -55,14 +103,9 @@ fn test_read_module() {
get_local 0
i32.const 0
call_indirect (type $t0)
memory.grow
)
(func $foobar (type $t0)
get_local 0
)
(func $bar (type $t0) (param i32) (result i32)
get_local 0
call $foo
))
"#;
let wasm = wat2wasm(wat).unwrap();
@ -71,86 +114,50 @@ fn test_read_module() {
let (module, intrinsics) = code::parse_function_bodies(&info, code_reader).unwrap();
{
Target::initialize_x86(&InitializationConfig {
asm_parser: true,
asm_printer: true,
base: true,
disassembler: true,
info: true,
machine_code: true,
});
let triple = TargetMachine::get_default_triple().to_string();
let target = Target::from_triple(&triple).unwrap();
let target_machine = target
.create_target_machine(
&triple,
&TargetMachine::get_host_cpu_name().to_string(),
&TargetMachine::get_host_cpu_features().to_string(),
OptimizationLevel::Default,
RelocMode::PIC,
CodeModel::Default,
)
.unwrap();
// let backend = backend::LLVMBackend::new(module, intrinsics);
let memory_buffer = target_machine
.write_to_memory_buffer(&module, FileType::Object)
.unwrap();
// std::fs::write("memory_buffer", memory_buffer.as_slice()).unwrap();
let mem_buf_slice = memory_buffer.as_slice();
let macho = goblin::mach::MachO::parse(mem_buf_slice, 0).unwrap();
let symbols = macho.symbols.as_ref().unwrap();
let relocations = macho.relocations().unwrap();
for (_, reloc_iter, section) in relocations.into_iter() {
println!("section: {:#?}", section);
for reloc_info in reloc_iter {
let reloc_info = reloc_info.unwrap();
println!("\treloc_info: {:#?}", reloc_info);
println!(
"\tsymbol: {:#?}",
symbols.get(reloc_info.r_symbolnum()).unwrap()
);
}
}
extern "C" {
fn test_cpp();
}
let exec_engine = module
.create_jit_execution_engine(OptimizationLevel::Default)
.unwrap();
unsafe { test_cpp() };
exec_engine.add_global_mapping(
&intrinsics.memory_grow_dynamic_local,
vmcalls::local_dynamic_memory_grow as usize,
);
exec_engine.add_global_mapping(
&intrinsics.memory_grow_static_local,
vmcalls::local_static_memory_grow as usize,
);
exec_engine.add_global_mapping(
&intrinsics.memory_grow_dynamic_import,
vmcalls::imported_dynamic_memory_grow as usize,
);
exec_engine.add_global_mapping(
&intrinsics.memory_grow_static_import,
vmcalls::imported_static_memory_grow as usize,
);
exec_engine.add_global_mapping(
&intrinsics.memory_size_dynamic_local,
vmcalls::local_dynamic_memory_size as usize,
);
exec_engine.add_global_mapping(
&intrinsics.memory_size_static_local,
vmcalls::local_static_memory_size as usize,
);
exec_engine.add_global_mapping(
&intrinsics.memory_size_dynamic_import,
vmcalls::imported_dynamic_memory_size as usize,
);
exec_engine.add_global_mapping(
&intrinsics.memory_size_static_import,
vmcalls::imported_static_memory_size as usize,
);
// let exec_engine = module
// .create_jit_execution_engine(OptimizationLevel::Default)
// .unwrap();
// exec_engine.add_global_mapping(
// &intrinsics.memory_grow_dynamic_local,
// vmcalls::local_dynamic_memory_grow as usize,
// );
// exec_engine.add_global_mapping(
// &intrinsics.memory_grow_static_local,
// vmcalls::local_static_memory_grow as usize,
// );
// exec_engine.add_global_mapping(
// &intrinsics.memory_grow_dynamic_import,
// vmcalls::imported_dynamic_memory_grow as usize,
// );
// exec_engine.add_global_mapping(
// &intrinsics.memory_grow_static_import,
// vmcalls::imported_static_memory_grow as usize,
// );
// exec_engine.add_global_mapping(
// &intrinsics.memory_size_dynamic_local,
// vmcalls::local_dynamic_memory_size as usize,
// );
// exec_engine.add_global_mapping(
// &intrinsics.memory_size_static_local,
// vmcalls::local_static_memory_size as usize,
// );
// exec_engine.add_global_mapping(
// &intrinsics.memory_size_dynamic_import,
// vmcalls::imported_dynamic_memory_size as usize,
// );
// exec_engine.add_global_mapping(
// &intrinsics.memory_size_static_import,
// vmcalls::imported_static_memory_size as usize,
// );
// unsafe {
// let func: JitFunction<unsafe extern fn(*mut u8, i32) -> i32> = exec_engine.get_function("fn0").unwrap();