From 64d4e1ef8a987ba48dd033efa637369405414c6d Mon Sep 17 00:00:00 2001 From: tyfkda Date: Wed, 21 Feb 2024 09:04:08 +0900 Subject: [PATCH] Specify WASM import module name by __attribute__ * Keep attributes in `Table` * Use for WASI module functions --- libsrc/_wasm/wasi.h | 36 ++++++------ src/cc/frontend/ast.c | 3 +- src/cc/frontend/ast.h | 3 +- src/cc/frontend/parser.c | 115 ++++++++++++++++++++++++++------------- src/wcc/emit_wasm.c | 12 +++- src/wcc/traverse.c | 27 +++++++++ src/wcc/wcc.c | 4 +- src/wcc/wcc.h | 2 + 8 files changed, 139 insertions(+), 63 deletions(-) diff --git a/libsrc/_wasm/wasi.h b/libsrc/_wasm/wasi.h index 4f14e4961..ab2b5110d 100644 --- a/libsrc/_wasm/wasi.h +++ b/libsrc/_wasm/wasi.h @@ -3,6 +3,8 @@ #include // size_t #include +#define WASI_MODULE __attribute__((import_module("wasi_snapshot_preview1"))) + // Fdflags #define FDFLAGS_APPEND (1 << 0) #define FDFLAGS_DSYNC (1 << 1) @@ -97,25 +99,25 @@ enum Filetype { FILETYPE_SYMBOLIC_LINK, }; -int args_sizes_get(int *pargc, int *plen); -int args_get(char **pargv, char *pstr); -void proc_exit(int) __attribute__((noreturn)); +WASI_MODULE int args_sizes_get(int *pargc, int *plen); +WASI_MODULE int args_get(char **pargv, char *pstr); +WASI_MODULE void proc_exit(int) __attribute__((noreturn)); -int fd_prestat_get(int fd, Prestat *prestat); -int fd_prestat_dir_name(int fd, char *out, size_t size); +WASI_MODULE int fd_prestat_get(int fd, Prestat *prestat); +WASI_MODULE int fd_prestat_dir_name(int fd, char *out, size_t size); -int path_open(int fd, int dirflags, const char *path, size_t path_len, int oflags, - uint64_t fs_rights_base, uint64_t fs_rights_inherting, uint16_t fdflags, - uint32_t *opend_fd); -int path_unlink_file(int fd, const char *path, size_t path_len); -int path_filestat_get(int fd, int flags, const char *path, size_t path_len, Filestat *out); +WASI_MODULE int path_open(int fd, int dirflags, const char *path, size_t path_len, int oflags, + uint64_t fs_rights_base, uint64_t fs_rights_inherting, uint16_t fdflags, + uint32_t *opend_fd); +WASI_MODULE int path_unlink_file(int fd, const char *path, size_t path_len); +WASI_MODULE int path_filestat_get(int fd, int flags, const char *path, size_t path_len, Filestat *out); -int fd_read(int fd, const void *iov, int count, size_t *out); -int fd_write(int fd, const void *iov, int count, size_t *out); -int fd_close(int fd); -int fd_seek(int fd, int64_t offset, int whence, size_t *psize); -int fd_filestat_get(int fd, Filestat *out); +WASI_MODULE int fd_read(int fd, const void *iov, int count, size_t *out); +WASI_MODULE int fd_write(int fd, const void *iov, int count, size_t *out); +WASI_MODULE int fd_close(int fd); +WASI_MODULE int fd_seek(int fd, int64_t offset, int whence, size_t *psize); +WASI_MODULE int fd_filestat_get(int fd, Filestat *out); -int clock_time_get(int clockid, uint64_t precision, uint64_t *out); +WASI_MODULE int clock_time_get(int clockid, uint64_t precision, uint64_t *out); -int random_get(void *buf, size_t buf_len); +WASI_MODULE int random_get(void *buf, size_t buf_len); diff --git a/src/cc/frontend/ast.c b/src/cc/frontend/ast.c index ff9bd5633..1735c003d 100644 --- a/src/cc/frontend/ast.c +++ b/src/cc/frontend/ast.c @@ -348,7 +348,7 @@ Declaration *new_decl_asm(Expr *str) { // Function -Function *new_func(Type *type, const Name *name, const Vector *params, int flag) { +Function *new_func(Type *type, const Name *name, const Vector *params, Table *attributes, int flag) { assert(type->kind == TY_FUNC); Function *func = malloc_or_die(sizeof(*func)); func->type = type; @@ -360,6 +360,7 @@ Function *new_func(Type *type, const Name *name, const Vector *params, int flag) func->label_table = NULL; func->gotos = NULL; func->extra = NULL; + func->attributes = attributes; func->flag = flag; return func; diff --git a/src/cc/frontend/ast.h b/src/cc/frontend/ast.h index 663a76306..bd805f53d 100644 --- a/src/cc/frontend/ast.h +++ b/src/cc/frontend/ast.h @@ -467,6 +467,7 @@ typedef struct Function { Table *label_table; // Vector *gotos; // void *extra; + Table *attributes; int flag; } Function; @@ -474,7 +475,7 @@ typedef struct Function { #define FUNCF_STACK_MODIFIED (1 << 1) #define FUNCF_HAS_FUNCALL (1 << 2) -Function *new_func(Type *type, const Name *name, const Vector *params, int flag); +Function *new_func(Type *type, const Name *name, const Vector *params, Table *attributes, int flag); // Declaration diff --git a/src/cc/frontend/parser.c b/src/cc/frontend/parser.c index 0c07007f3..fa0510278 100644 --- a/src/cc/frontend/parser.c +++ b/src/cc/frontend/parser.c @@ -619,48 +619,66 @@ static Stmt *parse_stmt(void) { return new_stmt_expr(str_to_char_array_var(curscope, val)); } -extern inline int parse_attribute(void) { - if (consume(TK_LPAR, "`(' expected") == NULL) { +static Table *parse_attribute(Table *attributes) { // + // __attribute__((name1, name2(p, q, ...), ...)) + + if (consume(TK_LPAR, "`(' expected") == NULL || consume(TK_LPAR, "`(' expected") == NULL) { + match(TK_RPAR); match(TK_RPAR); - return 0; + return NULL; } - int paren_count = 0; - int flag = 0; - for (bool loop = true; loop; ) { - Token *tok = match(-1); - if (tok->kind == TK_EOF) { - parse_error(PE_NOFATAL, tok, "`)' expected"); - break; - } - switch (tok->kind) { - case TK_LPAR: - ++paren_count; + for (;;) { + if (match(TK_RPAR)) break; - case TK_RPAR: - if (paren_count <= 0) { - loop = false; - break; - } - --paren_count; + + const Token *name = consume(TK_IDENT, "attribute name expected"); + if (name == NULL) break; - case TK_IDENT: - { - static const char kNoreturn[] = "noreturn"; - if (tok->end - tok->begin == sizeof(kNoreturn) - 1 && - memcmp(tok->begin, kNoreturn, sizeof(kNoreturn) - 1) == 0) - flag |= FUNCF_NORETURN; + + Vector *params = NULL; + if (match(TK_LPAR)) { + params = new_vector(); + if (!match(TK_RPAR)) { + for (;;) { + Token *token = match(-1); + if (token->kind == TK_EOF) { + parse_error(PE_NOFATAL, token, "`)' expected"); + break; + } + vec_push(params, token); + if (!match(TK_COMMA)) { + if (!match(TK_RPAR)) + parse_error(PE_NOFATAL, token, "`)' expected"); + break; + } + } } + } + if (attributes == NULL) + attributes = alloc_table(); + table_put(attributes, name->ident, params); + + if (!match(TK_COMMA)) { + if (!match(TK_RPAR)) + parse_error(PE_NOFATAL, NULL, "`)' expected"); break; - default: break; } } - return flag; + + consume(TK_RPAR, "`)' expected"); + return attributes; } static Function *define_func(Type *functype, const Token *ident, const Vector *param_vars, - int storage, int flag) { - Function *func = new_func(functype, ident->ident, functype->func.param_vars, flag); + int storage, Table *attributes) { + int flag = 0; + if (attributes != NULL) { + if (table_try_get(attributes, alloc_name("noreturn", NULL, false), NULL)) + flag |= FUNCF_NORETURN; + } + + Function *func = new_func(functype, ident->ident, functype->func.param_vars, attributes, flag); func->params = param_vars; VarInfo *varinfo = scope_find(global_scope, func->name, NULL); if (varinfo == NULL) { @@ -673,6 +691,18 @@ static Function *define_func(Type *functype, const Token *ident, const Vector *p int merge_flag = (flag | predecl->defun.func->flag) & FUNCF_NORETURN; func->flag |= merge_flag; predecl->defun.func->flag |= merge_flag; + + if (attributes != NULL) { + if (predecl->defun.func->attributes != NULL) { + const Name *name; + Vector *params; + for (int it = 0; (it = table_iterate(predecl->defun.func->attributes, it, &name, (void**)¶ms)) != -1; ) { + if (!table_try_get(attributes, name, NULL)) + table_put(attributes, name, params); + } + } + predecl->defun.func->attributes = attributes; + } } } @@ -706,7 +736,8 @@ static void modify_funparam_vla_type(Type *type, Scope *scope) { } } -static Declaration *parse_defun(Type *functype, int storage, Token *ident, const Token *tok) { +static Declaration *parse_defun(Type *functype, int storage, Token *ident, const Token *tok, + Table *attributes) { assert(functype->kind == TY_FUNC); const Vector *param_vars = functype->func.param_vars; @@ -717,7 +748,7 @@ static Declaration *parse_defun(Type *functype, int storage, Token *ident, const param_vars = new_vector(); } - Function *func = define_func(functype, ident, param_vars, storage, 0); + Function *func = define_func(functype, ident, param_vars, storage, attributes); VarInfo *varinfo = scope_find(global_scope, ident->ident, NULL); assert(varinfo != NULL); if (varinfo->global.func != NULL) { @@ -779,12 +810,12 @@ static Declaration *parse_defun(Type *functype, int storage, Token *ident, const return decl; } -static Declaration *parse_global_var_decl(Type *rawtype, int storage, Type *type, Token *ident) { +static Declaration *parse_global_var_decl(Type *rawtype, int storage, Type *type, Token *ident, + Table *attributes) { Vector *decls = NULL; for (;;) { - int attr = 0; - if (match(TK_ATTRIBUTE)) - attr = parse_attribute(); + while (match(TK_ATTRIBUTE)) + attributes = parse_attribute(attributes); if (!(type->kind == TY_PTR && type->pa.ptrof->kind == TY_FUNC) && type->kind != TY_VOID) @@ -813,7 +844,7 @@ static Declaration *parse_global_var_decl(Type *rawtype, int storage, Type *type parse_error(PE_NOFATAL, NULL, "ident expected"); } else { Function *func = define_func(type, ident, type->func.param_vars, storage | VS_EXTERN, - attr); + attributes); VarInfo *varinfo = scope_find(global_scope, ident->ident, NULL); assert(varinfo != NULL); @@ -852,6 +883,8 @@ static Declaration *parse_global_var_decl(Type *rawtype, int storage, Type *type if (!match(TK_COMMA)) break; + attributes = NULL; // TODO: Confirm. + // Next declaration. type = parse_declarator(rawtype, &ident); } @@ -868,6 +901,10 @@ static Declaration *parse_declaration(void) { return new_decl_asm(asm_->asm_.str); } + Table *attributes = NULL; + while (match(TK_ATTRIBUTE)) + attributes = parse_attribute(attributes); + Type *rawtype = NULL; int storage; Token *ident; @@ -894,12 +931,12 @@ static Declaration *parse_declaration(void) { const Token *tok = match(TK_LBRACE); if (tok != NULL) - return parse_defun(type, storage, ident, tok); + return parse_defun(type, storage, ident, tok, attributes); // Function prototype declaration: // Join with global variable declaration to handle multiple prototype declarations. } - return parse_global_var_decl(rawtype, storage, type, ident); + return parse_global_var_decl(rawtype, storage, type, ident, attributes); } parse_error(PE_NOFATAL, NULL, "Unexpected token"); match(-1); // Drop the token. diff --git a/src/wcc/emit_wasm.c b/src/wcc/emit_wasm.c index f171134dd..2bc1ad8e5 100644 --- a/src/wcc/emit_wasm.c +++ b/src/wcc/emit_wasm.c @@ -290,8 +290,16 @@ static void emit_import_section(EmitWasm *ew) { error("Import: `%.*s' is not public", NAMES(name)); } - data_string(&imports_section, module_name, module_name_len); // import module name - data_string(&imports_section, name->chars, name->bytes); // import name + const char *modname = module_name; + size_t modnamelen = module_name_len; + if (info->module_name != NULL) { + modname = info->module_name->chars; + modnamelen = info->module_name->bytes; + } + const Name *fn = info->func_name; + + data_string(&imports_section, modname, modnamelen); // import module name + data_string(&imports_section, fn->chars, fn->bytes); // import name data_push(&imports_section, IMPORT_FUNC); // import kind data_uleb128(&imports_section, -1, info->type_index); // import signature index ++imports_count; diff --git a/src/wcc/traverse.c b/src/wcc/traverse.c index b6be33647..a1801bb97 100644 --- a/src/wcc/traverse.c +++ b/src/wcc/traverse.c @@ -78,6 +78,7 @@ static FuncInfo *register_func_info(const Name *funcname, Function *func, VarInf info = calloc_or_die(sizeof(*info)); table_put(&func_info_table, funcname, info); info->type_index = (uint32_t)-1; + info->func_name = funcname; if (varinfo == NULL) { varinfo = scope_find(global_scope, funcname, NULL); @@ -92,6 +93,32 @@ static FuncInfo *register_func_info(const Name *funcname, Function *func, VarInf if (info->type_index == (uint32_t)-1) info->type_index = getsert_func_type_index(info->varinfo->type, true); info->flag |= flag; + + Table *attributes = NULL; + if (func != NULL) + attributes = func->attributes; + if (attributes == NULL && varinfo != NULL && varinfo->global.funcdecl != NULL) { + assert(varinfo->global.funcdecl->defun.func != NULL); + attributes = varinfo->global.funcdecl->defun.func->attributes; + } + if (attributes != NULL) { + const Vector *params; + if (table_try_get(attributes, alloc_name("import_module", NULL, false), (void**)¶ms)) { + const Token *token = params->len > 0 ? params->data[0] : NULL; + if (params->len != 1 && token->kind != TK_STR) + parse_error(PE_NOFATAL, token, "import_module: string expected"); + else + info->module_name = alloc_name(token->str.buf, token->str.buf + token->str.len - 1, false); + } + if (table_try_get(attributes, alloc_name("import_name", NULL, false), (void**)¶ms)) { + const Token *token = params->len > 0 ? params->data[0] : NULL; + if (params->len != 1 && token->kind != TK_STR) + parse_error(PE_NOFATAL, token, "import_name: string expected"); + else + info->func_name = alloc_name(token->str.buf, token->str.buf + token->str.len - 1, false); + } + } + return info; } diff --git a/src/wcc/wcc.c b/src/wcc/wcc.c index 5fa593fd3..30c7b11bc 100644 --- a/src/wcc/wcc.c +++ b/src/wcc/wcc.c @@ -21,7 +21,7 @@ // #define USE_EMCC_AS_LINKER 1 -static const char DEFAULT_IMPORT_MODULE_NAME[] = "wasi_snapshot_preview1"; +static const char DEFAULT_IMPORT_MODULE_NAME[] = "env"; #define DEFAULT_STACK_SIZE (8 * 1024) @@ -350,8 +350,6 @@ int main(int argc, char *argv[]) { do_emcc_link = true; out_type = OutObject; } - if (import_module_name == DEFAULT_IMPORT_MODULE_NAME) - import_module_name = "env"; #endif if (out_type >= OutExecutable && entry_point == NULL) { entry_point = "_start"; diff --git a/src/wcc/wcc.h b/src/wcc/wcc.h index bf669e761..91ab0c2e4 100644 --- a/src/wcc/wcc.h +++ b/src/wcc/wcc.h @@ -35,6 +35,8 @@ extern uint32_t data_end_address; typedef struct { Function *func; VarInfo *varinfo; + const Name *module_name; + const Name *func_name; const Name *bpname; uint32_t index; // also represents symbol_index (because functions are put first in symbol table.) int flag;