summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/binary-reader-linker.c321
-rw-r--r--src/binary-reader-linker.h33
-rw-r--r--src/binary-reader-objdump.c35
-rw-r--r--src/binary-reader.c22
-rw-r--r--src/binary-reader.h6
-rw-r--r--src/binary-writer.c30
-rw-r--r--src/common.c4
-rw-r--r--src/common.h11
-rw-r--r--src/tools/wasm-link.c920
-rw-r--r--src/tools/wasmdump.c9
-rw-r--r--src/wasm-link.h133
-rw-r--r--test/binary/bad-export-func.txt2
-rw-r--r--test/link/export.txt24
-rw-r--r--test/link/function_calls.txt46
-rw-r--r--test/link/function_calls_incremental.txt63
-rw-r--r--test/link/globals.txt51
-rw-r--r--test/link/incremental.txt84
-rw-r--r--test/link/interp.txt103
-rw-r--r--test/link/names.txt74
-rw-r--r--test/link/table.txt11
-rwxr-xr-xtest/run-wasm-link.py38
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(&section_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, &section, "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, &section_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, &section->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(&section_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 = &section->relocations.data[i];
+ WasmReloc* reloc = &section->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 = &sections[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 = &sections[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, &sections[i]))
- section_indices[i] = section_index++;
+ write_combined_section(ctx, i, &sections[i]);
}
- /* Write custom sections */
- SectionPtrVector* custom_sections = &sections[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,
- &section->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, &sections[i], section_indices[i]);
+ write_reloc_section(ctx, i, &sections[i]);
}
for (i = 0; i < WASM_NUM_BINARY_SECTIONS; i++) {
- wasm_destroy_section_ptr_vector(s_allocator, &sections[i]);
+ wasm_destroy_section_ptr_vector(ctx->allocator, &sections[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: