Last active
September 29, 2024 02:00
-
-
Save GavinRay97/8e83758cf8c1c9d886df154ee2a6b7d7 to your computer and use it in GitHub Desktop.
WASM copy structs to memory from host -> module
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstring> | |
#include <fstream> | |
#include <sstream> | |
#include <vector> | |
#include <wasmtime.hh> | |
struct MyStruct { | |
int a; | |
int b; | |
}; | |
std::string read_file(const char* name) | |
{ | |
std::ifstream wat_file; | |
wat_file.open(name); | |
std::stringstream str_stream; | |
str_stream << wat_file.rdbuf(); | |
return str_stream.str(); | |
} | |
int main() | |
{ | |
auto config = wasmtime::Config(); | |
config.strategy(wasmtime::Strategy::Auto); | |
// Init engine | |
auto engine = wasmtime::Engine(); | |
// Load wasm module | |
printf("Loading module...\n"); | |
auto store = wasmtime::Store(engine); | |
std::string wasm_module = read_file("module.wasm"); | |
wasmtime::Span<uint8_t> wasm_module_span(reinterpret_cast<uint8_t*>(wasm_module.data()), wasm_module.size()); | |
auto module = wasmtime::Module::compile(engine, wasm_module_span).unwrap(); | |
// Configure WASI and store it within our `wasmtime_store_t` | |
wasmtime::WasiConfig wasi; | |
wasi.inherit_argv(); | |
wasi.inherit_env(); | |
wasi.inherit_stdin(); | |
wasi.inherit_stdout(); | |
wasi.inherit_stderr(); | |
store.context().set_wasi(std::move(wasi)).unwrap(); | |
// Create our linker which will be linking our modules together, and then add | |
// our WASI instance to it. | |
wasmtime::Linker linker(engine); | |
linker.define_wasi().unwrap(); | |
// Prepare data | |
MyStruct data[] = { { 1, 2 }, { 3, 4 }, { 5, 6 } }; | |
int32_t count = sizeof(data) / sizeof(MyStruct); | |
// Instantiate module and get the imported function | |
auto instance = linker.instantiate(store.context(), module).unwrap(); | |
printf("Getting processData...\n"); | |
auto process_data = std::get<wasmtime::Func>(*instance.get(store, "process_data")); | |
printf("Getting malloc...\n"); | |
auto wasm_malloc = std::get<wasmtime::Func>(*instance.get(store, "malloc")); | |
printf("Getting free...\n"); | |
auto wasm_free = std::get<wasmtime::Func>(*instance.get(store, "free")); | |
printf("Getting memory...\n"); | |
auto memory = std::get<wasmtime::Memory>(*instance.get(store, "memory")); | |
auto serialized_data_ptr = wasm_malloc.call(store, { wasmtime::Val((int32_t)sizeof(data)) }).unwrap(); | |
auto serialized_data_ptr_value = serialized_data_ptr[0].i32(); | |
printf("Serialized data ptr: %x\n", serialized_data_ptr_value); | |
// Copy serialized data to wasm memory | |
auto memory_base = memory.data(store); | |
auto memory_size_pages = memory.size(store); | |
auto serialzed_data_ptr_offset = serialized_data_ptr_value; | |
auto serialized_data_ptr_end = serialzed_data_ptr_offset + sizeof(data); | |
printf("Memory base: %x\n", memory_base.data()); | |
printf("Memory size (WASM pages): %d\n", memory_size_pages); | |
printf("Serialized data ptr offset: %d\n", serialzed_data_ptr_offset); | |
printf("Serialized data ptr end: %d\n", serialized_data_ptr_end); | |
memcpy(memory_base.data() + serialzed_data_ptr_offset, data, sizeof(data)); | |
// Call the function | |
printf("Calling processData...\n"); | |
auto result = process_data.call(store, { wasmtime::Val(serialized_data_ptr_value), wasmtime::Val(count) }).unwrap(); | |
// Free the memory | |
printf("Freeing memory...\n"); | |
wasm_free.call(store, { wasmtime::Val(serialized_data_ptr_value) }).unwrap(); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
WASI_VERSION_FULL = 20.0 | |
WASMTIME_DIR = ../third-party/wasmtime-dev-x86_64-linux-c-api | |
WASI_SDK_PATH = ./wasi-sdk-$(WASI_VERSION_FULL) | |
CC = clang++ | |
WASM_CC = $(WASI_SDK_PATH)/bin/clang++ --sysroot=$(WASI_SDK_PATH)/share/wasi-sysroot | |
CFLAGS = -std=c++20 -I$(WASMTIME_DIR)/include -L$(WASMTIME_DIR)/lib | |
LIBS = -lwasmtime | |
all: host module | |
host: host.cpp | |
$(CC) $(CFLAGS) host.cpp -o host $(LIBS) | |
module: module.cpp | |
$(WASM_CC) module.cpp -Wl,--export-all -Wl,--export-memory -mexec-model=reactor -o module.wasm | |
run: host module | |
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(shell pwd) ./host | |
clean: | |
rm -f host | |
rm -f module.wasm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdio> | |
#include <cstdlib> | |
extern "C" { | |
struct MyStruct { | |
int a; | |
int b; | |
}; | |
void* _malloc(size_t size) | |
{ | |
return malloc(size); | |
} | |
void _free(void* ptr) | |
{ | |
free(ptr); | |
} | |
void process_data(MyStruct* structs, int count) | |
{ | |
for (int i = 0; i < count; ++i) { | |
MyStruct current = structs[i]; | |
printf("a: %d, b: %d\n", current.a, current.b); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ ./host | |
Loading module... | |
Getting processData... | |
Getting malloc... | |
Getting free... | |
Getting memory... | |
Serialized data ptr: 114a0 | |
Memory base: ac000000 | |
Memory size (WASM pages): 2 | |
Serialized data ptr offset: 70816 | |
Serialized data ptr end: 70840 | |
Calling processData... | |
a: 1, b: 2 | |
a: 3, b: 4 | |
a: 5, b: 6 | |
Freeing memory... |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment