Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasm2c: uvwasi support #2002

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
27 changes: 27 additions & 0 deletions wasm2c/examples/build-standlone/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
WABT_ROOT=../../..
WASM2C=$(WABT_ROOT)/bin/wasm2c

WASM2C_RUNTIME_PATH=$(WABT_ROOT)/wasm2c/
WASM2C_RUNTIME_FILES=$(addprefix $(WASM2C_RUNTIME_PATH), wasm-rt-impl.c uvwasi-rt.c)

UVWASI_PATH=$(WABT_ROOT)/third_party/uvwasi

DEPS=-I$(UVWASI_PATH)/include -L$(WABT_ROOT)/build/_deps/libuv-build -L$(WABT_ROOT)/build/third_party/uvwasi

LIBS=-luvwasi_a -luv_a -lpthread -ldl -lm

DBG_FLAGS=-g
REL_FLAGS=-O3 -flto -fomit-frame-pointer -fno-stack-protector

CFLAGS=$(REL_FLAGS)

all: input.elf

clean:
rm -rf $(ALL_RESULTS) input.*

input.c:
$(WASM2C) input.wasm -o input.c

input.elf: input.c uvwasi-rt-main.c $(WASM2C_RUNTIME_FILES)
$(CC) $(CFLAGS) input.c uvwasi-rt-main.c -o input.elf -I$(WASM2C_RUNTIME_PATH) $(WASM2C_RUNTIME_FILES) $(DEPS) $(LIBS)
24 changes: 24 additions & 0 deletions wasm2c/examples/build-standlone/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/bash
if [ -z "$1" ]
then
echo "Compiles wasm file into standalone binary"
echo "usage: build.sh foo.wasm"
echo "outputs: foo.elf"
exit
fi

ORIGIN_DIR=$(pwd)
SCRIPT_DIR=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
output_file=$(basename -- "$1")
output_file="${output_file%%.*}.elf"

set -v

cd $SCRIPT_DIR
make clean

cp ${ORIGIN_DIR}/$1 ./input.wasm
make input.c

make input.elf
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like this build-standalone idea. The mixing of a build.sh script and the Makefile file a find a little confusing, but I think we can iterate on it over time.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For sure, it was just a quick way to get something working, if we want to promote to a first class feature I can just replace it with a stand-alone script.

cp -f input.elf ${ORIGIN_DIR}/${output_file}
Binary file not shown.
76 changes: 76 additions & 0 deletions wasm2c/examples/build-standlone/uvwasi-rt-main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/* Link this with wasm2c output and uvwasi runtime to build a standalone app */
#include <stdio.h>
#include <stdlib.h>
#include "uvwasi.h"
#include "uvwasi-rt.h"

#define MODULE_NAME input
#define MODULE_HEADER "input.h"
#include MODULE_HEADER

//force pre-processor expansion of m_name
#define __module_init(m_name) Z_## m_name ##_init_module()
#define module_init(m_name) __module_init(m_name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also agree with @keithw that it would be nice to avoid these macros and assume that wasm2c was run with the correct -m flag.

Copy link
Author

@talg talg Oct 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For sure, they have been removed in 9703be9.


#define __module_instantiate(m_name, instance_p, wasi_p) Z_## m_name ##_instantiate(instance_p, wasi_p)
#define module_instantiate(m_name ,instance_p, wasi_p) __module_instantiate(m_name ,instance_p, wasi_p)

#define __module_free(m_name, instance_p) Z_## m_name ##_free(instance_p)
#define module_free(m_name, instance_p) __module_free(m_name, instance_p)

#define __module_start(m_name, instance_p) Z_ ## m_name ## Z__start(instance_p)
#define module_start(m_name, instance_p) __module_start(m_name, instance_p)

int main(int argc, const char** argv)
{
Z_input_instance_t local_instance;
uvwasi_t local_uvwasi_state;

struct Z_wasi_snapshot_preview1_instance_t wasi_state = {
.uvwasi = &local_uvwasi_state,
.instance_memory = &local_instance.w2c_memory
};

uvwasi_options_t init_options;

//pass in standard descriptors
init_options.in = 0;
init_options.out = 1;
init_options.err = 2;
init_options.fd_table_size = 3;

//pass in args and environement
extern const char ** environ;
init_options.argc = argc;
init_options.argv = argv;
init_options.envp = (const char **) environ;

//no sandboxing enforced, binary has access to everything user does
init_options.preopenc = 2;
init_options.preopens = calloc(2, sizeof(uvwasi_preopen_t));

init_options.preopens[0].mapped_path = "/";
init_options.preopens[0].real_path = "/";
init_options.preopens[1].mapped_path = "./";
init_options.preopens[1].real_path = ".";

init_options.allocator = NULL;

wasm_rt_init();
uvwasi_errno_t ret = uvwasi_init(&local_uvwasi_state, &init_options);

if (ret != UVWASI_ESUCCESS) {
printf("uvwasi_init failed with error %d\n", ret);
exit(1);
}

module_init(MODULE_NAME);
module_instantiate(MODULE_NAME, &local_instance, (struct Z_wasi_snapshot_preview1_instance_t *) &wasi_state);
module_start(MODULE_NAME, &local_instance);
module_free(MODULE_NAME, &local_instance);

uvwasi_destroy(&local_uvwasi_state);
wasm_rt_free();

return 0;
}