llvm-capstone/lld/wasm/WriterUtils.cpp
Sam Clegg b862159683 [WebAssembly] Allow function signature checking at link time
This change allows checking of function signatures but
does not yes enable it by default.  In this mode, linking
two objects that were compiled with a different signatures
for the same function will produce a link error.

New options for enabling and disabling this feature have been
added: (--check-signatures/--no-check-signatures).

Differential Revision: https://reviews.llvm.org/D40371

llvm-svn: 319396
2017-11-30 01:40:08 +00:00

216 lines
6.2 KiB
C++

//===- WriterUtils.cpp ----------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "WriterUtils.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/LEB128.h"
#define DEBUG_TYPE "lld"
using namespace llvm;
using namespace llvm::wasm;
using namespace lld::wasm;
static const char *valueTypeToString(int32_t Type) {
switch (Type) {
case WASM_TYPE_I32:
return "i32";
case WASM_TYPE_I64:
return "i64";
case WASM_TYPE_F32:
return "f32";
case WASM_TYPE_F64:
return "f64";
default:
llvm_unreachable("invalid value type");
}
}
namespace lld {
void wasm::debugWrite(uint64_t offset, Twine msg) {
DEBUG(dbgs() << format(" | %08" PRIx64 ": ", offset) << msg << "\n");
}
void wasm::writeUleb128(raw_ostream &OS, uint32_t Number, const char *msg) {
if (msg)
debugWrite(OS.tell(), msg + formatv(" [{0:x}]", Number));
encodeULEB128(Number, OS);
}
void wasm::writeSleb128(raw_ostream &OS, int32_t Number, const char *msg) {
if (msg)
debugWrite(OS.tell(), msg + formatv(" [{0:x}]", Number));
encodeSLEB128(Number, OS);
}
void wasm::writeBytes(raw_ostream &OS, const char *bytes, size_t count,
const char *msg) {
if (msg)
debugWrite(OS.tell(), msg + formatv(" [data[{0}]]", count));
OS.write(bytes, count);
}
void wasm::writeStr(raw_ostream &OS, const StringRef String, const char *msg) {
if (msg)
debugWrite(OS.tell(),
msg + formatv(" [str[{0}]: {1}]", String.size(), String));
writeUleb128(OS, String.size(), nullptr);
writeBytes(OS, String.data(), String.size());
}
void wasm::writeU8(raw_ostream &OS, uint8_t byte, const char *msg) {
OS << byte;
}
void wasm::writeU32(raw_ostream &OS, uint32_t Number, const char *msg) {
debugWrite(OS.tell(), msg + formatv("[{0:x}]", Number));
support::endian::Writer<support::little>(OS).write(Number);
}
void wasm::writeValueType(raw_ostream &OS, int32_t Type, const char *msg) {
debugWrite(OS.tell(), msg + formatv("[type: {0}]", valueTypeToString(Type)));
writeSleb128(OS, Type, nullptr);
}
void wasm::writeSig(raw_ostream &OS, const WasmSignature &Sig) {
writeSleb128(OS, WASM_TYPE_FUNC, "signature type");
writeUleb128(OS, Sig.ParamTypes.size(), "param count");
for (int32_t ParamType : Sig.ParamTypes) {
writeValueType(OS, ParamType, "param type");
}
if (Sig.ReturnType == WASM_TYPE_NORESULT) {
writeUleb128(OS, 0, "result count");
} else {
writeUleb128(OS, 1, "result count");
writeValueType(OS, Sig.ReturnType, "result type");
}
}
void wasm::writeInitExpr(raw_ostream &OS, const WasmInitExpr &InitExpr) {
writeU8(OS, InitExpr.Opcode, "opcode");
switch (InitExpr.Opcode) {
case WASM_OPCODE_I32_CONST:
writeSleb128(OS, InitExpr.Value.Int32, "literal (i32)");
break;
case WASM_OPCODE_I64_CONST:
writeSleb128(OS, InitExpr.Value.Int64, "literal (i64)");
break;
case WASM_OPCODE_GET_GLOBAL:
writeUleb128(OS, InitExpr.Value.Global, "literal (global index)");
break;
default:
fatal("unknown opcode in init expr: " + Twine(InitExpr.Opcode));
}
writeU8(OS, WASM_OPCODE_END, "opcode:end");
}
void wasm::writeLimits(raw_ostream &OS, const WasmLimits &Limits) {
writeUleb128(OS, Limits.Flags, "limits flags");
writeUleb128(OS, Limits.Initial, "limits initial");
if (Limits.Flags & WASM_LIMITS_FLAG_HAS_MAX)
writeUleb128(OS, Limits.Maximum, "limits max");
}
void wasm::writeGlobal(raw_ostream &OS, const WasmGlobal &Global) {
writeValueType(OS, Global.Type, "global type");
writeUleb128(OS, Global.Mutable, "global mutable");
writeInitExpr(OS, Global.InitExpr);
}
void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) {
writeStr(OS, Import.Module, "import module name");
writeStr(OS, Import.Field, "import field name");
writeU8(OS, Import.Kind, "import kind");
switch (Import.Kind) {
case WASM_EXTERNAL_FUNCTION:
writeUleb128(OS, Import.SigIndex, "import sig index");
break;
case WASM_EXTERNAL_GLOBAL:
writeValueType(OS, Import.Global.Type, "import global type");
writeUleb128(OS, Import.Global.Mutable, "import global mutable");
break;
case WASM_EXTERNAL_MEMORY:
writeLimits(OS, Import.Memory);
break;
default:
fatal("unsupported import type: " + Twine(Import.Kind));
}
}
void wasm::writeExport(raw_ostream &OS, const WasmExport &Export) {
writeStr(OS, Export.Name, "export name");
writeU8(OS, Export.Kind, "export kind");
switch (Export.Kind) {
case WASM_EXTERNAL_FUNCTION:
writeUleb128(OS, Export.Index, "function index");
break;
case WASM_EXTERNAL_GLOBAL:
writeUleb128(OS, Export.Index, "global index");
break;
case WASM_EXTERNAL_MEMORY:
writeUleb128(OS, Export.Index, "memory index");
break;
default:
fatal("unsupported export type: " + Twine(Export.Kind));
}
}
void wasm::writeReloc(raw_ostream &OS, const OutputRelocation &Reloc) {
writeUleb128(OS, Reloc.Reloc.Type, "reloc type");
writeUleb128(OS, Reloc.Reloc.Offset, "reloc offset");
writeUleb128(OS, Reloc.NewIndex, "reloc index");
switch (Reloc.Reloc.Type) {
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
case R_WEBASSEMBLY_MEMORY_ADDR_I32:
writeUleb128(OS, Reloc.Reloc.Addend, "reloc addend");
break;
default:
break;
}
}
} // namespace lld
std::string lld::toString(ValType Type) {
switch (Type) {
case ValType::I32:
return "I32";
case ValType::I64:
return "I64";
case ValType::F32:
return "F32";
case ValType::F64:
return "F64";
}
llvm_unreachable("Invalid wasm::ValType");
}
std::string lld::toString(const WasmSignature &Sig) {
SmallString<128> S("(");
for (uint32_t Type : Sig.ParamTypes) {
if (S.size() != 1)
S += ", ";
S += toString(static_cast<ValType>(Type));
}
S += ") -> ";
if (Sig.ReturnType == WASM_TYPE_NORESULT)
S += "void";
else
S += toString(static_cast<ValType>(Sig.ReturnType));
return S.str();
}