feat: dl functions with context

This commit is contained in:
Paul Pan 2023-02-07 15:06:40 +08:00
parent c430e73549
commit 55d7e94a52
9 changed files with 257 additions and 89 deletions

View File

@ -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)

View File

@ -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);
}

14
tests/wasm/dl.h Normal file
View File

@ -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

View File

@ -1,13 +1,5 @@
#include <stdio.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(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);
}

View File

@ -1,32 +1,53 @@
#ifndef WRT_LOG_H
#define WRT_LOG_H
#if WRT_DEBUG
#if WRT_DEBUG > 0
#include <stdio.h>
#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

117
wrt/dl.c
View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -28,6 +28,7 @@ typedef struct {
uint32_t wasm_buffer_size;
NativeSymbol *native_symbols;
uint32_t native_symbols_size;
DLContext *dl;
} program;
} WRTContext;