Skip to content

Instantly share code, notes, and snippets.

@GavinRay97
Last active July 26, 2023 22:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GavinRay97/8e83758cf8c1c9d886df154ee2a6b7d7 to your computer and use it in GitHub Desktop.
Save GavinRay97/8e83758cf8c1c9d886df154ee2a6b7d7 to your computer and use it in GitHub Desktop.
WASM copy structs to memory from host -> module
#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;
}
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
#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);
}
}
}
$ ./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