1 //===- WriterUtils.cpp ----------------------------------------------------===// 2 // 3 // The LLVM Linker 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "WriterUtils.h" 11 #include "lld/Common/ErrorHandler.h" 12 #include "llvm/Support/Debug.h" 13 #include "llvm/Support/EndianStream.h" 14 #include "llvm/Support/LEB128.h" 15 16 #define DEBUG_TYPE "lld" 17 18 using namespace llvm; 19 using namespace llvm::wasm; 20 21 namespace lld { 22 23 void wasm::debugWrite(uint64_t Offset, const Twine &Msg) { 24 LLVM_DEBUG(dbgs() << format(" | %08lld: ", Offset) << Msg << "\n"); 25 } 26 27 void wasm::writeUleb128(raw_ostream &OS, uint32_t Number, const Twine &Msg) { 28 debugWrite(OS.tell(), Msg + "[" + utohexstr(Number) + "]"); 29 encodeULEB128(Number, OS); 30 } 31 32 void wasm::writeSleb128(raw_ostream &OS, int32_t Number, const Twine &Msg) { 33 debugWrite(OS.tell(), Msg + "[" + utohexstr(Number) + "]"); 34 encodeSLEB128(Number, OS); 35 } 36 37 void wasm::writeBytes(raw_ostream &OS, const char *Bytes, size_t Count, 38 const Twine &Msg) { 39 debugWrite(OS.tell(), Msg + " [data[" + Twine(Count) + "]]"); 40 OS.write(Bytes, Count); 41 } 42 43 void wasm::writeStr(raw_ostream &OS, StringRef String, const Twine &Msg) { 44 debugWrite(OS.tell(), 45 Msg + " [str[" + Twine(String.size()) + "]: " + String + "]"); 46 encodeULEB128(String.size(), OS); 47 OS.write(String.data(), String.size()); 48 } 49 50 void wasm::writeU8(raw_ostream &OS, uint8_t Byte, const Twine &Msg) { 51 debugWrite(OS.tell(), Msg + " [0x" + utohexstr(Byte) + "]"); 52 OS << Byte; 53 } 54 55 void wasm::writeU32(raw_ostream &OS, uint32_t Number, const Twine &Msg) { 56 debugWrite(OS.tell(), Msg + "[0x" + utohexstr(Number) + "]"); 57 support::endian::write(OS, Number, support::little); 58 } 59 60 void wasm::writeValueType(raw_ostream &OS, ValType Type, const Twine &Msg) { 61 writeU8(OS, static_cast<uint8_t>(Type), 62 Msg + "[type: " + toString(Type) + "]"); 63 } 64 65 void wasm::writeSig(raw_ostream &OS, const WasmSignature &Sig) { 66 writeU8(OS, WASM_TYPE_FUNC, "signature type"); 67 writeUleb128(OS, Sig.Params.size(), "param Count"); 68 for (ValType ParamType : Sig.Params) { 69 writeValueType(OS, ParamType, "param type"); 70 } 71 writeUleb128(OS, Sig.Returns.size(), "result Count"); 72 if (Sig.Returns.size()) { 73 writeValueType(OS, Sig.Returns[0], "result type"); 74 } 75 } 76 77 void wasm::writeInitExpr(raw_ostream &OS, const WasmInitExpr &InitExpr) { 78 writeU8(OS, InitExpr.Opcode, "opcode"); 79 switch (InitExpr.Opcode) { 80 case WASM_OPCODE_I32_CONST: 81 writeSleb128(OS, InitExpr.Value.Int32, "literal (i32)"); 82 break; 83 case WASM_OPCODE_I64_CONST: 84 writeSleb128(OS, InitExpr.Value.Int64, "literal (i64)"); 85 break; 86 case WASM_OPCODE_GET_GLOBAL: 87 writeUleb128(OS, InitExpr.Value.Global, "literal (global index)"); 88 break; 89 default: 90 fatal("unknown opcode in init expr: " + Twine(InitExpr.Opcode)); 91 } 92 writeU8(OS, WASM_OPCODE_END, "opcode:end"); 93 } 94 95 void wasm::writeLimits(raw_ostream &OS, const WasmLimits &Limits) { 96 writeU8(OS, Limits.Flags, "limits flags"); 97 writeUleb128(OS, Limits.Initial, "limits initial"); 98 if (Limits.Flags & WASM_LIMITS_FLAG_HAS_MAX) 99 writeUleb128(OS, Limits.Maximum, "limits max"); 100 } 101 102 void wasm::writeGlobalType(raw_ostream &OS, const WasmGlobalType &Type) { 103 // TODO: Update WasmGlobalType to use ValType and remove this cast. 104 writeValueType(OS, ValType(Type.Type), "global type"); 105 writeU8(OS, Type.Mutable, "global mutable"); 106 } 107 108 void wasm::writeGlobal(raw_ostream &OS, const WasmGlobal &Global) { 109 writeGlobalType(OS, Global.Type); 110 writeInitExpr(OS, Global.InitExpr); 111 } 112 113 void wasm::writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type) { 114 writeU8(OS, WASM_TYPE_ANYFUNC, "table type"); 115 writeLimits(OS, Type.Limits); 116 } 117 118 void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) { 119 writeStr(OS, Import.Module, "import module name"); 120 writeStr(OS, Import.Field, "import field name"); 121 writeU8(OS, Import.Kind, "import kind"); 122 switch (Import.Kind) { 123 case WASM_EXTERNAL_FUNCTION: 124 writeUleb128(OS, Import.SigIndex, "import sig index"); 125 break; 126 case WASM_EXTERNAL_GLOBAL: 127 writeGlobalType(OS, Import.Global); 128 break; 129 case WASM_EXTERNAL_MEMORY: 130 writeLimits(OS, Import.Memory); 131 break; 132 case WASM_EXTERNAL_TABLE: 133 writeTableType(OS, Import.Table); 134 break; 135 default: 136 fatal("unsupported import type: " + Twine(Import.Kind)); 137 } 138 } 139 140 void wasm::writeExport(raw_ostream &OS, const WasmExport &Export) { 141 writeStr(OS, Export.Name, "export name"); 142 writeU8(OS, Export.Kind, "export kind"); 143 switch (Export.Kind) { 144 case WASM_EXTERNAL_FUNCTION: 145 writeUleb128(OS, Export.Index, "function index"); 146 break; 147 case WASM_EXTERNAL_GLOBAL: 148 writeUleb128(OS, Export.Index, "global index"); 149 break; 150 case WASM_EXTERNAL_MEMORY: 151 writeUleb128(OS, Export.Index, "memory index"); 152 break; 153 case WASM_EXTERNAL_TABLE: 154 writeUleb128(OS, Export.Index, "table index"); 155 break; 156 default: 157 fatal("unsupported export type: " + Twine(Export.Kind)); 158 } 159 } 160 } // namespace lld 161 162 std::string lld::toString(ValType Type) { 163 switch (Type) { 164 case ValType::I32: 165 return "i32"; 166 case ValType::I64: 167 return "i64"; 168 case ValType::F32: 169 return "f32"; 170 case ValType::F64: 171 return "f64"; 172 case ValType::V128: 173 return "v128"; 174 case ValType::EXCEPT_REF: 175 return "except_ref"; 176 } 177 llvm_unreachable("Invalid wasm::ValType"); 178 } 179 180 std::string lld::toString(const WasmSignature &Sig) { 181 SmallString<128> S("("); 182 for (ValType Type : Sig.Params) { 183 if (S.size() != 1) 184 S += ", "; 185 S += toString(Type); 186 } 187 S += ") -> "; 188 if (Sig.Returns.size() == 0) 189 S += "void"; 190 else 191 S += toString(Sig.Returns[0]); 192 return S.str(); 193 } 194 195 std::string lld::toString(const WasmGlobalType &Sig) { 196 return (Sig.Mutable ? "var " : "const ") + 197 toString(static_cast<ValType>(Sig.Type)); 198 } 199