diff --git a/src/wcc/emit_wasm.c b/src/wcc/emit_wasm.c index 4f0eba18f..6cc3ab303 100644 --- a/src/wcc/emit_wasm.c +++ b/src/wcc/emit_wasm.c @@ -403,6 +403,32 @@ static void emit_global_section(EmitWasm *ew) { } } +static void emit_export_section(EmitWasm *ew) { + Vector *exports = ew->exports; + if (exports == NULL || exports->len <= 0) + return; + + DataStorage exports_section; + data_init(&exports_section); + data_open_chunk(&exports_section); + data_open_chunk(&exports_section); + for (int i = 0; i < exports->len; ++i) { + const Name *name = exports->data[i]; + + FuncInfo *info = table_get(&func_info_table, name); + assert(info != NULL); + + data_string(&exports_section, name->chars, name->bytes); // export name + data_uleb128(&exports_section, -1, IMPORT_FUNC); // export kind + data_uleb128(&exports_section, -1, info->index); // export func index + } + data_close_chunk(&exports_section, exports->len); // num exports + data_close_chunk(&exports_section, -1); + + fputc(SEC_EXPORT, ew->ofp); + fwrite(exports_section.buf, exports_section.len, 1, ew->ofp); +} + static void emit_elems_section(EmitWasm *ew) { int count = indirect_function_table.count; if (count == 0) @@ -774,12 +800,13 @@ static void emit_reloc_data_section(EmitWasm *ew, Vector *reloc_data) { emit_reloc_section(ew, ew->data_section_index, reloc_data, kRelocData); } -void emit_wasm(FILE *ofp, const char *import_module_name) { +void emit_wasm(FILE *ofp, const char *import_module_name, Vector *exports) { write_wasm_header(ofp); EmitWasm ew_body = { .ofp = ofp, .import_module_name = import_module_name, + .exports = exports, }; EmitWasm *ew = &ew_body; @@ -798,6 +825,9 @@ void emit_wasm(FILE *ofp, const char *import_module_name) { // Globals. emit_global_section(ew); + // Exports. + emit_export_section(ew); + // Elements. emit_elems_section(ew); diff --git a/src/wcc/wcc.c b/src/wcc/wcc.c index 48c57c634..6750447bd 100644 --- a/src/wcc/wcc.c +++ b/src/wcc/wcc.c @@ -121,7 +121,7 @@ static void compilec(FILE *ppin, const char *filename, Vector *toplevel) { } int compile_csource(const char *src, enum OutType out_type, const char *ofn, Vector *ld_cmd, - const char *import_module_name) { + const char *import_module_name, Vector *exports) { FILE *ppout; if (out_type == OutPreprocess) ppout = ofn != NULL ? fopen(ofn, "w") : stdout; @@ -181,6 +181,19 @@ int compile_csource(const char *src, enum OutType out_type, const char *ofn, Vec if (cc_flags.warn_as_error && compile_warning_count != 0) return 2; + if (exports != NULL) { + int undef = 0; + for (int i = 0; i < exports->len; ++i) { + const Name *name = exports->data[i]; + if (!table_try_get(&func_info_table, name, NULL)) { + fprintf(stderr, "Export: `%.*s' not defined\n", NAMES(name)); + ++undef; + } + } + if (undef > 0) + return 3; + } + FILE *ofp; const char *outfn = NULL; if (out_type >= OutExecutable) { @@ -205,7 +218,7 @@ int compile_csource(const char *src, enum OutType out_type, const char *ofn, Vec if (ofp == NULL) { error("Cannot open output file"); } else { - emit_wasm(ofp, import_module_name); + emit_wasm(ofp, import_module_name, exports); assert(compile_error_count == 0); fclose(ofp); } @@ -547,7 +560,8 @@ static int do_compile(Options *opts) { return 1; // exit case Clanguage: { - int res = compile_csource(src, opts->out_type, outfn, obj_files, opts->import_module_name); + Vector *exports = opts->out_type < OutExecutable ? opts->exports : NULL; + int res = compile_csource(src, opts->out_type, outfn, obj_files, opts->import_module_name, exports); if (res != 0) return 1; // exit } @@ -564,6 +578,16 @@ static int do_compile(Options *opts) { if (opts->out_type < OutExecutable) return 0; + + if (opts->entry_point == NULL) { + opts->entry_point = "_start"; + } + if (opts->entry_point != NULL && *opts->entry_point != '\0') { + vec_push(opts->exports, alloc_name(opts->entry_point, NULL, false)); + } else if (opts->exports->len == 0) { + error("no exports (require -e)\n"); + } + return do_link(obj_files, opts); } @@ -605,15 +629,6 @@ int main(int argc, char *argv[]) { add_inc_path(INC_AFTER, JOIN_PATHS(root, "include")); } - if (opts.out_type >= OutExecutable && opts.entry_point == NULL) { - opts.entry_point = "_start"; - } - if (opts.entry_point != NULL && *opts.entry_point != '\0') - vec_push(opts.exports, alloc_name(opts.entry_point, NULL, false)); - if (opts.exports->len == 0 && opts.out_type >= OutExecutable) { - error("no exports (require -e)\n"); - } - VERBOSES("### Exports\n"); for (int i = 0; i < opts.exports->len; ++i) { const Name *name = opts.exports->data[i]; diff --git a/src/wcc/wcc.h b/src/wcc/wcc.h index 81bb28ff8..fbd2d8bd5 100644 --- a/src/wcc/wcc.h +++ b/src/wcc/wcc.h @@ -106,6 +106,7 @@ void install_builtins(void); typedef struct { FILE *ofp; const char *import_module_name; + Vector *exports; Vector *data_segments; uint32_t section_index; uint32_t function_count; @@ -114,7 +115,7 @@ typedef struct { uint32_t import_global_count; } EmitWasm; -void emit_wasm(FILE *ofp, const char *import_module_name); +void emit_wasm(FILE *ofp, const char *import_module_name, Vector *exports); void emit_type_section(EmitWasm *ew); void emit_tag_section(EmitWasm *ew);