mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 06:15:33 +00:00
Get function addresses from llvm-compiled code
This commit is contained in:
parent
5d77769381
commit
d4ae5cdd40
46
Cargo.lock
generated
46
Cargo.lock
generated
@ -106,6 +106,22 @@ name = "byteorder"
|
|||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "capstone"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"capstone-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "capstone-sys"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cast"
|
name = "cast"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@ -262,28 +278,6 @@ dependencies = [
|
|||||||
"generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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.3.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]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.5.1"
|
version = "1.5.1"
|
||||||
@ -491,16 +485,16 @@ dependencies = [
|
|||||||
name = "llvm-backend"
|
name = "llvm-backend"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"capstone 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"inkwell 0.1.0 (git+https://github.com/TheDan64/inkwell?branch=llvm7-0)",
|
||||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 1.1.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)",
|
"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)",
|
"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)",
|
"wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"wasmer-runtime-core 0.1.2",
|
"wasmer-runtime-core 0.1.2",
|
||||||
"wasmparser 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"wasmparser 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1373,6 +1367,8 @@ dependencies = [
|
|||||||
"checksum block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d75255892aeb580d3c566f213a2b6fdc1c66667839f45719ee1d30ebf2aea591"
|
"checksum block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d75255892aeb580d3c566f213a2b6fdc1c66667839f45719ee1d30ebf2aea591"
|
||||||
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||||
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
|
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
|
||||||
|
"checksum capstone 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "00be9d203fa0e078b93b24603633fb081851dfe0c1086364431f52587a47157e"
|
||||||
|
"checksum capstone-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2dc8d32bc5c1e6d0fcde10af411c98b07d93498d51654f678757f08fa2acd6a6"
|
||||||
"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
|
"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
|
||||||
"checksum cbindgen 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "32e01024aaf5390d6a8145047371a4f5b0063a14c1e411bc731353bd2278ca44"
|
"checksum cbindgen 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "32e01024aaf5390d6a8145047371a4f5b0063a14c1e411bc731353bd2278ca44"
|
||||||
"checksum cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4390a3b5f4f6bce9c1d0c00128379df433e53777fdd30e92f16a529332baec4e"
|
"checksum cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4390a3b5f4f6bce9c1d0c00128379df433e53777fdd30e92f16a529332baec4e"
|
||||||
@ -1390,8 +1386,6 @@ dependencies = [
|
|||||||
"checksum cranelift-native 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "474bee81d620a473bf43411a3d6f10ffbf7965141dc5e5b76d8d2151dde3285d"
|
"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 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 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 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 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"
|
"checksum env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afb070faf94c85d17d50ca44f6ad076bce18ae92f0037d350947240a36e9d42e"
|
||||||
|
@ -11,8 +11,8 @@ inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "llvm7-0" }
|
|||||||
hashbrown = "0.1.8"
|
hashbrown = "0.1.8"
|
||||||
smallvec = "0.6.8"
|
smallvec = "0.6.8"
|
||||||
goblin = "0.0.20"
|
goblin = "0.0.20"
|
||||||
dlopen = "0.1.6"
|
libc = "0.2.49"
|
||||||
tempfile = "3.0.7"
|
capstone = "0.5.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cc = "1.0"
|
cc = "1.0"
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include "object_loader.hh"
|
#include "object_loader.hh"
|
||||||
#include <llvm/ExecutionEngine/RuntimeDyld.h>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -40,20 +39,26 @@ public:
|
|||||||
uintptr_t read_write_data_size,
|
uintptr_t read_write_data_size,
|
||||||
uint32_t read_write_data_align
|
uint32_t read_write_data_align
|
||||||
) override {
|
) override {
|
||||||
uint8_t *ptr_out = nullptr;
|
uint8_t *code_ptr_out = nullptr;
|
||||||
size_t size_out = 0;
|
size_t code_size_out = 0;
|
||||||
|
auto code_result = callbacks->alloc_memory(code_size, PROTECT_READ_WRITE, &code_ptr_out, &code_size_out);
|
||||||
|
assert(code_result == RESULT_OK);
|
||||||
|
code_section = Section { code_ptr_out, code_size_out };
|
||||||
|
code_bump_ptr = (uintptr_t)code_ptr_out;
|
||||||
|
|
||||||
auto code_result = callbacks->alloc_memory(code_size, PROTECT_READ_WRITE, &ptr_out, &size_out);
|
uint8_t *read_ptr_out = nullptr;
|
||||||
code_section = Section { ptr_out, size_out };
|
size_t read_size_out = 0;
|
||||||
code_bump_ptr = (uintptr_t)ptr_out;
|
auto read_result = callbacks->alloc_memory(read_data_size, PROTECT_READ_WRITE, &read_ptr_out, &read_size_out);
|
||||||
|
assert(read_result == RESULT_OK);
|
||||||
|
read_section = Section { read_ptr_out, read_size_out };
|
||||||
|
read_bump_ptr = (uintptr_t)read_ptr_out;
|
||||||
|
|
||||||
auto read_result = callbacks->alloc_memory(read_data_size, PROTECT_READ_WRITE, &ptr_out, &size_out);
|
uint8_t *readwrite_ptr_out = nullptr;
|
||||||
read_section = Section { ptr_out, size_out };
|
size_t readwrite_size_out = 0;
|
||||||
read_bump_ptr = (uintptr_t)ptr_out;
|
auto readwrite_result = callbacks->alloc_memory(read_write_data_size, PROTECT_READ_WRITE, &readwrite_ptr_out, &readwrite_size_out);
|
||||||
|
assert(readwrite_result == RESULT_OK);
|
||||||
auto readwrite_result = callbacks->alloc_memory(read_write_data_size, PROTECT_READ_WRITE, &ptr_out, &size_out);
|
readwrite_section = Section { readwrite_ptr_out, readwrite_size_out };
|
||||||
readwrite_section = Section { ptr_out, size_out };
|
readwrite_bump_ptr = (uintptr_t)readwrite_ptr_out;
|
||||||
readwrite_bump_ptr = (uintptr_t)ptr_out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Turn on the `reserveAllocationSpace` callback. */
|
/* Turn on the `reserveAllocationSpace` callback. */
|
||||||
@ -145,32 +150,37 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class WasmModule {
|
WasmModule::WasmModule(
|
||||||
public:
|
|
||||||
WasmModule(
|
|
||||||
const uint8_t *object_start,
|
const uint8_t *object_start,
|
||||||
size_t object_size,
|
size_t object_size,
|
||||||
callbacks_t *callbacks
|
callbacks_t *callbacks
|
||||||
|
) : memory_manager(std::unique_ptr<MemoryManager>(new MemoryManager(callbacks)))
|
||||||
|
{
|
||||||
|
object_file = llvm::cantFail(llvm::object::ObjectFile::createObjectFile(llvm::MemoryBufferRef(
|
||||||
|
llvm::StringRef((const char *)object_start, object_size), "object"
|
||||||
|
)));
|
||||||
|
|
||||||
) : memory_manager(std::unique_ptr<MemoryManager>(new MemoryManager(callbacks))) {
|
SymbolLookup symbol_resolver;
|
||||||
object_file = llvm::cantFail(llvm::object::ObjectFile::createObjectFile(llvm::MemoryBufferRef(
|
llvm::RuntimeDyld loader(*memory_manager, symbol_resolver);
|
||||||
llvm::StringRef((const char *)object_start, object_size), "object"
|
|
||||||
)));
|
|
||||||
|
|
||||||
SymbolLookup symbol_resolver;
|
loader.setProcessAllSections(true);
|
||||||
llvm::RuntimeDyld loader(*memory_manager, symbol_resolver);
|
|
||||||
|
|
||||||
loader.setProcessAllSections(true);
|
auto loaded_object_info = loader.loadObject(*object_file);
|
||||||
|
loader.finalizeWithMemoryManagerLocking();
|
||||||
|
|
||||||
auto loaded_object_info = loader.loadObject(*object_file);
|
assert(!loader.hasError());
|
||||||
loader.finalizeWithMemoryManagerLocking();
|
|
||||||
|
|
||||||
assert(!loader.hasError());
|
symbol_table = loader.getSymbolTable();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (auto const& pair : symbol_table) {
|
||||||
|
std::cout << "symbol: (" << (std::string)pair.first << ") => " << (void*)pair.second.getAddress() << std::endl;
|
||||||
}
|
}
|
||||||
private:
|
}
|
||||||
std::unique_ptr<MemoryManager> memory_manager;
|
|
||||||
std::unique_ptr<llvm::object::ObjectFile> object_file;
|
void* WasmModule::get_func(llvm::StringRef name) const {
|
||||||
};
|
try {
|
||||||
|
return (void*)symbol_table.at(name).getAddress();
|
||||||
|
} catch (const std::out_of_range& e) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <llvm/ExecutionEngine/RuntimeDyld.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PROTECT_NONE,
|
PROTECT_NONE,
|
||||||
@ -19,7 +20,7 @@ typedef enum {
|
|||||||
typedef result_t (*alloc_memory_t)(size_t size, mem_protect_t protect, uint8_t** ptr_out, size_t* size_out);
|
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 (*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 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 uintptr_t (*lookup_vm_symbol_t)(char* name_ptr);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* Memory management. */
|
/* Memory management. */
|
||||||
@ -30,11 +31,31 @@ typedef struct {
|
|||||||
lookup_vm_symbol_t lookup_vm_symbol;
|
lookup_vm_symbol_t lookup_vm_symbol;
|
||||||
} callbacks_t;
|
} callbacks_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class WasmModule {
|
||||||
|
public:
|
||||||
|
WasmModule(
|
||||||
|
const uint8_t *object_start,
|
||||||
|
size_t object_size,
|
||||||
|
callbacks_t *callbacks
|
||||||
|
);
|
||||||
|
|
||||||
|
void *get_func(llvm::StringRef name) const;
|
||||||
|
private:
|
||||||
|
std::unique_ptr<llvm::RuntimeDyld::MemoryManager> memory_manager;
|
||||||
|
std::unique_ptr<llvm::object::ObjectFile> object_file;
|
||||||
|
std::map<llvm::StringRef, llvm::JITEvaluatedSymbol> symbol_table;
|
||||||
|
};
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
result_t object_load(uint8_t* mem_ptr, size_t mem_size, callbacks_t* callbacks) {
|
result_t object_load(const uint8_t* mem_ptr, size_t mem_size, callbacks_t* callbacks, WasmModule** module_out) {
|
||||||
|
*module_out = new WasmModule(mem_ptr, mem_size, callbacks);
|
||||||
|
|
||||||
return RESULT_OK;
|
return RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_cpp() {
|
void* get_func_symbol(WasmModule* module, const char* name) {
|
||||||
|
return module->get_func(llvm::StringRef(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,19 +1,153 @@
|
|||||||
use crate::intrinsics::Intrinsics;
|
use crate::intrinsics::Intrinsics;
|
||||||
use dlopen::symbor::Library;
|
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
module::Module,
|
module::Module,
|
||||||
targets::{CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine},
|
targets::{CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine},
|
||||||
OptimizationLevel,
|
OptimizationLevel,
|
||||||
};
|
};
|
||||||
use std::{io::Write, ptr::NonNull};
|
use libc::{
|
||||||
use tempfile::NamedTempFile;
|
c_char, mmap, mprotect, munmap, MAP_ANON, MAP_PRIVATE, PROT_EXEC, PROT_NONE, PROT_READ,
|
||||||
|
PROT_WRITE,
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
ffi::CString,
|
||||||
|
ptr::{self, NonNull},
|
||||||
|
};
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
backend::FuncResolver, module::ModuleInner, structures::TypedIndex, types::LocalFuncIndex, vm,
|
backend::FuncResolver,
|
||||||
|
module::{ModuleInfo, ModuleInner},
|
||||||
|
structures::TypedIndex,
|
||||||
|
types::LocalFuncIndex,
|
||||||
|
vm,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct LLVMModule {
|
||||||
|
_private: [u8; 0],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
#[repr(C)]
|
||||||
|
enum MemProtect {
|
||||||
|
NONE,
|
||||||
|
READ,
|
||||||
|
READ_WRITE,
|
||||||
|
READ_EXECUTE,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
#[repr(C)]
|
||||||
|
enum LLVMResult {
|
||||||
|
OK,
|
||||||
|
ALLOCATE_FAILURE,
|
||||||
|
PROTECT_FAILURE,
|
||||||
|
DEALLOC_FAILURE,
|
||||||
|
OBJECT_LOAD_FAILURE,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct Callbacks {
|
||||||
|
alloc_memory: extern "C" fn(usize, MemProtect, &mut *mut u8, &mut usize) -> LLVMResult,
|
||||||
|
protect_memory: extern "C" fn(*mut u8, usize, MemProtect) -> LLVMResult,
|
||||||
|
dealloc_memory: extern "C" fn(*mut u8, usize) -> LLVMResult,
|
||||||
|
|
||||||
|
lookup_vm_symbol: extern "C" fn(*const c_char) -> *const vm::Func,
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn object_load(
|
||||||
|
mem_ptr: *const u8,
|
||||||
|
mem_size: usize,
|
||||||
|
callbacks: *const Callbacks,
|
||||||
|
module_out: &mut *mut LLVMModule,
|
||||||
|
) -> LLVMResult;
|
||||||
|
fn get_func_symbol(module: *mut LLVMModule, name: *const c_char) -> *const vm::Func;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_callbacks() -> Callbacks {
|
||||||
|
fn round_up_to_page_size(size: usize) -> usize {
|
||||||
|
(size + (4096 - 1)) & !(4096 - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn alloc_memory(
|
||||||
|
size: usize,
|
||||||
|
protect: MemProtect,
|
||||||
|
ptr_out: &mut *mut u8,
|
||||||
|
size_out: &mut usize,
|
||||||
|
) -> LLVMResult {
|
||||||
|
println!("size: {}", size);
|
||||||
|
let ptr = unsafe {
|
||||||
|
mmap(
|
||||||
|
ptr::null_mut(),
|
||||||
|
round_up_to_page_size(size),
|
||||||
|
match protect {
|
||||||
|
MemProtect::NONE => PROT_NONE,
|
||||||
|
MemProtect::READ => PROT_READ,
|
||||||
|
MemProtect::READ_WRITE => PROT_READ | PROT_WRITE,
|
||||||
|
MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC,
|
||||||
|
},
|
||||||
|
MAP_PRIVATE | MAP_ANON,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ptr as isize == -1 {
|
||||||
|
return LLVMResult::ALLOCATE_FAILURE;
|
||||||
|
}
|
||||||
|
*ptr_out = ptr as _;
|
||||||
|
*size_out = size;
|
||||||
|
LLVMResult::OK
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn protect_memory(ptr: *mut u8, size: usize, protect: MemProtect) -> LLVMResult {
|
||||||
|
println!("protect memory: {:p}:{} -> {:?}", ptr, size, protect);
|
||||||
|
let res = unsafe {
|
||||||
|
mprotect(
|
||||||
|
ptr as _,
|
||||||
|
round_up_to_page_size(size),
|
||||||
|
match protect {
|
||||||
|
MemProtect::NONE => PROT_NONE,
|
||||||
|
MemProtect::READ => PROT_READ,
|
||||||
|
MemProtect::READ_WRITE => PROT_READ | PROT_WRITE,
|
||||||
|
MemProtect::READ_EXECUTE => PROT_READ | PROT_EXEC,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if res == 0 {
|
||||||
|
LLVMResult::OK
|
||||||
|
} else {
|
||||||
|
LLVMResult::PROTECT_FAILURE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn dealloc_memory(ptr: *mut u8, size: usize) -> LLVMResult {
|
||||||
|
println!("dealloc_memory");
|
||||||
|
let res = unsafe { munmap(ptr as _, round_up_to_page_size(size)) };
|
||||||
|
|
||||||
|
if res == 0 {
|
||||||
|
LLVMResult::OK
|
||||||
|
} else {
|
||||||
|
LLVMResult::DEALLOC_FAILURE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn lookup_vm_symbol(_name_ptr: *const c_char) -> *const vm::Func {
|
||||||
|
ptr::null()
|
||||||
|
}
|
||||||
|
|
||||||
|
Callbacks {
|
||||||
|
alloc_memory,
|
||||||
|
protect_memory,
|
||||||
|
dealloc_memory,
|
||||||
|
lookup_vm_symbol,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for LLVMBackend {}
|
||||||
|
unsafe impl Sync for LLVMBackend {}
|
||||||
|
|
||||||
pub struct LLVMBackend {
|
pub struct LLVMBackend {
|
||||||
tempfile: NamedTempFile,
|
module: *mut LLVMModule,
|
||||||
library: Library,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LLVMBackend {
|
impl LLVMBackend {
|
||||||
@ -42,14 +176,50 @@ impl LLVMBackend {
|
|||||||
let memory_buffer = target_machine
|
let memory_buffer = target_machine
|
||||||
.write_to_memory_buffer(&module, FileType::Object)
|
.write_to_memory_buffer(&module, FileType::Object)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let mem_buf_slice = memory_buffer.as_slice();
|
||||||
|
|
||||||
let mut tempfile = NamedTempFile::new().unwrap();
|
let callbacks = get_callbacks();
|
||||||
tempfile.write_all(memory_buffer.as_slice()).unwrap();
|
let mut module: *mut LLVMModule = ptr::null_mut();
|
||||||
tempfile.flush().unwrap();
|
|
||||||
|
|
||||||
let library = Library::open(tempfile.path()).unwrap();
|
let res = unsafe {
|
||||||
|
object_load(
|
||||||
|
mem_buf_slice.as_ptr(),
|
||||||
|
mem_buf_slice.len(),
|
||||||
|
&callbacks,
|
||||||
|
&mut module,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
Self { tempfile, library }
|
if res != LLVMResult::OK {
|
||||||
|
panic!("failed to load object")
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { module }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_func(
|
||||||
|
&self,
|
||||||
|
info: &ModuleInfo,
|
||||||
|
local_func_index: LocalFuncIndex,
|
||||||
|
) -> Option<NonNull<vm::Func>> {
|
||||||
|
let index = local_func_index.index();
|
||||||
|
let name = if cfg!(target_os = "macos") {
|
||||||
|
format!("_fn{}", index)
|
||||||
|
} else {
|
||||||
|
format!("fn{}", index)
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("name: {}", name);
|
||||||
|
|
||||||
|
let c_str = CString::new(name).ok()?;
|
||||||
|
|
||||||
|
let ptr = unsafe { get_func_symbol(self.module, c_str.as_ptr()) };
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
disass_ptr(ptr as _, 0x20, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
NonNull::new(ptr as _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,18 +229,35 @@ impl FuncResolver for LLVMBackend {
|
|||||||
module: &ModuleInner,
|
module: &ModuleInner,
|
||||||
local_func_index: LocalFuncIndex,
|
local_func_index: LocalFuncIndex,
|
||||||
) -> Option<NonNull<vm::Func>> {
|
) -> Option<NonNull<vm::Func>> {
|
||||||
let index = module.info.imported_functions.len() + local_func_index.index();
|
self.get_func(&module.info, local_func_index)
|
||||||
let name = if cfg!(macos) {
|
}
|
||||||
format!("_fn{}", index)
|
}
|
||||||
} else {
|
|
||||||
format!("fn{}", index)
|
unsafe fn disass_ptr(ptr: *const u8, size: usize, inst_count: usize) {
|
||||||
};
|
use capstone::arch::BuildsCapstone;
|
||||||
|
let mut cs = capstone::Capstone::new() // Call builder-pattern
|
||||||
unsafe {
|
.x86() // X86 architecture
|
||||||
self.library
|
.mode(capstone::arch::x86::ArchMode::Mode64) // 64-bit mode
|
||||||
.symbol::<NonNull<vm::Func>>(&name)
|
.detail(true) // Generate extra instruction details
|
||||||
.ok()
|
.build()
|
||||||
.map(|symbol| *symbol)
|
.expect("Failed to create Capstone object");
|
||||||
}
|
|
||||||
|
// Get disassembled instructions
|
||||||
|
let insns = cs
|
||||||
|
.disasm_count(
|
||||||
|
std::slice::from_raw_parts(ptr, size),
|
||||||
|
ptr as u64,
|
||||||
|
inst_count,
|
||||||
|
)
|
||||||
|
.expect("Failed to disassemble");
|
||||||
|
|
||||||
|
println!("count = {}", insns.len());
|
||||||
|
for insn in insns.iter() {
|
||||||
|
println!(
|
||||||
|
"0x{:x}: {:6} {}",
|
||||||
|
insn.address(),
|
||||||
|
insn.mnemonic().unwrap_or(""),
|
||||||
|
insn.op_str().unwrap_or("")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -615,8 +615,9 @@ fn parse_function(
|
|||||||
// This is a multi-value return.
|
// This is a multi-value return.
|
||||||
let struct_value = basic_value.into_struct_value();
|
let struct_value = basic_value.into_struct_value();
|
||||||
for i in 0..(count as u32) {
|
for i in 0..(count as u32) {
|
||||||
let value =
|
let value = builder
|
||||||
builder.build_extract_value(struct_value, i, &state.var_name()).unwrap();
|
.build_extract_value(struct_value, i, &state.var_name())
|
||||||
|
.unwrap();
|
||||||
state.push1(value);
|
state.push1(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,24 +88,18 @@ impl Compiler for LLVMCompiler {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_read_module() {
|
fn test_read_module() {
|
||||||
|
use std::mem::transmute;
|
||||||
use wabt::wat2wasm;
|
use wabt::wat2wasm;
|
||||||
use wasmer_runtime_core::vmcalls;
|
use wasmer_runtime_core::{structures::TypedIndex, types::LocalFuncIndex, vm, vmcalls};
|
||||||
// let wasm = include_bytes!("../../spectests/examples/simple/simple.wasm") as &[u8];
|
// let wasm = include_bytes!("../../spectests/examples/simple/simple.wasm") as &[u8];
|
||||||
let wat = r#"
|
let wat = r#"
|
||||||
(module
|
(module
|
||||||
(type $t0 (func (param i32) (result i32)))
|
(type $t0 (func (param i32) (result i32)))
|
||||||
(type $t1 (func (result i32)))
|
(type $t1 (func (result i32)))
|
||||||
(memory 1)
|
(memory 1)
|
||||||
(table 10 anyfunc)
|
|
||||||
(elem (i32.const 0) $foobar)
|
|
||||||
(global $g0 (mut i32) (i32.const 0))
|
(global $g0 (mut i32) (i32.const 0))
|
||||||
(func $foo (type $t0) (param i32) (result i32)
|
(func $foo (type $t0) (param i32) (result i32)
|
||||||
get_local 0
|
get_local 0
|
||||||
i32.const 0
|
|
||||||
call_indirect (type $t0)
|
|
||||||
)
|
|
||||||
(func $foobar (type $t0)
|
|
||||||
get_local 0
|
|
||||||
))
|
))
|
||||||
"#;
|
"#;
|
||||||
let wasm = wat2wasm(wat).unwrap();
|
let wasm = wat2wasm(wat).unwrap();
|
||||||
@ -114,54 +108,15 @@ fn test_read_module() {
|
|||||||
|
|
||||||
let (module, intrinsics) = code::parse_function_bodies(&info, code_reader).unwrap();
|
let (module, intrinsics) = code::parse_function_bodies(&info, code_reader).unwrap();
|
||||||
|
|
||||||
// let backend = backend::LLVMBackend::new(module, intrinsics);
|
let backend = backend::LLVMBackend::new(module, intrinsics);
|
||||||
|
|
||||||
extern "C" {
|
let func_ptr = backend.get_func(&info, LocalFuncIndex::new(0)).unwrap();
|
||||||
fn test_cpp();
|
|
||||||
|
println!("func_ptr: {:p}", func_ptr.as_ptr());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let func: unsafe extern "C" fn(*mut vm::Ctx, i32) -> i32 = transmute(func_ptr);
|
||||||
|
let result = func(0 as _, 42);
|
||||||
|
println!("result: {}", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe { test_cpp() };
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
// let result = func.call(0 as _, 0);
|
|
||||||
// println!("result: {}", result);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user