| /* |
| * 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 <vector> |
| |
| #include "binary-reader-nop.h" |
| #include "wasm-link.h" |
| |
| #define RELOC_SIZE 5 |
| |
| namespace wabt { |
| namespace link { |
| |
| namespace { |
| |
| class BinaryReaderLinker : public BinaryReaderNop { |
| public: |
| explicit BinaryReaderLinker(LinkerInputBinary* binary); |
| |
| virtual Result BeginSection(BinarySection section_type, uint32_t size); |
| |
| virtual Result OnImport(uint32_t index, |
| StringSlice module_name, |
| StringSlice field_name); |
| virtual Result OnImportFunc(uint32_t import_index, |
| StringSlice module_name, |
| StringSlice field_name, |
| uint32_t func_index, |
| uint32_t sig_index); |
| virtual Result OnImportGlobal(uint32_t import_index, |
| StringSlice module_name, |
| StringSlice field_name, |
| uint32_t global_index, |
| Type type, |
| bool mutable_); |
| |
| virtual Result OnFunctionCount(uint32_t count); |
| |
| virtual Result OnTable(uint32_t index, |
| Type elem_type, |
| const Limits* elem_limits); |
| |
| virtual Result OnMemory(uint32_t index, const Limits* limits); |
| |
| virtual Result OnExport(uint32_t index, |
| ExternalKind kind, |
| uint32_t item_index, |
| StringSlice name); |
| |
| virtual Result OnElemSegmentFunctionIndexCount(uint32_t index, |
| uint32_t count); |
| |
| virtual Result BeginDataSegment(uint32_t index, uint32_t memory_index); |
| virtual Result OnDataSegmentData(uint32_t index, |
| const void* data, |
| uint32_t size); |
| |
| virtual Result BeginNamesSection(uint32_t size); |
| |
| virtual Result OnFunctionName(uint32_t function_index, |
| StringSlice function_name); |
| |
| virtual Result OnRelocCount(uint32_t count, |
| BinarySection section_code, |
| StringSlice section_name); |
| virtual Result OnReloc(RelocType type, |
| uint32_t offset, |
| uint32_t index, |
| uint32_t addend); |
| |
| virtual Result OnInitExprI32ConstExpr(uint32_t index, uint32_t value); |
| |
| private: |
| LinkerInputBinary* binary; |
| |
| Section* reloc_section = nullptr; |
| Section* current_section = nullptr; |
| uint32_t function_count = 0; |
| }; |
| |
| BinaryReaderLinker::BinaryReaderLinker(LinkerInputBinary* binary) |
| : binary(binary) {} |
| |
| Result BinaryReaderLinker::OnRelocCount(uint32_t count, |
| BinarySection section_code, |
| StringSlice section_name) { |
| if (section_code == BinarySection::Custom) { |
| WABT_FATAL("relocation for custom sections not yet supported\n"); |
| } |
| |
| for (const std::unique_ptr<Section>& section : binary->sections) { |
| if (section->section_code != section_code) |
| continue; |
| reloc_section = section.get(); |
| return Result::Ok; |
| } |
| |
| WABT_FATAL("section not found: %d\n", static_cast<int>(section_code)); |
| return Result::Error; |
| } |
| |
| Result BinaryReaderLinker::OnReloc(RelocType type, |
| uint32_t offset, |
| uint32_t index, |
| uint32_t addend) { |
| if (offset + RELOC_SIZE > reloc_section->size) { |
| WABT_FATAL("invalid relocation offset: %#x\n", offset); |
| } |
| |
| reloc_section->relocations.emplace_back(type, offset, index, addend); |
| |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderLinker::OnImport(uint32_t index, |
| StringSlice module_name, |
| StringSlice field_name) { |
| if (!string_slice_eq_cstr(&module_name, WABT_LINK_MODULE_NAME)) { |
| WABT_FATAL("unsupported import module: " PRIstringslice, |
| WABT_PRINTF_STRING_SLICE_ARG(module_name)); |
| } |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderLinker::OnImportFunc(uint32_t import_index, |
| StringSlice module_name, |
| StringSlice field_name, |
| uint32_t global_index, |
| uint32_t sig_index) { |
| binary->function_imports.emplace_back(); |
| FunctionImport* import = &binary->function_imports.back(); |
| import->name = field_name; |
| import->sig_index = sig_index; |
| import->active = true; |
| binary->active_function_imports++; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderLinker::OnImportGlobal(uint32_t import_index, |
| StringSlice module_name, |
| StringSlice field_name, |
| uint32_t global_index, |
| Type type, |
| bool mutable_) { |
| binary->global_imports.emplace_back(); |
| GlobalImport* import = &binary->global_imports.back(); |
| import->name = field_name; |
| import->type = type; |
| import->mutable_ = mutable_; |
| binary->active_global_imports++; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderLinker::OnFunctionCount(uint32_t count) { |
| function_count = count; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderLinker::BeginSection(BinarySection section_code, |
| uint32_t size) { |
| Section* sec = new Section(); |
| binary->sections.emplace_back(sec); |
| current_section = sec; |
| sec->section_code = section_code; |
| sec->size = size; |
| sec->offset = state->offset; |
| sec->binary = binary; |
| |
| if (sec->section_code != BinarySection::Custom && |
| sec->section_code != BinarySection::Start) { |
| size_t bytes_read = 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 Result::Ok; |
| } |
| |
| Result BinaryReaderLinker::OnTable(uint32_t index, |
| Type elem_type, |
| const Limits* elem_limits) { |
| if (elem_limits->has_max && (elem_limits->max != elem_limits->initial)) |
| WABT_FATAL("Tables with max != initial not supported by wabt-link\n"); |
| |
| binary->table_elem_count = elem_limits->initial; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderLinker::OnElemSegmentFunctionIndexCount(uint32_t index, |
| uint32_t count) { |
| Section* sec = current_section; |
| |
| /* Modify the payload to include only the actual function indexes */ |
| size_t delta = state->offset - sec->payload_offset; |
| sec->payload_offset += delta; |
| sec->payload_size -= delta; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderLinker::OnMemory(uint32_t index, const Limits* page_limits) { |
| Section* sec = current_section; |
| sec->data.memory_limits = *page_limits; |
| binary->memory_page_count = page_limits->initial; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderLinker::BeginDataSegment(uint32_t index, |
| uint32_t memory_index) { |
| Section* sec = current_section; |
| if (!sec->data.data_segments) { |
| sec->data.data_segments = new std::vector<DataSegment>(); |
| } |
| sec->data.data_segments->emplace_back(); |
| DataSegment& segment = sec->data.data_segments->back(); |
| segment.memory_index = memory_index; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderLinker::OnInitExprI32ConstExpr(uint32_t index, |
| uint32_t value) { |
| Section* sec = current_section; |
| if (sec->section_code != BinarySection::Data) |
| return Result::Ok; |
| DataSegment& segment = sec->data.data_segments->back(); |
| segment.offset = value; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderLinker::OnDataSegmentData(uint32_t index, |
| const void* src_data, |
| uint32_t size) { |
| Section* sec = current_section; |
| DataSegment& segment = sec->data.data_segments->back(); |
| segment.data = static_cast<const uint8_t*>(src_data); |
| segment.size = size; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderLinker::OnExport(uint32_t index, |
| ExternalKind kind, |
| uint32_t item_index, |
| StringSlice name) { |
| binary->exports.emplace_back(); |
| Export* export_ = &binary->exports.back(); |
| export_->name = name; |
| export_->kind = kind; |
| export_->index = item_index; |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderLinker::BeginNamesSection(uint32_t size) { |
| binary->debug_names.resize(function_count + binary->function_imports.size()); |
| return Result::Ok; |
| } |
| |
| Result BinaryReaderLinker::OnFunctionName(uint32_t index, StringSlice name) { |
| binary->debug_names[index] = string_slice_to_string(name); |
| return Result::Ok; |
| } |
| |
| } // namespace |
| |
| Result read_binary_linker(LinkerInputBinary* input_info, LinkOptions* options) { |
| BinaryReaderLinker reader(input_info); |
| |
| ReadBinaryOptions read_options = WABT_READ_BINARY_OPTIONS_DEFAULT; |
| read_options.read_debug_names = true; |
| read_options.log_stream = options->log_stream; |
| return read_binary(input_info->data, input_info->size, &reader, |
| &read_options); |
| } |
| |
| } // namespace link |
| } // namespace wabt |