/* * 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 "src/binary-reader-linker.h" #include #include "src/binary-reader-nop.h" #include "src/wasm-link.h" #define RELOC_SIZE 5 namespace wabt { namespace link { namespace { class BinaryReaderLinker : public BinaryReaderNop { public: explicit BinaryReaderLinker(LinkerInputBinary* binary); Result BeginSection(BinarySection section_type, Offset size) override; Result OnImportFunc(Index import_index, string_view module_name, string_view field_name, Index func_index, Index sig_index) override; Result OnImportGlobal(Index import_index, string_view module_name, string_view field_name, Index global_index, Type type, bool mutable_) override; Result OnImportMemory(Index import_index, string_view module_name, string_view field_name, Index memory_index, const Limits* page_limits) override; Result OnFunctionCount(Index count) override; Result OnTable(Index index, Type elem_type, const Limits* elem_limits) override; Result OnMemory(Index index, const Limits* limits) override; Result OnExport(Index index, ExternalKind kind, Index item_index, string_view name) override; Result OnElemSegmentFunctionIndexCount(Index index, Index count) override; Result BeginDataSegment(Index index, Index memory_index) override; Result OnDataSegmentData(Index index, const void* data, Address size) override; Result BeginNamesSection(Offset size) override; Result OnFunctionName(Index function_index, string_view function_name) override; Result OnRelocCount(Index count, BinarySection section_code, string_view section_name) override; Result OnReloc(RelocType type, Offset offset, Index index, uint32_t addend) override; Result OnInitExprI32ConstExpr(Index index, uint32_t value) override; private: LinkerInputBinary* binary_; Section* reloc_section_ = nullptr; Section* current_section_ = nullptr; }; BinaryReaderLinker::BinaryReaderLinker(LinkerInputBinary* binary) : binary_(binary) {} Result BinaryReaderLinker::OnRelocCount(Index count, BinarySection section_code, string_view section_name) { if (section_code == BinarySection::Custom) { WABT_FATAL("relocation for custom sections not yet supported\n"); } for (const std::unique_ptr
& 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(section_code)); return Result::Error; } Result BinaryReaderLinker::OnReloc(RelocType type, Offset offset, Index index, uint32_t addend) { if (offset + RELOC_SIZE > reloc_section_->size) { WABT_FATAL("invalid relocation offset: %#" PRIoffset "\n", offset); } reloc_section_->relocations.emplace_back(type, offset, index, addend); return Result::Ok; } Result BinaryReaderLinker::OnImportFunc(Index import_index, string_view module_name, string_view field_name, Index global_index, Index sig_index) { binary_->function_imports.emplace_back(); FunctionImport* import = &binary_->function_imports.back(); import->module_name = module_name.to_string(); import->name = field_name.to_string(); import->sig_index = sig_index; import->active = true; binary_->active_function_imports++; return Result::Ok; } Result BinaryReaderLinker::OnImportGlobal(Index import_index, string_view module_name, string_view field_name, Index global_index, Type type, bool mutable_) { binary_->global_imports.emplace_back(); GlobalImport* import = &binary_->global_imports.back(); import->module_name = module_name.to_string(); import->name = field_name.to_string(); import->type = type; import->mutable_ = mutable_; binary_->active_global_imports++; return Result::Ok; } Result BinaryReaderLinker::OnImportMemory(Index import_index, string_view module_name, string_view field_name, Index memory_index, const Limits* page_limits) { WABT_FATAL("Linker does not support imported memories"); return Result::Error; } Result BinaryReaderLinker::OnFunctionCount(Index count) { binary_->function_count = count; return Result::Ok; } Result BinaryReaderLinker::BeginSection(BinarySection section_code, Offset 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) { const uint8_t* start = &binary_->data[sec->offset]; // Must point to one-past-the-end, but we can't dereference end(). const uint8_t* end = &binary_->data.back() + 1; size_t bytes_read = ReadU32Leb128(start, end, &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(Index 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(Index index, Index 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(Index index, const Limits* page_limits) { Section* sec = current_section_; sec->data.initial = page_limits->initial; binary_->memory_page_count = page_limits->initial; return Result::Ok; } Result BinaryReaderLinker::BeginDataSegment(Index index, Index memory_index) { Section* sec = current_section_; if (!sec->data.data_segments) { sec->data.data_segments = new std::vector(); } sec->data.data_segments->emplace_back(); DataSegment& segment = sec->data.data_segments->back(); segment.memory_index = memory_index; return Result::Ok; } Result BinaryReaderLinker::OnInitExprI32ConstExpr(Index 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(Index index, const void* src_data, Address size) { Section* sec = current_section_; DataSegment& segment = sec->data.data_segments->back(); segment.data = static_cast(src_data); segment.size = size; return Result::Ok; } Result BinaryReaderLinker::OnExport(Index index, ExternalKind kind, Index item_index, string_view name) { if (kind == ExternalKind::Memory) { WABT_FATAL("Linker does not support exported memories"); } binary_->exports.emplace_back(); Export* export_ = &binary_->exports.back(); export_->name = name.to_string(); export_->kind = kind; export_->index = item_index; return Result::Ok; } Result BinaryReaderLinker::BeginNamesSection(Offset size) { binary_->debug_names.resize(binary_->function_count + binary_->function_imports.size()); return Result::Ok; } Result BinaryReaderLinker::OnFunctionName(Index index, string_view name) { binary_->debug_names[index] = name.to_string(); return Result::Ok; } } // end anonymous namespace Result ReadBinaryLinker(LinkerInputBinary* input_info, LinkOptions* options) { BinaryReaderLinker reader(input_info); ReadBinaryOptions read_options; read_options.read_debug_names = true; read_options.log_stream = options->log_stream; return ReadBinary(input_info->data.data(), input_info->data.size(), &reader, &read_options); } } // namespace link } // namespace wabt