-
Notifications
You must be signed in to change notification settings - Fork 721
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
base: main
Are you sure you want to change the base?
wasm2c: uvwasi support #2002
Changes from 4 commits
facbe9a
2109168
716760c
f22d786
a03de93
e9cd029
9703be9
9e91a3a
5509923
a24d4d1
fe560a2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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) |
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I really like this There was a problem hiding this comment. Choose a reason for hiding this commentThe 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} |
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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
#assumes wasi-sdk installed system wide in default location | ||
WASI_SDK_ROOT=/opt/wasi-sdk | ||
WABT_ROOT=../../.. | ||
|
||
WASI_CLANG=$(WASI_SDK_ROOT)/bin/clang | ||
WASI_SYSROOT=$(WASI_SDK_ROOT)/share/wasi-sysroot | ||
|
||
#CFLAGS for compiling files to place nice with wasm2c | ||
WASM_CFLAGS=-Wl,--export-all -Wl,--no-entry -Wl,--growable-table -Wl,--stack-first -Wl,-z,stack-size=1048576 | ||
|
||
|
||
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 | ||
|
||
ALL_RESULTS=hello.wasm hello.wasm.c hello.elf | ||
|
||
all: $(ALL_RESULTS) | ||
|
||
clean: | ||
rm -rf $(ALL_RESULTS) hello.wasm.h *.o | ||
|
||
hello.wasm: hello.c | ||
$(WASI_CLANG) --sysroot $(WASI_SYSROOT) $(WASM_CFLAGS) hello.c -o hello.wasm | ||
|
||
hello.wasm.c: hello.wasm | ||
$(WASM2C) hello.wasm -o hello.wasm.c | ||
|
||
hello.elf: hello.wasm.c uvwasi-rt-main.c $(WASM2C_RUNTIME_FILES) | ||
$(CC) -g hello.wasm.c uvwasi-rt-main.c -o hello.elf -I$(WASM2C_RUNTIME_PATH) $(WASM2C_RUNTIME_FILES) $(DEPS) $(LIBS) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
-address any XXX or TODO lines | ||
-make sure linear memory accesses are bounded checked |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#include <assert.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <unistd.h> | ||
|
||
int main(int argc, char * argv[]) { | ||
|
||
printf("printing args\n"); | ||
for (int i = 0; i < argc ; i++) { | ||
printf("[%d] %s \n", i, argv[i]); | ||
} | ||
|
||
printf("Writing to stdout\n"); | ||
char * hello_str = strdup("hello world!"); | ||
puts(hello_str); | ||
|
||
printf("writing test.out\n"); | ||
FILE * fp = fopen("test.out", "w+"); | ||
assert(fp != NULL); | ||
fprintf(fp,"hello filesystem\n"); | ||
fclose(fp); | ||
printf("removing test.out\n"); | ||
assert(!unlink("test.out")); | ||
|
||
printf("writing /tmp/test.out\n"); | ||
fp = fopen("/tmp/test.out", "w+"); | ||
assert(fp != NULL); | ||
fprintf(fp,"hello filesystem\n"); | ||
fclose(fp); | ||
printf("removing /tmp/test.out\n"); | ||
assert(!unlink("/tmp/test.out")); | ||
|
||
return 0; | ||
} |
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 hello | ||
#define MODULE_HEADER "hello.wasm.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) | ||
|
||
#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_hello_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; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already have a
WITH_WASI
flag .. is there some reason we can't use use that?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seemed to me like enabling the mostly not working wasi support in the interpreter, and allowing people to build their standalone apps with uvwasi were logically separate things. I'm not attached around the issue of wether this is enabled by default, so whatever makes sense just lmk.