diff options
Diffstat (limited to 'src/binary-reader-linker.cc')
-rw-r--r-- | src/binary-reader-linker.cc | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/src/binary-reader-linker.cc b/src/binary-reader-linker.cc new file mode 100644 index 00000000..6eae025a --- /dev/null +++ b/src/binary-reader-linker.cc @@ -0,0 +1,310 @@ +/* + * 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 { + WabtLinkerInputBinary* binary; + + WabtSection* reloc_section; + + WabtStringSlice import_name; + WabtSection* current_section; +} Context; + +static WabtResult on_reloc_count(uint32_t count, + WabtBinarySection section_code, + WabtStringSlice section_name, + void* user_data) { + Context* ctx = (Context*)user_data; + WabtLinkerInputBinary* binary = ctx->binary; + if (section_code == WABT_BINARY_SECTION_CUSTOM) { + WABT_FATAL("relocation for custom sections not yet supported\n"); + } + + uint32_t i; + for (i = 0; i < binary->sections.size; i++) { + WabtSection* sec = &binary->sections.data[i]; + if (sec->section_code != section_code) + continue; + ctx->reloc_section = sec; + return WABT_OK; + } + + WABT_FATAL("section not found: %d\n", section_code); + return WABT_ERROR; +} + +static WabtResult on_reloc(WabtRelocType type, + uint32_t offset, + void* user_data) { + Context* ctx = (Context*)user_data; + + if (offset + RELOC_SIZE > ctx->reloc_section->size) { + WABT_FATAL("invalid relocation offset: %#x\n", offset); + } + + WabtReloc* reloc = wabt_append_reloc(&ctx->reloc_section->relocations); + reloc->type = type; + reloc->offset = offset; + + return WABT_OK; +} + +static WabtResult on_import(uint32_t index, + WabtStringSlice module_name, + WabtStringSlice field_name, + void* user_data) { + Context* ctx = (Context*)user_data; + if (!wabt_string_slice_eq_cstr(&module_name, WABT_LINK_MODULE_NAME)) { + WABT_FATAL("unsupported import module: " PRIstringslice, + WABT_PRINTF_STRING_SLICE_ARG(module_name)); + } + ctx->import_name = field_name; + return WABT_OK; +} + +static WabtResult on_import_func(uint32_t import_index, + uint32_t global_index, + uint32_t sig_index, + void* user_data) { + Context* ctx = (Context*)user_data; + WabtFunctionImport* import = + wabt_append_function_import(&ctx->binary->function_imports); + import->name = ctx->import_name; + import->sig_index = sig_index; + import->active = true; + ctx->binary->active_function_imports++; + return WABT_OK; +} + +static WabtResult on_import_global(uint32_t import_index, + uint32_t global_index, + WabtType type, + bool mutable_, + void* user_data) { + Context* ctx = (Context*)user_data; + WabtGlobalImport* import = + wabt_append_global_import(&ctx->binary->global_imports); + import->name = ctx->import_name; + import->type = type; + import->mutable_ = mutable_; + ctx->binary->active_global_imports++; + return WABT_OK; +} + +static WabtResult begin_section(WabtBinaryReaderContext* ctx, + WabtBinarySection section_code, + uint32_t size) { + Context* context = (Context*)ctx->user_data; + WabtLinkerInputBinary* binary = context->binary; + WabtSection* sec = wabt_append_section(&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 != WABT_BINARY_SECTION_CUSTOM && + sec->section_code != WABT_BINARY_SECTION_START) { + size_t bytes_read = wabt_read_u32_leb128( + &binary->data[sec->offset], &binary->data[binary->size], &sec->count); + if (bytes_read == 0) + WABT_FATAL("error reading section element count\n"); + sec->payload_offset = sec->offset + bytes_read; + sec->payload_size = sec->size - bytes_read; + } + return WABT_OK; +} + +static WabtResult begin_custom_section(WabtBinaryReaderContext* ctx, + uint32_t size, + WabtStringSlice section_name) { + Context* context = (Context*)ctx->user_data; + WabtLinkerInputBinary* binary = context->binary; + WabtSection* 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 (wabt_string_slice_eq_cstr(§ion_name, "name")) { + size_t bytes_read = wabt_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 == + WABT_BINARY_SECTION_FUNCTION) { + total_funcs += binary->sections.data[i].count; + break; + } + } + if (total_funcs != sec->count) { + WABT_FATAL("name section count (%d) does not match function count (%d)\n", + sec->count, total_funcs); + } + } + + return WABT_OK; +} + +static WabtResult on_table(uint32_t index, + WabtType elem_type, + const WabtLimits* elem_limits, + void* user_data) { + if (elem_limits->has_max && (elem_limits->max != elem_limits->initial)) + WABT_FATAL("Tables with max != initial not supported by wabt-link\n"); + + Context* ctx = (Context*)user_data; + ctx->binary->table_elem_count = elem_limits->initial; + return WABT_OK; +} + +static WabtResult on_elem_segment_function_index_count( + WabtBinaryReaderContext* ctx, + uint32_t index, + uint32_t count) { + Context* context = (Context*)ctx->user_data; + WabtSection* 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 WABT_OK; +} + +static WabtResult on_memory(uint32_t index, + const WabtLimits* page_limits, + void* user_data) { + Context* ctx = (Context*)user_data; + WabtSection* sec = ctx->current_section; + sec->memory_limits = *page_limits; + ctx->binary->memory_page_count = page_limits->initial; + return WABT_OK; +} + +static WabtResult begin_data_segment(uint32_t index, + uint32_t memory_index, + void* user_data) { + Context* ctx = (Context*)user_data; + WabtSection* sec = ctx->current_section; + WabtDataSegment* segment = wabt_append_data_segment(&sec->data_segments); + segment->memory_index = memory_index; + return WABT_OK; +} + +static WabtResult on_init_expr_i32_const_expr(uint32_t index, + uint32_t value, + void* user_data) { + Context* ctx = (Context*)user_data; + WabtSection* sec = ctx->current_section; + if (sec->section_code != WABT_BINARY_SECTION_DATA) + return WABT_OK; + WabtDataSegment* segment = + &sec->data_segments.data[sec->data_segments.size - 1]; + segment->offset = value; + return WABT_OK; +} + +static WabtResult on_data_segment_data(uint32_t index, + const void* src_data, + uint32_t size, + void* user_data) { + Context* ctx = (Context*)user_data; + WabtSection* sec = ctx->current_section; + WabtDataSegment* segment = + &sec->data_segments.data[sec->data_segments.size - 1]; + segment->data = (uint8_t*)src_data; + segment->size = size; + return WABT_OK; +} + +static WabtResult on_export(uint32_t index, + WabtExternalKind kind, + uint32_t item_index, + WabtStringSlice name, + void* user_data) { + Context* ctx = (Context*)user_data; + WabtExport* export_ = wabt_append_export(&ctx->binary->exports); + export_->name = name; + export_->kind = kind; + export_->index = item_index; + return WABT_OK; +} + +static WabtResult on_function_name(uint32_t index, + WabtStringSlice name, + void* user_data) { + Context* ctx = (Context*)user_data; + wabt_append_string_slice_value(&ctx->binary->debug_names, &name); + return WABT_OK; +} + +WabtResult wabt_read_binary_linker(WabtLinkerInputBinary* input_info) { + Context context; + WABT_ZERO_MEMORY(context); + context.binary = input_info; + + WabtBinaryReader reader; + WABT_ZERO_MEMORY(reader); + reader.user_data = &context; + reader.begin_section = begin_section; + reader.begin_custom_section = begin_custom_section; + + reader.on_reloc_count = on_reloc_count; + reader.on_reloc = on_reloc; + + reader.on_import = on_import; + reader.on_import_func = on_import_func; + reader.on_import_global = on_import_global; + + reader.on_export = on_export; + + reader.on_table = on_table; + + reader.on_memory = on_memory; + + reader.begin_data_segment = begin_data_segment; + reader.on_init_expr_i32_const_expr = on_init_expr_i32_const_expr; + reader.on_data_segment_data = on_data_segment_data; + + reader.on_elem_segment_function_index_count = + on_elem_segment_function_index_count; + + reader.on_function_name = on_function_name; + + WabtReadBinaryOptions read_options = WABT_READ_BINARY_OPTIONS_DEFAULT; + read_options.read_debug_names = true; + return wabt_read_binary(input_info->data, input_info->size, &reader, 1, + &read_options); +} |