Add WASIX DL tests, switch to wasixcc for wasix tests to get DL support

This commit is contained in:
Arshia Ghafoori
2025-08-19 18:21:45 +04:00
parent 2ee5d29ea5
commit f18d948768
20 changed files with 332 additions and 75 deletions

View File

@@ -1,3 +1,4 @@
output*
*.webc
*.wasm
*.wasm
*.so

View File

@@ -11,9 +11,9 @@ typedef unsigned char bool;
int main()
{
const size_t expected_count = 7;
const char *expected_entries[] = {".", "..", "main.c", "main.wasm", "main-not-asyncified.wasm", "output", "run.sh"};
bool entries_observed[7] = {false};
const size_t expected_count = 6;
const char *expected_entries[] = {".", "..", "main.c", "main.wasm", "output", "run.sh"};
bool entries_observed[6] = {false};
for (int fd = 3; fd <= 5; fd++)
{

View File

View File

@@ -0,0 +1,4 @@
int main_needed_func(int x)
{
return x + 1;
}

View File

@@ -0,0 +1,49 @@
#include <stdio.h>
#include <dlfcn.h>
extern int main_needed_func(int);
int main()
{
if (main_needed_func(42) != 43)
{
fprintf(stderr, "main_needed_func returned unexpected value\n");
return 1;
}
void *handle = dlopen("./libside.so", RTLD_NOW | RTLD_GLOBAL);
if (!handle)
{
fprintf(stderr, "dlopen failed: %s\n", dlerror());
return 1;
}
int (*side_func)(int) = dlsym(handle, "side_func");
if (!side_func)
{
fprintf(stderr, "dlsym failed: %s\n", dlerror());
dlclose(handle);
return 1;
}
// side_func returns (x + 4) * 2
int res = side_func(42);
if (res != 92)
{
fprintf(stderr, "side_func returned unexpected value: %d\n", res);
dlclose(handle);
return 1;
}
if (dlclose(handle) != 0)
{
fprintf(stderr, "dlclose failed: %s\n", dlerror());
return 1;
}
// Print something to make sure printf and, by extension, data relocations work.
// Do *NOT* remote this.
printf("All tests passed successfully!\n");
return 0;
}

16
tests/wasix/dl-needed/run.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/bash
set -e
export WASIXCC_WASM_EXCEPTIONS=yes
export WASIXCC_PIC=yes
# main module and its needed side
wasixcc main-needed.c -o libmain-needed.so -Wl,-shared
wasixcc main.c libmain-needed.so -o main.wasm -Wl,-pie -Wl,-rpath,\$ORIGIN
# dlopen'ed side module and its needed side
wasixcc side-needed.c -o libside-needed.so -Wl,-shared
wasixcc side.c libside-needed.so -o libside.so -Wl,-shared -Wl,-rpath,\$ORIGIN
$WASMER -q run main.wasm --dir=.

View File

@@ -0,0 +1,4 @@
int side_needed_func(int x)
{
return x + 4;
}

View File

@@ -0,0 +1,6 @@
extern int side_needed_func(int);
int side_func(int x)
{
return side_needed_func(x) * 2;
}

View File

View File

@@ -0,0 +1,3 @@
int tls_base[4] = {0, 0, 0, 0};
_Thread_local int tls_var = 0;

135
tests/wasix/dl-tls/main.c Normal file
View File

@@ -0,0 +1,135 @@
#include <stdio.h>
#include <stdbool.h>
#include <dlfcn.h>
#include <pthread.h>
extern int side_func(int in_thread, int value);
bool all_unequal(int *arr, size_t size)
{
for (size_t i = 0; i < size; i++)
{
for (size_t j = i + 1; j < size; j++)
{
if (arr[i] == arr[j])
{
return false;
}
}
}
return true;
}
// Common storage where all functions can store data for the final check
// Indices are: main-main, main-side, thread-main, thread-side
extern int tls_base[4];
// TLS variable that should be shared between main and side, but be
// different in the thread
extern _Thread_local int tls_var;
// A simple global integer with a TLS pointer
int static_int = 1;
_Thread_local int *tls_ptr = &static_int;
void *thread_func(void *arg)
{
tls_base[2] = (int)__builtin_wasm_tls_base();
if (tls_ptr != &static_int)
{
fprintf(stderr, "TLS pointer does not point to static_int\n");
return (void *)1;
}
if (tls_var != 0)
{
fprintf(stderr, "TLS variable should initially be 0 in thread, got %d\n", tls_var);
return (void *)1;
}
tls_var = 50;
if (side_func(1, 100) != 0)
{
fprintf(stderr, "side_func failed in thread\n");
return (void *)1;
}
if (tls_var != 100)
{
fprintf(stderr, "TLS variable not set correctly in thread's side, expected 100, got %d\n", tls_var);
return (void *)1;
}
return (void *)0;
}
int do_main_tests()
{
tls_base[0] = (int)__builtin_wasm_tls_base();
// Test if tls_ptr gets set correctly in __wasm_apply_tls_relocs,
// repeated in the thread and the side module as well
if (tls_ptr != &static_int)
{
fprintf(stderr, "TLS pointer does not point to static_int\n");
return 1;
}
// Test that the side module gets the correct address for main's TLS vars
// from the linker, repeated in the thread as well
if (tls_var != 0)
{
fprintf(stderr, "TLS variable should initially be 0 in main, got %d\n", tls_var);
return 1;
}
tls_var = 20;
if (side_func(0, 40) != 0)
{
fprintf(stderr, "side_func failed in main\n");
return 1;
}
if (tls_var != 40)
{
fprintf(stderr, "TLS variable not set correctly in main's side, expected 40, got %d\n", tls_var);
return 1;
}
return 0;
}
int main()
{
pthread_t thread;
if (pthread_create(&thread, NULL, thread_func, NULL) != 0)
{
fprintf(stderr, "Failed to create thread\n");
return 1;
}
if (do_main_tests())
{
fprintf(stderr, "Main tests failed\n");
return 1;
}
void *thread_ret;
if (pthread_join(thread, &thread_ret) != 0)
{
fprintf(stderr, "Failed to join thread\n");
return 1;
}
if ((int)thread_ret != 0)
{
fprintf(stderr, "Thread function failed\n");
return 1;
}
// Make sure each instance got a different TLS base
if (!all_unequal(tls_base, 4))
{
fprintf(stderr, "TLS bases are not unique\n");
return 1;
}
return 0;
}

11
tests/wasix/dl-tls/run.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/bash
set -e
export WASIXCC_WASM_EXCEPTIONS=yes
export WASIXCC_PIC=yes
wasixcc common.c -o libcommon.so -Wl,-shared
wasixcc side.c libcommon.so -o libside.so -Wl,-shared -Wl,-rpath,\$ORIGIN
wasixcc main.c libside.so libcommon.so -o main.wasm -Wl,-pie -Wl,-rpath,\$ORIGIN
$WASMER -q run main.wasm --dir=.

21
tests/wasix/dl-tls/side.c Normal file
View File

@@ -0,0 +1,21 @@
#include <stdio.h>
extern int tls_base[4];
int side_static_int = 1;
_Thread_local int *side_tls_ptr = &side_static_int;
_Thread_local extern int tls_var;
int side_func(int in_thread, int value)
{
if (side_tls_ptr != &side_static_int)
{
fprintf(stderr, "TLS pointer does not point to static_int\n");
return 1;
}
tls_base[in_thread ? 1 : 3] = (int)__builtin_wasm_tls_base();
tls_var = value;
return 0;
}

View File

53
tests/wasix/dlopen/main.c Normal file
View File

@@ -0,0 +1,53 @@
#include <stdio.h>
#include <dlfcn.h>
int main()
{
void *handle = dlopen("./libside.so", RTLD_NOW | RTLD_GLOBAL);
if (!handle)
{
fprintf(stderr, "dlopen failed: %s\n", dlerror());
return 1;
}
int (*side_func)(int) = dlsym(handle, "side_func");
if (!side_func)
{
fprintf(stderr, "dlsym failed: %s\n", dlerror());
dlclose(handle);
return 1;
}
int res = side_func(42);
if (res != 84)
{
fprintf(stderr, "side_func returned unexpected value: %d\n", res);
dlclose(handle);
return 1;
}
if (dlclose(handle) != 0)
{
fprintf(stderr, "dlclose failed: %s\n", dlerror());
return 1;
}
if (dlclose((void *)0xffffff) == 0)
{
fprintf(stderr, "expected dlclose to fail for bad handle\n");
return 1;
}
char *error = dlerror();
if (!error || *error == '\0')
{
fprintf(stderr, "dlerror should not be empty after bad dlclose\n");
return 1;
}
// Print something to make sure printf and, by extension, data relocations work.
// Do *NOT* remote this.
printf("All tests passed successfully!\n");
return 0;
}

10
tests/wasix/dlopen/run.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/bash
set -e
export WASIXCC_WASM_EXCEPTIONS=yes
export WASIXCC_PIC=yes
wasixcc main.c -o main.wasm -Wl,-pie
wasixcc side.c -o libside.so -Wl,-shared
$WASMER -q run main.wasm --dir=.

View File

@@ -0,0 +1,4 @@
int side_func(int x)
{
return x * 2;
}

View File

View File

@@ -1,5 +1,8 @@
set -e
wasixcc -sRUN_WASM_OPT=no main.c -o main-not-asyncified.wasm
wasm-opt --asyncify main-not-asyncified.wasm -o main.wasm
rm -f output.yyy output.zzz
# Run the not-asyncified variant to make sure posix_spawn doesn't require asyncify

View File

@@ -1,72 +1,5 @@
#!/bin/bash
if [[ -z "${WASI_SDK}" ]]; then
echo "WASI_SDK is not found"
exit 1
fi
if [[ -z "${WASIX_SYSROOT}" ]]; then
echo "WASIX_SYSROOT is not found"
exit 1
fi
export RANLIB="$WASI_SDK/bin/ranlib"
export AR="$WASI_SDK/bin/ar"
export NM="$WASI_SDK/bin/nm"
export CC="$WASI_SDK/bin/clang"
export CXX="$WASI_SDK/bin/clang"
export CFLAGS="\
--sysroot=$WASIX_SYSROOT \
--target=wasm32-wasi \
-matomics \
-mbulk-memory \
-mmutable-globals \
-pthread \
-mthread-model posix \
-ftls-model=local-exec \
-fno-trapping-math \
-D_WASI_EMULATED_MMAN \
-D_WASI_EMULATED_SIGNAL \
-D_WASI_EMULATED_PROCESS_CLOCKS \
-O3 \
-g \
-flto"
export LD="$WASI_SDK/bin/wasm-ld"
export LDFLAGS="\
-Wl,--shared-memory \
-Wl,--max-memory=4294967296 \
-Wl,--import-memory \
-Wl,--export-dynamic \
-Wl,--export=__heap_base \
-Wl,--export=__stack_pointer \
-Wl,--export=__data_end \
-Wl,--export=__wasm_init_tls \
-Wl,--export=__wasm_signal \
-Wl,--export=__tls_size \
-Wl,--export=__tls_align \
-Wl,--export=__tls_base \
-lwasi-emulated-mman \
-O3 \
-g \
-flto"
export LIBS="\
-Wl,--shared-memory \
-Wl,--max-memory=4294967296 \
-Wl,--import-memory \
-Wl,--export-dynamic \
-Wl,--export=__heap_base \
-Wl,--export=__stack_pointer \
-Wl,--export=__data_end \
-Wl,--export=__wasm_init_tls \
-Wl,--export=__wasm_signal \
-Wl,--export=__tls_size \
-Wl,--export=__tls_align \
-Wl,--export=__tls_base \
-lwasi-emulated-mman \
-O3 \
-g \
-flto"
export WASMER=$(realpath "../../target/release/wasmer")
printf "\n\nStarting WASIX Test Suite:\n"
@@ -76,10 +9,14 @@ while read dir; do
dir=$(basename "$dir")
printf "Testing $dir..."
cmd="cd $dir; \
$CC $CFLAGS $LDFLAGS -o main-not-asyncified.wasm main.c; \
wasm-opt --asyncify main-not-asyncified.wasm -o main.wasm; \
./run.sh"
if [ -e "$dir/.no-build" ]; then
cmd="cd $dir; \
./run.sh"
else
cmd="cd $dir; \
wasixcc main.c -o main.wasm; \
./run.sh"
fi
if bash -c "$cmd"; then
printf "\rTesting $dir ✅\n"