diff --git a/CMakeLists.txt b/CMakeLists.txt index c1462a4..e5c11f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,15 @@ project(wrt) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fmacro-prefix-map=${CMAKE_SOURCE_DIR}=.") -add_definitions(-DWRT_DEBUG=4) + +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + add_definitions(-DWRT_DEBUG=4) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -g -fsanitize=address,undefined -fno-sanitize=alignment") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address,undefined -fno-sanitize=alignment") +else () + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") +endif () + # math find_library(M_LIBRARY m) diff --git a/tests/dl.cpp b/tests/dl.cpp index 5845dcb..e054ad2 100644 --- a/tests/dl.cpp +++ b/tests/dl.cpp @@ -4,9 +4,21 @@ extern "C" { #include "utils/defs.h" #include "wrt/dl.h" +#include "wasm_exec_env.h" -extern DLContext dl_context; -extern bool signature_check(const char *signature, int *arg_count, bool *has_ret); +extern bool signature_check(const char *signature, int *arg_count, bool *has_ret); +} + +DLContext dl_context; +WASMExecEnv exec_env; + +void init() { + dl_context.mem.malloc = malloc; + dl_context.mem.free = free; + dl_context.symTable = nullptr; + memset(dl_context.hnd, 0, sizeof(dl_context.hnd)); + memset(dl_context.sym, 0, sizeof(dl_context.sym)); + exec_env.attachment = &dl_context; } #define check_symbol_consistency(sym, postfix) \ @@ -22,11 +34,15 @@ extern bool signature_check(const char *signature, int *arg_count, bool *ha ASSERT_NE(dl_context.hnd[ref##postfix - 1].handle, nullptr); \ } while (0) -#define check_empty(postfix) \ +#define check_hnd_empty(postfix) \ do { \ for (auto &hnd##postfix : dl_context.hnd) { \ ASSERT_EQ(hnd##postfix.handle, nullptr); \ } \ + } while (0) + +#define check_sym_empty(postfix) \ + do { \ for (auto &sym##postfix : dl_context.sym) { \ ASSERT_EQ(sym##postfix.symbol, nullptr); \ ASSERT_EQ(sym##postfix.cif, nullptr); \ @@ -34,44 +50,72 @@ extern bool signature_check(const char *signature, int *arg_count, bool *ha } \ } while (0) -TEST(DLTest, OpenAndClose) { - dl_init(); +#define check_empty(postfix) \ + do { \ + check_sym_empty(postfix); \ + check_hnd_empty(postfix); \ + } while (0) - int handle = dl_open(nullptr, "./SimpleLib.so", RTLD_LAZY); +TEST(DLTest, InitAndFree) { + // use valgrind ! + auto *context = (DLContext *)malloc(sizeof(DLContext)); + ASSERT_NE(context, nullptr); + context->mem.malloc = malloc; + context->mem.free = free; + dl_init(context); + + EXPECT_NE(context->symTable, nullptr); + for (auto &hnd : context->hnd) { + EXPECT_EQ(hnd.handle, nullptr); + } + for (auto &sym : context->sym) { + EXPECT_EQ(sym.symbol, nullptr); + EXPECT_EQ(sym.cif, nullptr); + EXPECT_EQ(sym.backref, 0); + } + + dl_free(context); + free(context); +} + +TEST(DLTest, OpenAndClose) { + init(); + + int handle = dl_open(&exec_env, "./SimpleLib.so", RTLD_LAZY); ASSERT_GT(handle, 0); - int result = dl_close(nullptr, handle); + int result = dl_close(&exec_env, handle); ASSERT_EQ(result, WRT_OK); check_empty(0); - handle = dl_open(nullptr, "not_exists", RTLD_LAZY); + handle = dl_open(&exec_env, "not_exists", RTLD_LAZY); ASSERT_EQ(handle, WRT_ERROR); check_empty(1); - handle = dl_open(nullptr, "", RTLD_LAZY); + handle = dl_open(&exec_env, "", RTLD_LAZY); ASSERT_EQ(handle, WRT_ERROR); check_empty(2); - handle = dl_open(nullptr, nullptr, RTLD_LAZY); + handle = dl_open(&exec_env, nullptr, RTLD_LAZY); ASSERT_EQ(handle, WRT_ERROR); check_empty(3); } TEST(DLTest, ManyOpen) { - dl_init(); + init(); int handles[DL_MAX_HANDLES]; for (int &handle : handles) { - handle = dl_open(nullptr, "./SimpleLib.so", RTLD_LAZY); + handle = dl_open(&exec_env, "./SimpleLib.so", RTLD_LAZY); ASSERT_GT(handle, 0); } { - int handle = dl_open(nullptr, "./SimpleLib.so", RTLD_LAZY); + int handle = dl_open(&exec_env, "./SimpleLib.so", RTLD_LAZY); ASSERT_EQ(handle, WRT_ERROR); } for (int handle : handles) { - int result = dl_close(nullptr, handle); + int result = dl_close(&exec_env, handle); ASSERT_EQ(result, WRT_OK); } @@ -109,20 +153,25 @@ TEST(DLTest, SignatureCheck) { } } -TEST(DLTest, GetSym) { - dl_init(); +TEST(DLTest, GetCloseSym) { + init(); - int hnd = dl_open(nullptr, "./SimpleLib.so", RTLD_LAZY); + int hnd = dl_open(&exec_env, "./SimpleLib.so", RTLD_LAZY); { - int sym = dl_sym(nullptr, hnd, "fib_fast", "(i)i"); + int sym = dl_sym(&exec_env, hnd, "fib_fast", "(i)i"); check_symbol_consistency(sym, 0); } { - int sym = dl_sym(nullptr, hnd, "fib_fast", "(v)i"); + int sym = dl_sym(&exec_env, hnd, "fib_fast", "(v)i"); ASSERT_EQ(sym, WRT_ERROR); } - dl_close(nullptr, hnd); + { + dl_close_sym(&exec_env, hnd, 1); + check_sym_empty(0); + } + + dl_close(&exec_env, hnd); check_empty(0); } diff --git a/tests/wasm/dl.h b/tests/wasm/dl.h new file mode 100644 index 0000000..ffc49e3 --- /dev/null +++ b/tests/wasm/dl.h @@ -0,0 +1,14 @@ +#ifndef WRT_DL_H +#define WRT_DL_H + +typedef enum { + WRT_OK = 0, + WRT_ERROR = -1, +} Status; + +int dl_open(const char *filename, int flags); +int dl_sym(int handle, const char *symbol, const char *signature); +Status dl_close_sym(int handle, int symbol); +Status dl_close(int handle); + +#endif // WRT_DL_H diff --git a/tests/wasm/example.c b/tests/wasm/example.c index c4cfb4d..41fb2d4 100644 --- a/tests/wasm/example.c +++ b/tests/wasm/example.c @@ -1,13 +1,5 @@ #include - -typedef enum { - WRT_OK = 0, - WRT_ERROR = -1, -} Status; - -int dl_open(const char *filename, int flags); -int dl_sym(int handle, const char *symbol, const char *signature); -Status dl_close(int handle); +#include "dl.h" unsigned fib(unsigned n) { return n < 2 ? n : fib(n - 1) + fib(n - 2); } @@ -18,6 +10,8 @@ void entry() { printf("hnd = %d\n", hnd); int fib_iterate_sym = dl_sym(hnd, "fib_iterate", "(i)i"); printf("fib_iterate_sym = %d\n", fib_iterate_sym); - Status status = dl_close(hnd); - printf("status = %d\n", status); + Status status = dl_close_sym(hnd, fib_iterate_sym); + printf("close sym status = %d\n", status); + status = dl_close(hnd); + printf("close lib status = %d\n", status); } diff --git a/utils/log.h b/utils/log.h index 048a159..5c0e929 100644 --- a/utils/log.h +++ b/utils/log.h @@ -1,32 +1,53 @@ #ifndef WRT_LOG_H #define WRT_LOG_H -#if WRT_DEBUG +#if WRT_DEBUG > 0 #include - #define __COLOR_RED "\x1B[1;31m" - #define __COLOR_YELLOW "\x1B[1;33m" - #define __COLOR_GREEN "\x1B[1;32m" - #define __COLOR_CYAN "\x1B[1;36m" - #define __COLOR_RESET "\x1B[0m" + #define _COLOR_RED "\x1B[1;31m" + #define _COLOR_YELLOW "\x1B[1;33m" + #define _COLOR_GREEN "\x1B[1;32m" + #define _COLOR_CYAN "\x1B[1;36m" + #define _COLOR_RESET "\x1B[0m" - #define _LOG(color, level, fmt, ...) \ - do { \ - fprintf(stdout, color "[" level "] (%s:%d): " fmt __COLOR_RESET "\n", __FILE__, \ - __LINE__, ##__VA_ARGS__); \ + #define _LOG(color, level, fmt, ...) \ + do { \ + fprintf(stdout, color "[" level "] (%s:%d): " fmt _COLOR_RESET "\n", __FILE__, \ + __LINE__, ##__VA_ARGS__); \ } while (0) - #define LOG_ERR(fmt, ...) _LOG(__COLOR_RED, "E", fmt, ##__VA_ARGS__) - #define LOG_WARN(fmt, ...) _LOG(__COLOR_YELLOW, "W", fmt, ##__VA_ARGS__) - #define LOG_INFO(fmt, ...) _LOG(__COLOR_GREEN, "I", fmt, ##__VA_ARGS__) - #define LOG_DBG(fmt, ...) _LOG(__COLOR_CYAN, "D", fmt, ##__VA_ARGS__) + #define LOG_ERR(fmt, ...) _LOG(_COLOR_RED, "E", fmt, ##__VA_ARGS__) + #define LOG_WARN(fmt, ...) _LOG(_COLOR_YELLOW, "W", fmt, ##__VA_ARGS__) + #define LOG_INFO(fmt, ...) _LOG(_COLOR_GREEN, "I", fmt, ##__VA_ARGS__) + #define LOG_DBG(fmt, ...) _LOG(_COLOR_CYAN, "D", fmt, ##__VA_ARGS__) -#else - #define LOG_ERR(fmt, ...) - #define LOG_WARN(fmt, ...) - #define LOG_INFO(fmt, ...) - #define LOG_DBG(fmt, ...) + #if WRT_DEBUG == 1 + #undef LOG_DBG + #undef LOG_INFO + #undef LOG_WARN + #elif WRT_DEBUG == 2 + #undef LOG_DBG + #undef LOG_INFO + #elif WRT_DEBUG == 3 + #undef LOG_DBG + #endif #endif +#ifndef LOG_ERR + #define LOG_ERR(fmt, ...) +#endif + +#ifndef LOG_WARN + #define LOG_WARN(fmt, ...) +#endif + +#ifndef LOG_INFO + #define LOG_INFO(fmt, ...) +#endif + +#ifndef LOG_DBG + #define LOG_DBG(fmt, ...) +#endif + #endif // WRT_LOG_H diff --git a/wrt/dl.c b/wrt/dl.c index 4b27fa8..8b3643f 100644 --- a/wrt/dl.c +++ b/wrt/dl.c @@ -5,22 +5,65 @@ #include "utils/log.h" #include "wrt/dl.h" -DLContext dl_context = {0}; -Allocator dl_malloc = malloc; -DeAllocator dl_free = free; +// TODO: Stateful context -> per WRTContext #warning "TODO: Permission Check" -Status dl_init() { - memset(&dl_context, 0, sizeof(DLContext)); +Status dl_init(DLContext *ctx) { + memset(ctx->hnd, 0, sizeof(ctx->hnd)); + memset(ctx->sym, 0, sizeof(ctx->sym)); + + ctx->symTable = ctx->mem.malloc(sizeof(NativeSymbol) * DL_SYM_TABLE_SIZE); + if (ctx->symTable == NULL) { + LOG_ERR("dl_init: malloc failed"); + return WRT_ERROR; + } + +#define EXPORT(i, sym, sig) \ + do { \ + ctx->symTable[i].symbol = #sym; \ + ctx->symTable[i].func_ptr = (void *)sym; \ + ctx->symTable[i].signature = sig; \ + ctx->symTable[i].attachment = ctx; \ + } while (0) + + EXPORT(0, dl_open, "($i)i"); + EXPORT(1, dl_sym, "(i$$)i"); + EXPORT(2, dl_call, "(i)i"); + EXPORT(3, dl_close_sym, "(ii)i"); + EXPORT(4, dl_close, "(i)i"); + +#undef EXPORT return WRT_OK; } +Status dl_free(DLContext *ctx) { + ctx->mem.free(ctx->symTable); + for (int i = 0; i < DL_MAX_SYMBOLS; i++) { + if (ctx->sym[i].symbol) { + ctx->mem.free(ctx->sym[i].cif->arg_types); + ctx->mem.free(ctx->sym[i].cif); + } + } + for (int i = 0; i < DL_MAX_HANDLES; i++) { + if (ctx->hnd[i].handle) { + dlclose(ctx->hnd[i].handle); + } + } + return WRT_OK; +} + +#define GET_CONTEXT \ + DLContext *ctx = wasm_runtime_get_function_attachment(exec_env); \ + if (ctx == NULL) return WRT_ERROR; + int dl_open(wasm_exec_env_t exec_env, const char *filename, int flags) { if (filename == NULL) return WRT_ERROR; if (filename[0] == '\0') return WRT_ERROR; + GET_CONTEXT + void *handle = dlopen(filename, flags); if (handle == NULL) { LOG_ERR("dlopen failed: %s", dlerror()); @@ -28,8 +71,8 @@ int dl_open(wasm_exec_env_t exec_env, const char *filename, int flags) { } for (int i = 0; i < DL_MAX_HANDLES; i++) { - if (dl_context.hnd[i].handle == NULL) { - dl_context.hnd[i].handle = handle; + if (ctx->hnd[i].handle == NULL) { + ctx->hnd[i].handle = handle; LOG_DBG("dl_open: lib = %s, flags = %d, handle = %d", filename, flags, i + 1); return i + 1; } @@ -96,14 +139,14 @@ bool signature_check(const char *signature, int *arg_count, bool *has_ret) { return true; } -ffi_cif *create_ffi_cif(const char *signature) { +ffi_cif *create_ffi_cif(DLContext *ctx, const char *signature) { int arg_count; bool has_ret; if (!signature_check(signature, &arg_count, &has_ret)) return NULL; - ffi_cif *cif = dl_malloc(sizeof(ffi_cif)); - ffi_type **arg_types = dl_malloc(sizeof(ffi_type *) * arg_count); + ffi_cif *cif = ctx->mem.malloc(sizeof(ffi_cif)); + ffi_type **arg_types = ctx->mem.malloc(sizeof(ffi_type *) * arg_count); ffi_type *ret_type; const char *ch = signature + 1; @@ -151,8 +194,8 @@ ffi_cif *create_ffi_cif(const char *signature) { return cif; fail: - dl_free(arg_types); - dl_free(cif); + ctx->mem.free(arg_types); + ctx->mem.free(cif); return NULL; } @@ -160,7 +203,9 @@ int dl_sym(wasm_exec_env_t exec_env, int handle, const char *symbol, const char if (handle < 1 || handle > DL_MAX_HANDLES) return WRT_ERROR; if (symbol == NULL || signature == NULL) return WRT_ERROR; - void *ptr = dl_context.hnd[handle - 1].handle; + GET_CONTEXT + + void *ptr = ctx->hnd[handle - 1].handle; if (ptr == NULL) return WRT_ERROR; void *sym = dlsym(ptr, symbol); @@ -169,14 +214,14 @@ int dl_sym(wasm_exec_env_t exec_env, int handle, const char *symbol, const char return WRT_ERROR; } - ffi_cif *cif = create_ffi_cif(signature); + ffi_cif *cif = create_ffi_cif(ctx, signature); if (cif == NULL) return WRT_ERROR; for (int i = 0; i < DL_MAX_SYMBOLS; i++) { - if (dl_context.sym[i].symbol == NULL) { - dl_context.sym[i].backref = handle; - dl_context.sym[i].symbol = sym; - dl_context.sym[i].cif = cif; + if (ctx->sym[i].symbol == NULL) { + ctx->sym[i].backref = handle; + ctx->sym[i].symbol = sym; + ctx->sym[i].cif = cif; LOG_DBG("dl_sym: lib_hnd = %d, sym = %s, sym_id = %d", handle, symbol, i + 1); return i + 1; } @@ -218,21 +263,41 @@ void dl_call(wasm_exec_env_t exec_env) { // } } +Status dl_close_sym(wasm_exec_env_t exec_env, int handle, int symbol) { + if (handle < 1 || handle > DL_MAX_HANDLES) return WRT_ERROR; + if (symbol < 1 || symbol > DL_MAX_SYMBOLS) return WRT_ERROR; + + GET_CONTEXT + + void *sym = ctx->sym[symbol - 1].symbol; + if (sym == NULL) return WRT_ERROR; + + ctx->mem.free(ctx->sym[symbol - 1].cif->arg_types); + ctx->mem.free(ctx->sym[symbol - 1].cif); + ctx->sym[symbol - 1].cif = NULL; + ctx->sym[symbol - 1].backref = 0; + ctx->sym[symbol - 1].symbol = NULL; + + return WRT_OK; +} + Status dl_close(wasm_exec_env_t exec_env, int handle) { if (handle < 1 || handle > DL_MAX_HANDLES) return WRT_ERROR; - void *ptr = dl_context.hnd[handle - 1].handle; + GET_CONTEXT + + void *ptr = ctx->hnd[handle - 1].handle; if (ptr == NULL) return WRT_ERROR; - dl_context.hnd[handle - 1].handle = NULL; + ctx->hnd[handle - 1].handle = NULL; for (int i = 0; i < DL_MAX_SYMBOLS; i++) { - if (dl_context.sym[i].backref == handle) { - dl_context.sym[i].backref = 0; - dl_context.sym[i].symbol = NULL; + if (ctx->sym[i].backref == handle) { + ctx->sym[i].backref = 0; + ctx->sym[i].symbol = NULL; - dl_free(dl_context.sym[i].cif->arg_types); - dl_free(dl_context.sym[i].cif); - dl_context.sym[i].cif = NULL; + ctx->mem.free(ctx->sym[i].cif->arg_types); + ctx->mem.free(ctx->sym[i].cif); + ctx->sym[i].cif = NULL; LOG_DBG("dl_close: destroy sym_id = %d", i + 1); } diff --git a/wrt/dl.h b/wrt/dl.h index 27e1564..8d423f8 100644 --- a/wrt/dl.h +++ b/wrt/dl.h @@ -7,7 +7,14 @@ #include "utils/defs.h" +#define DL_SYM_TABLE_SIZE 5 + typedef struct { + struct { + Allocator malloc; + DeAllocator free; + } mem; + NativeSymbol *symTable; struct { void *handle; } hnd[DL_MAX_HANDLES]; @@ -18,10 +25,12 @@ typedef struct { } sym[DL_MAX_SYMBOLS]; } DLContext; -Status dl_init(); +Status dl_init(DLContext *context); +Status dl_free(DLContext *context); int dl_open(wasm_exec_env_t exec_env, const char *filename, int flags); int dl_sym(wasm_exec_env_t exec_env, int handle, const char *symbol, const char *signature); void dl_call(wasm_exec_env_t exec_env); // TODO +Status dl_close_sym(wasm_exec_env_t exec_env, int handle, int symbol); Status dl_close(wasm_exec_env_t exec_env, int handle); #endif // WRT_DL_H diff --git a/wrt/wrt.c b/wrt/wrt.c index 1bd6a98..a4a71d5 100644 --- a/wrt/wrt.c +++ b/wrt/wrt.c @@ -48,6 +48,12 @@ Status wrt_program_init(WRTContext *context, uint8_t *wasm_buffer, uint32_t wasm context->program.native_symbols = native_symbols; context->program.native_symbols_size = native_symbols_size; + // init dl + context->program.dl = context->platform.malloc(sizeof(DLContext)); + context->program.dl->mem.malloc = context->platform.malloc; + context->program.dl->mem.free = context->platform.free; + dl_init(context->program.dl); + return WRT_OK; } @@ -72,18 +78,12 @@ Status wrt_wamr_init(WRTContext *context, char *entry_func, uint32_t stack_size, return WRT_ERROR; } - // init dl - dl_init(); - // register dl functions - static NativeSymbol native_symbols[] = { - EXPORT_WASM_API_WITH_SIG(dl_open, "($i)i"), - EXPORT_WASM_API_WITH_SIG(dl_sym, "(i$$)i"), - EXPORT_WASM_API_WITH_SIG(dl_call, "(i)i"), // TODO - EXPORT_WASM_API_WITH_SIG(dl_close, "(i)i"), - }; - wasm_runtime_register_natives("env", native_symbols, - sizeof(native_symbols) / sizeof(NativeSymbol)); + wasm_runtime_register_natives("env", context->program.dl->symTable, DL_SYM_TABLE_SIZE); + + // register native symbols + wasm_runtime_register_natives("env", context->program.native_symbols, + context->program.native_symbols_size); // load module context->wamr.module = @@ -131,6 +131,7 @@ fail: } Status wrt_free(WRTContext *context) { + // wamr if (context->wamr.exec_env) { wasm_runtime_destroy_exec_env(context->wamr.exec_env); context->wamr.exec_env = NULL; @@ -148,11 +149,17 @@ Status wrt_free(WRTContext *context) { wasm_runtime_destroy(); + // mem context->platform.free(context->mem.error_buf); context->mem.error_buf_size = 0; context->platform.free(context->mem.heap_buf); context->mem.heap_buf_size = 0; + // program + dl_free(context->program.dl); + context->platform.free(context->program.dl); + context->program.dl = NULL; + return WRT_OK; } diff --git a/wrt/wrt.h b/wrt/wrt.h index d082f5b..4797c5a 100644 --- a/wrt/wrt.h +++ b/wrt/wrt.h @@ -28,6 +28,7 @@ typedef struct { uint32_t wasm_buffer_size; NativeSymbol *native_symbols; uint32_t native_symbols_size; + DLContext *dl; } program; } WRTContext;