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?