blob: 52a19adb0f4ce2973f184ca9b6fb64af5304d108 [file] [log] [blame]
/*
* 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