diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/binary-reader-linker.c | 321 | ||||
-rw-r--r-- | src/binary-reader-linker.h | 33 | ||||
-rw-r--r-- | src/binary-reader-objdump.c | 35 | ||||
-rw-r--r-- | src/binary-reader.c | 22 | ||||
-rw-r--r-- | src/binary-reader.h | 6 | ||||
-rw-r--r-- | src/binary-writer.c | 30 | ||||
-rw-r--r-- | src/common.c | 4 | ||||
-rw-r--r-- | src/common.h | 11 | ||||
-rw-r--r-- | src/tools/wasm-link.c | 920 | ||||
-rw-r--r-- | src/tools/wasmdump.c | 9 | ||||
-rw-r--r-- | src/wasm-link.h | 133 | ||||
-rw-r--r-- | test/binary/bad-export-func.txt | 2 | ||||
-rw-r--r-- | test/link/export.txt | 24 | ||||
-rw-r--r-- | test/link/function_calls.txt | 46 | ||||
-rw-r--r-- | test/link/function_calls_incremental.txt | 63 | ||||
-rw-r--r-- | test/link/globals.txt | 51 | ||||
-rw-r--r-- | test/link/incremental.txt | 84 | ||||
-rw-r--r-- | test/link/interp.txt | 103 | ||||
-rw-r--r-- | test/link/names.txt | 74 | ||||
-rw-r--r-- | test/link/table.txt | 11 | ||||
-rwxr-xr-x | test/run-wasm-link.py | 38 |
22 files changed, 1312 insertions, 710 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 44f9ec48..9a968167 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -254,7 +254,7 @@ if (NOT EMSCRIPTEN) target_link_libraries(wasmdump libwasm) # wasm-link - add_executable(wasm-link src/tools/wasm-link.c) + add_executable(wasm-link src/tools/wasm-link.c src/binary-reader-linker.c) add_dependencies(everything wasm-link) target_link_libraries(wasm-link libwasm) diff --git a/src/binary-reader-linker.c b/src/binary-reader-linker.c new file mode 100644 index 00000000..89e30811 --- /dev/null +++ b/src/binary-reader-linker.c @@ -0,0 +1,321 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "binary-reader-linker.h" + +#include "binary-reader.h" +#include "wasm-link.h" + +#define RELOC_SIZE 5 + +typedef struct Context { + WasmAllocator* allocator; + WasmLinkerInputBinary* binary; + + WasmSection* reloc_section; + + WasmStringSlice import_name; + WasmSection* current_section; +} Context; + +static WasmResult on_reloc_count(uint32_t count, + WasmBinarySection section_code, + WasmStringSlice section_name, + void* user_data) { + Context* ctx = user_data; + WasmLinkerInputBinary* binary = ctx->binary; + if (section_code == WASM_BINARY_SECTION_CUSTOM) { + WASM_FATAL("relocation for custom sections not yet supported\n"); + } + + uint32_t i; + for (i = 0; i < binary->sections.size; i++) { + WasmSection* sec = &binary->sections.data[i]; + if (sec->section_code != section_code) + continue; + ctx->reloc_section = sec; + return WASM_OK; + } + + WASM_FATAL("section not found: %d\n", section_code); + return WASM_ERROR; +} + +static WasmResult on_reloc(WasmRelocType type, + uint32_t offset, + void* user_data) { + Context* ctx = user_data; + + if (offset + RELOC_SIZE > ctx->reloc_section->size) { + WASM_FATAL("invalid relocation offset: %#x\n", offset); + } + + WasmReloc* reloc = + wasm_append_reloc(ctx->allocator, &ctx->reloc_section->relocations); + reloc->type = type; + reloc->offset = offset; + + return WASM_OK; +} + +static WasmResult on_import(uint32_t index, + WasmStringSlice module_name, + WasmStringSlice field_name, + void* user_data) { + Context* ctx = user_data; + if (!wasm_string_slice_eq_cstr(&module_name, WASM_LINK_MODULE_NAME)) { + WASM_FATAL("unsupported import module: " PRIstringslice, + WASM_PRINTF_STRING_SLICE_ARG(module_name)); + } + ctx->import_name = field_name; + return WASM_OK; +} + +static WasmResult on_import_func(uint32_t import_index, + uint32_t global_index, + uint32_t sig_index, + void* user_data) { + Context* ctx = user_data; + WasmFunctionImport* import = wasm_append_function_import( + ctx->allocator, &ctx->binary->function_imports); + import->name = ctx->import_name; + import->sig_index = sig_index; + import->active = WASM_TRUE; + ctx->binary->active_function_imports++; + return WASM_OK; +} + +static WasmResult on_import_global(uint32_t import_index, + uint32_t global_index, + WasmType type, + WasmBool mutable, + void* user_data) { + Context* ctx = user_data; + WasmGlobalImport* import = + wasm_append_global_import(ctx->allocator, &ctx->binary->global_imports); + import->name = ctx->import_name; + import->type = type; + import->mutable = mutable; + ctx->binary->active_global_imports++; + return WASM_OK; +} + +static WasmResult begin_section(WasmBinaryReaderContext* ctx, + WasmBinarySection section_code, + uint32_t size) { + Context* context = ctx->user_data; + WasmLinkerInputBinary* binary = context->binary; + WasmSection* sec = wasm_append_section(context->allocator, &binary->sections); + context->current_section = sec; + sec->section_code = section_code; + sec->size = size; + sec->offset = ctx->offset; + sec->binary = binary; + + if (sec->section_code != WASM_BINARY_SECTION_CUSTOM && + sec->section_code != WASM_BINARY_SECTION_START) { + size_t bytes_read = wasm_read_u32_leb128( + &binary->data[sec->offset], &binary->data[binary->size], &sec->count); + if (bytes_read == 0) + WASM_FATAL("error reading section element count\n"); + sec->payload_offset = sec->offset + bytes_read; + sec->payload_size = sec->size - bytes_read; + } + return WASM_OK; +} + +static WasmResult begin_custom_section(WasmBinaryReaderContext* ctx, + uint32_t size, + WasmStringSlice section_name) { + Context* context = ctx->user_data; + WasmLinkerInputBinary* binary = context->binary; + WasmSection* sec = context->current_section; + sec->data_custom.name = section_name; + + /* Modify section size and offset to not include the name itself. */ + size_t delta = ctx->offset - sec->offset; + sec->offset = sec->offset + delta; + sec->size = sec->size - delta; + sec->payload_offset = sec->offset; + sec->payload_size = sec->size; + + /* Special handling for certain CUSTOM sections */ + if (wasm_string_slice_eq_cstr(§ion_name, "name")) { + size_t bytes_read = wasm_read_u32_leb128( + &binary->data[sec->offset], &binary->data[binary->size], &sec->count); + sec->payload_offset += bytes_read; + sec->payload_size -= bytes_read; + + /* We don't currently support merging name sections unless they contain + * a name for every function. */ + size_t i; + uint32_t total_funcs = binary->function_imports.size; + for (i = 0; i < binary->sections.size; i++) { + if (binary->sections.data[i].section_code == + WASM_BINARY_SECTION_FUNCTION) { + total_funcs += binary->sections.data[i].count; + break; + } + } + if (total_funcs != sec->count) { + WASM_FATAL("name section count (%d) does not match function count (%d)\n", + sec->count, total_funcs); + } + } + + return WASM_OK; +} + +static WasmResult on_table(uint32_t index, + WasmType elem_type, + const WasmLimits* elem_limits, + void* user_data) { + if (elem_limits->has_max && (elem_limits->max != elem_limits->initial)) + WASM_FATAL("Tables with max != initial not supported by wasm-link\n"); + + Context* ctx = user_data; + ctx->binary->table_elem_count = elem_limits->initial; + return WASM_OK; +} + +static WasmResult on_elem_segment_function_index_count( + WasmBinaryReaderContext* ctx, + uint32_t index, + uint32_t count) { + Context* context = ctx->user_data; + WasmSection* sec = context->current_section; + + /* Modify the payload to include only the actual function indexes */ + size_t delta = ctx->offset - sec->payload_offset; + sec->payload_offset += delta; + sec->payload_size -= delta; + return WASM_OK; +} + +static WasmResult on_memory(uint32_t index, + const WasmLimits* page_limits, + void* user_data) { + Context* ctx = user_data; + WasmSection* sec = ctx->current_section; + sec->memory_limits = *page_limits; + ctx->binary->memory_page_count = page_limits->initial; + return WASM_OK; +} + +static WasmResult begin_data_segment(uint32_t index, + uint32_t memory_index, + void* user_data) { + Context* ctx = user_data; + WasmSection* sec = ctx->current_section; + WasmDataSegment* segment = + wasm_append_data_segment(ctx->allocator, &sec->data_segments); + segment->memory_index = memory_index; + return WASM_OK; +} + +static WasmResult on_init_expr_i32_const_expr(uint32_t index, + uint32_t value, + void* user_data) { + Context* ctx = user_data; + WasmSection* sec = ctx->current_section; + if (sec->section_code != WASM_BINARY_SECTION_DATA) + return WASM_OK; + WasmDataSegment* segment = + &sec->data_segments.data[sec->data_segments.size - 1]; + segment->offset = value; + return WASM_OK; +} + +static WasmResult on_data_segment_data(uint32_t index, + const void* src_data, + uint32_t size, + void* user_data) { + Context* ctx = user_data; + WasmSection* sec = ctx->current_section; + WasmDataSegment* segment = + &sec->data_segments.data[sec->data_segments.size - 1]; + segment->data = src_data; + segment->size = size; + return WASM_OK; +} + +static WasmResult on_export(uint32_t index, + WasmExternalKind kind, + uint32_t item_index, + WasmStringSlice name, + void* user_data) { + Context* ctx = user_data; + WasmExport* export = + wasm_append_export(ctx->allocator, &ctx->binary->exports); + export->name = name; + export->kind = kind; + export->index = item_index; + return WASM_OK; +} + +static WasmResult on_function_name(uint32_t index, + WasmStringSlice name, + void* user_data) { + Context* ctx = user_data; + wasm_append_string_slice_value(ctx->allocator, &ctx->binary->debug_names, + &name); + return WASM_OK; +} + +static WasmBinaryReader s_binary_reader = { + .begin_section = begin_section, + .begin_custom_section = begin_custom_section, + + .on_reloc_count = on_reloc_count, + .on_reloc = on_reloc, + + .on_import = on_import, + .on_import_func = on_import_func, + .on_import_global = on_import_global, + + .on_export = on_export, + + .on_table = on_table, + + .on_memory = on_memory, + + .begin_data_segment = begin_data_segment, + .on_init_expr_i32_const_expr = on_init_expr_i32_const_expr, + .on_data_segment_data = on_data_segment_data, + + .on_elem_segment_function_index_count = + on_elem_segment_function_index_count, + + .on_function_name = on_function_name, +}; + +WasmResult wasm_read_binary_linker(struct WasmAllocator* allocator, + WasmLinkerInputBinary* input_info) { + Context context; + WASM_ZERO_MEMORY(context); + context.allocator = allocator; + context.binary = input_info; + + WasmBinaryReader reader; + WASM_ZERO_MEMORY(reader); + reader = s_binary_reader; + reader.user_data = &context; + + WasmReadBinaryOptions read_options = WASM_READ_BINARY_OPTIONS_DEFAULT; + read_options.read_debug_names = WASM_TRUE; + return wasm_read_binary(allocator, input_info->data, input_info->size, + &reader, 1, &read_options); +} diff --git a/src/binary-reader-linker.h b/src/binary-reader-linker.h new file mode 100644 index 00000000..cfdb2276 --- /dev/null +++ b/src/binary-reader-linker.h @@ -0,0 +1,33 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WASM_BINARY_READER_LINKER_H_ +#define WASM_BINARY_READER_LINKER_H_ + +#include "common.h" +#include "stream.h" + +struct WasmAllocator; +struct WasmLinkerInputBinary; + +WASM_EXTERN_C_BEGIN + +WasmResult wasm_read_binary_linker(struct WasmAllocator* allocator, + struct WasmLinkerInputBinary* input_info); + +WASM_EXTERN_C_END + +#endif /* WASM_BINARY_READER_LINKER_H_ */ diff --git a/src/binary-reader-objdump.c b/src/binary-reader-objdump.c index 0c67e39b..cdc8f88d 100644 --- a/src/binary-reader-objdump.c +++ b/src/binary-reader-objdump.c @@ -23,9 +23,14 @@ #include "binary-reader.h" #include "literal.h" +#include "vector.h" + +typedef uint32_t Uint32; +WASM_DEFINE_VECTOR(uint32, Uint32); typedef struct Context { const WasmObjdumpOptions* options; + WasmAllocator* allocator; WasmStream* out_stream; const uint8_t* data; size_t size; @@ -37,11 +42,13 @@ typedef struct Context { WasmBool header_printed; int section_found; + uint32_t section_starts[WASM_NUM_BINARY_SECTIONS]; + WasmBinarySection reloc_section; + WasmStringSlice import_module_name; WasmStringSlice import_field_name; } Context; - static WasmBool should_print_details(Context* ctx) { if (ctx->options->mode != WASM_DUMP_DETAILS) return WASM_FALSE; @@ -97,8 +104,10 @@ static WasmResult do_begin_section(Context* ctx, static WasmResult begin_section(WasmBinaryReaderContext* ctx, WasmBinarySection type, uint32_t size) { - return do_begin_section(ctx->user_data, wasm_get_section_name(type), - ctx->offset, size); + Context* context = ctx->user_data; + context->section_starts[type] = ctx->offset; + return do_begin_section(context, wasm_get_section_name(type), ctx->offset, + size); } static WasmResult begin_custom_section(WasmBinaryReaderContext* ctx, @@ -565,12 +574,24 @@ static WasmResult on_local_name(uint32_t func_index, return WASM_OK; } +WasmResult on_reloc_count(uint32_t count, + WasmBinarySection section_code, + WasmStringSlice section_name, + void* user_data) { + Context* ctx = user_data; + ctx->reloc_section = section_code; + print_details(user_data, " - section: %s\n", + wasm_get_section_name(section_code)); + return WASM_OK; +} + WasmResult on_reloc(WasmRelocType type, - uint32_t section, uint32_t offset, void* user_data) { - print_details(user_data, " - %-20s section=%d offset=%#x\n", - wasm_get_reloc_type_name(type), section, offset); + Context* ctx = user_data; + uint32_t total_offset = ctx->section_starts[ctx->reloc_section] + offset; + print_details(user_data, " - %-18s offset=%#x (%#x)\n", + wasm_get_reloc_type_name(type), total_offset, offset); return WASM_OK; } @@ -665,6 +686,7 @@ static WasmBinaryReader s_binary_reader = { .on_function_name = on_function_name, .on_local_name = on_local_name, + .on_reloc_count = on_reloc_count, .on_reloc = on_reloc, .on_init_expr_i32_const_expr = on_init_expr_i32_const_expr, @@ -683,6 +705,7 @@ WasmResult wasm_read_binary_objdump(struct WasmAllocator* allocator, reader = s_binary_reader; Context context; WASM_ZERO_MEMORY(context); + context.allocator = allocator; context.header_printed = WASM_FALSE; context.print_details = WASM_FALSE; context.section_found = WASM_FALSE; diff --git a/src/binary-reader.c b/src/binary-reader.c index 7af6dd63..e98def74 100644 --- a/src/binary-reader.c +++ b/src/binary-reader.c @@ -625,7 +625,6 @@ LOGGING_UINT32(on_function_names_count) LOGGING_UINT32_UINT32(on_local_names_count, "index", "count") LOGGING_END(names_section) LOGGING_BEGIN(reloc_section) -LOGGING_UINT32(on_reloc_count) LOGGING_END(reloc_section) LOGGING_UINT32_UINT32(on_init_expr_get_global_expr, "index", "global_index") @@ -983,6 +982,18 @@ static WasmResult logging_on_init_expr_i64_const_expr(uint32_t index, FORWARD(on_init_expr_i64_const_expr, index, value); } +static WasmResult logging_on_reloc_count(uint32_t count, + WasmBinarySection section_code, + WasmStringSlice section_name, + void* user_data) { + LoggingContext* ctx = user_data; + LOGF("on_reloc_count(count: %d, section: %s, section_name: " PRIstringslice + ")\n", + count, wasm_get_section_name(section_code), + WASM_PRINTF_STRING_SLICE_ARG(section_name)); + FORWARD(on_reloc_count, count, section_code, section_name); +} + static WasmBinaryReader s_logging_binary_reader = { .user_data = NULL, .on_error = logging_on_error, @@ -1694,12 +1705,15 @@ static void read_custom_section(Context* ctx, uint32_t section_size) { uint32_t i, num_relocs, section; in_u32_leb128(ctx, §ion, "section"); in_u32_leb128(ctx, &num_relocs, "relocation count count"); - CALLBACK(on_reloc_count, num_relocs); + WASM_ZERO_MEMORY(section_name); + if (section == WASM_BINARY_SECTION_CUSTOM) + in_str(ctx, §ion_name, "section name"); + CALLBACK(on_reloc_count, num_relocs, section, section_name); for (i = 0; i < num_relocs; ++i) { uint32_t reloc_type, offset; in_u32_leb128(ctx, &reloc_type, "relocation type"); in_u32_leb128(ctx, &offset, "offset"); - CALLBACK(on_reloc, reloc_type, section, offset); + CALLBACK(on_reloc, reloc_type, offset); } CALLBACK0(end_reloc_section); } else { @@ -1897,7 +1911,7 @@ static void read_export_section(Context* ctx, uint32_t section_size) { switch (external_kind) { case WASM_EXTERNAL_KIND_FUNC: RAISE_ERROR_UNLESS(item_index < num_total_funcs(ctx), - "invalid export func index"); + "invalid export func index: %d", item_index); break; case WASM_EXTERNAL_KIND_TABLE: RAISE_ERROR_UNLESS(item_index < num_total_tables(ctx), diff --git a/src/binary-reader.h b/src/binary-reader.h index 1b93013d..6224f7f1 100644 --- a/src/binary-reader.h +++ b/src/binary-reader.h @@ -294,9 +294,11 @@ typedef struct WasmBinaryReader { /* names section */ WasmResult (*begin_reloc_section)(WasmBinaryReaderContext* ctx, uint32_t size); - WasmResult (*on_reloc_count)(uint32_t count, void* user_data); + WasmResult (*on_reloc_count)(uint32_t count, + WasmBinarySection section_code, + WasmStringSlice section_name, + void* user_data); WasmResult (*on_reloc)(WasmRelocType type, - uint32_t section_index, uint32_t offset, void* user_data); WasmResult (*end_reloc_section)(WasmBinaryReaderContext* ctx); diff --git a/src/binary-writer.c b/src/binary-writer.c index a1ce8658..675d0440 100644 --- a/src/binary-writer.c +++ b/src/binary-writer.c @@ -48,7 +48,7 @@ WASM_DEFINE_VECTOR(reloc, Reloc); typedef struct RelocSection { const char* name; - uint32_t section_index; + WasmBinarySection section_code; RelocVector relocations; } RelocSection; WASM_DEFINE_VECTOR(reloc_section, RelocSection); @@ -64,7 +64,6 @@ typedef struct Context { size_t last_section_offset; size_t last_section_leb_size_guess; - size_t last_section_index; WasmBinarySection last_section_type; size_t last_section_payload_offset; } Context; @@ -280,7 +279,6 @@ static void begin_known_section(Context* ctx, wasm_get_section_name(section_code), section_code); write_header(ctx, desc, PRINT_HEADER_NO_INDEX); wasm_write_u8(&ctx->stream, section_code, "section code"); - ctx->last_section_index++; ctx->last_section_type = section_code; ctx->last_section_leb_size_guess = leb_size_guess; ctx->last_section_offset = @@ -297,7 +295,6 @@ static void begin_custom_section(Context* ctx, write_header(ctx, desc, PRINT_HEADER_NO_INDEX); wasm_write_u8(&ctx->stream, WASM_BINARY_SECTION_CUSTOM, "custom section code"); - ctx->last_section_index++; ctx->last_section_type = WASM_BINARY_SECTION_CUSTOM; ctx->last_section_leb_size_guess = leb_size_guess; ctx->last_section_offset = @@ -328,12 +325,12 @@ static void write_expr_list(Context* ctx, static void add_reloc(Context* ctx, WasmRelocType reloc_type) { // Add a new reloc section if needed if (!ctx->current_reloc_section || - ctx->current_reloc_section->section_index != ctx->last_section_index) { + ctx->current_reloc_section->section_code != ctx->last_section_type) { ctx->current_reloc_section = wasm_append_reloc_section(ctx->allocator, &ctx->reloc_sections); ctx->current_reloc_section->name = wasm_get_section_name(ctx->last_section_type); - ctx->current_reloc_section->section_index = ctx->last_section_index; + ctx->current_reloc_section->section_code = ctx->last_section_type; } // Add a new relocation to the curent reloc section @@ -400,7 +397,7 @@ static void write_expr(Context* ctx, (index >= 0 && (size_t)index < module->funcs.size)); wasm_write_opcode(&ctx->stream, WASM_OPCODE_CALL); write_u32_leb128_with_reloc(ctx, index, "function index", - WASM_RELOC_FUNC_INDEX); + WASM_RELOC_FUNC_INDEX_LEB); break; } case WASM_EXPR_TYPE_CALL_INDIRECT: { @@ -455,7 +452,7 @@ static void write_expr(Context* ctx, int index = wasm_get_global_index_by_var(module, &expr->get_global.var); wasm_write_opcode(&ctx->stream, WASM_OPCODE_GET_GLOBAL); write_u32_leb128_with_reloc(ctx, index, "global index", - WASM_RELOC_GLOBAL_INDEX); + WASM_RELOC_GLOBAL_INDEX_LEB); break; } case WASM_EXPR_TYPE_GET_LOCAL: { @@ -506,7 +503,7 @@ static void write_expr(Context* ctx, int index = wasm_get_global_index_by_var(module, &expr->get_global.var); wasm_write_opcode(&ctx->stream, WASM_OPCODE_SET_GLOBAL); write_u32_leb128_with_reloc(ctx, index, "global index", - WASM_RELOC_GLOBAL_INDEX); + WASM_RELOC_GLOBAL_INDEX_LEB); break; } case WASM_EXPR_TYPE_SET_LOCAL: { @@ -636,8 +633,8 @@ static void write_reloc_section(Context* ctx, RelocSection* reloc_section) { sprintf(section_name, "%s.%s", WASM_BINARY_SECTION_RELOC, reloc_section->name); begin_custom_section(ctx, section_name, LEB_SECTION_SIZE_GUESS); - wasm_write_u32_leb128(&ctx->stream, reloc_section->section_index, - "reloc section"); + wasm_write_u32_leb128(&ctx->stream, reloc_section->section_code, + "reloc section type"); RelocVector* relocs = &reloc_section->relocations; wasm_write_u32_leb128(&ctx->stream, relocs->size, "num relocs"); @@ -695,9 +692,9 @@ static WasmResult write_module(Context* ctx, const WasmModule* module) { wasm_write_u8(&ctx->stream, import->kind, "import kind"); switch (import->kind) { case WASM_EXTERNAL_KIND_FUNC: - write_u32_leb128_with_reloc( - ctx, wasm_get_func_type_index_by_decl(module, &import->func.decl), - "import signature index", WASM_RELOC_TYPE_INDEX); + wasm_write_u32_leb128(&ctx->stream, wasm_get_func_type_index_by_decl( + module, &import->func.decl), + "import signature index"); break; case WASM_EXTERNAL_KIND_TABLE: write_table(ctx, &import->table); @@ -795,8 +792,7 @@ static WasmResult write_module(Context* ctx, const WasmModule* module) { int index = wasm_get_func_index_by_var(module, &export->var); assert(ctx->options->is_invalid || (index >= 0 && (size_t)index < module->funcs.size)); - write_u32_leb128_with_reloc(ctx, index, "export func index", - WASM_RELOC_FUNC_INDEX); + wasm_write_u32_leb128(&ctx->stream, index, "export func index"); break; } case WASM_EXTERNAL_KIND_TABLE: { @@ -857,7 +853,7 @@ static WasmResult write_module(Context* ctx, const WasmModule* module) { assert(ctx->options->is_invalid || (index >= 0 && (size_t)index < module->funcs.size)); write_u32_leb128_with_reloc(ctx, index, "function index", - WASM_RELOC_FUNC_INDEX); + WASM_RELOC_FUNC_INDEX_LEB); } } end_section(ctx); diff --git a/src/common.c b/src/common.c index df93af39..07599eeb 100644 --- a/src/common.c +++ b/src/common.c @@ -39,8 +39,8 @@ WASM_STATIC_ASSERT(WASM_ARRAY_SIZE(g_wasm_kind_name) == WASM_NUM_EXTERNAL_KINDS); const char* g_wasm_reloc_type_name[] = { - "RELOC_FUNC_INDEX", "RELOC_FUNC_INDEX_SLEB", "RELOC_TABLE_INDEX", - "RELOC_GLOBAL_INDEX", "RELOC_GLOBAL_TYPE_INDEX", "RELOC_DATA"}; + "R_FUNC_INDEX_LEB", "R_TABLE_INDEX_SLEB", "R_TABLE_INDEX_I32", + "R_GLOBAL_INDEX_LEB", "R_DATA"}; WASM_STATIC_ASSERT(WASM_ARRAY_SIZE(g_wasm_reloc_type_name) == WASM_NUM_RELOC_TYPES); diff --git a/src/common.h b/src/common.h index 27e3aef8..231d1dc9 100644 --- a/src/common.h +++ b/src/common.h @@ -154,12 +154,11 @@ typedef enum WasmType { } WasmType; typedef enum WasmRelocType { - WASM_RELOC_FUNC_INDEX = 0, - WASM_RELOC_FUNC_INDEX_SLEB = 1, - WASM_RELOC_TABLE_INDEX = 2, - WASM_RELOC_GLOBAL_INDEX = 3, - WASM_RELOC_TYPE_INDEX = 4, - WASM_RELOC_DATA = 5, + WASM_RELOC_FUNC_INDEX_LEB = 0, /* e.g. immediate of call instruction */ + WASM_RELOC_TABLE_INDEX_SLEB = 1, /* e.g. loading address of function */ + WASM_RELOC_TABLE_INDEX_I32 = 2, /* e.g. function address in DATA */ + WASM_RELOC_GLOBAL_INDEX_LEB = 3, /* e.g immediate of get_global inst */ + WASM_RELOC_DATA = 4, WASM_NUM_RELOC_TYPES, } WasmRelocType; diff --git a/src/tools/wasm-link.c b/src/tools/wasm-link.c index c152d24d..1fdc079f 100644 --- a/src/tools/wasm-link.c +++ b/src/tools/wasm-link.c @@ -14,21 +14,24 @@ * limitations under the License. */ +#include "wasm-link.h" + #include "allocator.h" #include "binary-reader.h" +#include "binding-hash.h" #include "binary-writer.h" #include "option-parser.h" #include "stream.h" #include "vector.h" #include "writer.h" +#include "binary-reader-linker.h" #define PROGRAM_NAME "wasm-link" #define NOPE WASM_OPTION_NO_ARGUMENT #define YEP WASM_OPTION_HAS_ARGUMENT -#define RELOC_SIZE 5 #define FIRST_KNOWN_SECTION WASM_BINARY_SECTION_TYPE -enum { FLAG_VERBOSE, FLAG_OUTPUT, FLAG_HELP, NUM_FLAGS }; +enum { FLAG_VERBOSE, FLAG_OUTPUT, FLAG_RELOCATABLE, FLAG_HELP, NUM_FLAGS }; static const char s_description[] = " link one or more wasm binary modules into a single binary module." @@ -39,6 +42,8 @@ static WasmOption s_options[] = { {FLAG_VERBOSE, 'v', "verbose", NULL, NOPE, "use multiple times for more info"}, {FLAG_OUTPUT, 'o', "output", "FILE", YEP, "output wasm binary file"}, + {FLAG_RELOCATABLE, 'r', "relocatable", NULL, NOPE, + "output a relocatable object file"}, {FLAG_HELP, 'h', "help", NULL, NOPE, "print this help message"}, }; WASM_STATIC_ASSERT(NUM_FLAGS == WASM_ARRAY_SIZE(s_options)); @@ -47,12 +52,19 @@ typedef const char* String; WASM_DEFINE_VECTOR(string, String); static WasmBool s_verbose; +static WasmBool s_relocatable; static const char* s_outfile = "a.wasm"; static StringVector s_infiles; -static WasmAllocator* s_allocator; static WasmFileWriter s_log_stream_writer; static WasmStream s_log_stream; +typedef struct Context { + WasmStream stream; + WasmLinkerInputBinaryVector inputs; + ssize_t current_section_payload_offset; + WasmAllocator* allocator; +} Context; + static void on_option(struct WasmOptionParser* parser, struct WasmOption* option, const char* argument) { @@ -67,6 +79,10 @@ static void on_option(struct WasmOptionParser* parser, s_outfile = argument; break; + case FLAG_RELOCATABLE: + s_relocatable = WASM_TRUE; + break; + case FLAG_HELP: wasm_print_help(parser, PROGRAM_NAME); exit(0); @@ -75,7 +91,8 @@ static void on_option(struct WasmOptionParser* parser, } static void on_argument(struct WasmOptionParser* parser, const char* argument) { - wasm_append_string_value(s_allocator, &s_infiles, &argument); + WasmAllocator* allocator = parser->user_data; + wasm_append_string_value(allocator, &s_infiles, &argument); } static void on_option_error(struct WasmOptionParser* parser, @@ -83,7 +100,7 @@ static void on_option_error(struct WasmOptionParser* parser, WASM_FATAL("%s\n", message); } -static void parse_options(int argc, char** argv) { +static void parse_options(WasmAllocator* allocator, int argc, char** argv) { WasmOptionParser parser; WASM_ZERO_MEMORY(parser); parser.description = s_description; @@ -92,6 +109,7 @@ static void parse_options(int argc, char** argv) { parser.on_option = on_option; parser.on_argument = on_argument; parser.on_error = on_option_error; + parser.user_data = allocator; wasm_parse_options(&parser, argc, argv); if (!s_infiles.size) { @@ -100,90 +118,7 @@ static void parse_options(int argc, char** argv) { } } -typedef struct DataSegment { - uint32_t memory_index; - uint32_t offset; - const uint8_t* data; - size_t size; -} DataSegment; -WASM_DEFINE_VECTOR(data_segment, DataSegment); - -typedef struct Reloc { - WasmRelocType type; - size_t offset; -} Reloc; -WASM_DEFINE_VECTOR(reloc, Reloc); - -struct InputBinary; - -typedef struct SectionDataCustom { - WasmBool linked; - /* Reference to string data stored in the containing InputBinary */ - WasmStringSlice name; -} SectionDataCustom; - -typedef struct Section { - struct InputBinary* binary; /* The binary to which this section belongs */ - RelocVector relocations; /* The relocations for this section */ - - WasmBinarySection section_code; - size_t size; - size_t offset; - - size_t payload_size; - size_t payload_offset; - - /* For known sections, the count of the number of elements in the section */ - uint32_t count; - - union { - /* CUSTOM section data */ - SectionDataCustom data_custom; - /* DATA section data */ - DataSegmentVector data_segments; - /* MEMORY section data */ - WasmLimits memory_limits; - }; - - /* The offset at which this section appears within the combined output - * section. */ - size_t output_payload_offset; -} Section; -WASM_DEFINE_VECTOR(section, Section); - -typedef Section* SectionPtr; -WASM_DEFINE_VECTOR(section_ptr, SectionPtr); - -typedef struct InputBinary { - uint8_t* data; - size_t size; - SectionVector sections; - Section* current_section; - - uint32_t type_index_offset; - uint32_t function_index_offset; - uint32_t imported_function_index_offset; - uint32_t global_index_offset; - uint32_t imported_global_index_offset; - uint32_t indirect_function_index_offset; - uint32_t memory_page_count; - uint32_t memory_page_offset; - - uint32_t num_func_imports; - uint32_t num_global_imports; - uint32_t table_elem_count; -} InputBinary; -WASM_DEFINE_VECTOR(binary, InputBinary); - -typedef struct Context { - WasmStream stream; - InputBinaryVector inputs; - uint32_t total_function_imports; - uint32_t total_global_imports; - ssize_t current_section_payload_offset; -} Context; - -void wasm_destroy_section(WasmAllocator* allocator, Section* section) { +void wasm_destroy_section(WasmAllocator* allocator, WasmSection* section) { wasm_destroy_reloc_vector(allocator, §ion->relocations); switch (section->section_code) { case WASM_BINARY_SECTION_DATA: @@ -194,271 +129,96 @@ void wasm_destroy_section(WasmAllocator* allocator, Section* section) { } } -void wasm_destroy_binary(WasmAllocator* allocator, InputBinary* binary) { +void wasm_destroy_binary(WasmAllocator* allocator, + WasmLinkerInputBinary* binary) { WASM_DESTROY_VECTOR_AND_ELEMENTS(allocator, binary->sections, section); + wasm_destroy_function_import_vector(allocator, &binary->function_imports); + wasm_destroy_global_import_vector(allocator, &binary->global_imports); + wasm_destroy_string_slice_vector(allocator, &binary->debug_names); + wasm_destroy_export_vector(allocator, &binary->exports); wasm_free(allocator, binary->data); } -static WasmResult on_reloc(WasmRelocType type, - uint32_t section_index, - uint32_t offset, - void* user_data) { - InputBinary* binary = user_data; - if (section_index >= binary->sections.size) { - WASM_FATAL("invalid section index: %d\n", section_index); - } - Section* sec = &binary->sections.data[section_index - 1]; - if (offset + RELOC_SIZE > sec->size) { - WASM_FATAL("invalid relocation offset: %#x\n", offset); - } - - Reloc* reloc = wasm_append_reloc(s_allocator, &sec->relocations); - reloc->type = type; - reloc->offset = offset; - - return WASM_OK; -} - -static WasmResult on_import_func(uint32_t import_index, - uint32_t func_index, - uint32_t sig_index, - void* user_data) { - InputBinary* binary = user_data; - binary->num_func_imports++; - return WASM_OK; -} - -static WasmResult on_import_global(uint32_t import_index, - uint32_t global_index, - WasmType type, - WasmBool mutable, - void* user_data) { - InputBinary* binary = user_data; - binary->num_global_imports++; - return WASM_OK; -} - -static WasmResult begin_section(WasmBinaryReaderContext* ctx, - WasmBinarySection section_code, - uint32_t size) { - InputBinary* binary = ctx->user_data; - Section* sec = wasm_append_section(s_allocator, &binary->sections); - binary->current_section = sec; - sec->section_code = section_code; - sec->size = size; - sec->offset = ctx->offset; - sec->binary = binary; - - if (sec->section_code != WASM_BINARY_SECTION_CUSTOM && - sec->section_code != WASM_BINARY_SECTION_START) { - size_t bytes_read = wasm_read_u32_leb128( - &binary->data[sec->offset], &binary->data[binary->size], &sec->count); - if (bytes_read == 0) - WASM_FATAL("error reading section element count\n"); - sec->payload_offset = sec->offset + bytes_read; - sec->payload_size = sec->size - bytes_read; - } - return WASM_OK; -} - -static WasmResult begin_custom_section(WasmBinaryReaderContext* ctx, - uint32_t size, - WasmStringSlice section_name) { - InputBinary* binary = ctx->user_data; - Section* sec = binary->current_section; - sec->data_custom.name = section_name; - - /* Modify section size and offset to not include the name itself. */ - size_t delta = ctx->offset - sec->offset; - sec->offset = sec->offset + delta; - sec->size = sec->size - delta; - sec->payload_offset = sec->offset; - sec->payload_size = sec->size; - - /* Special handling for certain CUSTOM sections */ - if (wasm_string_slice_eq_cstr(§ion_name, "name")) { - size_t bytes_read = wasm_read_u32_leb128( - &binary->data[sec->offset], &binary->data[binary->size], &sec->count); - sec->payload_offset += bytes_read; - sec->payload_size -= bytes_read; - - /* We don't currently support merging name sections unless they contain - * a name for every function. */ - size_t i; - for (i = 0; i < binary->sections.size; i++) { - if (binary->sections.data[i].section_code == - WASM_BINARY_SECTION_FUNCTION) { - if (binary->sections.data[i].count != sec->count) { - WASM_FATAL( - "name section count (%d) does not match function count (%d)\n", - sec->count, binary->sections.data[i].count); - } - } +static uint32_t relocate_func_index(WasmLinkerInputBinary* binary, + uint32_t function_index) { + uint32_t offset; + if (function_index >= binary->function_imports.size) { + /* locally declared function call */ + offset = binary->function_index_offset; + if (s_verbose) + wasm_writef(&s_log_stream, "func reloc %d + %d\n", function_index, + offset); + } else { + /* imported function call */ + WasmFunctionImport* import = &binary->function_imports.data[function_index]; + offset = binary->imported_function_index_offset; + if (!import->active) { + function_index = import->foreign_index; + offset = import->foreign_binary->function_index_offset; + if (s_verbose) + wasm_writef(&s_log_stream, + "reloc for disabled import. new index = %d + %d\n", + function_index, offset); } } - - return WASM_OK; -} - -static WasmResult on_table(uint32_t index, - WasmType elem_type, - const WasmLimits* elem_limits, - void* user_data) { - if (elem_limits->has_max && (elem_limits->max != elem_limits->initial)) - WASM_FATAL("Tables with max != initial not supported by wasm-link\n"); - - InputBinary* binary = user_data; - binary->table_elem_count = elem_limits->initial; - return WASM_OK; -} - -static WasmResult on_elem_segment_function_index_count( - WasmBinaryReaderContext* ctx, - uint32_t index, - uint32_t count) { - InputBinary* binary = ctx->user_data; - Section* sec = binary->current_section; - - /* Modify the payload to include only the actual function indexes */ - size_t delta = ctx->offset - sec->payload_offset; - sec->payload_offset += delta; - sec->payload_size -= delta; - return WASM_OK; + return function_index + offset; } -static WasmResult on_memory(uint32_t index, - const WasmLimits* page_limits, - void* user_data) { - InputBinary* binary = user_data; - Section* sec = binary->current_section; - sec->memory_limits = *page_limits; - binary->memory_page_count = page_limits->initial; - return WASM_OK; -} - -static WasmResult begin_data_segment(uint32_t index, - uint32_t memory_index, - void* user_data) { - InputBinary* binary = user_data; - Section* sec = binary->current_section; - DataSegment* segment = - wasm_append_data_segment(s_allocator, &sec->data_segments); - segment->memory_index = memory_index; - return WASM_OK; -} - -static WasmResult on_init_expr_i32_const_expr(uint32_t index, - uint32_t value, - void* user_data) { - InputBinary* binary = user_data; - Section* sec = binary->current_section; - if (sec->section_code != WASM_BINARY_SECTION_DATA) - return WASM_OK; - DataSegment* segment = &sec->data_segments.data[sec->data_segments.size - 1]; - segment->offset = value; - return WASM_OK; -} - -static WasmResult on_data_segment_data(uint32_t index, - const void* src_data, - uint32_t size, - void* user_data) { - InputBinary* binary = user_data; - Section* sec = binary->current_section; - DataSegment* segment = &sec->data_segments.data[sec->data_segments.size - 1]; - segment->data = src_data; - segment->size = size; - return WASM_OK; -} - -static WasmResult read_binary(uint8_t* data, - size_t size, - InputBinary* input_info) { - input_info->data = data; - input_info->size = size; - - WasmBinaryReader reader; - WASM_ZERO_MEMORY(reader); - - static WasmBinaryReader s_binary_reader = { - .begin_section = begin_section, - .begin_custom_section = begin_custom_section, - - .on_reloc = on_reloc, - - .on_import_func = on_import_func, - .on_import_global = on_import_global, - - .on_table = on_table, - - .on_memory = on_memory, - - .begin_data_segment = begin_data_segment, - .on_init_expr_i32_const_expr = on_init_expr_i32_const_expr, - .on_data_segment_data = on_data_segment_data, - - .on_elem_segment_function_index_count = - on_elem_segment_function_index_count, - }; - - reader = s_binary_reader; - reader.user_data = input_info; - - WasmReadBinaryOptions read_options = WASM_READ_BINARY_OPTIONS_DEFAULT; - return wasm_read_binary(s_allocator, data, size, &reader, 1, &read_options); -} - -static void apply_relocation(Section* section, Reloc* r) { - InputBinary* binary = section->binary; +static void apply_relocation(WasmSection* section, WasmReloc* r) { + WasmLinkerInputBinary* binary = section->binary; uint8_t* section_data = &binary->data[section->offset]; size_t section_size = section->size; - uint32_t cur_value = 0; + uint32_t cur_value = 0, new_value = 0; wasm_read_u32_leb128(section_data + r->offset, section_data + section_size, &cur_value); uint32_t offset = 0; switch (r->type) { - case WASM_RELOC_FUNC_INDEX: - if (cur_value >= binary->num_func_imports) { - offset = binary->function_index_offset; - } else { - offset = binary->imported_function_index_offset; - } + case WASM_RELOC_FUNC_INDEX_LEB: + new_value = relocate_func_index(binary, cur_value); break; - case WASM_RELOC_GLOBAL_INDEX: - if (cur_value >= binary->num_global_imports) { + case WASM_RELOC_TABLE_INDEX_SLEB: + printf("%s: table index reloc: %d offset=%d\n", binary->filename, + cur_value, binary->table_index_offset); + offset = binary->table_index_offset; + new_value = cur_value + offset; + break; + case WASM_RELOC_GLOBAL_INDEX_LEB: + if (cur_value >= binary->global_imports.size) { offset = binary->global_index_offset; } else { offset = binary->imported_global_index_offset; } - break; - case WASM_RELOC_TYPE_INDEX: - offset = binary->type_index_offset; + new_value = cur_value + offset; break; default: - WASM_FATAL("unhandled relocation type: %d\n", r->type); + WASM_FATAL("unhandled relocation type: %s\n", + wasm_get_reloc_type_name(r->type)); break; } - cur_value += offset; wasm_write_fixed_u32_leb128_raw(section_data + r->offset, - section_data + section_size, cur_value); + section_data + section_size, new_value); } -static void apply_relocations(Section* section) { +static void apply_relocations(WasmSection* section) { if (!section->relocations.size) return; + if (s_verbose) + wasm_writef(&s_log_stream, "apply_relocations: %s\n", + wasm_get_section_name(section->section_code)); + /* Perform relocations in-place */ size_t i; for (i = 0; i < section->relocations.size; i++) { - Reloc* reloc = §ion->relocations.data[i]; + WasmReloc* reloc = §ion->relocations.data[i]; apply_relocation(section, reloc); } } -static void write_section_payload(Context* ctx, Section* sec) { +static void write_section_payload(Context* ctx, WasmSection* sec) { assert(ctx->current_section_payload_offset != -1); sec->output_payload_offset = @@ -468,64 +228,28 @@ static void write_section_payload(Context* ctx, Section* sec) { wasm_write_data(&ctx->stream, payload, sec->payload_size, "section content"); } -#define WRITE_UNKNOWN_SIZE \ - uint32_t fixup_offset = stream->offset; \ - wasm_write_fixed_u32_leb128(stream, 0, "unknown size"); \ - ctx->current_section_payload_offset = ctx->stream.offset; \ - uint32_t start = stream->offset; - -#define FIXUP_SIZE \ - wasm_write_fixed_u32_leb128_at(stream, fixup_offset, stream->offset - start, \ - "fixup size"); - -static void write_combined_custom_section(Context* ctx, - const SectionPtrVector* sections, - const WasmStringSlice* name) { - /* Write this section, along with all the following sections with the - * same name. */ - size_t i; - size_t total_size = 0; - size_t total_count = 0; - - /* Reloc sections are handled seperatedly. */ - if (wasm_string_slice_startswith(name, "reloc")) - return; +static void write_c_str(WasmStream* stream, const char* str, const char* desc) { + wasm_write_str(stream, str, strlen(str), WASM_PRINT_CHARS, desc); +} - if (!wasm_string_slice_eq_cstr(name, "name")) { - WASM_FATAL("Don't know how to link custom section: " PRIstringslice "\n", - WASM_PRINTF_STRING_SLICE_ARG(*name)); - } +static void write_slice(WasmStream* stream, + WasmStringSlice str, + const char* desc) { + wasm_write_str(stream, str.start, str.length, WASM_PRINT_CHARS, desc); +} - /* First pass to calculate total size and count */ - for (i = 0; i < sections->size; i++) { - Section* sec = sections->data[i]; - if (!wasm_string_slices_are_equal(name, &sec->data_custom.name)) - continue; - total_size += sec->payload_size; - total_count += sec->count; - } +#define WRITE_UNKNOWN_SIZE(STREAM) \ + uint32_t fixup_offset = (STREAM)->offset; \ + wasm_write_fixed_u32_leb128(STREAM, 0, "unknown size"); \ + ctx->current_section_payload_offset = (STREAM)->offset; \ + uint32_t start = (STREAM)->offset; - WasmStream* stream = &ctx->stream; - wasm_write_u8(stream, WASM_BINARY_SECTION_CUSTOM, "section code"); - WRITE_UNKNOWN_SIZE; - wasm_write_str(stream, name->start, name->length, WASM_PRINT_CHARS, - "custom section name"); - wasm_write_u32_leb128(stream, total_count, "element count"); +#define FIXUP_SIZE(STREAM) \ + wasm_write_fixed_u32_leb128_at(STREAM, fixup_offset, \ + (STREAM)->offset - start, "fixup size"); - for (i = 0; i < sections->size; i++) { - Section* sec = sections->data[i]; - if (!wasm_string_slices_are_equal(name, &sec->data_custom.name)) - continue; - apply_relocations(sec); - write_section_payload(ctx, sec); - sec->data_custom.linked = WASM_TRUE; - } - - FIXUP_SIZE; -} - -static void write_combined_table_section(Context* ctx, - const SectionPtrVector* sections) { +static void write_table_section(Context* ctx, + const WasmSectionPtrVector* sections) { /* Total section size includes the element count leb128 which is * always 1 in the current spec */ uint32_t table_count = 1; @@ -534,29 +258,69 @@ static void write_combined_table_section(Context* ctx, size_t i; for (i = 0; i < sections->size; i++) { - Section* sec = sections->data[i]; + WasmSection* sec = sections->data[i]; elem_count += sec->binary->table_elem_count; } WasmStream* stream = &ctx->stream; - WRITE_UNKNOWN_SIZE; + WRITE_UNKNOWN_SIZE(stream); wasm_write_u32_leb128(stream, table_count, "table count"); wasm_write_type(stream, WASM_TYPE_ANYFUNC); wasm_write_u32_leb128(stream, flags, "table elem flags"); wasm_write_u32_leb128(stream, elem_count, "table initial length"); wasm_write_u32_leb128(stream, elem_count, "table max length"); - FIXUP_SIZE; + FIXUP_SIZE(stream); } -static void write_combined_elem_section(Context* ctx, - const SectionPtrVector* sections) { +static void write_export_section(Context* ctx) { + size_t i, j; + uint32_t total_exports = 0; + for (i = 0; i < ctx->inputs.size; i++) { + WasmLinkerInputBinary* binary = &ctx->inputs.data[i]; + total_exports += binary->exports.size; + /* + for (j = 0; j < binary->exports.size; j++) { + WasmExport* export = &binary->exports.data[j]; + if (exports) { + } + } + */ + } + WasmStream* stream = &ctx->stream; - WRITE_UNKNOWN_SIZE; + WRITE_UNKNOWN_SIZE(stream); + wasm_write_u32_leb128(stream, total_exports, "export count"); + + for (i = 0; i < ctx->inputs.size; i++) { + WasmLinkerInputBinary* binary = &ctx->inputs.data[i]; + for (j = 0; j < binary->exports.size; j++) { + WasmExport* export = &binary->exports.data[j]; + write_slice(stream, export->name, "export name"); + wasm_write_u8(stream, export->kind, "export kind"); + uint32_t index = export->index; + switch (export->kind) { + case WASM_EXTERNAL_KIND_FUNC: + index = relocate_func_index(binary, index); + break; + default: + WASM_FATAL("unsupport export type: %d\n", export->kind); + break; + } + wasm_write_u32_leb128(stream, index, "export index"); + } + } + FIXUP_SIZE(stream); +} + +static void write_elem_section(Context* ctx, + const WasmSectionPtrVector* sections) { + WasmStream* stream = &ctx->stream; + WRITE_UNKNOWN_SIZE(stream); size_t i; uint32_t total_elem_count = 0; for (i = 0; i < sections->size; i++) { - Section* sec = sections->data[i]; + WasmSection* sec = sections->data[i]; total_elem_count += sec->binary->table_elem_count; } @@ -570,18 +334,18 @@ static void write_combined_elem_section(Context* ctx, ctx->current_section_payload_offset = stream->offset; for (i = 0; i < sections->size; i++) { - Section* sec = sections->data[i]; + WasmSection* sec = sections->data[i]; apply_relocations(sec); write_section_payload(ctx, sec); } - FIXUP_SIZE; + FIXUP_SIZE(stream); } -static void write_combined_memory_section(Context* ctx, - const SectionPtrVector* sections) { +static void write_memory_section(Context* ctx, + const WasmSectionPtrVector* sections) { WasmStream* stream = &ctx->stream; - WRITE_UNKNOWN_SIZE; + WRITE_UNKNOWN_SIZE(stream); wasm_write_u32_leb128(stream, 1, "memory count"); @@ -590,26 +354,79 @@ static void write_combined_memory_section(Context* ctx, limits.has_max = WASM_TRUE; size_t i; for (i = 0; i < sections->size; i++) { - SectionPtr sec = sections->data[i]; + WasmSection* sec = sections->data[i]; limits.initial += sec->memory_limits.initial; } limits.max = limits.initial; wasm_write_limits(stream, &limits); - FIXUP_SIZE; + FIXUP_SIZE(stream); +} + +static void write_function_import(Context* ctx, + WasmFunctionImport* import, + uint32_t offset) { + write_c_str(&ctx->stream, WASM_LINK_MODULE_NAME, "import module name"); + write_slice(&ctx->stream, import->name, "import field name"); + wasm_write_u8(&ctx->stream, WASM_EXTERNAL_KIND_FUNC, "import kind"); + wasm_write_u32_leb128(&ctx->stream, import->sig_index + offset, + "import signature index"); +} + +static void write_global_import(Context* ctx, WasmGlobalImport* import) { + write_c_str(&ctx->stream, WASM_LINK_MODULE_NAME, "import module name"); + write_slice(&ctx->stream, import->name, "import field name"); + wasm_write_u8(&ctx->stream, WASM_EXTERNAL_KIND_GLOBAL, "import kind"); + wasm_write_type(&ctx->stream, import->type); + wasm_write_u8(&ctx->stream, import->mutable, "global mutability"); +} + +static void write_import_section(Context* ctx) { + uint32_t num_imports = 0; + size_t i, j; + for (i = 0; i < ctx->inputs.size; i++) { + WasmLinkerInputBinary* binary = &ctx->inputs.data[i]; + WasmFunctionImportVector* imports = &binary->function_imports; + for (j = 0; j < imports->size; j++) { + WasmFunctionImport* import = &imports->data[j]; + if (import->active) + num_imports++; + } + num_imports += binary->global_imports.size; + } + + WRITE_UNKNOWN_SIZE(&ctx->stream); + wasm_write_u32_leb128(&ctx->stream, num_imports, "num imports"); + + for (i = 0; i < ctx->inputs.size; i++) { + WasmLinkerInputBinary* binary = &ctx->inputs.data[i]; + WasmFunctionImportVector* imports = &binary->function_imports; + for (j = 0; j < imports->size; j++) { + WasmFunctionImport* import = &imports->data[j]; + if (import->active) + write_function_import(ctx, import, binary->type_index_offset); + } + + WasmGlobalImportVector* globals = &binary->global_imports; + for (j = 0; j < globals->size; j++) { + write_global_import(ctx, &globals->data[j]); + } + } + + FIXUP_SIZE(&ctx->stream); } -static void write_combined_function_section(Context* ctx, - const SectionPtrVector* sections, - uint32_t total_count) { +static void write_function_section(Context* ctx, + const WasmSectionPtrVector* sections, + uint32_t total_count) { WasmStream* stream = &ctx->stream; - WRITE_UNKNOWN_SIZE; + WRITE_UNKNOWN_SIZE(stream); wasm_write_u32_leb128(stream, total_count, "function count"); size_t i; for (i = 0; i < sections->size; i++) { - SectionPtr sec = sections->data[i]; + WasmSection* sec = sections->data[i]; uint32_t count = sec->count; uint32_t input_offset = 0; uint32_t sig_index = 0; @@ -624,11 +441,11 @@ static void write_combined_function_section(Context* ctx, } } - FIXUP_SIZE; + FIXUP_SIZE(stream); } static void write_data_segment(WasmStream* stream, - DataSegment* segment, + WasmDataSegment* segment, uint32_t offset) { assert(segment->memory_index == 0); wasm_write_u32_leb128(stream, segment->memory_index, "memory index"); @@ -639,36 +456,73 @@ static void write_data_segment(WasmStream* stream, wasm_write_data(stream, segment->data, segment->size, "segment data"); } -static void write_combined_data_section(Context* ctx, - SectionPtrVector* sections, - uint32_t total_count) { +static void write_data_section(Context* ctx, + WasmSectionPtrVector* sections, + uint32_t total_count) { WasmStream* stream = &ctx->stream; - WRITE_UNKNOWN_SIZE; + WRITE_UNKNOWN_SIZE(stream); wasm_write_u32_leb128(stream, total_count, "data segment count"); size_t i, j; for (i = 0; i < sections->size; i++) { - Section* sec = sections->data[i]; + WasmSection* sec = sections->data[i]; for (j = 0; j < sec->data_segments.size; j++) { - DataSegment* segment = &sec->data_segments.data[j]; + WasmDataSegment* segment = &sec->data_segments.data[j]; write_data_segment(stream, segment, sec->binary->memory_page_offset * WASM_PAGE_SIZE); } } - FIXUP_SIZE; + FIXUP_SIZE(stream); } -static void write_combined_reloc_section(Context* ctx, - WasmBinarySection section_code, - SectionPtrVector* sections, - uint32_t section_index) { +static void write_names_section(Context* ctx) { + uint32_t total_count = 0; + size_t i, j; + for (i = 0; i < ctx->inputs.size; i++) { + WasmLinkerInputBinary* binary = &ctx->inputs.data[i]; + for (j = 0; j < binary->debug_names.size; j++) { + if (j < binary->function_imports.size) { + if (!binary->function_imports.data[j].active) + continue; + } + total_count++; + } + } + + if (!total_count) + return; + + WasmStream* stream = &ctx->stream; + wasm_write_u8(stream, WASM_BINARY_SECTION_CUSTOM, "section code"); + WRITE_UNKNOWN_SIZE(stream); + write_c_str(stream, "name", "custom section name"); + wasm_write_u32_leb128(stream, total_count, "element count"); + + for (i = 0; i < ctx->inputs.size; i++) { + WasmLinkerInputBinary* binary = &ctx->inputs.data[i]; + for (j = 0; j < binary->debug_names.size; j++) { + if (j < binary->function_imports.size) { + if (!binary->function_imports.data[j].active) + continue; + } + write_slice(stream, binary->debug_names.data[j], "function name"); + wasm_write_u32_leb128(stream, 0, "local name count"); + } + } + + FIXUP_SIZE(stream); +} + +static void write_reloc_section(Context* ctx, + WasmBinarySection section_code, + WasmSectionPtrVector* sections) { size_t i, j; uint32_t total_relocs = 0; /* First pass to know total reloc count */ for (i = 0; i < sections->size; i++) { - Section* sec = sections->data[i]; + WasmSection* sec = sections->data[i]; total_relocs += sec->relocations.size; } @@ -681,15 +535,14 @@ static void write_combined_reloc_section(Context* ctx, WasmStream* stream = &ctx->stream; wasm_write_u8(stream, WASM_BINARY_SECTION_CUSTOM, "section code"); - WRITE_UNKNOWN_SIZE; - wasm_write_str(stream, section_name, strlen(section_name), WASM_PRINT_CHARS, - "reloc section name"); - wasm_write_u32_leb128(&ctx->stream, section_index, "reloc section"); + WRITE_UNKNOWN_SIZE(stream); + write_c_str(stream, section_name, "reloc section name"); + wasm_write_u32_leb128(&ctx->stream, section_code, "reloc section"); wasm_write_u32_leb128(&ctx->stream, total_relocs, "num relocs"); for (i = 0; i < sections->size; i++) { - Section* sec = sections->data[i]; - RelocVector* relocs = &sec->relocations; + WasmSection* sec = sections->data[i]; + WasmRelocVector* relocs = &sec->relocations; for (j = 0; j < relocs->size; j++) { wasm_write_u32_leb128(&ctx->stream, relocs->data[j].type, "reloc type"); uint32_t new_offset = relocs->data[j].offset + sec->output_payload_offset; @@ -697,12 +550,12 @@ static void write_combined_reloc_section(Context* ctx, } } - FIXUP_SIZE; + FIXUP_SIZE(stream); } static WasmBool write_combined_section(Context* ctx, WasmBinarySection section_code, - SectionPtrVector* sections) { + WasmSectionPtrVector* sections) { if (!sections->size) return WASM_FALSE; @@ -717,7 +570,7 @@ static WasmBool write_combined_section(Context* ctx, /* Sum section size and element count */ for (i = 0; i < sections->size; i++) { - Section* sec = sections->data[i]; + WasmSection* sec = sections->data[i]; total_size += sec->payload_size; total_count += sec->count; } @@ -726,20 +579,26 @@ static WasmBool write_combined_section(Context* ctx, ctx->current_section_payload_offset = -1; switch (section_code) { + case WASM_BINARY_SECTION_IMPORT: + write_import_section(ctx); + break; case WASM_BINARY_SECTION_FUNCTION: - write_combined_function_section(ctx, sections, total_count); + write_function_section(ctx, sections, total_count); break; case WASM_BINARY_SECTION_TABLE: - write_combined_table_section(ctx, sections); + write_table_section(ctx, sections); + break; + case WASM_BINARY_SECTION_EXPORT: + write_export_section(ctx); break; case WASM_BINARY_SECTION_ELEM: - write_combined_elem_section(ctx, sections); + write_elem_section(ctx, sections); break; case WASM_BINARY_SECTION_MEMORY: - write_combined_memory_section(ctx, sections); + write_memory_section(ctx, sections); break; case WASM_BINARY_SECTION_DATA: - write_combined_data_section(ctx, sections, total_count); + write_data_section(ctx, sections, total_count); break; default: { /* Total section size includes the element count leb128. */ @@ -751,7 +610,7 @@ static WasmBool write_combined_section(Context* ctx, wasm_write_u32_leb128(stream, total_count, "element count"); ctx->current_section_payload_offset = ctx->stream.offset; for (i = 0; i < sections->size; i++) { - Section* sec = sections->data[i]; + WasmSection* sec = sections->data[i]; apply_relocations(sec); write_section_payload(ctx, sec); } @@ -761,59 +620,134 @@ static WasmBool write_combined_section(Context* ctx, return WASM_TRUE; } -static void write_binary(Context* ctx) { - /* Find all the sections of each type */ - SectionPtrVector sections[WASM_NUM_BINARY_SECTIONS]; - WASM_ZERO_MEMORY(sections); - uint32_t section_indices[WASM_NUM_BINARY_SECTIONS]; - WASM_ZERO_MEMORY(section_indices); - uint32_t section_index = 1; +typedef struct ExportInfo { + WasmExport* export; + WasmLinkerInputBinary* binary; +} ExportInfo; +WASM_DEFINE_VECTOR(export_info, ExportInfo); - size_t i; - size_t j; +static void resolve_symbols(Context* ctx) { + /* Create hashmap of all exported symbols from all inputs */ + WasmBindingHash export_map; + WASM_ZERO_MEMORY(export_map); + ExportInfoVector export_list; + WASM_ZERO_MEMORY(export_list); + + size_t i, j; + for (i = 0; i < ctx->inputs.size; i++) { + WasmLinkerInputBinary* binary = &ctx->inputs.data[i]; + for (j = 0; j < binary->exports.size; j++) { + WasmExport* export = &binary->exports.data[j]; + ExportInfo* info = wasm_append_export_info(ctx->allocator, &export_list); + info->export = export; + info->binary = binary; + + /* TODO(sbc): Handle duplicate names */ + WasmStringSlice name = + wasm_dup_string_slice(ctx->allocator, export->name); + WasmBinding* binding = + wasm_insert_binding(ctx->allocator, &export_map, &name); + binding->index = export_list.size - 1; + } + } + + /* + * Iterate through all imported functions resolving them against exported + * ones. + */ + for (i = 0; i < ctx->inputs.size; i++) { + WasmLinkerInputBinary* binary = &ctx->inputs.data[i]; + for (j = 0; j < binary->function_imports.size; j++) { + WasmFunctionImport* import = &binary->function_imports.data[j]; + int export_index = + wasm_find_binding_index_by_name(&export_map, &import->name); + if (export_index == -1) { + if (!s_relocatable) + WASM_FATAL("undefined symbol: " PRIstringslice "\n", + WASM_PRINTF_STRING_SLICE_ARG(import->name)); + continue; + } + + /* We found the symbol exported by another module */ + ExportInfo* export_info = &export_list.data[export_index]; + + /* TODO(sbc): verify the foriegn function has the correct signature */ + import->active = WASM_FALSE; + import->foreign_binary = export_info->binary; + import->foreign_index = export_info->export->index; + binary->active_function_imports--; + } + } + + wasm_destroy_export_info_vector(ctx->allocator, &export_list); + wasm_destroy_binding_hash(ctx->allocator, &export_map); +} + +static void calculate_reloc_offsets(Context* ctx) { + size_t i, j; uint32_t memory_page_offset = 0; - for (j = 0; j < ctx->inputs.size; j++) { - InputBinary* binary = &ctx->inputs.data[j]; + uint32_t type_count = 0; + uint32_t global_count = 0; + uint32_t function_count = 0; + uint32_t table_elem_count = 0; + uint32_t total_function_imports = 0; + uint32_t total_global_imports = 0; + for (i = 0; i < ctx->inputs.size; i++) { + WasmLinkerInputBinary* binary = &ctx->inputs.data[i]; /* The imported_function_index_offset is the sum of all the function * imports from objects that precede this one. i.e. the current running * total */ - binary->imported_function_index_offset = ctx->total_function_imports; - binary->imported_global_index_offset = ctx->total_global_imports; + binary->imported_function_index_offset = total_function_imports; + binary->imported_global_index_offset = total_global_imports; binary->memory_page_offset = memory_page_offset; memory_page_offset += binary->memory_page_count; - ctx->total_function_imports += binary->num_func_imports; - ctx->total_global_imports += binary->num_global_imports; - for (i = 0; i < binary->sections.size; i++) { - Section* s = &binary->sections.data[i]; - SectionPtrVector* sec_list = §ions[s->section_code]; - wasm_append_section_ptr_value(s_allocator, sec_list, &s); + total_function_imports += binary->active_function_imports; + total_global_imports += binary->global_imports.size; + } + + for (i = 0; i < ctx->inputs.size; i++) { + WasmLinkerInputBinary* binary = &ctx->inputs.data[i]; + binary->table_index_offset = table_elem_count; + table_elem_count += binary->table_elem_count; + for (j = 0; j < binary->sections.size; j++) { + WasmSection* sec = &binary->sections.data[j]; + switch (sec->section_code) { + case WASM_BINARY_SECTION_TYPE: + binary->type_index_offset = type_count; + type_count += sec->count; + break; + case WASM_BINARY_SECTION_GLOBAL: + binary->global_index_offset = total_global_imports - + sec->binary->global_imports.size + + global_count; + global_count += sec->count; + break; + case WASM_BINARY_SECTION_FUNCTION: + binary->function_index_offset = total_function_imports - + sec->binary->function_imports.size + + function_count; + function_count += sec->count; + break; + default: + break; + } } } +} - /* Calculate offsets needed for relocation */ - uint32_t total_count = 0; - for (i = 0; i < sections[WASM_BINARY_SECTION_TYPE].size; i++) { - Section* sec = sections[WASM_BINARY_SECTION_TYPE].data[i]; - sec->binary->type_index_offset = total_count; - total_count += sec->count; - } - - total_count = 0; - for (i = 0; i < sections[WASM_BINARY_SECTION_GLOBAL].size; i++) { - Section* sec = sections[WASM_BINARY_SECTION_GLOBAL].data[i]; - sec->binary->global_index_offset = ctx->total_global_imports - - sec->binary->num_global_imports + - total_count; - total_count += sec->count; - } +static void write_binary(Context* ctx) { + /* Find all the sections of each type */ + WasmSectionPtrVector sections[WASM_NUM_BINARY_SECTIONS]; + WASM_ZERO_MEMORY(sections); - total_count = 0; - for (i = 0; i < sections[WASM_BINARY_SECTION_FUNCTION].size; i++) { - Section* sec = sections[WASM_BINARY_SECTION_FUNCTION].data[i]; - sec->binary->function_index_offset = ctx->total_function_imports - - sec->binary->num_func_imports + - total_count; - total_count += sec->count; + size_t i, j; + for (j = 0; j < ctx->inputs.size; j++) { + WasmLinkerInputBinary* binary = &ctx->inputs.data[j]; + for (i = 0; i < binary->sections.size; i++) { + WasmSection* s = &binary->sections.data[i]; + WasmSectionPtrVector* sec_list = §ions[s->section_code]; + wasm_append_section_ptr_value(ctx->allocator, sec_list, &s); + } } /* Write the final binary */ @@ -822,34 +756,47 @@ static void write_binary(Context* ctx) { /* Write known sections first */ for (i = FIRST_KNOWN_SECTION; i < WASM_NUM_BINARY_SECTIONS; i++) { - if (write_combined_section(ctx, i, §ions[i])) - section_indices[i] = section_index++; + write_combined_section(ctx, i, §ions[i]); } - /* Write custom sections */ - SectionPtrVector* custom_sections = §ions[WASM_BINARY_SECTION_CUSTOM]; - for (i = 0; i < custom_sections->size; i++) { - Section* section = custom_sections->data[i]; - if (section->data_custom.linked) - continue; - write_combined_custom_section(ctx, custom_sections, - §ion->data_custom.name); - } + write_names_section(ctx); /* Generate a new set of reloction sections */ for (i = FIRST_KNOWN_SECTION; i < WASM_NUM_BINARY_SECTIONS; i++) { - write_combined_reloc_section(ctx, i, §ions[i], section_indices[i]); + write_reloc_section(ctx, i, §ions[i]); } for (i = 0; i < WASM_NUM_BINARY_SECTIONS; i++) { - wasm_destroy_section_ptr_vector(s_allocator, §ions[i]); + wasm_destroy_section_ptr_vector(ctx->allocator, §ions[i]); + } +} + +static void dump_reloc_offsets(Context* ctx) { + if (s_verbose) { + uint32_t i; + for (i = 0; i < ctx->inputs.size; i++) { + WasmLinkerInputBinary* binary = &ctx->inputs.data[i]; + wasm_writef(&s_log_stream, "Relocation info for: %s\n", binary->filename); + wasm_writef(&s_log_stream, " - type index offset : %d\n", + binary->type_index_offset); + wasm_writef(&s_log_stream, " - mem page offset : %d\n", + binary->memory_page_offset); + wasm_writef(&s_log_stream, " - function index offset : %d\n", + binary->function_index_offset); + wasm_writef(&s_log_stream, " - global index offset : %d\n", + binary->global_index_offset); + wasm_writef(&s_log_stream, " - imported function offset: %d\n", + binary->imported_function_index_offset); + wasm_writef(&s_log_stream, " - imported global offset : %d\n", + binary->imported_global_index_offset); + } } } static WasmResult perform_link(Context* ctx) { WasmMemoryWriter writer; WASM_ZERO_MEMORY(writer); - if (WASM_FAILED(wasm_init_mem_writer(s_allocator, &writer))) + if (WASM_FAILED(wasm_init_mem_writer(ctx->allocator, &writer))) WASM_FATAL("unable to open memory writer for writing\n"); WasmStream* log_stream = NULL; @@ -859,6 +806,10 @@ static WasmResult perform_link(Context* ctx) { if (s_verbose) wasm_writef(&s_log_stream, "writing file: %s\n", s_outfile); + calculate_reloc_offsets(ctx); + resolve_symbols(ctx); + calculate_reloc_offsets(ctx); + dump_reloc_offsets(ctx); wasm_init_stream(&ctx->stream, &writer.base, log_stream); write_binary(ctx); @@ -870,12 +821,13 @@ static WasmResult perform_link(Context* ctx) { } int main(int argc, char** argv) { - s_allocator = &g_wasm_libc_allocator; wasm_init_stdio(); - parse_options(argc, argv); Context context; WASM_ZERO_MEMORY(context); + context.allocator = &g_wasm_libc_allocator; + + parse_options(context.allocator, argc, argv); WasmResult result = WASM_OK; size_t i; @@ -885,11 +837,15 @@ int main(int argc, char** argv) { wasm_writef(&s_log_stream, "reading file: %s\n", input_filename); void* data; size_t size; - result = wasm_read_file(s_allocator, input_filename, &data, &size); + result = wasm_read_file(context.allocator, input_filename, &data, &size); if (WASM_FAILED(result)) return result; - InputBinary* b = wasm_append_binary(s_allocator, &context.inputs); - result = read_binary(data, size, b); + WasmLinkerInputBinary* b = + wasm_append_binary(context.allocator, &context.inputs); + b->data = data; + b->size = size; + b->filename = input_filename; + result = wasm_read_binary_linker(context.allocator, b); if (WASM_FAILED(result)) WASM_FATAL("error parsing file: %s\n", input_filename); } @@ -899,10 +855,10 @@ int main(int argc, char** argv) { return result; /* Cleanup */ - WASM_DESTROY_VECTOR_AND_ELEMENTS(s_allocator, context.inputs, binary); - wasm_destroy_string_vector(s_allocator, &s_infiles); + WASM_DESTROY_VECTOR_AND_ELEMENTS(context.allocator, context.inputs, binary); + wasm_destroy_string_vector(context.allocator, &s_infiles); - wasm_print_allocator_stats(s_allocator); - wasm_destroy_allocator(s_allocator); + wasm_print_allocator_stats(context.allocator); + wasm_destroy_allocator(context.allocator); return result; } diff --git a/src/tools/wasmdump.c b/src/tools/wasmdump.c index feb00c5f..a9452f8f 100644 --- a/src/tools/wasmdump.c +++ b/src/tools/wasmdump.c @@ -147,6 +147,15 @@ int main(int argc, char** argv) { // Perform serveral passed over the binary in order to print out different // types of information. s_objdump_options.print_header = 1; + if (!s_objdump_options.headers && !s_objdump_options.details && + !s_objdump_options.disassemble && !s_objdump_options.raw) { + printf("At least one of the following switches must be given:\n"); + printf(" -d/--disassemble\n"); + printf(" -h/--headers\n"); + printf(" -x/--details\n"); + printf(" -s/--full-contents\n"); + return 1; + } // Pass 1: Print the section headers if (s_objdump_options.headers) { diff --git a/src/wasm-link.h b/src/wasm-link.h new file mode 100644 index 00000000..bee00614 --- /dev/null +++ b/src/wasm-link.h @@ -0,0 +1,133 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WASM_LINK_H_ +#define WASM_LINK_H_ + +#include "binary.h" +#include "common.h" +#include "vector.h" + +#define WASM_LINK_MODULE_NAME "__extern" + +struct WasmLinkerInputBinary; + +typedef struct WasmFunctionImport { + WasmStringSlice name; + uint32_t sig_index; + WasmBool active; /* Is this import present in the linked binary */ + struct WasmLinkerInputBinary* foreign_binary; + uint32_t foreign_index; +} WasmFunctionImport; +WASM_DEFINE_VECTOR(function_import, WasmFunctionImport); + +typedef struct WasmGlobalImport { + WasmStringSlice name; + WasmType type; + WasmBool mutable; +} WasmGlobalImport; +WASM_DEFINE_VECTOR(global_import, WasmGlobalImport); + +typedef struct WasmDataSegment { + uint32_t memory_index; + uint32_t offset; + const uint8_t* data; + size_t size; +} WasmDataSegment; +WASM_DEFINE_VECTOR(data_segment, WasmDataSegment); + +typedef struct WasmReloc { + WasmRelocType type; + size_t offset; +} WasmReloc; +WASM_DEFINE_VECTOR(reloc, WasmReloc); + +typedef struct WasmExport { + WasmExternalKind kind; + WasmStringSlice name; + uint32_t index; +} WasmExport; +WASM_DEFINE_VECTOR(export, WasmExport); + +typedef struct WasmSectionDataCustom { + /* Reference to string data stored in the containing InputBinary */ + WasmStringSlice name; +} WasmSectionDataCustom; + +typedef struct WasmSection { + /* The binary to which this section belongs */ + struct WasmLinkerInputBinary* binary; + WasmRelocVector relocations; /* The relocations for this section */ + + WasmBinarySection section_code; + size_t size; + size_t offset; + + size_t payload_size; + size_t payload_offset; + + /* For known sections, the count of the number of elements in the section */ + uint32_t count; + + union { + /* CUSTOM section data */ + WasmSectionDataCustom data_custom; + /* DATA section data */ + WasmDataSegmentVector data_segments; + /* MEMORY section data */ + WasmLimits memory_limits; + }; + + /* The offset at which this section appears within the combined output + * section. */ + size_t output_payload_offset; +} WasmSection; +WASM_DEFINE_VECTOR(section, WasmSection); + +typedef WasmSection* WasmSectionPtr; +WASM_DEFINE_VECTOR(section_ptr, WasmSectionPtr); + +WASM_DEFINE_VECTOR(string_slice, WasmStringSlice); + +typedef struct WasmLinkerInputBinary { + const char* filename; + uint8_t* data; + size_t size; + WasmSectionVector sections; + + WasmExportVector exports; + + WasmFunctionImportVector function_imports; + uint32_t active_function_imports; + WasmGlobalImportVector global_imports; + uint32_t active_global_imports; + + uint32_t type_index_offset; + uint32_t function_index_offset; + uint32_t imported_function_index_offset; + uint32_t global_index_offset; + uint32_t imported_global_index_offset; + uint32_t table_index_offset; + uint32_t memory_page_count; + uint32_t memory_page_offset; + + uint32_t table_elem_count; + + WasmStringSliceVector debug_names; +} WasmLinkerInputBinary; +WASM_DEFINE_VECTOR(binary, WasmLinkerInputBinary); + +#endif /* WASM_LINK_H_ */ diff --git a/test/binary/bad-export-func.txt b/test/binary/bad-export-func.txt index 7640560e..21e82c00 100644 --- a/test/binary/bad-export-func.txt +++ b/test/binary/bad-export-func.txt @@ -7,6 +7,6 @@ section(FUNCTION) { count[1] sig[0] } section(EXPORT) { count[1] str("foo") func_kind func[1] } (;; STDERR ;;; Error running "wasm2wast": -error: @0x0000001b: invalid export func index +error: @0x0000001b: invalid export func index: 1 ;;; STDERR ;;) diff --git a/test/link/export.txt b/test/link/export.txt index c4f80006..e34f9a43 100644 --- a/test/link/export.txt +++ b/test/link/export.txt @@ -18,10 +18,9 @@ linked.wasm: file format wasm 0x00000d Sections: TYPE start=0x0000000a end=0x00000013 (size=0x00000009) count: 2 FUNCTION start=0x00000019 end=0x0000001c (size=0x00000003) count: 2 - EXPORT start=0x0000001e end=0x00000033 (size=0x00000015) count: 2 - CODE start=0x00000035 end=0x0000004c (size=0x00000017) count: 2 - CUSTOM start=0x00000052 end=0x00000065 (size=0x00000013) "reloc.EXPORT" - CUSTOM start=0x0000006b end=0x0000007c (size=0x00000011) "reloc.CODE" + EXPORT start=0x00000022 end=0x0000002f (size=0x0000000d) count: 2 + CODE start=0x00000031 end=0x00000048 (size=0x00000017) count: 2 + CUSTOM start=0x0000004e end=0x0000005f (size=0x00000011) "reloc.CODE" Section Details: TYPE: @@ -37,19 +36,16 @@ CODE: - func 0 - func 1 CUSTOM: - - name: "reloc.EXPORT" - - RELOC_FUNC_INDEX section=3 offset=0x6 - - RELOC_FUNC_INDEX section=3 offset=0x10 -CUSTOM: - name: "reloc.CODE" - - RELOC_FUNC_INDEX section=4 offset=0x6 - - RELOC_FUNC_INDEX section=4 offset=0x11 + - section: CODE + - R_FUNC_INDEX_LEB offset=0x37 (0x6) + - R_FUNC_INDEX_LEB offset=0x42 (0x11) Code Disassembly: func 0 - 000038: 41 01 | i32.const 0x1 - 00003a: 10 80 80 80 80 00 | call 0 + 000034: 41 01 | i32.const 0x1 + 000036: 10 80 80 80 80 00 | call 0 func 1 - 000043: 41 02 | i32.const 0x2 - 000045: 10 81 80 80 80 00 | call 0x1 + 00003f: 41 02 | i32.const 0x2 + 000041: 10 81 80 80 80 00 | call 0x1 ;;; STDOUT ;;) diff --git a/test/link/function_calls.txt b/test/link/function_calls.txt index a03a7821..d7ec425b 100644 --- a/test/link/function_calls.txt +++ b/test/link/function_calls.txt @@ -1,14 +1,14 @@ ;;; TOOL: run-wasm-link -;;; FLAGS: +;;; FLAGS: -r (module - (import "foo" "bar" (func (param i32) (result i32))) + (import "__extern" "bar" (func (param i32) (result i32))) (func (param i32) get_local 0 call 0 call 1) ) (module - (import "does" "nothing" (func (param f64))) + (import "__extern" "baz" (func (param f64))) (func (param i64) f64.const 1 call 0 @@ -20,11 +20,10 @@ linked.wasm: file format wasm 0x00000d Sections: TYPE start=0x0000000a end=0x0000001c (size=0x00000012) count: 4 - IMPORT start=0x0000001e end=0x00000040 (size=0x00000022) count: 2 - FUNCTION start=0x00000046 end=0x00000049 (size=0x00000003) count: 2 - CODE start=0x0000004b end=0x00000077 (size=0x0000002c) count: 2 - CUSTOM start=0x0000007d end=0x00000090 (size=0x00000013) "reloc.IMPORT" - CUSTOM start=0x00000096 end=0x000000ab (size=0x00000015) "reloc.CODE" + IMPORT start=0x00000022 end=0x00000041 (size=0x0000001f) count: 2 + FUNCTION start=0x00000047 end=0x0000004a (size=0x00000003) count: 2 + CODE start=0x0000004c end=0x00000078 (size=0x0000002c) count: 2 + CUSTOM start=0x0000007e end=0x00000093 (size=0x00000015) "reloc.CODE" Section Details: TYPE: @@ -33,8 +32,8 @@ TYPE: - [2] (f64) -> nil - [3] (i64) -> nil IMPORT: - - func[0] sig=0 <- foo.bar - - func[1] sig=2 <- does.nothing + - func[0] sig=0 <- __extern.bar + - func[1] sig=2 <- __extern.baz FUNCTION: - func[2] sig=1 - func[3] sig=3 @@ -42,24 +41,21 @@ CODE: - func 2 - func 3 CUSTOM: - - name: "reloc.IMPORT" - - RELOC_GLOBAL_TYPE_INDEX section=2 offset=0xa - - RELOC_GLOBAL_TYPE_INDEX section=2 offset=0x1d -CUSTOM: - name: "reloc.CODE" - - RELOC_FUNC_INDEX section=4 offset=0x6 - - RELOC_FUNC_INDEX section=4 offset=0xc - - RELOC_FUNC_INDEX section=4 offset=0x1e - - RELOC_FUNC_INDEX section=4 offset=0x26 + - section: CODE + - R_FUNC_INDEX_LEB offset=0x52 (0x6) + - R_FUNC_INDEX_LEB offset=0x58 (0xc) + - R_FUNC_INDEX_LEB offset=0x6a (0x1e) + - R_FUNC_INDEX_LEB offset=0x72 (0x26) Code Disassembly: func 2 - 00004e: 20 00 | get_local 0 - 000050: 10 80 80 80 80 00 | call 0 - 000056: 10 82 80 80 80 00 | call 0x2 + 00004f: 20 00 | get_local 0 + 000051: 10 80 80 80 80 00 | call 0 + 000057: 10 82 80 80 80 00 | call 0x2 func 3 - 00005f: 44 00 00 00 00 00 00 f0 3f | f64.const 0x1p+0 - 000068: 10 81 80 80 80 00 | call 0x1 - 00006e: 42 0a | i64.const 10 - 000070: 10 83 80 80 80 00 | call 0x3 + 000060: 44 00 00 00 00 00 00 f0 3f | f64.const 0x1p+0 + 000069: 10 81 80 80 80 00 | call 0x1 + 00006f: 42 0a | i64.const 10 + 000071: 10 83 80 80 80 00 | call 0x3 ;;; STDOUT ;;) diff --git a/test/link/function_calls_incremental.txt b/test/link/function_calls_incremental.txt index afab75f5..acf62de4 100644 --- a/test/link/function_calls_incremental.txt +++ b/test/link/function_calls_incremental.txt @@ -1,14 +1,14 @@ ;;; TOOL: run-wasm-link -;;; FLAGS: --incremental +;;; FLAGS: --incremental -r (module - (import "foo" "bar" (func (param i32) (result i32))) + (import "__extern" "bar" (func (param i32) (result i32))) (func (param i32) get_local 0 call 0 call 1) ) (module - (import "does" "nothing" (func (param f64))) + (import "__extern" "does_nothing" (func (param f64))) (func (param i64) f64.const 1 call 0 @@ -16,7 +16,7 @@ call 1) ) (module - (import "hello" "world" (func (param f32))) + (import "__extern" "hello_world" (func (param f32))) (func (param i32) f32.const 1 call 0 @@ -28,11 +28,10 @@ linked.wasm: file format wasm 0x00000d Sections: TYPE start=0x0000000a end=0x00000024 (size=0x0000001a) count: 6 - IMPORT start=0x00000026 end=0x0000005a (size=0x00000034) count: 3 - FUNCTION start=0x00000060 end=0x00000064 (size=0x00000004) count: 3 - CODE start=0x00000066 end=0x000000a8 (size=0x00000042) count: 3 - CUSTOM start=0x000000ae end=0x000000c3 (size=0x00000015) "reloc.IMPORT" - CUSTOM start=0x000000c9 end=0x000000e2 (size=0x00000019) "reloc.CODE" + IMPORT start=0x0000002a end=0x00000069 (size=0x0000003f) count: 3 + FUNCTION start=0x0000006f end=0x00000073 (size=0x00000004) count: 3 + CODE start=0x00000075 end=0x000000b7 (size=0x00000042) count: 3 + CUSTOM start=0x000000bd end=0x000000d6 (size=0x00000019) "reloc.CODE" Section Details: TYPE: @@ -43,9 +42,9 @@ TYPE: - [4] (f32) -> nil - [5] (i32) -> nil IMPORT: - - func[0] sig=0 <- foo.bar - - func[1] sig=2 <- does.nothing - - func[2] sig=4 <- hello.world + - func[0] sig=0 <- __extern.bar + - func[1] sig=2 <- __extern.does_nothing + - func[2] sig=4 <- __extern.hello_world FUNCTION: - func[3] sig=1 - func[4] sig=3 @@ -55,32 +54,28 @@ CODE: - func 4 - func 5 CUSTOM: - - name: "reloc.IMPORT" - - RELOC_GLOBAL_TYPE_INDEX section=2 offset=0xa - - RELOC_GLOBAL_TYPE_INDEX section=2 offset=0x1d - - RELOC_GLOBAL_TYPE_INDEX section=2 offset=0x2f -CUSTOM: - name: "reloc.CODE" - - RELOC_FUNC_INDEX section=4 offset=0x6 - - RELOC_FUNC_INDEX section=4 offset=0xc - - RELOC_FUNC_INDEX section=4 offset=0x1e - - RELOC_FUNC_INDEX section=4 offset=0x26 - - RELOC_FUNC_INDEX section=4 offset=0x34 - - RELOC_FUNC_INDEX section=4 offset=0x3c + - section: CODE + - R_FUNC_INDEX_LEB offset=0x7b (0x6) + - R_FUNC_INDEX_LEB offset=0x81 (0xc) + - R_FUNC_INDEX_LEB offset=0x93 (0x1e) + - R_FUNC_INDEX_LEB offset=0x9b (0x26) + - R_FUNC_INDEX_LEB offset=0xa9 (0x34) + - R_FUNC_INDEX_LEB offset=0xb1 (0x3c) Code Disassembly: func 3 - 000069: 20 00 | get_local 0 - 00006b: 10 80 80 80 80 00 | call 0 - 000071: 10 83 80 80 80 00 | call 0x3 + 000078: 20 00 | get_local 0 + 00007a: 10 80 80 80 80 00 | call 0 + 000080: 10 83 80 80 80 00 | call 0x3 func 4 - 00007a: 44 00 00 00 00 00 00 f0 3f | f64.const 0x1p+0 - 000083: 10 81 80 80 80 00 | call 0x1 - 000089: 42 0a | i64.const 10 - 00008b: 10 84 80 80 80 00 | call 0x4 + 000089: 44 00 00 00 00 00 00 f0 3f | f64.const 0x1p+0 + 000092: 10 81 80 80 80 00 | call 0x1 + 000098: 42 0a | i64.const 10 + 00009a: 10 84 80 80 80 00 | call 0x4 func 5 - 000094: 43 00 00 80 3f | f32.const 0x1p+0 - 000099: 10 82 80 80 80 00 | call 0x2 - 00009f: 41 0a | i32.const 0xa - 0000a1: 10 85 80 80 80 00 | call 0x5 + 0000a3: 43 00 00 80 3f | f32.const 0x1p+0 + 0000a8: 10 82 80 80 80 00 | call 0x2 + 0000ae: 41 0a | i32.const 0xa + 0000b0: 10 85 80 80 80 00 | call 0x5 ;;; STDOUT ;;) diff --git a/test/link/globals.txt b/test/link/globals.txt index b5da3feb..fcbe3fda 100644 --- a/test/link/globals.txt +++ b/test/link/globals.txt @@ -1,7 +1,7 @@ ;;; TOOL: run-wasm-link ;;; FLAGS: (module - (import "foo" "bar" (global i32)) + (import "__extern" "bar" (global i32)) (global i32 (i32.const 1)) (global i32 (i32.const 2)) (func (param i32) @@ -13,7 +13,7 @@ call 0) ) (module - (import "a" "b" (global i64)) + (import "__extern" "baz" (global i64)) (global i64 (i64.const 2)) (func (param i64) (param i64) get_global 0 @@ -25,19 +25,19 @@ linked.wasm: file format wasm 0x00000d Sections: TYPE start=0x0000000a end=0x00000014 (size=0x0000000a) count: 2 - IMPORT start=0x00000016 end=0x00000029 (size=0x00000013) count: 2 - FUNCTION start=0x0000002f end=0x00000032 (size=0x00000003) count: 2 - GLOBAL start=0x00000034 end=0x00000044 (size=0x00000010) count: 3 - CODE start=0x00000046 end=0x00000079 (size=0x00000033) count: 2 - CUSTOM start=0x0000007f end=0x0000009a (size=0x0000001b) "reloc.CODE" + IMPORT start=0x0000001a end=0x0000003b (size=0x00000021) count: 2 + FUNCTION start=0x00000041 end=0x00000044 (size=0x00000003) count: 2 + GLOBAL start=0x00000046 end=0x00000056 (size=0x00000010) count: 3 + CODE start=0x00000058 end=0x0000008b (size=0x00000033) count: 2 + CUSTOM start=0x00000091 end=0x000000ac (size=0x0000001b) "reloc.CODE" Section Details: TYPE: - [0] (i32) -> nil - [1] (i64, i64) -> nil IMPORT: - - global[0] i32 mutable=0 <- foo.bar - - global[1] i64 mutable=0 <- a.b + - global[0] i32 mutable=0 <- __extern.bar + - global[1] i64 mutable=0 <- __extern.baz FUNCTION: - func[0] sig=0 - func[1] sig=1 @@ -50,24 +50,25 @@ CODE: - func 1 CUSTOM: - name: "reloc.CODE" - - RELOC_GLOBAL_INDEX section=5 offset=0x4 - - RELOC_GLOBAL_INDEX section=5 offset=0xa - - RELOC_GLOBAL_INDEX section=5 offset=0x11 - - RELOC_FUNC_INDEX section=5 offset=0x18 - - RELOC_GLOBAL_INDEX section=5 offset=0x21 - - RELOC_GLOBAL_INDEX section=5 offset=0x27 - - RELOC_FUNC_INDEX section=5 offset=0x2d + - section: CODE + - R_GLOBAL_INDEX_LEB offset=0x5c (0x4) + - R_GLOBAL_INDEX_LEB offset=0x62 (0xa) + - R_GLOBAL_INDEX_LEB offset=0x69 (0x11) + - R_FUNC_INDEX_LEB offset=0x70 (0x18) + - R_GLOBAL_INDEX_LEB offset=0x79 (0x21) + - R_GLOBAL_INDEX_LEB offset=0x7f (0x27) + - R_FUNC_INDEX_LEB offset=0x85 (0x2d) Code Disassembly: func 0 - 000049: 23 83 80 80 80 00 | get_global 0x3 - 00004f: 23 82 80 80 80 00 | get_global 0x2 - 000055: 6a | i32.add - 000056: 23 80 80 80 80 00 | get_global 0 - 00005c: 6a | i32.add - 00005d: 10 80 80 80 80 00 | call 0 + 00005b: 23 83 80 80 80 00 | get_global 0x3 + 000061: 23 82 80 80 80 00 | get_global 0x2 + 000067: 6a | i32.add + 000068: 23 80 80 80 80 00 | get_global 0 + 00006e: 6a | i32.add + 00006f: 10 80 80 80 80 00 | call 0 func 1 - 000066: 23 81 80 80 80 00 | get_global 0x1 - 00006c: 23 84 80 80 80 00 | get_global 0x4 - 000072: 10 81 80 80 80 00 | call 0x1 + 000078: 23 81 80 80 80 00 | get_global 0x1 + 00007e: 23 84 80 80 80 00 | get_global 0x4 + 000084: 10 81 80 80 80 00 | call 0x1 ;;; STDOUT ;;) diff --git a/test/link/incremental.txt b/test/link/incremental.txt index 663f693f..6bca9944 100644 --- a/test/link/incremental.txt +++ b/test/link/incremental.txt @@ -1,7 +1,7 @@ ;;; TOOL: run-wasm-link -;;; FLAGS: --incremental +;;; FLAGS: --incremental -r (module - (import "foo" "bar" (func (param i32) (result i32))) + (import "__extern" "bar" (func (param i32) (result i32))) (func $func1 (param i32) get_local 0 call 0 @@ -9,7 +9,7 @@ (table anyfunc (elem $func1 $func1 $func1)) ) (module - (import "does" "nothing" (func (param f64))) + (import "__extern" "does_nothing" (func (param f64))) (func $func2 (param i64) f64.const 1 call 0 @@ -18,7 +18,7 @@ (table anyfunc (elem $func2 $func2)) ) (module - (import "hello" "world" (func (param f32))) + (import "__extern" "hello_world" (func (param f32))) (func $func3 (param i32) f32.const 1 call 0 @@ -31,14 +31,13 @@ linked.wasm: file format wasm 0x00000d Sections: TYPE start=0x0000000a end=0x00000024 (size=0x0000001a) count: 6 - IMPORT start=0x00000026 end=0x0000005a (size=0x00000034) count: 3 - FUNCTION start=0x00000060 end=0x00000064 (size=0x00000004) count: 3 - TABLE start=0x0000006a end=0x0000006f (size=0x00000005) count: 1 - ELEM start=0x00000075 end=0x0000009e (size=0x00000029) count: 1 - CODE start=0x000000a0 end=0x000000e2 (size=0x00000042) count: 3 - CUSTOM start=0x000000e8 end=0x000000fd (size=0x00000015) "reloc.IMPORT" - CUSTOM start=0x00000103 end=0x0000011e (size=0x0000001b) "reloc.ELEM" - CUSTOM start=0x00000124 end=0x0000013d (size=0x00000019) "reloc.CODE" + IMPORT start=0x0000002a end=0x00000069 (size=0x0000003f) count: 3 + FUNCTION start=0x0000006f end=0x00000073 (size=0x00000004) count: 3 + TABLE start=0x00000079 end=0x0000007e (size=0x00000005) count: 1 + ELEM start=0x00000084 end=0x000000ad (size=0x00000029) count: 1 + CODE start=0x000000af end=0x000000f1 (size=0x00000042) count: 3 + CUSTOM start=0x000000f7 end=0x00000112 (size=0x0000001b) "reloc.ELEM" + CUSTOM start=0x00000118 end=0x00000131 (size=0x00000019) "reloc.CODE" Section Details: TYPE: @@ -49,9 +48,9 @@ TYPE: - [4] (f32) -> nil - [5] (i32) -> nil IMPORT: - - func[0] sig=0 <- foo.bar - - func[1] sig=2 <- does.nothing - - func[2] sig=4 <- hello.world + - func[0] sig=0 <- __extern.bar + - func[1] sig=2 <- __extern.does_nothing + - func[2] sig=4 <- __extern.hello_world FUNCTION: - func[3] sig=1 - func[4] sig=3 @@ -73,41 +72,38 @@ CODE: - func 4 - func 5 CUSTOM: - - name: "reloc.IMPORT" - - RELOC_GLOBAL_TYPE_INDEX section=2 offset=0xa - - RELOC_GLOBAL_TYPE_INDEX section=2 offset=0x1d - - RELOC_GLOBAL_TYPE_INDEX section=2 offset=0x2f -CUSTOM: - name: "reloc.ELEM" - - RELOC_FUNC_INDEX section=5 offset=0x6 - - RELOC_FUNC_INDEX section=5 offset=0xb - - RELOC_FUNC_INDEX section=5 offset=0x10 - - RELOC_FUNC_INDEX section=5 offset=0x15 - - RELOC_FUNC_INDEX section=5 offset=0x1a - - RELOC_FUNC_INDEX section=5 offset=0x1f - - RELOC_FUNC_INDEX section=5 offset=0x24 + - section: ELEM + - R_FUNC_INDEX_LEB offset=0x8a (0x6) + - R_FUNC_INDEX_LEB offset=0x8f (0xb) + - R_FUNC_INDEX_LEB offset=0x94 (0x10) + - R_FUNC_INDEX_LEB offset=0x99 (0x15) + - R_FUNC_INDEX_LEB offset=0x9e (0x1a) + - R_FUNC_INDEX_LEB offset=0xa3 (0x1f) + - R_FUNC_INDEX_LEB offset=0xa8 (0x24) CUSTOM: - name: "reloc.CODE" - - RELOC_FUNC_INDEX section=6 offset=0x6 - - RELOC_FUNC_INDEX section=6 offset=0xc - - RELOC_FUNC_INDEX section=6 offset=0x1e - - RELOC_FUNC_INDEX section=6 offset=0x26 - - RELOC_FUNC_INDEX section=6 offset=0x34 - - RELOC_FUNC_INDEX section=6 offset=0x3c + - section: CODE + - R_FUNC_INDEX_LEB offset=0xb5 (0x6) + - R_FUNC_INDEX_LEB offset=0xbb (0xc) + - R_FUNC_INDEX_LEB offset=0xcd (0x1e) + - R_FUNC_INDEX_LEB offset=0xd5 (0x26) + - R_FUNC_INDEX_LEB offset=0xe3 (0x34) + - R_FUNC_INDEX_LEB offset=0xeb (0x3c) Code Disassembly: func 3 - 0000a3: 20 00 | get_local 0 - 0000a5: 10 80 80 80 80 00 | call 0 - 0000ab: 10 83 80 80 80 00 | call 0x3 + 0000b2: 20 00 | get_local 0 + 0000b4: 10 80 80 80 80 00 | call 0 + 0000ba: 10 83 80 80 80 00 | call 0x3 func 4 - 0000b4: 44 00 00 00 00 00 00 f0 3f | f64.const 0x1p+0 - 0000bd: 10 81 80 80 80 00 | call 0x1 - 0000c3: 42 0a | i64.const 10 - 0000c5: 10 84 80 80 80 00 | call 0x4 + 0000c3: 44 00 00 00 00 00 00 f0 3f | f64.const 0x1p+0 + 0000cc: 10 81 80 80 80 00 | call 0x1 + 0000d2: 42 0a | i64.const 10 + 0000d4: 10 84 80 80 80 00 | call 0x4 func 5 - 0000ce: 43 00 00 80 3f | f32.const 0x1p+0 - 0000d3: 10 82 80 80 80 00 | call 0x2 - 0000d9: 41 0a | i32.const 0xa - 0000db: 10 85 80 80 80 00 | call 0x5 + 0000dd: 43 00 00 80 3f | f32.const 0x1p+0 + 0000e2: 10 82 80 80 80 00 | call 0x2 + 0000e8: 41 0a | i32.const 0xa + 0000ea: 10 85 80 80 80 00 | call 0x5 ;;; STDOUT ;;) diff --git a/test/link/interp.txt b/test/link/interp.txt new file mode 100644 index 00000000..4820d37a --- /dev/null +++ b/test/link/interp.txt @@ -0,0 +1,103 @@ +;;; TOOL: run-wasm-link +;;; FLAGS: --spec +(module + (export "export1" (func $export1)) + (export "call_import1" (func $call_import1)) + (export "call_import2" (func $call_import2)) + (import "__extern" "export2" (func $import1 (result i32))) + (import "__extern" "export3" (func $import2 (result i64))) + (func $export1 (result f32) + f32.const 1 + return + ) + (func $call_import1 (result i32) + call $import1 + return + ) + (func $call_import2 (result i64) + call $import2 + return + ) +) +(module + (export "export2" (func $export2)) + (func $export2 (result i32) + i32.const 42 + return + ) +) +(module + (export "export3" (func $export3)) + (func $export3 (result i64) + i64.const 99 + return + ) +) + +(assert_return (invoke "export1") (f32.const 1)) +(assert_return (invoke "export2") (i32.const 42)) +(assert_return (invoke "export3") (i64.const 99)) +(assert_return (invoke "call_import1") (i32.const 42)) +(assert_return (invoke "call_import2") (i64.const 99)) + +(;; STDOUT ;;; +linked.wasm: file format wasm 0x00000d + +Sections: + TYPE start=0x0000000a end=0x0000001f (size=0x00000015) count: 5 + IMPORT start=0x00000025 end=0x00000026 (size=0x00000001) count: 0 + FUNCTION start=0x0000002c end=0x00000032 (size=0x00000006) count: 5 + EXPORT start=0x00000038 end=0x00000075 (size=0x0000003d) count: 5 + CODE start=0x00000077 end=0x000000a2 (size=0x0000002b) count: 5 + CUSTOM start=0x000000a8 end=0x000000b9 (size=0x00000011) "reloc.CODE" + +Section Details: +TYPE: + - [0] () -> i32 + - [1] () -> i64 + - [2] () -> f32 + - [3] () -> i32 + - [4] () -> i64 +IMPORT: +FUNCTION: + - func[0] sig=2 + - func[1] sig=0 + - func[2] sig=1 + - func[3] sig=3 + - func[4] sig=4 +EXPORT: + - func[0] export1 + - func[1] call_import1 + - func[2] call_import2 + - func[3] export2 + - func[4] export3 +CODE: + - func 0 + - func 1 + - func 2 + - func 3 + - func 4 +CUSTOM: + - name: "reloc.CODE" + - section: CODE + - R_FUNC_INDEX_LEB offset=0x84 (0xd) + - R_FUNC_INDEX_LEB offset=0x8e (0x17) + +Code Disassembly: +func 0 + 00007a: 43 00 00 80 3f | f32.const 0x1p+0 + 00007f: 0f | return +func 1 + 000083: 10 83 80 80 80 00 | call 0x3 + 000089: 0f | return +func 2 + 00008d: 10 84 80 80 80 00 | call 0x4 + 000093: 0f | return +func 3 + 000097: 41 2a | i32.const 0x2a + 000099: 0f | return +func 4 + 00009d: 42 e3 00 | i64.const 99 + 0000a0: 0f | return +5/5 tests passed. +;;; STDOUT ;;) diff --git a/test/link/names.txt b/test/link/names.txt index 527d2502..863b8a3d 100644 --- a/test/link/names.txt +++ b/test/link/names.txt @@ -1,7 +1,9 @@ ;;; TOOL: run-wasm-link -;;; FLAGS: --debug-names +;;; FLAGS: --debug-names -r (module - (export "foo" (func 0)) + (import "__extern" "baz" (func $import_func1)) + (import "__extern" "missing" (func $import_func2)) + (export "foo" (func $name1)) (func $name1 (param $param1 i32) i32.const 1 call 0) @@ -10,7 +12,7 @@ call 1) ) (module - (export "bar" (func 0)) + (export "baz" (func 0)) (func $name3 (param $param3 i32) i32.const 2 call 0) @@ -19,56 +21,54 @@ linked.wasm: file format wasm 0x00000d Sections: - TYPE start=0x0000000a end=0x00000017 (size=0x0000000d) count: 3 - FUNCTION start=0x0000001d end=0x00000021 (size=0x00000004) count: 3 - EXPORT start=0x00000023 end=0x00000038 (size=0x00000015) count: 2 - CODE start=0x0000003a end=0x0000005c (size=0x00000022) count: 3 - CUSTOM start=0x00000062 end=0x00000098 (size=0x00000036) "name" - CUSTOM start=0x0000009e end=0x000000b1 (size=0x00000013) "reloc.EXPORT" - CUSTOM start=0x000000b7 end=0x000000ca (size=0x00000013) "reloc.CODE" + TYPE start=0x0000000a end=0x0000001a (size=0x00000010) count: 4 + IMPORT start=0x00000020 end=0x00000034 (size=0x00000014) count: 1 + FUNCTION start=0x0000003a end=0x0000003e (size=0x00000004) count: 3 + EXPORT start=0x00000044 end=0x00000051 (size=0x0000000d) count: 2 + CODE start=0x00000053 end=0x00000075 (size=0x00000022) count: 3 + CUSTOM start=0x0000007b end=0x000000a8 (size=0x0000002d) "name" + CUSTOM start=0x000000ae end=0x000000c1 (size=0x00000013) "reloc.CODE" Section Details: TYPE: - - [0] (i32) -> nil - - [1] (i64) -> nil - - [2] (i32) -> nil + - [0] () -> nil + - [1] (i32) -> nil + - [2] (i64) -> nil + - [3] (i32) -> nil +IMPORT: + - func[0] sig=0 <- __extern.missing FUNCTION: - - func[0] sig=0 - func[1] sig=1 - func[2] sig=2 + - func[3] sig=3 EXPORT: - - func[0] foo - - func[2] bar + - func[1] foo + - func[3] baz CODE: - - func 0 - func 1 - func 2 + - func 3 CUSTOM: - name: "name" - - func[0] $name1 - - local[0] $param1 - - func[1] $name2 - - local[0] $param2 - - func[2] $name3 - - local[0] $param3 -CUSTOM: - - name: "reloc.EXPORT" - - RELOC_FUNC_INDEX section=3 offset=0x6 - - RELOC_FUNC_INDEX section=3 offset=0x10 + - func[0] $import_func2 + - func[1] $name1 + - func[2] $name2 + - func[3] $name3 CUSTOM: - name: "reloc.CODE" - - RELOC_FUNC_INDEX section=4 offset=0x6 - - RELOC_FUNC_INDEX section=4 offset=0x11 - - RELOC_FUNC_INDEX section=4 offset=0x1c + - section: CODE + - R_FUNC_INDEX_LEB offset=0x59 (0x6) + - R_FUNC_INDEX_LEB offset=0x64 (0x11) + - R_FUNC_INDEX_LEB offset=0x6f (0x1c) Code Disassembly: -func 0 - 00003d: 41 01 | i32.const 0x1 - 00003f: 10 80 80 80 80 00 | call 0 func 1 - 000048: 42 01 | i64.const 1 - 00004a: 10 81 80 80 80 00 | call 0x1 + 000056: 41 01 | i32.const 0x1 + 000058: 10 83 80 80 80 00 | call 0x3 func 2 - 000053: 41 02 | i32.const 0x2 - 000055: 10 82 80 80 80 00 | call 0x2 + 000061: 42 01 | i64.const 1 + 000063: 10 81 80 80 80 00 | call 0x1 +func 3 + 00006c: 41 02 | i32.const 0x2 + 00006e: 10 83 80 80 80 00 | call 0x3 ;;; STDOUT ;;) diff --git a/test/link/table.txt b/test/link/table.txt index 2ba4f80b..e161ddeb 100644 --- a/test/link/table.txt +++ b/test/link/table.txt @@ -45,11 +45,12 @@ CODE: - func 2 CUSTOM: - name: "reloc.ELEM" - - RELOC_FUNC_INDEX section=4 offset=0x6 - - RELOC_FUNC_INDEX section=4 offset=0xb - - RELOC_FUNC_INDEX section=4 offset=0x10 - - RELOC_FUNC_INDEX section=4 offset=0x15 - - RELOC_FUNC_INDEX section=4 offset=0x1a + - section: ELEM + - R_FUNC_INDEX_LEB offset=0x38 (0x6) + - R_FUNC_INDEX_LEB offset=0x3d (0xb) + - R_FUNC_INDEX_LEB offset=0x42 (0x10) + - R_FUNC_INDEX_LEB offset=0x47 (0x15) + - R_FUNC_INDEX_LEB offset=0x4c (0x1a) Code Disassembly: func 0 diff --git a/test/run-wasm-link.py b/test/run-wasm-link.py index e138ba08..14b09895 100755 --- a/test/run-wasm-link.py +++ b/test/run-wasm-link.py @@ -16,9 +16,11 @@ # import argparse +import json import os import sys import tempfile +from collections import OrderedDict import find_exe import utils @@ -28,6 +30,8 @@ def main(args): parser = argparse.ArgumentParser() parser.add_argument('-v', '--verbose', help='print more diagnotic messages.', action='store_true') + parser.add_argument('-r', '--relocatable', action='store_true', + help='final output is relocatable') parser.add_argument('-o', '--out-dir', metavar='PATH', help='output directory for files.') parser.add_argument('--bindir', metavar='PATH', @@ -44,6 +48,8 @@ def main(args): ' a time to produce the final linked binary.', action='store_true') parser.add_argument('--debug-names', action='store_true') + parser.add_argument('--dump-verbose', action='store_true') + parser.add_argument('--spec', action='store_true') parser.add_argument('--use-libc-allocator', action='store_true') parser.add_argument('file', help='test file.') options = parser.parse_args(args) @@ -54,22 +60,28 @@ def main(args): wast2wasm.AppendOptionalArgs({ '--debug-names': options.debug_names, '--use-libc-allocator': options.use_libc_allocator, - '-v': options.verbose, + '-v': options.dump_verbose, }) wasm_link = utils.Executable( find_exe.GetWasmlinkExecutable(options.bindir), error_cmdline=options.error_cmdline) - wasm_link.AppendOptionalArgs({'-v': options.verbose,}) + wasm_link.AppendOptionalArgs({ + '-v': options.verbose, + '-r': options.relocatable, + }) wasmdump = utils.Executable( find_exe.GetWasmdumpExecutable(options.bindir), error_cmdline=options.error_cmdline) - wasmdump.AppendOptionalArgs({}) + + wasm_interp = utils.Executable(find_exe.GetWasmInterpExecutable( + options.bindir), error_cmdline=options.error_cmdline) wast2wasm.verbose = options.print_cmd wasm_link.verbose = options.print_cmd wasmdump.verbose = options.print_cmd + wasm_interp.verbose = options.print_cmd filename = options.file @@ -77,7 +89,8 @@ def main(args): basename = os.path.basename(filename) basename_noext = os.path.splitext(basename)[0] out_file = os.path.join(out_dir, basename_noext + '.json') - wast2wasm.RunWithArgs('--spec', '-r', '-o', out_file, filename) + wast2wasm.RunWithArgs('--spec', '--no-check', '-r', '-o', out_file, + filename) wasm_files = utils.GetModuleFilenamesFromSpecJSON(out_file) wasm_files = [utils.ChangeDir(f, out_dir) for f in wasm_files] @@ -90,13 +103,28 @@ def main(args): wasm_link.RunWithArgs('-o', output, f) else: os.rename(output, partialy_linked) - wasm_link.RunWithArgs('-o', output, partialy_linked, f) + wasm_link.RunWithArgs('-r', '-o', output, partialy_linked, f) #wasmdump.RunWithArgs('-d', '-h', output) wasmdump.RunWithArgs('-d', '-x', '-h', output) else: wasm_link.RunWithArgs('-o', output, *wasm_files) wasmdump.RunWithArgs('-d', '-x', '-h', output) + if options.spec: + with open(out_file) as json_file: + spec = json.load(json_file, object_pairs_hook=OrderedDict) + spec['commands'] = [c for c in spec['commands'] + if c['type'] != 'module'] + module = OrderedDict([('type', 'module'), + ('line', 0), + ('filename', os.path.basename(output)),]) + spec['commands'].insert(0, module) + + with open(out_file, 'wb') as json_file: + json.dump(spec, json_file, indent=4) + + wasm_interp.RunWithArgs('--spec', out_file) + if __name__ == '__main__': try: |