2

I am using WebAssembly to implement a sandboxed plugin system in a C application. Users can write plugins in any language that will compile to WASM, and we just say "you can import a, b, c functions, and you must export x, y, z, functions". At the moment, WASM modules must export malloc and free so that the runtime environment can allocate space in WASM memory for passing arguments in, and free space used by arguments or return values passed out.

That seems rather inefficient, as it involves every module having its own duplicated copy of the memory management functions, as well as wasting space in WASM memory with heap management overhead and running memory functions in the WASM VM rather than as native code.

I would like to be able to be able to implement my own memory manager that runs in native code and keeps track of heap overhead externally, but that requires knowing something about the static memory layout of the module.

I'm using Wasmtime for the embedded WASM VM, and I would like to be able to give users documentation on how to produce a compliant module with Emscripten. Emscripten has an option to omit a malloc implementation and provide your own, but I can't find any documentation on how to actually do the "provide your own" part. I cannot figure out how to get it to export a __heap_base symbol, and I've found conflicting claims about how the stack layout works, which complicates figuring out how to grow memory (do we just add more, or does the stack segment need to be copied to expand space between the stack and heap? And if the latter, how would the WASM program be informed of the address change?) I thought I might be able to compute a heap base on my own by inspecting the static data declarations in a WASM module to figure out where that ends, but Wasmtime doesn't seem to provide any means of doing so.

So, how can I actually do this? Is there an example I can reference somewhere of replacing malloc and free with imported functions?

1 Answer 1

0

By default the layout is this (going from address 0 to larger): data - stack - heap, but it's preferable to use -Wl,--stack-first so that it would be stack - data - heap so that a stack underflow (stack pointers go down, a function that needs stack starts the function by decreasing the global0 which is the stack pointer and ends by reincreasing it) would be at negative addresses instead of getting on the data range. Either way you get a constant __heap_base and you do whatever you want at or above it up to the size of the linear memory, which you can enlarge, and the stack and static data section aren't affected (although the whole linear memory might be relocated from the point of view of the host, but that doesn't affect the module). I for one choose to start writing data about my allocator at __heap_base so my host can read there and see if it recognises my allocator.

So you need the following:

  • Know the module's linear memory address in the host's address space for directly access using wasmtime_memory_data().

  • Know where the heap starts. I don't currently use emcc as I directly use vanilla Clang to cross-compile to Wasm (with no libc other than my own), so to export symbols like __heap_base I do this: -Wl,--export=__heap_base,--export=__data_end,--export=__stack_pointer , and in my host I import the symbol using wasmtime_global_get().

  • Know how big the linear memory is with wasmtime_memory_data_size() so you'll know when you need more.

  • Increase it with wasmtime_memory_grow().

And with this you're set, that's everything you need to make your external allocator. As for an example you can reference you might get some good ideas from my own Wasm-oriented allocator which as it is does everything from the module but could be adapted as an external allocator. The top of cita_wasm.h shows how I suppress the default allocator by doing things like void *malloc(size_t size) { return NULL; } while later I use a macro to define my real implementation of malloc() by doing #define malloc(s) cita_wasm_malloc((s), __FILE_NAME__, __func__, __LINE__).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.