Stream: wasi

Topic: Custom WASI LIBC


view this post on Zulip Axel Persinger (Dec 25 2025 at 01:48):

First off, sorry if this is the wrong place/format to ask this question, I'm new to Zulip.
I'm looking to implement my own libc (my code runs in a special container environment that doesn't have access to the normal libc - so I can't use the regular WASI). I'm using wasmtime to run my WASM code, and I'm linking in (wasmtime_linker_define_func) my own functions by declaring them with the "wasi_snapshot_preview1" module and whatever name is being imported. For instance, I have random_get defined as:

static wasm_trap_t* random_get(
    void* env,
    wasmtime_caller_t* caller,
    const wasmtime_val_t* args,
    size_t nargs,
    wasmtime_val_t* results,
    size_t nresults)
{
    LOG_DEBUG(
        "%s(%s, %p, %p, %zu, %p, %zu)",
        __FUNCTION__, (char*)env, caller, args, nargs, results, nresults);

    LOG_DEBUG("Arguments:");
    for (size_t i = 0; i < nargs; i++) {
        print_arg(&args[i]);
    }

    uint32_t buf = args[0].of.i32;
    uint32_t len = args[1].of.i32;

    const wasmtime_context_t* store = NULL;
    wasmtime_memory_t memory = { 0 };
    wasmtime_extern_t mem_extern = { 0 };
    uint8_t* data = NULL;
    size_t size = 0;

    store = wasmtime_caller_context(caller);
    assert(store);

    assert(wasmtime_caller_export_get(
        caller,
        "memory",
        sizeof("memory") - 1,
        &mem_extern));
    assert(mem_extern.kind == WASMTIME_EXTERN_MEMORY);

    memory = mem_extern.of.memory;
    data = wasmtime_memory_data(store, &memory);
    size = wasmtime_memory_data_size(store, &memory);

    if ((uint64_t)buf + len > size) {
        if (nresults > 0) {
            results[0].kind = WASMTIME_I32;
            results[0].of.i32 = 1;
        }
        return NULL;
    }

    for (uint32_t i = 0; i < len; i++) {
        data[buf + i] = (uint8_t)0; // Pretend I'm not doing something naughty here!
    }

    LOG_DEBUG("Results:");
    for (size_t i = 0; i < nresults; i++) {
        print_arg(&results[i]);
    }

    return NULL;
}

My issue is for more complicated functions like clock_time_get, I need the macros from WASI-libc (for instance __WASI_CLOCKID_MONOTONIC). But I'm not sure how to include the WASI header file properly because it complains to me that I need to build it with the WASI sys root (but I want to build it for x86!).

Any advice?

view this post on Zulip bjorn3 (Dec 25 2025 at 22:21):

The wasi-libc headers are only meant to be used from within the guest, not to be used on the host when implementing the wasi interfaces. For example it defines the buf field of __wasi_iovec_t as a pointer, when it is a 32bit index into the linear memory. You could copy paste and whatever you need and change it as necessary though. There won't be breaking changes to wasip1 (or any changes for that matter give that wasip2 and wasip3 now exist)

view this post on Zulip Axel Persinger (Dec 25 2025 at 23:33):

Okay, that makes sense. So is the only real way to implement this libc linked layer to just copy-paste the definitions between the extern C guards?

view this post on Zulip Alex Crichton (Jan 05 2026 at 17:24):

bjorn3 is right yeah, you'll want to copy out these definitions for wasip1 if you want to use wasip1 APIs.

wasip1 is defined with *.witx which is the "formal" definition although the format itself never got fully specified. With components this is all formalized in *.wit with host and guest bindings generators which solves this problem


Last updated: Jan 09 2026 at 13:15 UTC