From 1001cf1715584eac61f6ae07bf21b7266800938e Mon Sep 17 00:00:00 2001 From: tyfkda Date: Mon, 19 Feb 2024 21:49:07 +0900 Subject: [PATCH 1/6] Generate library(.a) file for WASM * Generate object files with `-c` * Generate .a using `llvm-ar` --- Makefile | 26 +++++++---------- README.md | 4 +++ libsrc/Makefile | 74 ++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 78 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index eda968716..f07dca7f0 100644 --- a/Makefile +++ b/Makefile @@ -134,7 +134,7 @@ test-libs: all clean: rm -rf $(EXES) $(OBJ_DIR) a.out gen2* gen3* tmp.s \ dump_expr* dump_ir* dump_type* \ - wcc wcc-ld cc.wasm a.wasm public release $(WCC_LIBS) + wcc wcc-ld cc.wasm a.wasm public release $(WCC_LIBS) $(WCC_OBJ_DIR) $(WCC_LIB_DIR) @$(MAKE) -C libsrc clean @$(MAKE) -C tests clean @@ -187,6 +187,7 @@ test-self-hosting: self-hosting ### Wasm version WCC_OBJ_DIR:=obj/wcc +WCC_LIB_DIR:=lib WCC_DIR:=src/wcc WCC_CFLAGS:=$(CFLAGS) -I$(CPP_DIR) @@ -196,10 +197,15 @@ WCC_SRCS:=$(wildcard $(WCC_DIR)/*.c) \ $(CPP_DIR)/preprocessor.c $(CPP_DIR)/pp_parser.c $(CPP_DIR)/macro.c \ $(UTIL_DIR)/util.c $(UTIL_DIR)/table.c WCC_OBJS:=$(addprefix $(WCC_OBJ_DIR)/,$(notdir $(WCC_SRCS:.c=.o))) -WCC_LIBS:=$(LIBSRC_DIR)/_wasm/crt0.c $(LIBSRC_DIR)/_wasm/libc.c +WCC_LIBS:=$(WCC_LIB_DIR)/wcrt0.a $(WCC_LIB_DIR)/wlibc.a -wcc: $(PARENT_DEPS) $(WCC_OBJS) $(WCC_LIBS) +wcc: $(PARENT_DEPS) $(WCC_OBJS) $(CC) -o $@ $(WCC_OBJS) $(LDFLAGS) + $(MAKE) wcc-libs + +.PHONY: wcc-libs +wcc-libs: + $(MAKE) CC=../wcc AR=llvm-ar -C libsrc wcc-libs WCCLD_SRCS:=$(DEBUG_DIR)/wcc-ld.c $(WCC_DIR)/wasm_linker.c \ $(WCC_DIR)/wcc_util.c $(WCC_DIR)/emit_wasm.c $(WCC_DIR)/traverse.c $(WCC_DIR)/traverse_setjmp.c \ @@ -228,18 +234,6 @@ WCC_LIBC_SRCS:=$(wildcard $(LIBSRC_DIR)/math/*.c) \ $(wildcard $(LIBSRC_DIR)/string/*.c) \ $(wildcard $(LIBSRC_DIR)/_wasm/unistd/*.c) -define GENERATE_INCLUDE_SRCS - (cd $(LIBSRC_DIR); \ - for dir in $1; do \ - find $${dir} -name '*.c' -exec echo '#include <{}>' \; | sort; \ - done) -endef - -$(LIBSRC_DIR)/_wasm/crt0.c: $(WCC_CRT0_SRCS) - $(call GENERATE_INCLUDE_SRCS,_wasm/crt0) > $@ -$(LIBSRC_DIR)/_wasm/libc.c: $(WCC_LIBC_SRCS) - $(call GENERATE_INCLUDE_SRCS,math misc stdio stdlib string _wasm/unistd) > $@ - .PHONY: test-wcc test-wcc: wcc $(MAKE) -C tests clean && $(MAKE) -C tests test-wcc @@ -281,7 +275,7 @@ wcc-self-hosting: $(WCC_TARGET)cc.wasm test-wcc-self-hosting: $(MAKE) -C tests clean && $(MAKE) WCC="$(TARGET_CC)" -C tests test-wcc -$(WCC_TARGET)cc.wasm: $(WCC_SRCS) $(WCC_LIBS) $(WCC_PARENT) +$(WCC_TARGET)cc.wasm: $(WCC_SRCS) wcc-libs $(WCC_PARENT) $(HOST_WCC) -o $@ $(WCC_CFLAGS) \ -I$(CC1_FE_DIR) -I$(CPP_DIR) -I$(UTIL_DIR) \ $(WCC_SRCS) diff --git a/README.md b/README.md index 5bcdcdcdd..1ed123573 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,10 @@ Compile C to WebAssembly/WASI binary. [Online demo](https://tyfkda.github.io/xcc/) +#### Requirements + + * `llvm-ar` + #### Build ```sh diff --git a/libsrc/Makefile b/libsrc/Makefile index 37171aa55..4cf4f3dd9 100644 --- a/libsrc/Makefile +++ b/libsrc/Makefile @@ -15,15 +15,23 @@ endif ### Library -CRT0_SRCS:=$(wildcard $(SRC_DIR)/crt0/*.c) +CRT0_DIR:=$(SRC_DIR)/crt0 +MATH_DIR:=$(SRC_DIR)/math +MISC_DIR:=$(SRC_DIR)/misc +STDIO_DIR:=$(SRC_DIR)/stdio +STDLIB_DIR:=$(SRC_DIR)/stdlib +STRING_DIR:=$(SRC_DIR)/string +UNISTD_DIR:=$(SRC_DIR)/unistd + +CRT0_SRCS:=$(wildcard $(CRT0_DIR)/*.c) LIBC_SRCS:=\ - $(wildcard $(SRC_DIR)/math/*.c) \ - $(wildcard $(SRC_DIR)/misc/*.c) \ - $(wildcard $(SRC_DIR)/stdio/*.c) \ - $(wildcard $(SRC_DIR)/stdlib/*.c) \ - $(wildcard $(SRC_DIR)/string/*.c) \ - $(wildcard $(SRC_DIR)/unistd/*.c) \ + $(wildcard $(MATH_DIR)/*.c) \ + $(wildcard $(MISC_DIR)/*.c) \ + $(wildcard $(STDIO_DIR)/*.c) \ + $(wildcard $(STDLIB_DIR)/*.c) \ + $(wildcard $(STRING_DIR)/*.c) \ + $(wildcard $(UNISTD_DIR)/*.c) \ CRT0_OBJS:=$(addprefix $(OBJ_DIR)/,$(notdir $(CRT0_SRCS:.c=.o))) LIBC_OBJS:=$(addprefix $(OBJ_DIR)/,$(notdir $(LIBC_SRCS:.c=.o))) @@ -33,7 +41,7 @@ libs: $(LIBS) .PHONY: clean clean: clean-test - rm -rf $(OBJ_DIR) $(LIB_DIR) + rm -rf $(OBJ_DIR) $(LIB_DIR) $(WCC_OBJ_DIR) $(WCC_LIB_DIR) $(LIB_DIR)/crt0.a: $(CRT0_OBJS) @mkdir -p $(LIB_DIR) @@ -43,9 +51,13 @@ $(LIB_DIR)/libc.a: $(LIBC_OBJS) @mkdir -p $(LIB_DIR) $(AR) r $@ $^ -$(OBJ_DIR)/%.o: $(SRC_DIR)/**/%.c +define DEFINE_OBJ_TARGET +$(OBJ_DIR)/%.o: $(1)/%.c $(PARENT_DEPS) @mkdir -p $(OBJ_DIR) - $(CC) -c -o $@ -Werror -ffreestanding $(CFLAGS) $< + $(CC) -c -o $$@ -Werror -ffreestanding $(CFLAGS) $$< +endef +LIB_SRC_DIRS:=$(CRT0_DIR) $(MATH_DIR) $(MISC_DIR) $(STDIO_DIR) $(STDLIB_DIR) $(STRING_DIR) $(UNISTD_DIR) +$(foreach D, $(LIB_SRC_DIRS), $(eval $(call DEFINE_OBJ_TARGET,$(D)))) ### Test @@ -81,6 +93,48 @@ $(foreach D, $(TESTS), $(eval $(call DEFINE_TEST_TARGET,$(D)))) WCC:=../wcc WCC_TESTS:=$(TESTS) +WCC_OBJ_DIR:=./obj/wcc +WCC_LIB_DIR:=../lib + +WCC_LIBS:=$(WCC_LIB_DIR)/wcrt0.a $(WCC_LIB_DIR)/wlibc.a + +WASM_UNISTD_DIR:=$(SRC_DIR)/_wasm/unistd +WASM_CRT0_DIR:=$(SRC_DIR)/_wasm/crt0 + +WCC_CRT0_SRCS:=$(wildcard $(WASM_CRT0_DIR)/*.c) + +WCC_LIBC_SRCS:=\ + $(wildcard $(MATH_DIR)/*.c) \ + $(wildcard $(MISC_DIR)/*.c) \ + $(wildcard $(STDIO_DIR)/*.c) \ + $(wildcard $(STDLIB_DIR)/*.c) \ + $(wildcard $(STRING_DIR)/*.c) \ + $(wildcard $(WASM_UNISTD_DIR)/*.c) \ + +WCC_CRT0_OBJS:=$(addprefix $(WCC_OBJ_DIR)/,$(notdir $(WCC_CRT0_SRCS:.c=.o))) +WCC_LIBC_OBJS:=$(addprefix $(WCC_OBJ_DIR)/,$(notdir $(WCC_LIBC_SRCS:.c=.o))) + +echo-wcc-libc-objs: + @echo $(WCC_LIBC_OBJS) + +$(WCC_LIB_DIR)/wcrt0.a: $(WCC_CRT0_OBJS) + @mkdir -p $(WCC_LIB_DIR) + $(AR) r $@ $^ + +$(WCC_LIB_DIR)/wlibc.a: $(WCC_LIBC_OBJS) + @mkdir -p $(WCC_LIB_DIR) + $(AR) r $@ $^ + +define DEFINE_WCCOBJ_TARGET +$(WCC_OBJ_DIR)/%.o: $(1)/%.c + @mkdir -p $(WCC_OBJ_DIR) + $(CC) -c -o $$@ -Werror $(WCC_CFLAGS) $$< +endef +WCC_SRC_DIRS:=$(MATH_DIR) $(MISC_DIR) $(STDIO_DIR) $(STDLIB_DIR) $(STRING_DIR) $(WASM_UNISTD_DIR) $(WASM_CRT0_DIR) +$(foreach D, $(WCC_SRC_DIRS), $(eval $(call DEFINE_WCCOBJ_TARGET,$(D)))) + +.PHONY: wcc-libs +wcc-libs: $(WCC_LIBS) .PHONY: test-wcc test-wcc: $(foreach D, $(WCC_TESTS), $(addprefix test-wcc-,$(D))) From 0f87b6ca7c269909b1940cdcb7515116507614b7 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Mon, 19 Feb 2024 19:28:00 +0900 Subject: [PATCH 2/6] Handle .a file in wcc-ld Use `FOREACH_FILE_ARCONTENT` macro to process object files in an archive file. --- Makefile | 4 +- src/ld/ld.c | 4 +- src/wcc/wasm_linker.c | 728 ++++++++++++++++++++++++++++-------------- 3 files changed, 493 insertions(+), 243 deletions(-) diff --git a/Makefile b/Makefile index f07dca7f0..2dcbc774c 100644 --- a/Makefile +++ b/Makefile @@ -193,7 +193,7 @@ WCC_DIR:=src/wcc WCC_CFLAGS:=$(CFLAGS) -I$(CPP_DIR) WCC_SRCS:=$(wildcard $(WCC_DIR)/*.c) \ - $(wildcard $(CC1_FE_DIR)/*.c) \ + $(wildcard $(CC1_FE_DIR)/*.c) $(UTIL_DIR)/archive.c \ $(CPP_DIR)/preprocessor.c $(CPP_DIR)/pp_parser.c $(CPP_DIR)/macro.c \ $(UTIL_DIR)/util.c $(UTIL_DIR)/table.c WCC_OBJS:=$(addprefix $(WCC_OBJ_DIR)/,$(notdir $(WCC_SRCS:.c=.o))) @@ -210,7 +210,7 @@ wcc-libs: WCCLD_SRCS:=$(DEBUG_DIR)/wcc-ld.c $(WCC_DIR)/wasm_linker.c \ $(WCC_DIR)/wcc_util.c $(WCC_DIR)/emit_wasm.c $(WCC_DIR)/traverse.c $(WCC_DIR)/traverse_setjmp.c \ $(wildcard $(CC1_FE_DIR)/*.c) \ - $(UTIL_DIR)/util.c $(UTIL_DIR)/table.c + $(UTIL_DIR)/util.c $(UTIL_DIR)/table.c $(UTIL_DIR)/archive.c WCCLD_OBJS:=$(addprefix $(WCC_OBJ_DIR)/,$(notdir $(WCCLD_SRCS:.c=.o))) wcc-ld: $(WCCLD_OBJS) diff --git a/src/ld/ld.c b/src/ld/ld.c index de838c2a0..5596a77da 100644 --- a/src/ld/ld.c +++ b/src/ld/ld.c @@ -94,9 +94,7 @@ typedef struct { } LinkEditor; void ld_init(LinkEditor *ld, int nfiles) { - size_t size = sizeof(*ld->files) * nfiles; - ld->files = malloc_or_die(size); - memset(ld->files, 0x00, size); + ld->files = calloc_or_die(sizeof(*ld->files) * nfiles); ld->nfiles = nfiles; for (int secno = 0; secno < SEC_BSS + 1; ++secno) { diff --git a/src/wcc/wasm_linker.c b/src/wcc/wasm_linker.c index 4f650c414..3a2867253 100644 --- a/src/wcc/wasm_linker.c +++ b/src/wcc/wasm_linker.c @@ -1,13 +1,16 @@ #include "../../config.h" #include "wasm_linker.h" +#include #include #include #include #include #include #include +#include +#include "archive.h" #include "table.h" #include "util.h" #include "wasm.h" @@ -547,10 +550,70 @@ static WasmObj *read_wasm(FILE *fp, const char *filename, size_t filesize) { // +typedef struct { + WasmObj *wasmobj; + size_t size; + char name[1]; // [sizeof(((struct ar_hdr*)0)->ar_name) + 1] +} ArContent; + +#define FOREACH_FILE_ARCONTENT(ar, content, body) \ + {Vector *contents = (ar)->contents; \ + for (int i = 0; i < contents->len; i += 2) { \ + ArContent *content = contents->data[i + 1]; \ + body \ + }} + +WasmObj *load_archive_wasmobj(Archive *ar, uint32_t offset) { + Vector *contents = ar->contents; + for (int i = 0; i < contents->len; i += 2) { + if (VOIDP2INT(contents->data[i]) == offset) { + // Already loaded. + return NULL; + } + } + + fseek(ar->fp, offset, SEEK_SET); + + struct ar_hdr hdr; + read_or_die(ar->fp, &hdr, sizeof(hdr), "hdr"); + if (memcmp(hdr.ar_fmag, ARFMAG, sizeof(hdr.ar_fmag)) != 0) + error("Malformed archive"); + + ArContent *content = malloc_or_die(sizeof(*content) + sizeof(hdr.ar_name)); + + memcpy(content->name, hdr.ar_name, sizeof(hdr.ar_name)); + char *p = memchr(content->name, '/', sizeof(hdr.ar_name)); + if (p == NULL) + p = &content->name[sizeof(hdr.ar_name)]; + *p = '\0'; + + char sizestr[sizeof(hdr.ar_size) + 1]; + memcpy(sizestr, hdr.ar_size, sizeof(hdr.ar_size)); + sizestr[sizeof(hdr.ar_size)] = '\0'; + content->size = strtoul(sizestr, NULL, 10); + + WasmObj *wasmobj = read_wasm(ar->fp, content->name, content->size); + if (wasmobj == NULL) + return false; + content->wasmobj = wasmobj; + + vec_push(contents, INT2VOIDP(offset)); + vec_push(contents, content); + + return wasmobj; +} + +// + struct File { const char *filename; + enum { + FK_WASMOBJ, + FK_ARCHIVE, + } kind; union { WasmObj *wasmobj; + Archive *archive; }; }; @@ -578,13 +641,46 @@ static int resolve_symbols_wasmobj(WasmLinker *linker, WasmObj *wasmobj) { return err_count; } +static int resolve_symbols_archive(WasmLinker *linker, Archive *ar) { + Table *unresolved = &linker->unresolved; + Table *table = &ar->symbol_table; + for (;;) { + bool retry = false; + const Name *name; + void *dummy; + for (int it = 0; (it = table_iterate(unresolved, it, &name, &dummy)) != -1;) { + ArSymbol *symbol; + if (!table_try_get(table, name, (void**)&symbol)) + continue; + table_delete(unresolved, name); + + WasmObj *wasmobj = load_archive_wasmobj(ar, symbol->offset); + if (wasmobj != NULL) { + resolve_symbols_wasmobj(linker, wasmobj); + retry = true; + break; + } + } + if (!retry) + break; + } + return 0; +} + static bool resolve_symbols(WasmLinker *linker) { int err_count = 0; // Traverse all wasmobj files and enumerate defined and unresolved symbols. for (int i = 0; i < linker->files->len; ++i) { File *file = linker->files->data[i]; - err_count += resolve_symbols_wasmobj(linker, file->wasmobj); + switch (file->kind) { + case FK_WASMOBJ: + err_count += resolve_symbols_wasmobj(linker, file->wasmobj); + break; + case FK_ARCHIVE: + err_count += resolve_symbols_archive(linker, file->archive); + break; + } } // Enumerate unresolved: import @@ -633,6 +729,49 @@ static bool resolve_symbols(WasmLinker *linker) { return err_count == 0; } +static void renumber_symbols_wasmobj(WasmObj *wasmobj, uint32_t *defined_count) { + Vector *symtab = wasmobj->linking.symtab; + uint32_t import_count[3]; + import_count[SIK_SYMTAB_FUNCTION] = wasmobj->import.functions->len; + import_count[SIK_SYMTAB_DATA] = 0; + for (int j = 0; j < symtab->len; ++j) { + SymbolInfo *sym = symtab->data[j]; + if (sym->flags & WASM_SYM_UNDEFINED) + continue; + switch (sym->kind) { + default: assert(false); // Fallthrough to suppress warning. + case SIK_SYMTAB_FUNCTION: + case SIK_SYMTAB_DATA: + sym->combined_index = sym->local_index + defined_count[sym->kind] - import_count[sym->kind]; + break; + case SIK_SYMTAB_GLOBAL: + // Handled differently (just below). + break; + case SIK_SYMTAB_EVENT: + { + if (sym->tag.typeindex >= (uint32_t)wasmobj->types->len) + error("illegal type index for event: %.*s", NAMES(sym->name)); + uint32_t typeindex = VOIDP2INT(wasmobj->types->data[sym->tag.typeindex]); + TagInfo *ti = getsert_tag(sym->name, typeindex); + sym->combined_index = ti->index; + } + break; + } + } + + // Increment count_table according to defined counts. + static const int kSecTable[] = {SEC_FUNC, SEC_DATA}; + for (size_t i = 0; i < sizeof(kSecTable) / sizeof(kSecTable[0]); ++i) { + int secidx = kSecTable[i]; + WasmSection *sec = find_section(wasmobj, secidx); + if (sec != NULL) { + unsigned char *p = sec->start; + uint32_t num = read_uleb128(p, &p); + defined_count[i] += num; + } + } +} + static void renumber_symbols(WasmLinker *linker) { // Enumerate defined functions and data. uint32_t defined_count[] = { @@ -640,46 +779,16 @@ static void renumber_symbols(WasmLinker *linker) { [SIK_SYMTAB_DATA] = 0, }; for (int i = 0; i < linker->files->len; ++i) { - WasmObj *wasmobj = ((File*)linker->files->data[i])->wasmobj; - Vector *symtab = wasmobj->linking.symtab; - uint32_t import_count[3]; - import_count[SIK_SYMTAB_FUNCTION] = wasmobj->import.functions->len; - import_count[SIK_SYMTAB_DATA] = 0; - for (int j = 0; j < symtab->len; ++j) { - SymbolInfo *sym = symtab->data[j]; - if (sym->flags & WASM_SYM_UNDEFINED) - continue; - switch (sym->kind) { - default: assert(false); // Fallthrough to suppress warning. - case SIK_SYMTAB_FUNCTION: - case SIK_SYMTAB_DATA: - sym->combined_index = sym->local_index + defined_count[sym->kind] - import_count[sym->kind]; - break; - case SIK_SYMTAB_GLOBAL: - // Handled differently (just below). - break; - case SIK_SYMTAB_EVENT: - { - if (sym->tag.typeindex >= (uint32_t)wasmobj->types->len) - error("illegal type index for event: %.*s", NAMES(sym->name)); - uint32_t typeindex = VOIDP2INT(wasmobj->types->data[sym->tag.typeindex]); - TagInfo *ti = getsert_tag(sym->name, typeindex); - sym->combined_index = ti->index; - } - break; - } - } - - // Increment count_table according to defined counts. - static const int kSecTable[] = {SEC_FUNC, SEC_DATA}; - for (size_t i = 0; i < sizeof(kSecTable) / sizeof(kSecTable[0]); ++i) { - int secidx = kSecTable[i]; - WasmSection *sec = find_section(wasmobj, secidx); - if (sec != NULL) { - unsigned char *p = sec->start; - uint32_t num = read_uleb128(p, &p); - defined_count[i] += num; - } + File *file = linker->files->data[i]; + switch (file->kind) { + case FK_WASMOBJ: + renumber_symbols_wasmobj(file->wasmobj, defined_count); + break; + case FK_ARCHIVE: + FOREACH_FILE_ARCONTENT(file->archive, content, { + renumber_symbols_wasmobj(content->wasmobj, defined_count); + }); + break; } } @@ -696,91 +805,131 @@ static void renumber_symbols(WasmLinker *linker) { } } +static void renumber_func_types_wasmobj(WasmObj *wasmobj) { + Vector *type_indices = wasmobj->types; + Vector *symtab = wasmobj->linking.symtab; + for (int j = 0; j < symtab->len; ++j) { + SymbolInfo *sym = symtab->data[j]; + if (sym->kind != SIK_SYMTAB_FUNCTION) + continue; + if (sym->func.type_index >= (uint32_t)type_indices->len) + error("illegal type index for %.*s: %d\n", NAMES(sym->name), sym->func.type_index); + sym->func.type_index = VOIDP2INT(type_indices->data[sym->func.type_index]); + } +} + static void renumber_func_types(WasmLinker *linker) { for (int i = 0; i < linker->files->len; ++i) { - WasmObj *wasmobj = ((File*)linker->files->data[i])->wasmobj; - Vector *type_indices = wasmobj->types; - Vector *symtab = wasmobj->linking.symtab; - for (int j = 0; j < symtab->len; ++j) { - SymbolInfo *sym = symtab->data[j]; - if (sym->kind != SIK_SYMTAB_FUNCTION) - continue; - if (sym->func.type_index >= (uint32_t)type_indices->len) - error("illegal type index for %.*s: %d\n", NAMES(sym->name), sym->func.type_index); - sym->func.type_index = VOIDP2INT(type_indices->data[sym->func.type_index]); + File *file = linker->files->data[i]; + switch (file->kind) { + case FK_WASMOBJ: + renumber_func_types_wasmobj(file->wasmobj); + break; + case FK_ARCHIVE: + FOREACH_FILE_ARCONTENT(file->archive, content, { + renumber_func_types_wasmobj(content->wasmobj); + }); + break; } } } +static uint32_t remap_data_address_wasmobj(WasmObj *wasmobj, uint32_t address) { + address = ALIGN(address, 16); // TODO: + uint32_t max = address; + for (uint32_t j = 0; j < wasmobj->data.count; ++j) { + DataSegmentForLink *d = &wasmobj->data.segments[j]; + d->start += address; + uint32_t end = d->start + d->size; + if (end > max) + max = end; + } + address = max; + + Vector *symtab = wasmobj->linking.symtab; + for (int k = 0; k < symtab->len; ++k) { + SymbolInfo *sym = symtab->data[k]; + if (sym->kind != SIK_SYMTAB_DATA || sym->flags & WASM_SYM_UNDEFINED) + continue; + if (sym->local_index >= wasmobj->data.count) + error("illegal index for data segment %.*s: %d\n", NAMES(sym->name), sym->local_index); + DataSegmentForLink *d = &wasmobj->data.segments[sym->local_index]; + uint32_t addr = d->start + sym->data.offset; + sym->data.address = addr; + } + return address; +} + static void remap_data_address(WasmLinker *linker) { uint32_t address = 0; for (int i = 0; i < linker->files->len; ++i) { - WasmObj *wasmobj = ((File*)linker->files->data[i])->wasmobj; - address = ALIGN(address, 16); // TODO: - uint32_t max = address; - for (uint32_t j = 0; j < wasmobj->data.count; ++j) { - DataSegmentForLink *d = &wasmobj->data.segments[j]; - d->start += address; - uint32_t end = d->start + d->size; - if (end > max) - max = end; - } - address = max; - - Vector *symtab = wasmobj->linking.symtab; - for (int k = 0; k < symtab->len; ++k) { - SymbolInfo *sym = symtab->data[k]; - if (sym->kind != SIK_SYMTAB_DATA || sym->flags & WASM_SYM_UNDEFINED) - continue; - if (sym->local_index >= wasmobj->data.count) - error("illegal index for data segment %.*s: %d\n", NAMES(sym->name), sym->local_index); - DataSegmentForLink *d = &wasmobj->data.segments[sym->local_index]; - uint32_t addr = d->start + sym->data.offset; - sym->data.address = addr; + File *file = linker->files->data[i]; + switch (file->kind) { + case FK_WASMOBJ: + address = remap_data_address_wasmobj(file->wasmobj, address); + break; + case FK_ARCHIVE: + FOREACH_FILE_ARCONTENT(file->archive, content, { + address = remap_data_address_wasmobj(content->wasmobj, address); + }); + break; } } linker->data_end_address = address; } -static void renumber_indirect_functions(WasmLinker *linker) { +static void renumber_indirect_functions_wasmobj(WasmLinker *linker, WasmObj *wasmobj) { Table *indirect_functions = &linker->indirect_functions; - for (int i = 0; i < linker->files->len; ++i) { - WasmObj *wasmobj = ((File*)linker->files->data[i])->wasmobj; - - uint32_t segnum = wasmobj->elem.count; - ElemSegmentForLink *segments = wasmobj->elem.segments; - for (uint32_t i = 0; i < segnum; ++i) { - ElemSegmentForLink *segment = &segments[i]; - uint32_t count = segment->count; - for (uint32_t j = 0; j < count; ++j) { - uint32_t index = segment->content[j]; - SymbolInfo *sym = NULL; - { - Vector *symtab = wasmobj->linking.symtab; - for (int k = 0; k < symtab->len; ++k) { - SymbolInfo *p = symtab->data[k]; - if (p->kind == SIK_SYMTAB_FUNCTION && p->local_index == index) { - sym = p; - break; - } + uint32_t segnum = wasmobj->elem.count; + ElemSegmentForLink *segments = wasmobj->elem.segments; + for (uint32_t i = 0; i < segnum; ++i) { + ElemSegmentForLink *segment = &segments[i]; + uint32_t count = segment->count; + for (uint32_t j = 0; j < count; ++j) { + uint32_t index = segment->content[j]; + SymbolInfo *sym = NULL; + { + Vector *symtab = wasmobj->linking.symtab; + for (int k = 0; k < symtab->len; ++k) { + SymbolInfo *p = symtab->data[k]; + if (p->kind == SIK_SYMTAB_FUNCTION && p->local_index == index) { + sym = p; + break; } } - if (sym == NULL) { - error("indirect function not found: %d", index); - } - if (!(sym->flags & WASM_SYM_BINDING_LOCAL)) { - const Name *name = sym->name; - if (!table_try_get(&linker->defined, name, (void**)&sym)) { - if (!table_try_get(&linker->unresolved, name, (void**)&sym)) { - error("indirect function not found: %.*s", NAMES(name)); - } + } + if (sym == NULL) { + error("indirect function not found: %d", index); + } + if (!(sym->flags & WASM_SYM_BINDING_LOCAL)) { + const Name *name = sym->name; + if (!table_try_get(&linker->defined, name, (void**)&sym)) { + if (!table_try_get(&linker->unresolved, name, (void**)&sym)) { + error("indirect function not found: %.*s", NAMES(name)); } } - table_put(indirect_functions, sym->name, sym); } + table_put(indirect_functions, sym->name, sym); + } + } +} + +static void renumber_indirect_functions(WasmLinker *linker) { + for (int i = 0; i < linker->files->len; ++i) { + File *file = linker->files->data[i]; + switch (file->kind) { + case FK_WASMOBJ: + renumber_indirect_functions_wasmobj(linker, file->wasmobj); + break; + case FK_ARCHIVE: + FOREACH_FILE_ARCONTENT(file->archive, content, { + renumber_indirect_functions_wasmobj(linker, content->wasmobj); + }); + break; } } + Table *indirect_functions = &linker->indirect_functions; const Name *name; SymbolInfo *sym; uint32_t index = INDIRECT_FUNCTION_TABLE_START_INDEX; @@ -828,73 +977,86 @@ static void put_i32(unsigned char *p, int32_t x) { } } -static void apply_relocation(WasmLinker *linker) { - for (int i = 0; i < linker->files->len; ++i) { - WasmObj *wasmobj = ((File*)linker->files->data[i])->wasmobj; - Vector *symtab = wasmobj->linking.symtab; - for (int j = 0; j < 2; ++j) { - uint32_t count = wasmobj->reloc[j].count; - if (count == 0) - continue; - - uint32_t section_index = wasmobj->reloc[j].section_index; - WasmSection *sec = &wasmobj->sections[section_index]; - RelocInfo *relocs = wasmobj->reloc[j].relocs; - for (uint32_t k = 0; k < count; ++k) { - RelocInfo *p = &relocs[k]; - unsigned char *q = sec->start + p->offset; - switch (p->type) { - case R_WASM_TYPE_INDEX_LEB: - { - assert(wasmobj->types != NULL); - if (p->index >= (uint32_t)wasmobj->types->len) - error("illegal type index: %d", p->index); - uint32_t index = VOIDP2INT(wasmobj->types->data[p->index]); - put_varuint32(q, index, p); - } - continue; - case R_WASM_TAG_INDEX_LEB: - { - if (p->index >= (uint32_t)symtab->len) - error("illegal symbol index: %d", p->index); - SymbolInfo *sym = symtab->data[p->index]; - put_varuint32(q, sym->combined_index, p); - } - continue; +static void apply_relocation_wasmobj(WasmLinker *linker, WasmObj *wasmobj) { + Vector *symtab = wasmobj->linking.symtab; + for (int j = 0; j < 2; ++j) { + uint32_t count = wasmobj->reloc[j].count; + if (count == 0) + continue; - default: break; + uint32_t section_index = wasmobj->reloc[j].section_index; + WasmSection *sec = &wasmobj->sections[section_index]; + RelocInfo *relocs = wasmobj->reloc[j].relocs; + for (uint32_t k = 0; k < count; ++k) { + RelocInfo *p = &relocs[k]; + unsigned char *q = sec->start + p->offset; + switch (p->type) { + case R_WASM_TYPE_INDEX_LEB: + { + assert(wasmobj->types != NULL); + if (p->index >= (uint32_t)wasmobj->types->len) + error("illegal type index: %d", p->index); + uint32_t index = VOIDP2INT(wasmobj->types->data[p->index]); + put_varuint32(q, index, p); } - - // Symbol resolution. - if (p->index >= (uint32_t)symtab->len) - error("illegal index for reloc: %d", p->index); - SymbolInfo *sym = symtab->data[p->index]; - SymbolInfo *target = sym; - if (!table_try_get(&linker->defined, sym->name, (void**)&target)) - table_try_get(&linker->unresolved, sym->name, (void**)&target); - - switch (p->type) { - case R_WASM_FUNCTION_INDEX_LEB: - case R_WASM_GLOBAL_INDEX_LEB: - put_varuint32(q, target->combined_index, p); - break; - case R_WASM_MEMORY_ADDR_LEB: - put_varuint32(q, target->data.address, p); - break; - case R_WASM_MEMORY_ADDR_I32: - put_i32(q, target->data.address + p->addend); - break; - case R_WASM_TABLE_INDEX_SLEB: - put_varint32(q, target->func.indirect_index, p); - break; - case R_WASM_TABLE_INDEX_I32: - put_i32(q, target->func.indirect_index); - break; - default: - error("Relocation not handled: type=%d", p->type); - break; + continue; + case R_WASM_TAG_INDEX_LEB: + { + if (p->index >= (uint32_t)symtab->len) + error("illegal symbol index: %d", p->index); + SymbolInfo *sym = symtab->data[p->index]; + put_varuint32(q, sym->combined_index, p); } + continue; + + default: break; } + + // Symbol resolution. + if (p->index >= (uint32_t)symtab->len) + error("illegal index for reloc: %d", p->index); + SymbolInfo *sym = symtab->data[p->index]; + SymbolInfo *target = sym; + if (!table_try_get(&linker->defined, sym->name, (void**)&target)) + table_try_get(&linker->unresolved, sym->name, (void**)&target); + + switch (p->type) { + case R_WASM_FUNCTION_INDEX_LEB: + case R_WASM_GLOBAL_INDEX_LEB: + put_varuint32(q, target->combined_index, p); + break; + case R_WASM_MEMORY_ADDR_LEB: + put_varuint32(q, target->data.address, p); + break; + case R_WASM_MEMORY_ADDR_I32: + put_i32(q, target->data.address + p->addend); + break; + case R_WASM_TABLE_INDEX_SLEB: + put_varint32(q, target->func.indirect_index, p); + break; + case R_WASM_TABLE_INDEX_I32: + put_i32(q, target->func.indirect_index); + break; + default: + error("Relocation not handled: type=%d", p->type); + break; + } + } + } +} + +static void apply_relocation(WasmLinker *linker) { + for (int i = 0; i < linker->files->len; ++i) { + File *file = linker->files->data[i]; + switch (file->kind) { + case FK_WASMOBJ: + apply_relocation_wasmobj(linker, file->wasmobj); + break; + case FK_ARCHIVE: + FOREACH_FILE_ARCONTENT(file->archive, content, { + apply_relocation_wasmobj(linker, content->wasmobj); + }); + break; } } } @@ -931,6 +1093,21 @@ static void out_import_section(WasmLinker *linker) { } } +static uint32_t out_function_section_wasmobj(WasmObj *wasmobj, DataStorage *functions_section) { + Vector *symtab = wasmobj->linking.symtab; + uint32_t function_count = 0; + for (int j = 0; j < symtab->len; ++j) { + SymbolInfo *sym = symtab->data[j]; + if (sym->kind != SIK_SYMTAB_FUNCTION || (sym->flags & WASM_SYM_UNDEFINED)) + continue; + // assert(sym->combined_index == function_count + linker->unresolved_func_count); + ++function_count; + int type_index = sym->func.type_index; + data_uleb128(functions_section, -1, type_index); // function i signature index + } + return function_count; +} + static void out_function_section(WasmLinker *linker) { DataStorage functions_section; data_init(&functions_section); @@ -939,16 +1116,21 @@ static void out_function_section(WasmLinker *linker) { uint32_t function_count = 0; for (int i = 0; i < linker->files->len; ++i) { - WasmObj *wasmobj = ((File*)linker->files->data[i])->wasmobj; - Vector *symtab = wasmobj->linking.symtab; - for (int j = 0; j < symtab->len; ++j) { - SymbolInfo *sym = symtab->data[j]; - if (sym->kind != SIK_SYMTAB_FUNCTION || (sym->flags & WASM_SYM_UNDEFINED)) - continue; - assert(sym->combined_index == function_count + linker->unresolved_func_count); - ++function_count; - int type_index = sym->func.type_index; - data_uleb128(&functions_section, -1, type_index); // function i signature index + File *file = linker->files->data[i]; + switch (file->kind) { + case FK_WASMOBJ: + function_count += out_function_section_wasmobj(file->wasmobj, &functions_section); + break; + case FK_ARCHIVE: + { + Archive *ar = file->archive; + Vector *contents = ar->contents; + for (int i = 0; i < contents->len; i += 2) { + ArContent *content = contents->data[i + 1]; + function_count += out_function_section_wasmobj(content->wasmobj, &functions_section); + } + } + break; } } @@ -1091,6 +1273,16 @@ static void out_elems_section(WasmLinker *linker) { fwrite(elems_section.buf, elems_section.len, 1, linker->ofp); } +static uint32_t out_code_section_wasmobj(WasmObj *wasmobj, DataStorage *codesec) { + WasmSection *sec = find_section(wasmobj, SEC_CODE); + if (sec == NULL) + return 0; + unsigned char *p = sec->start; + uint32_t num = read_uleb128(p, &p); + data_append(codesec, p, sec->size - (p - sec->start)); + return num; +} + static void out_code_section(WasmLinker *linker) { DataStorage codesec; data_init(&codesec); @@ -1099,14 +1291,22 @@ static void out_code_section(WasmLinker *linker) { uint32_t code_count = 0; for (int i = 0; i < linker->files->len; ++i) { - WasmObj *wasmobj = ((File*)linker->files->data[i])->wasmobj; - WasmSection *sec = find_section(wasmobj, SEC_CODE); - if (sec == NULL) - continue; - unsigned char *p = sec->start; - uint32_t num = read_uleb128(p, &p); - data_append(&codesec, p, sec->size - (p - sec->start)); - code_count += num; + File *file = linker->files->data[i]; + switch (file->kind) { + case FK_WASMOBJ: + code_count += out_code_section_wasmobj(file->wasmobj, &codesec); + break; + case FK_ARCHIVE: + { + Archive *ar = file->archive; + Vector *contents = ar->contents; + for (int i = 0; i < contents->len; i += 2) { + ArContent *content = contents->data[i + 1]; + code_count += out_code_section_wasmobj(content->wasmobj, &codesec); + } + } + break; + } } data_close_chunk(&codesec, code_count); @@ -1116,6 +1316,35 @@ static void out_code_section(WasmLinker *linker) { fwrite(codesec.buf, codesec.len, 1, linker->ofp); } +static uint32_t out_data_section_wasmobj(WasmObj *wasmobj, DataStorage *datasec) { + DataSegmentForLink *segments = wasmobj->data.segments; + uint32_t data_count = 0; + for (uint32_t j = 0, count = wasmobj->data.count; j < count; ++j) { + DataSegmentForLink *segment = &segments[j]; + uint32_t size = segment->size; + const unsigned char *content = segment->content; + uint32_t non_zero_size; + for (non_zero_size = size; non_zero_size > 0; --non_zero_size) { + if (content[non_zero_size - 1] != 0x00) + break; + } + if (non_zero_size == 0) // BSS + continue; + + data_push(datasec, 0); // flags + // Init (address). + uint32_t address = segment->start; + data_push(datasec, OP_I32_CONST); + data_leb128(datasec, -1, address); + data_push(datasec, OP_END); + // Content + data_uleb128(datasec, -1, non_zero_size); + data_append(datasec, segment->content, non_zero_size); + ++data_count; + } + return data_count; +} + static void out_data_section(WasmLinker *linker) { DataStorage datasec; data_init(&datasec); @@ -1124,30 +1353,21 @@ static void out_data_section(WasmLinker *linker) { uint32_t data_count = 0; for (int i = 0; i < linker->files->len; ++i) { - WasmObj *wasmobj = ((File*)linker->files->data[i])->wasmobj; - DataSegmentForLink *segments = wasmobj->data.segments; - for (uint32_t j = 0, count = wasmobj->data.count; j < count; ++j) { - DataSegmentForLink *segment = &segments[j]; - uint32_t size = segment->size; - const unsigned char *content = segment->content; - uint32_t non_zero_size; - for (non_zero_size = size; non_zero_size > 0; --non_zero_size) { - if (content[non_zero_size - 1] != 0x00) - break; + File *file = linker->files->data[i]; + switch (file->kind) { + case FK_WASMOBJ: + data_count += out_data_section_wasmobj(file->wasmobj, &datasec); + break; + case FK_ARCHIVE: + { + Archive *ar = file->archive; + Vector *contents = ar->contents; + for (int i = 0; i < contents->len; i += 2) { + ArContent *content = contents->data[i + 1]; + data_count += out_data_section_wasmobj(content->wasmobj, &datasec); + } } - if (non_zero_size == 0) // BSS - continue; - - data_push(&datasec, 0); // flags - // Init (address). - uint32_t address = segment->start; - data_push(&datasec, OP_I32_CONST); - data_leb128(&datasec, -1, address); - data_push(&datasec, OP_END); - // Content - data_uleb128(&datasec, -1, non_zero_size); - data_append(&datasec, segment->content, non_zero_size); - ++data_count; + break; } } data_close_chunk(&datasec, data_count); @@ -1172,28 +1392,54 @@ void linker_init(WasmLinker *linker) { } bool read_wasm_obj(WasmLinker *linker, const char *filename) { - FILE *fp; - if (!is_file(filename) || (fp = fopen(filename, "r")) == NULL) { - fprintf(stderr, "cannot open: %s\n", filename); - return false; - } - - fseek(fp, 0, SEEK_END); - long filesize = ftell(fp); - fseek(fp, 0, SEEK_SET); - - WasmObj *wasmobj = read_wasm(fp, filename, filesize); - fclose(fp); - if (wasmobj == NULL) - return false; - File *file = calloc_or_die(sizeof(*file)); file->filename = filename; - file->wasmobj = wasmobj; - vec_push(linker->files, file); + + char *ext = get_ext(filename); + if (strcasecmp(ext, "o") == 0) { + FILE *fp; + if (!is_file(filename) || (fp = fopen(filename, "r")) == NULL) { + fprintf(stderr, "cannot open: %s\n", filename); + return false; + } + + fseek(fp, 0, SEEK_END); + long filesize = ftell(fp); + fseek(fp, 0, SEEK_SET); + + WasmObj *wasmobj = read_wasm(fp, filename, filesize); + fclose(fp); + if (wasmobj == NULL) + return false; + + file->kind = FK_WASMOBJ; + file->wasmobj = wasmobj; + vec_push(linker->files, file); + } else if (strcasecmp(ext, "a") == 0) { + Archive *archive = load_archive(filename); + if (archive == NULL) { + fprintf(stderr, "load failed: %s\n", filename); + return false; + } + file->kind = FK_ARCHIVE; + file->archive = archive; + vec_push(linker->files, file); + } else { + error("Unsupported file: %s", filename); + } return true; } +static void verbose_symbols(WasmObj *wasmobj, enum SymInfoKind kind) { + Vector *symtab = wasmobj->linking.symtab; + for (int j = 0; j < symtab->len; ++j) { + SymbolInfo *sym = symtab->data[j]; + if (sym->flags & WASM_SYM_UNDEFINED || sym->kind != kind) + continue; + printf("%2d: %.*s\n", sym->combined_index, NAMES(sym->name)); + } +} + bool link_wasm_objs(WasmLinker *linker, Vector *exports, uint32_t stack_size) { for (int i = 0; i < exports->len; ++i) { const Name *name = exports->data[i]; @@ -1246,13 +1492,16 @@ bool link_wasm_objs(WasmLinker *linker, Vector *exports, uint32_t stack_size) { // Defined. for (int i = 0; i < linker->files->len; ++i) { File *file = linker->files->data[i]; - WasmObj *wasmobj = file->wasmobj; - Vector *symtab = wasmobj->linking.symtab; - for (int j = 0; j < symtab->len; ++j) { - SymbolInfo *sym = symtab->data[j]; - if (sym->flags & WASM_SYM_UNDEFINED || sym->kind != SIK_SYMTAB_FUNCTION) - continue; - printf("%2d: %.*s\n", sym->combined_index, NAMES(sym->name)); + switch (file->kind) { + case FK_WASMOBJ: + verbose_symbols(file->wasmobj, SIK_SYMTAB_FUNCTION); + break; + case FK_ARCHIVE: + for (int j = 0; j < file->archive->contents->len; j += 2) { + ArContent *content = file->archive->contents->data[j + 1]; + verbose_symbols(content->wasmobj, SIK_SYMTAB_FUNCTION); + } + break; } } @@ -1266,13 +1515,16 @@ bool link_wasm_objs(WasmLinker *linker, Vector *exports, uint32_t stack_size) { printf("### Data\n"); for (int i = 0; i < linker->files->len; ++i) { File *file = linker->files->data[i]; - WasmObj *wasmobj = file->wasmobj; - Vector *symtab = wasmobj->linking.symtab; - for (int j = 0; j < symtab->len; ++j) { - SymbolInfo *sym = symtab->data[j]; - if (sym->flags & WASM_SYM_UNDEFINED || sym->kind != SIK_SYMTAB_DATA) - continue; - printf("%2d: %.*s\n", sym->combined_index, NAMES(sym->name)); + switch (file->kind) { + case FK_WASMOBJ: + verbose_symbols(file->wasmobj, SIK_SYMTAB_DATA); + break; + case FK_ARCHIVE: + for (int j = 0; j < file->archive->contents->len; j += 2) { + ArContent *content = file->archive->contents->data[j + 1]; + verbose_symbols(content->wasmobj, SIK_SYMTAB_DATA); + } + break; } } } From 72ae0e01815abc7202752f8365b2ad8eca9d187c Mon Sep 17 00:00:00 2001 From: tyfkda Date: Sat, 24 Feb 2024 10:13:57 +0900 Subject: [PATCH 3/6] Link with wcc-ld --- src/wcc/wcc.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/wcc/wcc.c b/src/wcc/wcc.c index 56ca695d7..576331e71 100644 --- a/src/wcc/wcc.c +++ b/src/wcc/wcc.c @@ -20,6 +20,7 @@ #include "wasm.h" // #define USE_EMCC_AS_LINKER 1 +// #define USE_WCCLD_AS_LINKER 1 static const char DEFAULT_IMPORT_MODULE_NAME[] = "env"; @@ -342,7 +343,7 @@ int main(int argc, char *argv[]) { #endif } -#if USE_EMCC_AS_LINKER +#if USE_EMCC_AS_LINKER || USE_WCCLD_AS_LINKER bool do_emcc_link = false; if (out_type >= OutExecutable) { do_emcc_link = true; @@ -415,7 +416,7 @@ int main(int argc, char *argv[]) { return 2; FILE *ofp; -#if USE_EMCC_AS_LINKER +#if USE_EMCC_AS_LINKER || USE_WCCLD_AS_LINKER char *tmpfn; if (do_emcc_link) { char template[] = "/tmp/xcc-XXXXXX.o"; @@ -448,7 +449,7 @@ int main(int argc, char *argv[]) { fclose(ofp); } -#if USE_EMCC_AS_LINKER +#if USE_EMCC_AS_LINKER || USE_WCCLD_AS_LINKER if (do_emcc_link) { char *finalfn = (char*)ofn; if (finalfn == NULL) { @@ -457,13 +458,25 @@ int main(int argc, char *argv[]) { finalfn = change_ext(finalfn, "wasm"); } +#if USE_EMCC_AS_LINKER + char *cc = "emcc"; +#else // if USE_WCCLD_AS_LINKER + char *cc = JOIN_PATHS(root, "wcc-ld"); +#endif + char *argv[] = { - "emcc", + cc, "-o", finalfn, tmpfn, +#if USE_WCCLD_AS_LINKER + JOIN_PATHS(root, "lib/wcrt0.a"), + JOIN_PATHS(root, "lib/wlibc.a"), +#endif NULL, }; - return execvp("emcc", argv); + execvp(cc, argv); + perror(cc); + return 1; } #endif From c87bd0289cda1488845897c03d4528bfdafbfe8f Mon Sep 17 00:00:00 2001 From: tyfkda Date: Mon, 26 Feb 2024 15:27:04 +0900 Subject: [PATCH 4/6] Must use linker * Always output object file and link with library * Output function even if `FF_REFERRED` is not set --- src/_debug/wcc-ld.c | 1 - src/wcc/emit_wasm.c | 191 ++++++++---------------------------------- src/wcc/gen_wasm.c | 189 +++++++++++++++++------------------------ src/wcc/traverse.c | 41 ++------- src/wcc/wasm_linker.c | 22 ++++- src/wcc/wcc.c | 114 ++++++++++++++----------- src/wcc/wcc.h | 6 +- src/wcc/wcc_util.c | 1 - 8 files changed, 211 insertions(+), 354 deletions(-) diff --git a/src/_debug/wcc-ld.c b/src/_debug/wcc-ld.c index 0b9414831..b678eef39 100644 --- a/src/_debug/wcc-ld.c +++ b/src/_debug/wcc-ld.c @@ -12,7 +12,6 @@ #include "util.h" static void init(void) { - out_type = OutExecutable; functypes = new_vector(); tags = new_vector(); table_init(&indirect_function_table); diff --git a/src/wcc/emit_wasm.c b/src/wcc/emit_wasm.c index d39b9eb6d..7f072c1a0 100644 --- a/src/wcc/emit_wasm.c +++ b/src/wcc/emit_wasm.c @@ -99,40 +99,36 @@ static void emit_number(void *ud, const Type *type, Expr *var, Fixnum offset) { assert(v == 0); v = get_indirect_function_index(var->var.name); - if (out_type < OutExecutable) { - FuncInfo *info = table_get(&func_info_table, var->var.name); - if (info == NULL) - error("`%.*s' not found", NAMES(var->var.name)); - - RelocInfo *ri = calloc_or_die(sizeof(*ri)); - ri->type = R_WASM_TABLE_INDEX_I32; - ri->offset = ds->len; - ri->addend = offset; - ri->index = info->index; - - Vector *reloc_data = edp->reloc_data; - if (reloc_data == NULL) - edp->reloc_data = reloc_data = new_vector(); - vec_push(reloc_data, ri); - } + FuncInfo *info = table_get(&func_info_table, var->var.name); + if (info == NULL) + error("`%.*s' not found", NAMES(var->var.name)); + + RelocInfo *ri = calloc_or_die(sizeof(*ri)); + ri->type = R_WASM_TABLE_INDEX_I32; + ri->offset = ds->len; + ri->addend = offset; + ri->index = info->index; + + Vector *reloc_data = edp->reloc_data; + if (reloc_data == NULL) + edp->reloc_data = reloc_data = new_vector(); + vec_push(reloc_data, ri); } else { assert(var->kind == EX_VAR); const GVarInfo *info = get_gvar_info(var); assert(!is_prim_type(info->varinfo->type) || (info->varinfo->storage & VS_REF_TAKEN)); v += info->non_prim.address; - if (out_type < OutExecutable) { - RelocInfo *ri = calloc_or_die(sizeof(*ri)); - ri->type = R_WASM_MEMORY_ADDR_I32; - ri->offset = ds->len; - ri->addend = offset; - ri->index = info->symbol_index; - - Vector *reloc_data = edp->reloc_data; - if (reloc_data == NULL) - edp->reloc_data = reloc_data = new_vector(); - vec_push(reloc_data, ri); - } + RelocInfo *ri = calloc_or_die(sizeof(*ri)); + ri->type = R_WASM_MEMORY_ADDR_I32; + ri->offset = ds->len; + ri->addend = offset; + ri->index = info->symbol_index; + + Vector *reloc_data = edp->reloc_data; + if (reloc_data == NULL) + edp->reloc_data = reloc_data = new_vector(); + vec_push(reloc_data, ri); } } emit_fixnum(ds, v, type_size(type)); @@ -221,8 +217,6 @@ static Vector *construct_data_segment(void) { address = adr + type_size(varinfo->type); #endif } - if (out_type >= OutExecutable) - break; } return segments; } @@ -256,7 +250,7 @@ static void emit_import_section(EmitWasm *ew) { uint32_t imports_count = 0; uint32_t global_count = 0; - if (out_type < OutExecutable) { + { static const char kMemoryName[] = "__linear_memory"; data_string(&imports_section, env_module_name, sizeof(env_module_name) - 1); // import module name data_string(&imports_section, kMemoryName, sizeof(kMemoryName) - 1); // import name @@ -265,7 +259,7 @@ static void emit_import_section(EmitWasm *ew) { data_uleb128(&imports_section, -1, 0); // size ++imports_count; } - if (indirect_function_table.count > 0 && out_type < OutExecutable) { + if (indirect_function_table.count > 0) { static const char kTableName[] = "__indirect_function_table"; data_string(&imports_section, env_module_name, sizeof(env_module_name) - 1); // import module name data_string(&imports_section, kTableName, sizeof(kTableName) - 1); // import name @@ -353,8 +347,7 @@ static void emit_function_section(EmitWasm *ew) { const Name *name; FuncInfo *info; for (int it = 0; (it = table_iterate(&func_info_table, it, &name, (void**)&info)) != -1; ) { - Function *func = info->func; - if (func == NULL || info->flag == 0) + if (info->func == NULL) continue; if (satisfy_inline_criteria(info->varinfo) && !(info->varinfo->storage & VS_STATIC)) continue; @@ -374,49 +367,6 @@ static void emit_function_section(EmitWasm *ew) { } } -void emit_table_section(EmitWasm *ew) { - if (out_type < OutExecutable) - return; - if (indirect_function_table.count <= 0) - return; - - DataStorage table_section; - data_init(&table_section); - data_open_chunk(&table_section); - data_leb128(&table_section, -1, 1); // num tables - data_push(&table_section, WT_FUNCREF); - data_push(&table_section, 0x00); // limits: flags - data_leb128(&table_section, -1, INDIRECT_FUNCTION_TABLE_START_INDEX + indirect_function_table.count); // initial - data_close_chunk(&table_section, -1); - - fputc(SEC_TABLE, ew->ofp); - fwrite(table_section.buf, table_section.len, 1, ew->ofp); - ++ew->section_index; -} - -void emit_memory_section(EmitWasm *ew) { - if (out_type < OutExecutable) - return; - - DataStorage memory_section; - data_init(&memory_section); - data_open_chunk(&memory_section); - data_open_chunk(&memory_section); - { - uint32_t page_count = (ew->address_bottom + MEMORY_PAGE_SIZE - 1) / MEMORY_PAGE_SIZE; - if (page_count <= 0) - page_count = 1; - data_uleb128(&memory_section, -1, 0); // limits (no maximum page size) - data_uleb128(&memory_section, -1, page_count); - data_close_chunk(&memory_section, 1); // count - data_close_chunk(&memory_section, -1); - } - - fputc(SEC_MEMORY, ew->ofp); - fwrite(memory_section.buf, memory_section.len, 1, ew->ofp); - ++ew->section_index; -} - static void emit_global_section(EmitWasm *ew) { DataStorage globals_section; data_init(&globals_section); @@ -453,62 +403,7 @@ static void emit_global_section(EmitWasm *ew) { } } -static void emit_export_section(EmitWasm *ew, Vector *exports) { - if (out_type < OutExecutable) - return; - - DataStorage exports_section; - data_init(&exports_section); - data_open_chunk(&exports_section); - data_open_chunk(&exports_section); - int num_exports = 0; - for (int i = 0; i < exports->len; ++i) { - const Name *name = exports->data[i]; - FuncInfo *info = table_get(&func_info_table, name); - if (info == NULL) { - error("Export: `%.*s' not found", NAMES(name)); - } - assert(info->func != NULL); - VarInfo *varinfo = info->varinfo; - if (varinfo->storage & VS_STATIC) { - error("Export: `%.*s' is not public", NAMES(name)); - } - - 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 - ++num_exports; - } - // Export globals. - { - const Name *name; - GVarInfo *info; - for (int it = 0; (it = table_iterate(&gvar_info_table, it, &name, (void**)&info)) != -1; ) { - const VarInfo *varinfo = info->varinfo; - if (!(info->flag & GVF_EXPORT) || !is_prim_type(varinfo->type) || (varinfo->storage & VS_REF_TAKEN)) - continue; - data_string(&exports_section, name->chars, name->bytes); // export name - data_push(&exports_section, IMPORT_GLOBAL); // export kind - data_uleb128(&exports_section, -1, info->prim.index); // export global index - ++num_exports; - } - } - /*if (memory_section.len > 0)*/ { // TODO: Export only if memory exists - static const char name[] = "memory"; - data_string(&exports_section, name, sizeof(name) - 1); // export name - data_uleb128(&exports_section, -1, IMPORT_MEMORY); // export kind - data_uleb128(&exports_section, -1, 0); // export global index - ++num_exports; - } - data_close_chunk(&exports_section, num_exports); // num exports - data_close_chunk(&exports_section, -1); - - fputc(SEC_EXPORT, ew->ofp); - fwrite(exports_section.buf, exports_section.len, 1, ew->ofp); - ++ew->section_index; -} - -void emit_elems_section(EmitWasm *ew) { +static void emit_elems_section(EmitWasm *ew) { int count = indirect_function_table.count; if (count == 0) return; @@ -574,7 +469,7 @@ static void emit_code_section(EmitWasm *ew) { size_t offset = codesec.len; for (int it = 0; (it = table_iterate(&func_info_table, it, &name, (void**)&info)) != -1; ) { Function *func = info->func; - if (func == NULL || info->flag == 0) + if (func == NULL) continue; if (satisfy_inline_criteria(info->varinfo) && !(info->varinfo->storage & VS_STATIC)) continue; @@ -659,9 +554,8 @@ static void emit_linking_section(EmitWasm *ew) { const Name *name; FuncInfo *info; for (int it = 0; (it = table_iterate(&func_info_table, it, &name, (void**)&info)) != -1; ) { - if (info->flag == 0 || - (k == 0 && info->func != NULL) || // Put external function first. - (k == 1 && info->func == NULL)) // Defined function later. + if ((k == 0 && (info->func != NULL || info->flag == 0)) || // Put external function first. + (k == 1 && info->func == NULL)) // Defined function later. continue; if (satisfy_inline_criteria(info->varinfo) && !(info->varinfo->storage & VS_STATIC)) continue; @@ -816,7 +710,7 @@ static void emit_reloc_code_section(EmitWasm *ew) { FuncInfo *info; for (int it = 0; (it = table_iterate(&func_info_table, it, &name, (void**)&info)) != -1; ) { Function *func = info->func; - if (func == NULL || info->flag == 0) + if (func == NULL) continue; if (satisfy_inline_criteria(info->varinfo) && !(info->varinfo->storage & VS_STATIC)) continue; @@ -855,8 +749,7 @@ 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, Vector *exports, const char *import_module_name, - uint32_t address_bottom) { +void emit_wasm(FILE *ofp, const char *import_module_name, uint32_t address_bottom) { write_wasm_header(ofp); EmitWasm ew_body = { @@ -875,21 +768,12 @@ void emit_wasm(FILE *ofp, Vector *exports, const char *import_module_name, // Functions. emit_function_section(ew); - // Table. - emit_table_section(ew); - - // Memory. - emit_memory_section(ew); - // Tag (must put earlier than Global section.) emit_tag_section(ew); // Globals. emit_global_section(ew); - // Exports. - emit_export_section(ew, exports); - // Elements. emit_elems_section(ew); @@ -901,9 +785,8 @@ void emit_wasm(FILE *ofp, Vector *exports, const char *import_module_name, ew->data_section_index = ew->section_index; Vector *reloc_data = emit_data_section(ew); - if (out_type < OutExecutable) { - emit_linking_section(ew); - emit_reloc_code_section(ew); - emit_reloc_data_section(ew, reloc_data); - } + // Linking. + emit_linking_section(ew); + emit_reloc_code_section(ew); + emit_reloc_data_section(ew, reloc_data); } diff --git a/src/wcc/gen_wasm.c b/src/wcc/gen_wasm.c index 4fc673688..98c193e6f 100644 --- a/src/wcc/gen_wasm.c +++ b/src/wcc/gen_wasm.c @@ -265,20 +265,16 @@ static void gen_funcall_by_name(const Name *funcname) { FuncInfo *info = table_get(&func_info_table, funcname); assert(info != NULL); ADD_CODE(OP_CALL); - if (out_type >= OutExecutable) { - ADD_ULEB128(info->index); - } else { - FuncExtra *extra = curfunc->extra; - DataStorage *code = extra->code; - RelocInfo *ri = calloc_or_die(sizeof(*ri)); - ri->type = R_WASM_FUNCTION_INDEX_LEB; - ri->offset = code->len; - ri->addend = 0; - ri->index = info->index; - vec_push(extra->reloc_code, ri); + FuncExtra *extra = curfunc->extra; + DataStorage *code = extra->code; + RelocInfo *ri = calloc_or_die(sizeof(*ri)); + ri->type = R_WASM_FUNCTION_INDEX_LEB; + ri->offset = code->len; + ri->addend = 0; + ri->index = info->index; + vec_push(extra->reloc_code, ri); - ADD_VARUINT32(info->index); - } + ADD_VARUINT32(info->index); } static void gen_funcall(Expr *expr) { @@ -402,19 +398,15 @@ static void gen_funcall(Expr *expr) { int index = get_func_type_index(functype); assert(index >= 0); ADD_CODE(OP_CALL_INDIRECT); - if (out_type >= OutExecutable) { - ADD_ULEB128(index); // signature index - } else { - FuncExtra *extra = curfunc->extra; - DataStorage *code = extra->code; - RelocInfo *ri = calloc_or_die(sizeof(*ri)); - ri->type = R_WASM_TYPE_INDEX_LEB; - ri->index = index; - ri->offset = code->len; - vec_push(extra->reloc_code, ri); - - ADD_VARUINT32(index); - } + FuncExtra *extra = curfunc->extra; + DataStorage *code = extra->code; + RelocInfo *ri = calloc_or_die(sizeof(*ri)); + ri->type = R_WASM_TYPE_INDEX_LEB; + ri->index = index; + ri->offset = code->len; + vec_push(extra->reloc_code, ri); + + ADD_VARUINT32(index); ADD_ULEB128(0); // table index } @@ -471,39 +463,30 @@ static void gen_ref_sub(Expr *expr) { if (is_global_scope(scope) || !is_local_storage(varinfo)) { if (varinfo->type->kind == TY_FUNC) { ADD_CODE(OP_I32_CONST); - if (out_type >= OutExecutable) { - uint32_t indirect_func = get_indirect_function_index(expr->var.name); - ADD_LEB128(indirect_func); - } else { - FuncInfo *info = table_get(&indirect_function_table, expr->var.name); - assert(info != NULL && info->indirect_index > 0); - FuncExtra *extra = curfunc->extra; - DataStorage *code = extra->code; - RelocInfo *ri = calloc_or_die(sizeof(*ri)); - ri->type = R_WASM_TABLE_INDEX_SLEB; - ri->offset = code->len; - ri->index = info->index; // Assume that symtab index is same as function index. - vec_push(extra->reloc_code, ri); - - ADD_VARUINT32(info->indirect_index); - } + FuncInfo *info = table_get(&indirect_function_table, expr->var.name); + assert(info != NULL && info->indirect_index > 0); + FuncExtra *extra = curfunc->extra; + DataStorage *code = extra->code; + RelocInfo *ri = calloc_or_die(sizeof(*ri)); + ri->type = R_WASM_TABLE_INDEX_SLEB; + ri->offset = code->len; + ri->index = info->index; // Assume that symtab index is same as function index. + vec_push(extra->reloc_code, ri); + + ADD_VARUINT32(info->indirect_index); } else { GVarInfo *info = get_gvar_info(expr); ADD_CODE(OP_I32_CONST); - if (out_type >= OutExecutable) { - ADD_LEB128(info->non_prim.address); - } else { - FuncExtra *extra = curfunc->extra; - DataStorage *code = extra->code; - RelocInfo *ri = calloc_or_die(sizeof(*ri)); - ri->type = R_WASM_MEMORY_ADDR_LEB; - ri->offset = code->len; - ri->addend = 0; - ri->index = info->symbol_index; - vec_push(extra->reloc_code, ri); - - ADD_VARUINT32(info->non_prim.address); - } + FuncExtra *extra = curfunc->extra; + DataStorage *code = extra->code; + RelocInfo *ri = calloc_or_die(sizeof(*ri)); + ri->type = R_WASM_MEMORY_ADDR_LEB; + ri->offset = code->len; + ri->addend = 0; + ri->index = info->symbol_index; + vec_push(extra->reloc_code, ri); + + ADD_VARUINT32(info->non_prim.address); } } else { VReg *vreg = varinfo->local.vreg; @@ -566,20 +549,16 @@ static void gen_var(Expr *expr, bool needval) { } else { GVarInfo *info = get_gvar_info(expr); ADD_CODE(OP_GLOBAL_GET); - if (out_type >= OutExecutable) { - ADD_ULEB128(info->prim.index); - } else { - FuncExtra *extra = curfunc->extra; - DataStorage *code = extra->code; - RelocInfo *ri = calloc_or_die(sizeof(*ri)); - ri->type = R_WASM_GLOBAL_INDEX_LEB; - ri->offset = code->len; - ri->addend = 0; - ri->index = info->symbol_index; - vec_push(extra->reloc_code, ri); - - ADD_VARUINT32(info->prim.index); - } + FuncExtra *extra = curfunc->extra; + DataStorage *code = extra->code; + RelocInfo *ri = calloc_or_die(sizeof(*ri)); + ri->type = R_WASM_GLOBAL_INDEX_LEB; + ri->offset = code->len; + ri->addend = 0; + ri->index = info->symbol_index; + vec_push(extra->reloc_code, ri); + + ADD_VARUINT32(info->prim.index); } } break; @@ -632,20 +611,16 @@ static void gen_set_to_var(Expr *var) { assert(!is_global_datsec_var(varinfo, var->var.scope)); GVarInfo *info = get_gvar_info(var); ADD_CODE(OP_GLOBAL_SET); - if (out_type >= OutExecutable) { - ADD_ULEB128(info->prim.index); - } else { - FuncExtra *extra = curfunc->extra; - DataStorage *code = extra->code; - RelocInfo *ri = calloc_or_die(sizeof(*ri)); - ri->type = R_WASM_GLOBAL_INDEX_LEB; - ri->offset = code->len; - ri->addend = 0; - ri->index = info->symbol_index; - vec_push(extra->reloc_code, ri); - - ADD_VARUINT32(info->prim.index); - } + FuncExtra *extra = curfunc->extra; + DataStorage *code = extra->code; + RelocInfo *ri = calloc_or_die(sizeof(*ri)); + ri->type = R_WASM_GLOBAL_INDEX_LEB; + ri->offset = code->len; + ri->addend = 0; + ri->index = info->symbol_index; + vec_push(extra->reloc_code, ri); + + ADD_VARUINT32(info->prim.index); } } @@ -1804,20 +1779,16 @@ static void gen_builtin_longjmp(Expr *expr, enum BuiltinFunctionPhase phase) { gen_expr(env, true); TagInfo *ti = register_longjmp_tag(); ADD_CODE(OP_THROW); - if (out_type >= OutExecutable) { - ADD_ULEB128(ti->index); - } else { - FuncExtra *extra = curfunc->extra; - DataStorage *code = extra->code; - RelocInfo *ri = calloc_or_die(sizeof(*ri)); - ri->type = R_WASM_TAG_INDEX_LEB; - ri->offset = code->len; - ri->addend = 0; - ri->index = ti->symbol_index; - vec_push(extra->reloc_code, ri); + FuncExtra *extra = curfunc->extra; + DataStorage *code = extra->code; + RelocInfo *ri = calloc_or_die(sizeof(*ri)); + ri->type = R_WASM_TAG_INDEX_LEB; + ri->offset = code->len; + ri->addend = 0; + ri->index = ti->symbol_index; + vec_push(extra->reloc_code, ri); - ADD_VARUINT32(ti->index); - } + ADD_VARUINT32(ti->index); } static void gen_builtin_try_catch_longjmp(Expr *expr, enum BuiltinFunctionPhase phase) { @@ -1838,20 +1809,16 @@ static void gen_builtin_try_catch_longjmp(Expr *expr, enum BuiltinFunctionPhase ADD_CODE(OP_BR, 2); } ADD_CODE(OP_CATCH); { TagInfo *ti = register_longjmp_tag(); - if (out_type >= OutExecutable) { - ADD_ULEB128(ti->index); - } else { - FuncExtra *extra = curfunc->extra; - DataStorage *code = extra->code; - RelocInfo *ri = calloc_or_die(sizeof(*ri)); - ri->type = R_WASM_TAG_INDEX_LEB; - ri->offset = code->len; - ri->addend = 0; - ri->index = ti->symbol_index; - vec_push(extra->reloc_code, ri); - - ADD_VARUINT32(ti->index); - } + FuncExtra *extra = curfunc->extra; + DataStorage *code = extra->code; + RelocInfo *ri = calloc_or_die(sizeof(*ri)); + ri->type = R_WASM_TAG_INDEX_LEB; + ri->offset = code->len; + ri->addend = 0; + ri->index = ti->symbol_index; + vec_push(extra->reloc_code, ri); + + ADD_VARUINT32(ti->index); // Assume env has no side effect. Expr *env = args->data[0]; diff --git a/src/wcc/traverse.c b/src/wcc/traverse.c index 76fc91e9b..873934ac2 100644 --- a/src/wcc/traverse.c +++ b/src/wcc/traverse.c @@ -279,10 +279,10 @@ static void te_var(Expr **pexpr, bool needval) { register_indirect_function(expr->var.name); traverse_func_expr(pexpr); } else { - if (out_type < OutExecutable && is_global_scope(expr->var.scope)) { + if (is_global_scope(expr->var.scope)) { // Register used global variable even if the entity is `extern`. get_gvar_info(expr); - } + } } } @@ -579,7 +579,7 @@ static void traverse_vardecl(Stmt *stmt) { register_func_info(decl->ident, NULL, varinfo, 0); } else if (varinfo->storage & VS_EXTERN) { assert(!is_global_scope(curscope)); - if (out_type < OutExecutable && scope_find(global_scope, decl->ident, NULL) == NULL) { + if (scope_find(global_scope, decl->ident, NULL) == NULL) { // Register into global to output linking information. GVarInfo *info = register_gvar_info(decl->ident, varinfo); info->flag |= GVF_UNRESOLVED; @@ -732,8 +732,6 @@ static void add_builtins(void) { const Name *names[2]; names[0] = alloc_name(SP_NAME, NULL, false); int n = 1; - if (out_type >= OutExecutable) - names[n++] = alloc_name(BREAK_ADDRESS_NAME, NULL, false); for (int i = 0; i < n; ++i) { const Name *name = names[i]; @@ -743,19 +741,11 @@ static void add_builtins(void) { } else { if (!same_type(varinfo->type, &tyVoidPtr)) parse_error(PE_NOFATAL, NULL, "Illegal type: %.*s", NAMES(name)); - if (out_type >= OutExecutable) - varinfo->storage &= ~VS_EXTERN; } GVarInfo *info = get_gvar_info_from_name(name); if (info == NULL) info = register_gvar_info(name, varinfo); - if (out_type < OutExecutable) - info->flag |= GVF_UNRESOLVED; - if (out_type >= OutExecutable && varinfo->global.init == NULL) { - Initializer *init = new_initializer(IK_SINGLE, NULL); - init->single = new_expr_fixlit(varinfo->type, NULL, 0); // Dummy - varinfo->global.init = init; - } + info->flag |= GVF_UNRESOLVED; } } @@ -804,7 +794,7 @@ uint32_t traverse_ast(Vector *decls, Vector *exports, uint32_t stack_size) { const Name *name; FuncInfo *info; for (int it = 0; (it = table_iterate(&func_info_table, it, &name, (void**)&info)) != -1; ) { - if (info->flag == 0) + if (info->flag == 0 && info->func == NULL) continue; if (satisfy_inline_criteria(info->varinfo) && !(info->varinfo->storage & VS_STATIC)) continue; @@ -852,7 +842,8 @@ uint32_t traverse_ast(Vector *decls, Vector *exports, uint32_t stack_size) { int32_t index = 0; for (int k = 0; k < 2; ++k) { // 0: import, 1: defined-and-referred for (int it = 0; (it = table_iterate(&func_info_table, it, &name, (void**)&info)) != -1; ) { - if (info->flag == 0 || (k == 0) == (info->func != NULL)) + if ((k == 0 && (info->func != NULL || info->flag == 0)) || // Put external function first. + (k == 1 && info->func == NULL)) // Defined function later. continue; if (satisfy_inline_criteria(info->varinfo) && !(info->varinfo->storage & VS_STATIC)) continue; @@ -893,24 +884,6 @@ uint32_t traverse_ast(Vector *decls, Vector *exports, uint32_t stack_size) { // Set initial values. sp_bottom = ALIGN(address + stack_size, 16); - if (out_type >= OutExecutable) { - { // Stack pointer. - VarInfo *varinfo = scope_find(global_scope, alloc_name(SP_NAME, NULL, false), NULL); - assert(varinfo != NULL); - Initializer *init = varinfo->global.init; - assert(init != NULL && init->kind == IK_SINGLE && init->single->kind == EX_FIXNUM); - init->single->fixnum = sp_bottom; - VERBOSE("SP bottom: 0x%x (size=0x%x)\n", sp_bottom, stack_size); - } - { // Break address. - VarInfo *varinfo = scope_find(global_scope, alloc_name(BREAK_ADDRESS_NAME, NULL, false), NULL); - assert(varinfo != NULL); - Initializer *init = varinfo->global.init; - assert(init != NULL && init->kind == IK_SINGLE && init->single->kind == EX_FIXNUM); - init->single->fixnum = sp_bottom; - VERBOSE("Break address: 0x%x\n", sp_bottom); - } - } } return sp_bottom; diff --git a/src/wcc/wasm_linker.c b/src/wcc/wasm_linker.c index 3a2867253..e6c27dff1 100644 --- a/src/wcc/wasm_linker.c +++ b/src/wcc/wasm_linker.c @@ -1161,6 +1161,26 @@ static void out_table_section(WasmLinker *linker) { fwrite(table_section.buf, table_section.len, 1, linker->ofp); } +static void out_memory_section(EmitWasm *ew) { + DataStorage memory_section; + data_init(&memory_section); + data_open_chunk(&memory_section); + data_open_chunk(&memory_section); + { + uint32_t page_count = (ew->address_bottom + MEMORY_PAGE_SIZE - 1) / MEMORY_PAGE_SIZE; + if (page_count <= 0) + page_count = 1; + data_uleb128(&memory_section, -1, 0); // limits (no maximum page size) + data_uleb128(&memory_section, -1, page_count); + data_close_chunk(&memory_section, 1); // count + data_close_chunk(&memory_section, -1); + } + + fputc(SEC_MEMORY, ew->ofp); + fwrite(memory_section.buf, memory_section.len, 1, ew->ofp); + ++ew->section_index; +} + static void out_global_section(WasmLinker *linker) { DataStorage globals_section; data_init(&globals_section); @@ -1562,7 +1582,7 @@ bool linker_emit_wasm(WasmLinker *linker, const char *ofn, Vector *exports) { out_table_section(linker); // Memory. - emit_memory_section(ew); + out_memory_section(ew); // Tag (must put earlier than Global section.) emit_tag_section(ew); diff --git a/src/wcc/wcc.c b/src/wcc/wcc.c index 576331e71..b4ed1271d 100644 --- a/src/wcc/wcc.c +++ b/src/wcc/wcc.c @@ -18,6 +18,7 @@ #include "util.h" #include "var.h" #include "wasm.h" +#include "wasm_linker.h" // #define USE_EMCC_AS_LINKER 1 // #define USE_WCCLD_AS_LINKER 1 @@ -129,7 +130,7 @@ int main(int argc, char *argv[]) { Vector *lib_paths = new_vector(); bool export_all = false; bool export_stack_pointer = false; - out_type = OutExecutable; + enum OutType final_out_type = OutExecutable; FILE *ppout = tmpfile(); if (ppout == NULL) @@ -221,7 +222,7 @@ int main(int argc, char *argv[]) { ofn = optarg; break; case 'c': - out_type = OutObject; + final_out_type = OutObject; break; case 'e': if (*optarg != '\0') { @@ -343,21 +344,14 @@ int main(int argc, char *argv[]) { #endif } -#if USE_EMCC_AS_LINKER || USE_WCCLD_AS_LINKER - bool do_emcc_link = false; - if (out_type >= OutExecutable) { - do_emcc_link = true; - out_type = OutObject; - } -#endif - if (out_type >= OutExecutable && entry_point == NULL) { + if (final_out_type >= OutExecutable && entry_point == NULL) { entry_point = "_start"; - if (exports->len == 0) - vec_push(exports, alloc_name("main", NULL, false)); + // if (exports->len == 0) + // vec_push(exports, alloc_name("main", NULL, false)); } if (entry_point != NULL && *entry_point != '\0') vec_push(exports, alloc_name(entry_point, NULL, false)); - if (exports->len == 0 && !(export_all || out_type < OutExecutable)) { + if (exports->len == 0 && !(export_all || final_out_type < OutExecutable)) { error("no exports (require -e)\n"); } @@ -368,29 +362,29 @@ int main(int argc, char *argv[]) { } VERBOSES("\n"); - Vector *libs = new_vector(); - if (out_type >= OutExecutable) { +// Vector *libs = new_vector(); + if (final_out_type >= OutExecutable) { #if defined(__WASM) vec_push(lib_paths, "/usr/lib"); #else - vec_push(lib_paths, JOIN_PATHS(root, "./libsrc/_wasm")); + vec_push(lib_paths, JOIN_PATHS(root, "./lib")); #endif - if (!nostdlib) - add_lib(lib_paths, "crt0.c", libs); - if (!nodefaultlibs && !nostdlib) - add_lib(lib_paths, "libc.c", libs); + // if (!nostdlib) + // add_lib(lib_paths, "crt0.c", libs); + // if (!nodefaultlibs && !nostdlib) + // add_lib(lib_paths, "libc.c", libs); } Vector *toplevel = new_vector(); preprocess_and_compile(ppout, sources, toplevel); - if (export_all || out_type < OutExecutable) + if (export_all || final_out_type < OutExecutable) export_non_static_functions(exports); - preprocess_and_compile(ppout, libs, toplevel); + // preprocess_and_compile(ppout, libs, toplevel); fclose(ppout); - uint32_t address_bottom = traverse_ast(toplevel, exports, stack_size); + uint32_t address_bottom = traverse_ast(toplevel, new_vector(), stack_size); if (compile_error_count != 0) return 1; @@ -400,15 +394,15 @@ int main(int argc, char *argv[]) { } gen(toplevel); - if (out_type >= OutExecutable && unresolved_gvar_table.count > 0) { - const Name *name; - VarInfo *varinfo; - for (int it = 0; - (it = table_iterate(&unresolved_gvar_table, it, &name, (void**)&varinfo)) != -1; ) { - fprintf(stderr, "Global variable not resolved: %.*s\n", NAMES(name)); - } - ++compile_error_count; - } + // if (final_out_type >= OutExecutable && unresolved_gvar_table.count > 0) { + // const Name *name; + // VarInfo *varinfo; + // for (int it = 0; + // (it = table_iterate(&unresolved_gvar_table, it, &name, (void**)&varinfo)) != -1; ) { + // fprintf(stderr, "Global variable not resolved: %.*s\n", NAMES(name)); + // } + // ++compile_error_count; + // } if (compile_error_count != 0) return 1; @@ -416,9 +410,8 @@ int main(int argc, char *argv[]) { return 2; FILE *ofp; -#if USE_EMCC_AS_LINKER || USE_WCCLD_AS_LINKER - char *tmpfn; - if (do_emcc_link) { + char *tmpfn = NULL; + if (final_out_type >= OutExecutable) { char template[] = "/tmp/xcc-XXXXXX.o"; int obj_fd = mkstemps(template, 2); if (obj_fd == -1) { @@ -427,30 +420,28 @@ int main(int argc, char *argv[]) { } tmpfn = strdup(template); ofp = fdopen(obj_fd, "wb"); - } else -#endif - { + } else { const char *outfn = ofn; if (outfn == NULL) { - if (out_type == OutObject) { - char *src = sources->data[0]; // TODO: - outfn = change_ext(basename(src), "o"); - } else { - outfn = "a.wasm"; - } + char *src = sources->data[0]; // TODO: + outfn = src != NULL ? change_ext(basename(src), "o") : "a.o"; } ofp = fopen(outfn, "wb"); } if (ofp == NULL) { error("Cannot open output file"); } else { - emit_wasm(ofp, exports, import_module_name, address_bottom); + emit_wasm(ofp, import_module_name, address_bottom); assert(compile_error_count == 0); fclose(ofp); } + if (final_out_type >= OutExecutable) { #if USE_EMCC_AS_LINKER || USE_WCCLD_AS_LINKER - if (do_emcc_link) { + UNUSED(nodefaultlibs); + UNUSED(nostdlib); + UNUSED(add_lib); + char *finalfn = (char*)ofn; if (finalfn == NULL) { finalfn = "a.wasm"; @@ -477,8 +468,37 @@ int main(int argc, char *argv[]) { execvp(cc, argv); perror(cc); return 1; - } +#else + Vector *obj_files = new_vector(); + vec_push(obj_files, tmpfn); + if (!nostdlib) + add_lib(lib_paths, "wcrt0.a", obj_files); + if (!nodefaultlibs && !nostdlib) + add_lib(lib_paths, "wlibc.a", obj_files); + + const char *outfn = ofn != NULL ? ofn : "a.wasm"; + + functypes = new_vector(); + tags = new_vector(); + table_init(&indirect_function_table); + + WasmLinker linker_body; + WasmLinker *linker = &linker_body; + linker_init(linker); + + for (int i = 0; i < obj_files->len; ++i) { + const char *objfn = obj_files->data[i]; + if (!read_wasm_obj(linker, objfn)) { + fprintf(stderr, "error: failed to read wasm object file: %s\n", objfn); + return 1; + } + } + + if (!link_wasm_objs(linker, exports, stack_size) || + !linker_emit_wasm(linker, outfn, exports)) + return 2; #endif + } return 0; } diff --git a/src/wcc/wcc.h b/src/wcc/wcc.h index 2c06abce3..2b26a96e1 100644 --- a/src/wcc/wcc.h +++ b/src/wcc/wcc.h @@ -115,13 +115,10 @@ typedef struct { uint32_t import_global_count; } EmitWasm; -void emit_wasm(FILE *ofp, Vector *exports, const char *import_module_name, uint32_t address_bottom); +void emit_wasm(FILE *ofp, const char *import_module_name, uint32_t address_bottom); void emit_type_section(EmitWasm *ew); -void emit_table_section(EmitWasm *ew); -void emit_memory_section(EmitWasm *ew); void emit_tag_section(EmitWasm *ew); -void emit_elems_section(EmitWasm *ew); // wcc_util enum OutType { @@ -135,7 +132,6 @@ extern const char SP_NAME[]; extern const char BREAK_ADDRESS_NAME[]; extern bool verbose; -extern enum OutType out_type; extern Table func_info_table; extern Table gvar_info_table; extern Table indirect_function_table; // diff --git a/src/wcc/wcc_util.c b/src/wcc/wcc_util.c index 5462de7dc..a40477b10 100644 --- a/src/wcc/wcc_util.c +++ b/src/wcc/wcc_util.c @@ -15,7 +15,6 @@ const char SP_NAME[] = "__stack_pointer"; // Variable name for stack pointer (g const char BREAK_ADDRESS_NAME[] = "__curbrk"; bool verbose; -enum OutType out_type; Table func_info_table; Table gvar_info_table; Vector *functypes; // From 60ae5070c164e518ac3468851fad0631953f71f4 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Tue, 27 Feb 2024 11:09:28 +0900 Subject: [PATCH 5/6] Use .a files on browser ``` 3036 default.css 3474 index.html 128421 main.js 185195 wasi_worker.js 125219 wccfiles.zip ``` --- .gitignore | 3 - Makefile | 7 +- src/wcc/wcc.c | 2 - src/wcc/www/lib_list.json | 162 +------------------------------------- tool/pack_libs.js | 2 +- tool/run-gen2wcc.sh | 3 +- tool/update_lib_list.ts | 60 -------------- 7 files changed, 6 insertions(+), 233 deletions(-) delete mode 100644 tool/update_lib_list.ts diff --git a/.gitignore b/.gitignore index 6e99d4207..bc16a7393 100644 --- a/.gitignore +++ b/.gitignore @@ -36,9 +36,6 @@ core ### wasm -libsrc/_wasm/crt0.c -libsrc/_wasm/libc.c - *.wasm /wcc /wcc-ld diff --git a/Makefile b/Makefile index 2dcbc774c..c456bfbde 100644 --- a/Makefile +++ b/Makefile @@ -275,7 +275,7 @@ wcc-self-hosting: $(WCC_TARGET)cc.wasm test-wcc-self-hosting: $(MAKE) -C tests clean && $(MAKE) WCC="$(TARGET_CC)" -C tests test-wcc -$(WCC_TARGET)cc.wasm: $(WCC_SRCS) wcc-libs $(WCC_PARENT) +$(WCC_TARGET)cc.wasm: $(WCC_SRCS) wcc $(WCC_PARENT) $(HOST_WCC) -o $@ $(WCC_CFLAGS) \ -I$(CC1_FE_DIR) -I$(CPP_DIR) -I$(UTIL_DIR) \ $(WCC_SRCS) @@ -287,10 +287,7 @@ ASSETS_DIR:=public .PHONY: assets assets: $(ASSETS_DIR)/wccfiles.zip -$(WCC_DIR)/www/lib_list.json: $(LIBSRC_DIR)/_wasm/crt0.c $(LIBSRC_DIR)/_wasm/libc.c - npx ts-node tool/update_lib_list.ts --base=./libsrc $^ - -$(ASSETS_DIR)/wccfiles.zip: $(WCC_DIR)/www/lib_list.json cc.wasm +$(ASSETS_DIR)/wccfiles.zip: $(WCC_DIR)/www/lib_list.json cc.wasm wcc-libs @mkdir -p $(ASSETS_DIR) npx ts-node tool/pack_libs.js $(WCC_DIR)/www/lib_list.json $@ diff --git a/src/wcc/wcc.c b/src/wcc/wcc.c index b4ed1271d..e51fc7497 100644 --- a/src/wcc/wcc.c +++ b/src/wcc/wcc.c @@ -337,10 +337,8 @@ int main(int argc, char *argv[]) { if (!nostdinc) { #if defined(__WASM) add_inc_path(INC_AFTER, "/usr/include"); - add_inc_path(INC_AFTER, "/usr/local/include"); #else add_inc_path(INC_AFTER, JOIN_PATHS(root, "include")); - add_inc_path(INC_AFTER, JOIN_PATHS(root, "libsrc")); #endif } diff --git a/src/wcc/www/lib_list.json b/src/wcc/www/lib_list.json index 18ade83e6..7dd4fe66c 100644 --- a/src/wcc/www/lib_list.json +++ b/src/wcc/www/lib_list.json @@ -32,166 +32,8 @@ "wasi.h": "./libsrc/_wasm/wasi.h" }, "lib": { - "_file.h": "./libsrc/stdio/_file.h", - "_fileman.h": "./libsrc/stdio/_fileman.h", - "_malloc.h": "./libsrc/stdlib/_malloc.h", - "_ieee.h": "./libsrc/math/_ieee.h", - "crt0.c": [ - "./libsrc/_wasm/crt0/_start.c" - ], - "libc.c": [ - "./libsrc/math/_normalize_radian.c", - "./libsrc/math/acos.c", - "./libsrc/math/acosh.c", - "./libsrc/math/asin.c", - "./libsrc/math/asinh.c", - "./libsrc/math/atan.c", - "./libsrc/math/atan2.c", - "./libsrc/math/atanh.c", - "./libsrc/math/ceil.c", - "./libsrc/math/copysign.c", - "./libsrc/math/cos.c", - "./libsrc/math/cosh.c", - "./libsrc/math/exp.c", - "./libsrc/math/fabs.c", - "./libsrc/math/floor.c", - "./libsrc/math/fmod.c", - "./libsrc/math/frexp.c", - "./libsrc/math/isfinite.c", - "./libsrc/math/isinf.c", - "./libsrc/math/isnan.c", - "./libsrc/math/log.c", - "./libsrc/math/log10.c", - "./libsrc/math/modf.c", - "./libsrc/math/pow.c", - "./libsrc/math/round.c", - "./libsrc/math/sin.c", - "./libsrc/math/sinh.c", - "./libsrc/math/sqrt.c", - "./libsrc/math/tan.c", - "./libsrc/math/tanh.c", - "./libsrc/misc/basename.c", - "./libsrc/misc/dirname.c", - "./libsrc/misc/errno.c", - "./libsrc/misc/isalnum.c", - "./libsrc/misc/isalpha.c", - "./libsrc/misc/isdigit.c", - "./libsrc/misc/islower.c", - "./libsrc/misc/isspace.c", - "./libsrc/misc/isupper.c", - "./libsrc/misc/isxdigit.c", - "./libsrc/misc/longjmp.c", - "./libsrc/misc/setjmp.c", - "./libsrc/misc/tolower.c", - "./libsrc/misc/toupper.c", - "./libsrc/stdio/_fclose.c", - "./libsrc/stdio/_fflush.c", - "./libsrc/stdio/_finit.c", - "./libsrc/stdio/_fread.c", - "./libsrc/stdio/_fseek.c", - "./libsrc/stdio/_fwrite.c", - "./libsrc/stdio/assert.c", - "./libsrc/stdio/fclose.c", - "./libsrc/stdio/fdopen.c", - "./libsrc/stdio/feof.c", - "./libsrc/stdio/fflush.c", - "./libsrc/stdio/fgetc.c", - "./libsrc/stdio/fgets.c", - "./libsrc/stdio/fileno.c", - "./libsrc/stdio/fmemopen.c", - "./libsrc/stdio/fopen.c", - "./libsrc/stdio/fprintf.c", - "./libsrc/stdio/fputc.c", - "./libsrc/stdio/fputs.c", - "./libsrc/stdio/fread.c", - "./libsrc/stdio/fseek.c", - "./libsrc/stdio/ftell.c", - "./libsrc/stdio/fwrite.c", - "./libsrc/stdio/getline.c", - "./libsrc/stdio/open_memstream.c", - "./libsrc/stdio/perror.c", - "./libsrc/stdio/printf.c", - "./libsrc/stdio/putchar.c", - "./libsrc/stdio/puts.c", - "./libsrc/stdio/remove.c", - "./libsrc/stdio/snprintf.c", - "./libsrc/stdio/sprintf.c", - "./libsrc/stdio/stdin.c", - "./libsrc/stdio/tmpfile.c", - "./libsrc/stdio/vfprintf.c", - "./libsrc/stdio/vprintf.c", - "./libsrc/stdio/vsnprintf.c", - "./libsrc/stdio/vsprintf.c", - "./libsrc/stdlib/atexit.c", - "./libsrc/stdlib/atof.c", - "./libsrc/stdlib/atoi.c", - "./libsrc/stdlib/atol.c", - "./libsrc/stdlib/atoll.c", - "./libsrc/stdlib/calloc.c", - "./libsrc/stdlib/drand48.c", - "./libsrc/stdlib/erand48.c", - "./libsrc/stdlib/exit.c", - "./libsrc/stdlib/getrandom.c", - "./libsrc/stdlib/lrand48.c", - "./libsrc/stdlib/malloc.c", - "./libsrc/stdlib/mkstemp.c", - "./libsrc/stdlib/mkstemps.c", - "./libsrc/stdlib/nrand48.c", - "./libsrc/stdlib/qsort.c", - "./libsrc/stdlib/rand.c", - "./libsrc/stdlib/realloc.c", - "./libsrc/stdlib/srand.c", - "./libsrc/stdlib/strtod.c", - "./libsrc/stdlib/strtol.c", - "./libsrc/stdlib/strtold.c", - "./libsrc/stdlib/strtoll.c", - "./libsrc/stdlib/strtoul.c", - "./libsrc/stdlib/strtoull.c", - "./libsrc/string/memccpy.c", - "./libsrc/string/memchr.c", - "./libsrc/string/memcmp.c", - "./libsrc/string/memcpy.c", - "./libsrc/string/memmove.c", - "./libsrc/string/memset.c", - "./libsrc/string/stpcpy.c", - "./libsrc/string/stpncpy.c", - "./libsrc/string/strcasecmp.c", - "./libsrc/string/strcat.c", - "./libsrc/string/strchr.c", - "./libsrc/string/strcmp.c", - "./libsrc/string/strcoll.c", - "./libsrc/string/strcpy.c", - "./libsrc/string/strcspn.c", - "./libsrc/string/strdup.c", - "./libsrc/string/strerror.c", - "./libsrc/string/strerror_r.c", - "./libsrc/string/strlen.c", - "./libsrc/string/strncasecmp.c", - "./libsrc/string/strncat.c", - "./libsrc/string/strncmp.c", - "./libsrc/string/strncpy.c", - "./libsrc/string/strndup.c", - "./libsrc/string/strnlen.c", - "./libsrc/string/strpbrk.c", - "./libsrc/string/strrchr.c", - "./libsrc/string/strspn.c", - "./libsrc/string/strstr.c", - "./libsrc/string/strtok.c", - "./libsrc/string/strtok_r.c", - "./libsrc/_wasm/unistd/brk.c", - "./libsrc/_wasm/unistd/clock_gettime.c", - "./libsrc/_wasm/unistd/close.c", - "./libsrc/_wasm/unistd/fstat.c", - "./libsrc/_wasm/unistd/getcwd.c", - "./libsrc/_wasm/unistd/lseek.c", - "./libsrc/_wasm/unistd/lstat.c", - "./libsrc/_wasm/unistd/open.c", - "./libsrc/_wasm/unistd/read.c", - "./libsrc/_wasm/unistd/stat.c", - "./libsrc/_wasm/unistd/time.c", - "./libsrc/_wasm/unistd/unlink.c", - "./libsrc/_wasm/unistd/write.c" - ] + "wcrt0.a": "./lib/wcrt0.a", + "wlibc.a": "./lib/wlibc.a" } } } diff --git a/tool/pack_libs.js b/tool/pack_libs.js index 460416355..5ce933846 100644 --- a/tool/pack_libs.js +++ b/tool/pack_libs.js @@ -5,7 +5,7 @@ const fsPromise = require('fs').promises const {zip} = require('fflate') function isBinFile(fileName) { - return fileName.match(/\.(wasm)$/) != null + return fileName.match(/\.(wasm|a)$/) != null } function replaceRelativeInclude(content) { diff --git a/tool/run-gen2wcc.sh b/tool/run-gen2wcc.sh index e6c8ace02..b9c506ad0 100755 --- a/tool/run-gen2wcc.sh +++ b/tool/run-gen2wcc.sh @@ -14,6 +14,5 @@ fi --dir=. \ --dir=/tmp \ "--mapdir=/usr/include::$PRJROOT/include" \ - "--mapdir=/usr/lib::$PRJROOT/libsrc/_wasm" \ - "--mapdir=/usr/local/include::$PRJROOT/libsrc" \ + "--mapdir=/usr/lib::$PRJROOT/lib" \ "$WCCWASM" -- "$@" diff --git a/tool/update_lib_list.ts b/tool/update_lib_list.ts deleted file mode 100644 index e660c935a..000000000 --- a/tool/update_lib_list.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { assert } from 'console' -import fsPromise from 'node:fs/promises' -import path from 'path' - -const JSON_FN = 'src/wcc/www/lib_list.json' - -async function readIncludeFiles(fn: string): Promise> { - const content = await fsPromise.readFile(fn, 'utf8') - const files = content.split('\n') - .map(line => { - const m = line.match(/^#include\s+<(.+)>$/) - return m ? m[1] : null - }) - .filter(src => src != null) as Array - return files -} - -function updateJsonLibContent(fileList: Record, fn: string, fileEntries: Array): void { - assert(fileList && fileList['usr'] && fileList['usr']['lib']) - fileList['usr']['lib'][fn] = fileEntries -} - -async function updateJson(contentMap: Map>): Promise { - const content = await fsPromise.readFile(JSON_FN, 'utf8') - const json = JSON.parse(content) as object - - contentMap.forEach((fileEntries, fn) => updateJsonLibContent(json, fn, fileEntries)) - - const updated = JSON.stringify(json, null, 2) - await fsPromise.writeFile(JSON_FN, `${updated}\n`) -} - -async function main(): Promise { - let baseDir: string | undefined - - const program = require('commander') - program - .option('--base ', 'Specify base directory', (value: string) => baseDir = value) - .description('Update lib_list.json') - .usage('[options] ') - .parse(process.argv) - - const files = program.args - if (files.length <= 0) { - program.help() - process.exit(1) - } - - const contentMap = new Map>() - for (const fn of files) { - let files = await readIncludeFiles(fn) - if (baseDir != null) { - files = files.map(fn => `${baseDir}/${fn}`) - } - contentMap.set(path.basename(fn), files) - } - updateJson(contentMap) -} - -main() From b3e969d32c34e19fa0aacbf062f42238b9cf7a2b Mon Sep 17 00:00:00 2001 From: tyfkda Date: Wed, 28 Feb 2024 10:17:50 +0900 Subject: [PATCH 6/6] Fix Github Actions to use llvm-ar --- .github/workflows/deploywcc.yml | 2 ++ .github/workflows/test.yml | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploywcc.yml b/.github/workflows/deploywcc.yml index d556de0f4..254088254 100644 --- a/.github/workflows/deploywcc.yml +++ b/.github/workflows/deploywcc.yml @@ -17,6 +17,8 @@ jobs: uses: actions/setup-node@v3 with: node-version: 20.x + - name: Setup llvm-ar + run: sudo apt install llvm-dev - name: Install NPM packages run: npm ci - name: Build release diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5145ec582..798a54dac 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,9 @@ jobs: run: make test-gen2 - name: setup - run: npm ci + run: | + npm ci + sudo apt update && sudo apt install llvm-dev - name: make wcc run: make -j8 wcc - name: test wcc