diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binary-reader-linker.cc | 301 | ||||
-rw-r--r-- | src/binary-reader-linker.h | 40 | ||||
-rw-r--r-- | src/tools/wasm-link.cc | 849 | ||||
-rw-r--r-- | src/tools/wast2json.cc | 2 | ||||
-rw-r--r-- | src/tools/wat2wasm.cc | 2 | ||||
-rw-r--r-- | src/wasm-link.h | 135 |
6 files changed, 2 insertions, 1327 deletions
diff --git a/src/binary-reader-linker.cc b/src/binary-reader-linker.cc deleted file mode 100644 index a0c63882..00000000 --- a/src/binary-reader-linker.cc +++ /dev/null @@ -1,301 +0,0 @@ -/* - * 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 <vector> - -#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>& 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, - 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<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(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<const uint8_t*>(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 diff --git a/src/binary-reader-linker.h b/src/binary-reader-linker.h deleted file mode 100644 index 79b43878..00000000 --- a/src/binary-reader-linker.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 WABT_BINARY_READER_LINKER_H_ -#define WABT_BINARY_READER_LINKER_H_ - -#include "src/common.h" -#include "src/stream.h" - -namespace wabt { - -class Stream; - -namespace link { - -class LinkerInputBinary; - -struct LinkOptions { - Stream* log_stream; -}; - -Result ReadBinaryLinker(LinkerInputBinary* input_info, LinkOptions* options); - -} // namespace link -} // namespace wabt - -#endif /* WABT_BINARY_READER_LINKER_H_ */ diff --git a/src/tools/wasm-link.cc b/src/tools/wasm-link.cc deleted file mode 100644 index cafa0d23..00000000 --- a/src/tools/wasm-link.cc +++ /dev/null @@ -1,849 +0,0 @@ -/* - * Copyright 2016 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/wasm-link.h" - -#include <memory> -#include <vector> - -#include "src/binary-reader.h" -#include "src/binding-hash.h" -#include "src/binary-writer.h" -#include "src/leb128.h" -#include "src/option-parser.h" -#include "src/stream.h" -#include "src/binary-reader-linker.h" - -#define FIRST_KNOWN_SECTION static_cast<size_t>(BinarySection::Type) -#define LOG_DEBUG(fmt, ...) if (s_debug) s_log_stream->Writef(fmt, __VA_ARGS__); - -using namespace wabt; -using namespace wabt::link; - -static const char s_description[] = -R"( link one or more wasm binary modules into a single binary module. - $ wasm-link m1.wasm m2.wasm -o out.wasm -)"; - -static bool s_debug; -static bool s_relocatable; -static const char* s_outfile = "a.wasm"; -static std::vector<std::string> s_infiles; -static std::unique_ptr<FileStream> s_log_stream; - -static void ParseOptions(int argc, char** argv) { - OptionParser parser("wasm-link", s_description); - - parser.AddOption("debug", - "Log extra information when reading and writing wasm files", - []() { - s_debug = true; - s_log_stream = FileStream::CreateStdout(); - }); - parser.AddOption('o', "output", "FILE", "Output wasm binary file", - [](const char* argument) { s_outfile = argument; }); - parser.AddOption('r', "relocatable", "Output a relocatable object file", - []() { s_relocatable = true; }); - parser.AddHelpOption(); - - parser.AddArgument( - "filename", OptionParser::ArgumentCount::OneOrMore, - [](const std::string& argument) { s_infiles.emplace_back(argument); }); - - parser.Parse(argc, argv); -} - -Section::Section() - : binary(nullptr), - section_code(BinarySection::Invalid), - size(0), - offset(0), - payload_size(0), - payload_offset(0), - count(0), - output_payload_offset(0) { - ZeroMemory(data); -} - -Section::~Section() { - if (section_code == BinarySection::Data) { - delete data.data_segments; - } -} - -LinkerInputBinary::LinkerInputBinary(const char* filename, - const std::vector<uint8_t>& data) - : filename(filename), - data(data), - active_function_imports(0), - active_global_imports(0), - type_index_offset(0), - function_index_offset(0), - imported_function_index_offset(0), - table_index_offset(0), - memory_page_count(0), - memory_page_offset(0), - table_elem_count(0) {} - -bool LinkerInputBinary::IsFunctionImport(Index index) { - assert(IsValidFunctionIndex(index)); - return index < function_imports.size(); -} - -bool LinkerInputBinary::IsInactiveFunctionImport(Index index){ - return IsFunctionImport(index) && !function_imports[index].active; -} - -bool LinkerInputBinary::IsValidFunctionIndex(Index index) { - return index < function_imports.size() + function_count; -} - -Index LinkerInputBinary::RelocateFuncIndex(Index function_index) { - Index offset; - if (!IsFunctionImport(function_index)) { - // locally declared function call. - offset = function_index_offset; - LOG_DEBUG("func reloc %d + %d\n", function_index, offset); - } else { - // imported function call. - FunctionImport* import = &function_imports[function_index]; - if (!import->active) { - function_index = import->foreign_index; - offset = import->foreign_binary->function_index_offset; - LOG_DEBUG("reloc for disabled import. new index = %d + %d\n", - function_index, offset); - } else { - Index new_index = import->relocated_function_index; - LOG_DEBUG("reloc for active import. old index = %d, new index = %d\n", - function_index, new_index); - return new_index; - } - } - return function_index + offset; -} - -Index LinkerInputBinary::RelocateTypeIndex(Index type_index) { - return type_index + type_index_offset; -} - -Index LinkerInputBinary::RelocateGlobalIndex(Index global_index) { - Index offset; - if (global_index >= global_imports.size()) { - offset = global_index_offset; - } else { - offset = imported_global_index_offset; - } - return global_index + offset; -} - -static void ApplyRelocation(const Section* section, const Reloc* r) { - LinkerInputBinary* binary = section->binary; - uint8_t* section_data = &binary->data[section->offset]; - size_t section_size = section->size; - - Index cur_value = 0, new_value = 0; - ReadU32Leb128(section_data + r->offset, section_data + section_size, - &cur_value); - - switch (r->type) { - case RelocType::FuncIndexLEB: - new_value = binary->RelocateFuncIndex(cur_value); - break; - case RelocType::TypeIndexLEB: - new_value = binary->RelocateTypeIndex(cur_value); - break; - case RelocType::TableIndexSLEB: - new_value = cur_value + binary->table_index_offset; - break; - case RelocType::GlobalIndexLEB: - new_value = binary->RelocateGlobalIndex(cur_value); - break; - case RelocType::TableIndexI32: - case RelocType::MemoryAddressLEB: - case RelocType::MemoryAddressSLEB: - case RelocType::MemoryAddressI32: - WABT_FATAL("unhandled relocation type: %s\n", GetRelocTypeName(r->type)); - } - - WriteFixedU32Leb128Raw(section_data + r->offset, section_data + section_size, - new_value); -} - -static void ApplyRelocations(const Section* section) { - if (!section->relocations.size()) { - return; - } - - LOG_DEBUG("ApplyRelocations: %s\n", GetSectionName(section->section_code)); - - // Perform relocations in-place. - for (const Reloc& reloc: section->relocations) { - ApplyRelocation(section, &reloc); - } -} - -class Linker { - public: - WABT_DISALLOW_COPY_AND_ASSIGN(Linker); - Linker() = default; - - void AppendBinary(LinkerInputBinary* binary) { inputs_.emplace_back(binary); } - Result PerformLink(); - - private: - typedef std::pair<Offset, Offset> Fixup; - Fixup WriteUnknownSize(); - void FixupSize(Fixup); - - void WriteSectionPayload(Section* sec); - void WriteTableSection(const SectionPtrVector& sections); - void WriteExportSection(); - void WriteElemSection(const SectionPtrVector& sections); - void WriteMemorySection(const SectionPtrVector& sections); - void WriteFunctionImport(const FunctionImport& import, Index offset); - void WriteGlobalImport(const GlobalImport& import); - void WriteImportSection(); - void WriteFunctionSection(const SectionPtrVector& sections, - Index total_count); - void WriteDataSegment(const DataSegment& segment, Address offset); - void WriteDataSection(const SectionPtrVector& sections, Index total_count); - void WriteNamesSection(); - void WriteLinkingSection(uint32_t data_size, uint32_t data_alignment); - void WriteRelocSection(BinarySection section_code, - const SectionPtrVector& sections); - bool WriteCombinedSection(BinarySection section_code, - const SectionPtrVector& sections); - void ResolveSymbols(); - void CalculateRelocOffsets(); - void WriteBinary(); - void DumpRelocOffsets(); - - MemoryStream stream_; - std::vector<std::unique_ptr<LinkerInputBinary>> inputs_; - ssize_t current_section_payload_offset_ = 0; -}; - -void Linker::WriteSectionPayload(Section* sec) { - assert(current_section_payload_offset_ != -1); - - sec->output_payload_offset = - stream_.offset() - current_section_payload_offset_; - - uint8_t* payload = &sec->binary->data[sec->payload_offset]; - stream_.WriteData(payload, sec->payload_size, "section content"); -} - -Linker::Fixup Linker::WriteUnknownSize() { - Offset fixup_offset = stream_.offset(); - WriteFixedU32Leb128(&stream_, 0, "unknown size"); - current_section_payload_offset_ = stream_.offset(); - return std::make_pair(fixup_offset, current_section_payload_offset_); -} - -void Linker::FixupSize(Fixup fixup) { - WriteFixedU32Leb128At(&stream_, fixup.first, stream_.offset() - fixup.second, - "fixup size"); -} - -void Linker::WriteTableSection(const SectionPtrVector& sections) { - // Total section size includes the element count leb128 which is always 1 in - // the current spec. - Index table_count = 1; - uint32_t flags = WABT_BINARY_LIMITS_HAS_MAX_FLAG; - Index elem_count = 0; - - for (Section* section: sections) { - elem_count += section->binary->table_elem_count; - } - - Fixup fixup = WriteUnknownSize(); - WriteU32Leb128(&stream_, table_count, "table count"); - WriteType(&stream_, Type::Anyfunc); - WriteU32Leb128(&stream_, flags, "table elem flags"); - WriteU32Leb128(&stream_, elem_count, "table initial length"); - WriteU32Leb128(&stream_, elem_count, "table max length"); - FixupSize(fixup); -} - -void Linker::WriteExportSection() { - Index total_exports = 0; - for (const std::unique_ptr<LinkerInputBinary>& binary : inputs_) { - total_exports += binary->exports.size(); - } - - Fixup fixup = WriteUnknownSize(); - WriteU32Leb128(&stream_, total_exports, "export count"); - - for (const std::unique_ptr<LinkerInputBinary>& binary : inputs_) { - for (const Export& export_ : binary->exports) { - WriteStr(&stream_, export_.name, "export name"); - stream_.WriteU8Enum(export_.kind, "export kind"); - Index index = export_.index; - switch (export_.kind) { - case ExternalKind::Func: - index = binary->RelocateFuncIndex(index); - break; - default: - WABT_FATAL("unsupport export type: %d\n", - static_cast<int>(export_.kind)); - break; - } - WriteU32Leb128(&stream_, index, "export index"); - } - } - - FixupSize(fixup); -} - -void Linker::WriteElemSection(const SectionPtrVector& sections) { - Fixup fixup = WriteUnknownSize(); - - Index total_elem_count = 0; - for (Section* section : sections) { - total_elem_count += section->binary->table_elem_count; - } - - WriteU32Leb128(&stream_, 1, "segment count"); - WriteU32Leb128(&stream_, 0, "table index"); - WriteOpcode(&stream_, Opcode::I32Const); - WriteS32Leb128(&stream_, 0U, "elem init literal"); - WriteOpcode(&stream_, Opcode::End); - WriteU32Leb128(&stream_, total_elem_count, "num elements"); - - current_section_payload_offset_ = stream_.offset(); - - for (Section* section : sections) { - ApplyRelocations(section); - WriteSectionPayload(section); - } - - FixupSize(fixup); -} - -void Linker::WriteMemorySection(const SectionPtrVector& sections) { - Fixup fixup = WriteUnknownSize(); - - WriteU32Leb128(&stream_, 1, "memory count"); - - Limits limits; - limits.has_max = true; - for (Section* section: sections) { - limits.initial += section->data.initial; - } - limits.max = limits.initial; - WriteLimits(&stream_, &limits); - - FixupSize(fixup); -} - -void Linker::WriteFunctionImport(const FunctionImport& import, Index offset) { - WriteStr(&stream_, import.module_name, "import module name"); - WriteStr(&stream_, import.name, "import field name"); - stream_.WriteU8Enum(ExternalKind::Func, "import kind"); - WriteU32Leb128(&stream_, import.sig_index + offset, "import signature index"); -} - -void Linker::WriteGlobalImport(const GlobalImport& import) { - WriteStr(&stream_, import.module_name, "import module name"); - WriteStr(&stream_, import.name, "import field name"); - stream_.WriteU8Enum(ExternalKind::Global, "import kind"); - WriteType(&stream_, import.type); - stream_.WriteU8(import.mutable_, "global mutability"); -} - -void Linker::WriteImportSection() { - Index num_imports = 0; - for (const std::unique_ptr<LinkerInputBinary>& binary: inputs_) { - for (const FunctionImport& import : binary->function_imports) { - if (import.active) { - num_imports++; - } - } - num_imports += binary->global_imports.size(); - } - - Fixup fixup = WriteUnknownSize(); - WriteU32Leb128(&stream_, num_imports, "num imports"); - - for (const std::unique_ptr<LinkerInputBinary>& binary: inputs_) { - for (const FunctionImport& function_import : binary->function_imports) { - if (function_import.active) { - WriteFunctionImport(function_import, binary->type_index_offset); - } - } - - for (const GlobalImport& global_import : binary->global_imports) { - WriteGlobalImport(global_import); - } - } - - FixupSize(fixup); -} - -void Linker::WriteFunctionSection(const SectionPtrVector& sections, - Index total_count) { - Fixup fixup = WriteUnknownSize(); - - WriteU32Leb128(&stream_, total_count, "function count"); - - for (Section* sec: sections) { - Index count = sec->count; - Offset input_offset = 0; - Index sig_index = 0; - const uint8_t* start = &sec->binary->data[sec->payload_offset]; - const uint8_t* end = - &sec->binary->data[sec->payload_offset + sec->payload_size]; - while (count--) { - input_offset += ReadU32Leb128(start + input_offset, end, &sig_index); - WriteU32Leb128(&stream_, sec->binary->RelocateTypeIndex(sig_index), - "sig"); - } - } - - FixupSize(fixup); -} - -void Linker::WriteDataSegment(const DataSegment& segment, Address offset) { - assert(segment.memory_index == 0); - WriteU32Leb128(&stream_, segment.memory_index, "memory index"); - WriteOpcode(&stream_, Opcode::I32Const); - WriteU32Leb128(&stream_, segment.offset + offset, "offset"); - WriteOpcode(&stream_, Opcode::End); - WriteU32Leb128(&stream_, segment.size, "segment size"); - stream_.WriteData(segment.data, segment.size, "segment data"); -} - -void Linker::WriteDataSection(const SectionPtrVector& sections, - Index total_count) { - Fixup fixup = WriteUnknownSize(); - - WriteU32Leb128(&stream_, total_count, "data segment count"); - for (const Section* sec: sections) { - for (const DataSegment& segment: *sec->data.data_segments) { - WriteDataSegment(segment, - sec->binary->memory_page_offset * WABT_PAGE_SIZE); - } - } - - FixupSize(fixup); -} - -void Linker::WriteNamesSection() { - Index total_count = 0; - for (const std::unique_ptr<LinkerInputBinary>& binary : inputs_) { - for (size_t i = 0; i < binary->debug_names.size(); i++) { - if (binary->debug_names[i].empty()) { - continue; - } - if (binary->IsInactiveFunctionImport(i)) { - continue; - } - total_count++; - } - } - - if (!total_count) { - return; - } - - stream_.WriteU8Enum(BinarySection::Custom, "section code"); - Fixup fixup_section = WriteUnknownSize(); - WriteStr(&stream_, "name", "custom section name"); - - stream_.WriteU8Enum(NameSectionSubsection::Function, "subsection code"); - Fixup fixup_subsection = WriteUnknownSize(); - WriteU32Leb128(&stream_, total_count, "element count"); - - // Write import names. - for (const std::unique_ptr<LinkerInputBinary>& binary : inputs_) { - for (size_t i = 0; i < binary->debug_names.size(); i++) { - if (binary->debug_names[i].empty() || !binary->IsFunctionImport(i)) { - continue; - } - if (binary->IsInactiveFunctionImport(i)) { - continue; - } - WriteU32Leb128(&stream_, binary->RelocateFuncIndex(i), "function index"); - WriteStr(&stream_, binary->debug_names[i], "function name"); - } - } - - // Write non-import names. - for (const std::unique_ptr<LinkerInputBinary>& binary : inputs_) { - for (size_t i = 0; i < binary->debug_names.size(); i++) { - if (binary->debug_names[i].empty() || binary->IsFunctionImport(i)) { - continue; - } - WriteU32Leb128(&stream_, binary->RelocateFuncIndex(i), "function index"); - WriteStr(&stream_, binary->debug_names[i], "function name"); - } - } - - FixupSize(fixup_subsection); - FixupSize(fixup_section); -} - -void Linker::WriteLinkingSection(uint32_t data_size, uint32_t data_alignment) { - stream_.WriteU8Enum(BinarySection::Custom, "section code"); - Fixup fixup = WriteUnknownSize(); - - WriteStr(&stream_, "linking", "linking section name"); - - if (data_size) { - WriteU32Leb128(&stream_, LinkingEntryType::DataSize, "subsection code"); - Fixup fixup_subsection = WriteUnknownSize(); - WriteU32Leb128(&stream_, data_size, "data size"); - FixupSize(fixup_subsection); - } - - FixupSize(fixup); -} - -void Linker::WriteRelocSection(BinarySection section_code, - const SectionPtrVector& sections) { - Index total_relocs = 0; - - // First pass to know total reloc count. - for (Section* sec: sections) - total_relocs += sec->relocations.size(); - - if (!total_relocs) { - return; - } - - std::string section_name = StringPrintf("%s.%s", WABT_BINARY_SECTION_RELOC, - GetSectionName(section_code)); - - stream_.WriteU8Enum(BinarySection::Custom, "section code"); - Fixup fixup = WriteUnknownSize(); - WriteStr(&stream_, section_name, "reloc section name"); - WriteU32Leb128(&stream_, section_code, "reloc section"); - WriteU32Leb128(&stream_, total_relocs, "num relocs"); - - for (Section* sec: sections) { - for (const Reloc& reloc: sec->relocations) { - WriteU32Leb128(&stream_, reloc.type, "reloc type"); - Offset new_offset = reloc.offset + sec->output_payload_offset; - WriteU32Leb128(&stream_, new_offset, "reloc offset"); - Index relocated_index = 0; - switch (reloc.type) { - case RelocType::FuncIndexLEB: - relocated_index = sec->binary->RelocateFuncIndex(reloc.index); - break; - case RelocType::TypeIndexLEB: - relocated_index = sec->binary->RelocateTypeIndex(reloc.index); - break; - case RelocType::GlobalIndexLEB: - relocated_index = sec->binary->RelocateGlobalIndex(reloc.index); - break; - case RelocType::MemoryAddressLEB: - case RelocType::MemoryAddressSLEB: - case RelocType::MemoryAddressI32: - case RelocType::TableIndexSLEB: - case RelocType::TableIndexI32: - WABT_FATAL("Unhandled reloc type: %s\n", - GetRelocTypeName(reloc.type)); - } - WriteU32Leb128(&stream_, relocated_index, "reloc index"); - } - } - - FixupSize(fixup); -} - -bool Linker::WriteCombinedSection(BinarySection section_code, - const SectionPtrVector& sections) { - if (!sections.size()) { - return false; - } - - if (section_code == BinarySection::Start && sections.size() > 1) { - WABT_FATAL("Don't know how to combine sections of type: %s\n", - GetSectionName(section_code)); - } - - Index total_count = 0; - Index total_size = 0; - - // Sum section size and element count. - for (Section* sec : sections) { - total_size += sec->payload_size; - total_count += sec->count; - } - - stream_.WriteU8Enum(section_code, "section code"); - current_section_payload_offset_ = -1; - - switch (section_code) { - case BinarySection::Import: - WriteImportSection(); - break; - case BinarySection::Function: - WriteFunctionSection(sections, total_count); - break; - case BinarySection::Table: - WriteTableSection(sections); - break; - case BinarySection::Export: - WriteExportSection(); - break; - case BinarySection::Elem: - WriteElemSection(sections); - break; - case BinarySection::Memory: - WriteMemorySection(sections); - break; - case BinarySection::Data: - WriteDataSection(sections, total_count); - break; - default: { - // Total section size includes the element count leb128. - total_size += U32Leb128Length(total_count); - - // Write section to stream. - WriteU32Leb128(&stream_, total_size, "section size"); - WriteU32Leb128(&stream_, total_count, "element count"); - current_section_payload_offset_ = stream_.offset(); - for (Section* sec : sections) { - ApplyRelocations(sec); - WriteSectionPayload(sec); - } - } - } - - return true; -} - -struct ExportInfo { - ExportInfo(const Export* export_, LinkerInputBinary* binary) - : export_(export_), binary(binary) {} - - const Export* export_; - LinkerInputBinary* binary; -}; - -void Linker::ResolveSymbols() { - // Create hashmap of all exported symbols from all inputs. - BindingHash export_map; - std::vector<ExportInfo> export_list; - - for (const std::unique_ptr<LinkerInputBinary>& binary: inputs_) { - for (const Export& export_ : binary->exports) { - export_list.emplace_back(&export_, binary.get()); - - // TODO(sbc): Handle duplicate names. - export_map.emplace(export_.name, Binding(export_list.size() - 1)); - } - } - - // Iterate through all imported functions resolving them against exported - // ones. - for (std::unique_ptr<LinkerInputBinary>& binary: inputs_) { - for (FunctionImport& import: binary->function_imports) { - Index export_index = export_map.FindIndex(import.name); - if (export_index == kInvalidIndex) { - if (!s_relocatable) { - WABT_FATAL("undefined symbol: %s\n", import.name.c_str()); - } - continue; - } - - // We found the symbol exported by another module. - const ExportInfo& export_info = export_list[export_index]; - - // TODO(sbc): verify the foriegn function has the correct signature. - import.active = false; - import.foreign_binary = export_info.binary; - import.foreign_index = export_info.export_->index; - binary->active_function_imports--; - } - } -} - -void Linker::CalculateRelocOffsets() { - Index memory_page_offset = 0; - Index type_count = 0; - Index global_count = 0; - Index function_count = 0; - Index table_elem_count = 0; - Index total_function_imports = 0; - Index total_global_imports = 0; - - for (std::unique_ptr<LinkerInputBinary>& binary : inputs_) { - // 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 = total_function_imports; - binary->imported_global_index_offset = total_global_imports; - binary->memory_page_offset = memory_page_offset; - - size_t delta = 0; - for (size_t i = 0; i < binary->function_imports.size(); i++) { - if (!binary->function_imports[i].active) { - delta++; - } else { - binary->function_imports[i].relocated_function_index = - total_function_imports + i - delta; - } - } - - memory_page_offset += binary->memory_page_count; - total_function_imports += binary->active_function_imports; - total_global_imports += binary->global_imports.size(); - } - - for (std::unique_ptr<LinkerInputBinary>& binary : inputs_) { - binary->table_index_offset = table_elem_count; - table_elem_count += binary->table_elem_count; - for (std::unique_ptr<Section>& sec : binary->sections) { - switch (sec->section_code) { - case BinarySection::Type: - binary->type_index_offset = type_count; - type_count += sec->count; - break; - case BinarySection::Global: - binary->global_index_offset = total_global_imports - - sec->binary->global_imports.size() + - global_count; - global_count += sec->count; - break; - case BinarySection::Function: - binary->function_index_offset = total_function_imports - - sec->binary->function_imports.size() + - function_count; - function_count += sec->count; - break; - default: - break; - } - } - } -} - -void Linker::WriteBinary() { - // Find all the sections of each type. - SectionPtrVector sections[kBinarySectionCount]; - - for (std::unique_ptr<LinkerInputBinary>& binary : inputs_) { - for (std::unique_ptr<Section>& sec : binary->sections) { - SectionPtrVector& sec_list = - sections[static_cast<int>(sec->section_code)]; - sec_list.push_back(sec.get()); - } - } - - // Write the final binary. - stream_.WriteU32(WABT_BINARY_MAGIC, "WABT_BINARY_MAGIC"); - stream_.WriteU32(WABT_BINARY_VERSION, "WABT_BINARY_VERSION"); - - // Write known sections first. - for (size_t i = FIRST_KNOWN_SECTION; i < kBinarySectionCount; i++) { - WriteCombinedSection(static_cast<BinarySection>(i), sections[i]); - } - - WriteNamesSection(); - - /* Generate a new set of reloction sections */ - if (s_relocatable) { - WriteLinkingSection(0, 0); - for (size_t i = FIRST_KNOWN_SECTION; i < kBinarySectionCount; i++) { - WriteRelocSection(static_cast<BinarySection>(i), sections[i]); - } - } -} - -void Linker::DumpRelocOffsets() { - if (s_debug) { - for (const std::unique_ptr<LinkerInputBinary>& binary : inputs_) { - LOG_DEBUG("Relocation info for: %s\n", binary->filename); - LOG_DEBUG(" - type index offset : %d\n", binary->type_index_offset); - LOG_DEBUG(" - mem page offset : %d\n", - binary->memory_page_offset); - LOG_DEBUG(" - function index offset : %d\n", - binary->function_index_offset); - LOG_DEBUG(" - global index offset : %d\n", - binary->global_index_offset); - LOG_DEBUG(" - imported function offset: %d\n", - binary->imported_function_index_offset); - LOG_DEBUG(" - imported global offset : %d\n", - binary->imported_global_index_offset); - } - } -} - -Result Linker::PerformLink() { - if (s_debug) { - stream_.set_log_stream(s_log_stream.get()); - } - - LOG_DEBUG("writing file: %s\n", s_outfile); - CalculateRelocOffsets(); - ResolveSymbols(); - CalculateRelocOffsets(); - DumpRelocOffsets(); - WriteBinary(); - - if (Failed(stream_.WriteToFile(s_outfile))) { - WABT_FATAL("error writing linked output to file\n"); - } - - return Result::Ok; -} - -int ProgramMain(int argc, char** argv) { - InitStdio(); - - Linker linker; - - printf(R"( -****************************************************************** -WARNING: wasm-link is deprecated. Where possible, use lld instead. -****************************************************************** -)"); - - ParseOptions(argc, argv); - - Result result = Result::Ok; - for (const std::string& input_filename: s_infiles) { - LOG_DEBUG("reading file: %s\n", input_filename.c_str()); - std::vector<uint8_t> file_data; - result = ReadFile(input_filename.c_str(), &file_data); - if (Failed(result)) { - return result != Result::Ok; - } - - auto binary = new LinkerInputBinary(input_filename.c_str(), file_data); - linker.AppendBinary(binary); - - LinkOptions options = { NULL }; - if (s_debug) { - options.log_stream = s_log_stream.get(); - } - result = ReadBinaryLinker(binary, &options); - if (Failed(result)) { - WABT_FATAL("error parsing file: %s\n", input_filename.c_str()); - } - } - - result = linker.PerformLink(); - return result != Result::Ok; -} - -int main(int argc, char** argv) { - WABT_TRY - return ProgramMain(argc, argv); - WABT_CATCH_BAD_ALLOC_AND_EXIT -} diff --git a/src/tools/wast2json.cc b/src/tools/wast2json.cc index 21c62f9d..aa200136 100644 --- a/src/tools/wast2json.cc +++ b/src/tools/wast2json.cc @@ -73,7 +73,7 @@ static void ParseOptions(int argc, char* argv[]) { [](const char* argument) { s_outfile = argument; }); parser.AddOption( 'r', "relocatable", - "Create a relocatable wasm binary (suitable for linking with wasm-link)", + "Create a relocatable wasm binary (suitable for linking with e.g. lld)", []() { s_write_binary_options.relocatable = true; }); parser.AddOption( "no-canonicalize-leb128s", diff --git a/src/tools/wat2wasm.cc b/src/tools/wat2wasm.cc index 2f376e63..0268011f 100644 --- a/src/tools/wat2wasm.cc +++ b/src/tools/wat2wasm.cc @@ -82,7 +82,7 @@ static void ParseOptions(int argc, char* argv[]) { [](const char* argument) { s_outfile = argument; }); parser.AddOption( 'r', "relocatable", - "Create a relocatable wasm binary (suitable for linking with wasm-link)", + "Create a relocatable wasm binary (suitable for linking with e.g. lld)", []() { s_write_binary_options.relocatable = true; }); parser.AddOption( "no-canonicalize-leb128s", diff --git a/src/wasm-link.h b/src/wasm-link.h deleted file mode 100644 index f3467cee..00000000 --- a/src/wasm-link.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * 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 WABT_LINK_H_ -#define WABT_LINK_H_ - -#include <memory> -#include <vector> - -#include "src/binary.h" -#include "src/common.h" - -namespace wabt { -namespace link { - -class LinkerInputBinary; - -struct FunctionImport { - std::string module_name; - std::string name; - Index sig_index; - bool active; /* Is this import present in the linked binary */ - Index relocated_function_index; - LinkerInputBinary* foreign_binary; - Index foreign_index; -}; - -struct GlobalImport { - std::string module_name; - std::string name; - Type type; - bool mutable_; -}; - -struct DataSegment { - Index memory_index; - Address offset; - const uint8_t* data; - size_t size; -}; - -struct Export { - ExternalKind kind; - std::string name; - Index index; -}; - -struct Section { - WABT_DISALLOW_COPY_AND_ASSIGN(Section); - Section(); - ~Section(); - - /* The binary to which this section belongs */ - LinkerInputBinary* binary; - std::vector<Reloc> relocations; /* The relocations for this section */ - - BinarySection 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 */ - Index count; - - union { - /* DATA section data */ - std::vector<DataSegment>* data_segments; - /* MEMORY section data */ - uint64_t initial; - } data; - - /* The offset at which this section appears within the combined output - * section. */ - size_t output_payload_offset; -}; - -typedef std::vector<Section*> SectionPtrVector; - -class LinkerInputBinary { - public: - WABT_DISALLOW_COPY_AND_ASSIGN(LinkerInputBinary); - LinkerInputBinary(const char* filename, const std::vector<uint8_t>& data); - - Index RelocateFuncIndex(Index findex); - Index RelocateTypeIndex(Index index); - Index RelocateGlobalIndex(Index index); - - bool IsValidFunctionIndex(Index index); - bool IsFunctionImport(Index index); - bool IsInactiveFunctionImport(Index index); - - const char* filename; - std::vector<uint8_t> data; - std::vector<std::unique_ptr<Section>> sections; - std::vector<Export> exports; - - std::vector<FunctionImport> function_imports; - Index active_function_imports; - std::vector<GlobalImport> global_imports; - Index active_global_imports; - - Index type_index_offset; - Index function_index_offset; - Index imported_function_index_offset; - Index global_index_offset; - Index imported_global_index_offset; - Index table_index_offset; - Index memory_page_count; - Index memory_page_offset; - - Index table_elem_count = 0; - Index function_count = 0; - - std::vector<std::string> debug_names; -}; - -} // namespace link -} // namespace wabt - -#endif /* WABT_LINK_H_ */ |