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 12 #include "lld/Common/ErrorHandler.h" 13 14 #include "llvm/Support/Debug.h" 15 #include "llvm/Support/EndianStream.h" 16 #include "llvm/Support/FormatVariadic.h" 17 #include "llvm/Support/LEB128.h" 18 19 #define DEBUG_TYPE "lld" 20 21 using namespace llvm; 22 using namespace llvm::wasm; 23 using namespace lld::wasm; 24 25 static const char *valueTypeToString(int32_t Type) { 26 switch (Type) { 27 case WASM_TYPE_I32: 28 return "i32"; 29 case WASM_TYPE_I64: 30 return "i64"; 31 case WASM_TYPE_F32: 32 return "f32"; 33 case WASM_TYPE_F64: 34 return "f64"; 35 default: 36 llvm_unreachable("invalid value type"); 37 } 38 } 39 40 namespace lld { 41 42 void wasm::debugWrite(uint64_t offset, Twine msg) { 43 DEBUG(dbgs() << format(" | %08" PRIx64 ": ", offset) << msg << "\n"); 44 } 45 46 void wasm::writeUleb128(raw_ostream &OS, uint32_t Number, const char *msg) { 47 if (msg) 48 debugWrite(OS.tell(), msg + formatv(" [{0:x}]", Number)); 49 encodeULEB128(Number, OS); 50 } 51 52 void wasm::writeSleb128(raw_ostream &OS, int32_t Number, const char *msg) { 53 if (msg) 54 debugWrite(OS.tell(), msg + formatv(" [{0:x}]", Number)); 55 encodeSLEB128(Number, OS); 56 } 57 58 void wasm::writeBytes(raw_ostream &OS, const char *bytes, size_t count, 59 const char *msg) { 60 if (msg) 61 debugWrite(OS.tell(), msg + formatv(" [data[{0}]]", count)); 62 OS.write(bytes, count); 63 } 64 65 void wasm::writeStr(raw_ostream &OS, const StringRef String, const char *msg) { 66 if (msg) 67 debugWrite(OS.tell(), 68 msg + formatv(" [str[{0}]: {1}]", String.size(), String)); 69 writeUleb128(OS, String.size(), nullptr); 70 writeBytes(OS, String.data(), String.size()); 71 } 72 73 void wasm::writeU8(raw_ostream &OS, uint8_t byte, const char *msg) { 74 OS << byte; 75 } 76 77 void wasm::writeU32(raw_ostream &OS, uint32_t Number, const char *msg) { 78 debugWrite(OS.tell(), msg + formatv("[{0:x}]", Number)); 79 support::endian::Writer<support::little>(OS).write(Number); 80 } 81 82 void wasm::writeValueType(raw_ostream &OS, int32_t Type, const char *msg) { 83 debugWrite(OS.tell(), msg + formatv("[type: {0}]", valueTypeToString(Type))); 84 writeSleb128(OS, Type, nullptr); 85 } 86 87 void wasm::writeSig(raw_ostream &OS, const WasmSignature &Sig) { 88 writeSleb128(OS, WASM_TYPE_FUNC, "signature type"); 89 writeUleb128(OS, Sig.ParamTypes.size(), "param count"); 90 for (int32_t ParamType : Sig.ParamTypes) { 91 writeValueType(OS, ParamType, "param type"); 92 } 93 if (Sig.ReturnType == WASM_TYPE_NORESULT) { 94 writeUleb128(OS, 0, "result count"); 95 } else { 96 writeUleb128(OS, 1, "result count"); 97 writeValueType(OS, Sig.ReturnType, "result type"); 98 } 99 } 100 101 void wasm::writeInitExpr(raw_ostream &OS, const WasmInitExpr &InitExpr) { 102 writeU8(OS, InitExpr.Opcode, "opcode"); 103 switch (InitExpr.Opcode) { 104 case WASM_OPCODE_I32_CONST: 105 writeSleb128(OS, InitExpr.Value.Int32, "literal (i32)"); 106 break; 107 case WASM_OPCODE_I64_CONST: 108 writeSleb128(OS, InitExpr.Value.Int64, "literal (i64)"); 109 break; 110 case WASM_OPCODE_GET_GLOBAL: 111 writeUleb128(OS, InitExpr.Value.Global, "literal (global index)"); 112 break; 113 default: 114 fatal("unknown opcode in init expr: " + Twine(InitExpr.Opcode)); 115 } 116 writeU8(OS, WASM_OPCODE_END, "opcode:end"); 117 } 118 119 void wasm::writeLimits(raw_ostream &OS, const WasmLimits &Limits) { 120 writeUleb128(OS, Limits.Flags, "limits flags"); 121 writeUleb128(OS, Limits.Initial, "limits initial"); 122 if (Limits.Flags & WASM_LIMITS_FLAG_HAS_MAX) 123 writeUleb128(OS, Limits.Maximum, "limits max"); 124 } 125 126 void wasm::writeGlobal(raw_ostream &OS, const WasmGlobal &Global) { 127 writeValueType(OS, Global.Type, "global type"); 128 writeUleb128(OS, Global.Mutable, "global mutable"); 129 writeInitExpr(OS, Global.InitExpr); 130 } 131 132 void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) { 133 writeStr(OS, Import.Module, "import module name"); 134 writeStr(OS, Import.Field, "import field name"); 135 writeU8(OS, Import.Kind, "import kind"); 136 switch (Import.Kind) { 137 case WASM_EXTERNAL_FUNCTION: 138 writeUleb128(OS, Import.SigIndex, "import sig index"); 139 break; 140 case WASM_EXTERNAL_GLOBAL: 141 writeValueType(OS, Import.Global.Type, "import global type"); 142 writeUleb128(OS, Import.Global.Mutable, "import global mutable"); 143 break; 144 case WASM_EXTERNAL_MEMORY: 145 writeLimits(OS, Import.Memory); 146 break; 147 default: 148 fatal("unsupported import type: " + Twine(Import.Kind)); 149 } 150 } 151 152 void wasm::writeExport(raw_ostream &OS, const WasmExport &Export) { 153 writeStr(OS, Export.Name, "export name"); 154 writeU8(OS, Export.Kind, "export kind"); 155 switch (Export.Kind) { 156 case WASM_EXTERNAL_FUNCTION: 157 writeUleb128(OS, Export.Index, "function index"); 158 break; 159 case WASM_EXTERNAL_GLOBAL: 160 writeUleb128(OS, Export.Index, "global index"); 161 break; 162 case WASM_EXTERNAL_MEMORY: 163 writeUleb128(OS, Export.Index, "memory index"); 164 break; 165 default: 166 fatal("unsupported export type: " + Twine(Export.Kind)); 167 } 168 } 169 170 void wasm::writeReloc(raw_ostream &OS, const OutputRelocation &Reloc) { 171 writeUleb128(OS, Reloc.Reloc.Type, "reloc type"); 172 writeUleb128(OS, Reloc.Reloc.Offset, "reloc offset"); 173 writeUleb128(OS, Reloc.NewIndex, "reloc index"); 174 175 switch (Reloc.Reloc.Type) { 176 case R_WEBASSEMBLY_MEMORY_ADDR_LEB: 177 case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: 178 case R_WEBASSEMBLY_MEMORY_ADDR_I32: 179 writeUleb128(OS, Reloc.Reloc.Addend, "reloc addend"); 180 break; 181 default: 182 break; 183 } 184 } 185 186 } // namespace lld 187 188 std::string lld::toString(ValType Type) { 189 switch (Type) { 190 case ValType::I32: 191 return "I32"; 192 case ValType::I64: 193 return "I64"; 194 case ValType::F32: 195 return "F32"; 196 case ValType::F64: 197 return "F64"; 198 } 199 llvm_unreachable("Invalid wasm::ValType"); 200 } 201 202 std::string lld::toString(const WasmSignature &Sig) { 203 SmallString<128> S("("); 204 for (uint32_t Type : Sig.ParamTypes) { 205 if (S.size() != 1) 206 S += ", "; 207 S += toString(static_cast<ValType>(Type)); 208 } 209 S += ") -> "; 210 if (Sig.ReturnType == WASM_TYPE_NORESULT) 211 S += "void"; 212 else 213 S += toString(static_cast<ValType>(Sig.ReturnType)); 214 return S.str(); 215 } 216