2026-06-12 11:40:26 +00:00

75 lines
2.3 KiB
C++

// WASM-PROPOSAL Phase 0 — core module stub.
//
// Stands in for the future "core module" (uce_lib + libc compiled to wasm):
// owns linear memory, the allocator, and libc/libc++ (statically linked,
// per the §10 mitigation: avoid shared wasi-libc entirely). Built as a
// non-PIC wasm32-wasi reactor with everything exported so unit modules can
// import from it.
//
// Deliberately avoids WASI I/O (no printf-to-fd): output accumulates in a
// buffer the host reads back, so the module can be instantiated through the
// plain wasm-c-api without a WASI context if need be.
#include <string>
#include <functional>
#include <cstdio>
#include <cstring>
static std::string g_output;
extern "C" {
// data symbol referenced from the unit module → must arrive there as a
// GOT.mem import
int core_counter = 7;
void uce_print(const char* s, size_t len)
{
g_output.append(s, len);
}
// heap C++ object created in core, handed to the unit by pointer —
// validates one-heap/one-allocator pointer semantics (§3.4)
std::string* core_make_string(const char* s)
{
return(new std::string(s));
}
void core_append_string(std::string* str, const char* s)
{
str->append(s);
}
// plain function pointer crossing: unit passes its own function, core calls
// it back — validates the shared funcref table
void core_invoke_callback(void (*cb)(int), int arg)
{
cb(arg);
}
// std::function allocated by unit code, executed here — validates fat
// callable objects (lambdas) across module boundaries
void core_invoke_function(std::function<int(int)>* f, int arg)
{
char buf[64];
snprintf(buf, sizeof(buf), "[fn:%d]", (*f)(arg));
g_output.append(buf);
}
// GOT.func resolution helper: taking the address here forces uce_print into
// core's elem segment at link time, and on wasm a function pointer IS its
// table index — so the loader can resolve GOT.func.uce_print with a plain
// call instead of host-side funcref injection (which WAMR does not allow).
// The production core will generalize this into a name → funcptr registry.
intptr_t core_table_index_of_uce_print()
{
return(reinterpret_cast<intptr_t>(uce_print));
}
// host reads the result out of linear memory via these
const char* core_output_data() { return(g_output.data()); }
size_t core_output_size() { return(g_output.size()); }
void core_output_clear() { g_output.clear(); }
}