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::writeGlobalType(raw_ostream &OS, const WasmGlobalType &Type) { 127 writeValueType(OS, Type.Type, "global type"); 128 writeUleb128(OS, Type.Mutable, "global mutable"); 129 } 130 131 void wasm::writeGlobal(raw_ostream &OS, const WasmGlobal &Global) { 132 writeGlobalType(OS, Global.Type); 133 writeInitExpr(OS, Global.InitExpr); 134 } 135 136 void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) { 137 writeStr(OS, Import.Module, "import module name"); 138 writeStr(OS, Import.Field, "import field name"); 139 writeU8(OS, Import.Kind, "import kind"); 140 switch (Import.Kind) { 141 case WASM_EXTERNAL_FUNCTION: 142 writeUleb128(OS, Import.SigIndex, "import sig index"); 143 break; 144 case WASM_EXTERNAL_GLOBAL: 145 writeGlobalType(OS, Import.Global); 146 break; 147 case WASM_EXTERNAL_MEMORY: 148 writeLimits(OS, Import.Memory); 149 break; 150 default: 151 fatal("unsupported import type: " + Twine(Import.Kind)); 152 } 153 } 154 155 void wasm::writeExport(raw_ostream &OS, const WasmExport &Export) { 156 writeStr(OS, Export.Name, "export name"); 157 writeU8(OS, Export.Kind, "export kind"); 158 switch (Export.Kind) { 159 case WASM_EXTERNAL_FUNCTION: 160 writeUleb128(OS, Export.Index, "function index"); 161 break; 162 case WASM_EXTERNAL_GLOBAL: 163 writeUleb128(OS, Export.Index, "global index"); 164 break; 165 case WASM_EXTERNAL_MEMORY: 166 writeUleb128(OS, Export.Index, "memory index"); 167 break; 168 default: 169 fatal("unsupported export type: " + Twine(Export.Kind)); 170 } 171 } 172 173 void wasm::writeReloc(raw_ostream &OS, const OutputRelocation &Reloc) { 174 writeUleb128(OS, Reloc.Reloc.Type, "reloc type"); 175 writeUleb128(OS, Reloc.Reloc.Offset, "reloc offset"); 176 writeUleb128(OS, Reloc.NewIndex, "reloc index"); 177 178 switch (Reloc.Reloc.Type) { 179 case R_WEBASSEMBLY_MEMORY_ADDR_LEB: 180 case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: 181 case R_WEBASSEMBLY_MEMORY_ADDR_I32: 182 writeUleb128(OS, Reloc.Reloc.Addend, "reloc addend"); 183 break; 184 default: 185 break; 186 } 187 } 188 189 } // namespace lld 190 191 std::string lld::toString(ValType Type) { 192 switch (Type) { 193 case ValType::I32: 194 return "I32"; 195 case ValType::I64: 196 return "I64"; 197 case ValType::F32: 198 return "F32"; 199 case ValType::F64: 200 return "F64"; 201 } 202 llvm_unreachable("Invalid wasm::ValType"); 203 } 204 205 std::string lld::toString(const WasmSignature &Sig) { 206 SmallString<128> S("("); 207 for (uint32_t Type : Sig.ParamTypes) { 208 if (S.size() != 1) 209 S += ", "; 210 S += toString(static_cast<ValType>(Type)); 211 } 212 S += ") -> "; 213 if (Sig.ReturnType == WASM_TYPE_NORESULT) 214 S += "void"; 215 else 216 S += toString(static_cast<ValType>(Sig.ReturnType)); 217 return S.str(); 218 } 219