blob: aba6f0fa8b3582320f4579a2681fe22e9f29f6d1 [file] [log] [blame]
Sam Cleggc94d3932017-11-17 18:14:09 +00001//===- 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
21using namespace llvm;
22using namespace llvm::wasm;
23using namespace lld::wasm;
24
25static 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
40namespace lld {
41
Rui Ueyama7b9ed652018-02-16 19:53:29 +000042void wasm::debugWrite(uint64_t Offset, Twine Msg) {
43 DEBUG(dbgs() << format(" | %08" PRIx64 ": ", Offset) << Msg << "\n");
Sam Cleggc94d3932017-11-17 18:14:09 +000044}
45
Rui Ueyama7b9ed652018-02-16 19:53:29 +000046void wasm::writeUleb128(raw_ostream &OS, uint32_t Number, const char *Msg) {
47 if (Msg)
48 debugWrite(OS.tell(), Msg + formatv(" [{0:x}]", Number));
Sam Cleggc94d3932017-11-17 18:14:09 +000049 encodeULEB128(Number, OS);
50}
51
Rui Ueyama7b9ed652018-02-16 19:53:29 +000052void wasm::writeSleb128(raw_ostream &OS, int32_t Number, const char *Msg) {
53 if (Msg)
54 debugWrite(OS.tell(), Msg + formatv(" [{0:x}]", Number));
Sam Cleggc94d3932017-11-17 18:14:09 +000055 encodeSLEB128(Number, OS);
56}
57
Rui Ueyama7b9ed652018-02-16 19:53:29 +000058void 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);
Sam Cleggc94d3932017-11-17 18:14:09 +000063}
64
Rui Ueyama7b9ed652018-02-16 19:53:29 +000065void wasm::writeStr(raw_ostream &OS, const StringRef String, const char *Msg) {
66 if (Msg)
Sam Cleggc94d3932017-11-17 18:14:09 +000067 debugWrite(OS.tell(),
Rui Ueyama7b9ed652018-02-16 19:53:29 +000068 Msg + formatv(" [str[{0}]: {1}]", String.size(), String));
Sam Cleggc94d3932017-11-17 18:14:09 +000069 writeUleb128(OS, String.size(), nullptr);
70 writeBytes(OS, String.data(), String.size());
71}
72
Rui Ueyama7b9ed652018-02-16 19:53:29 +000073void wasm::writeU8(raw_ostream &OS, uint8_t byte, const char *Msg) {
Sam Cleggc94d3932017-11-17 18:14:09 +000074 OS << byte;
75}
76
Rui Ueyama7b9ed652018-02-16 19:53:29 +000077void wasm::writeU32(raw_ostream &OS, uint32_t Number, const char *Msg) {
78 debugWrite(OS.tell(), Msg + formatv("[{0:x}]", Number));
Sam Cleggc94d3932017-11-17 18:14:09 +000079 support::endian::Writer<support::little>(OS).write(Number);
80}
81
Rui Ueyama7b9ed652018-02-16 19:53:29 +000082void wasm::writeValueType(raw_ostream &OS, int32_t Type, const char *Msg) {
83 debugWrite(OS.tell(), Msg + formatv("[type: {0}]", valueTypeToString(Type)));
Sam Cleggc94d3932017-11-17 18:14:09 +000084 writeSleb128(OS, Type, nullptr);
85}
86
87void wasm::writeSig(raw_ostream &OS, const WasmSignature &Sig) {
88 writeSleb128(OS, WASM_TYPE_FUNC, "signature type");
Rui Ueyama7b9ed652018-02-16 19:53:29 +000089 writeUleb128(OS, Sig.ParamTypes.size(), "param Count");
Sam Cleggc94d3932017-11-17 18:14:09 +000090 for (int32_t ParamType : Sig.ParamTypes) {
91 writeValueType(OS, ParamType, "param type");
92 }
93 if (Sig.ReturnType == WASM_TYPE_NORESULT) {
Rui Ueyama7b9ed652018-02-16 19:53:29 +000094 writeUleb128(OS, 0, "result Count");
Sam Cleggc94d3932017-11-17 18:14:09 +000095 } else {
Rui Ueyama7b9ed652018-02-16 19:53:29 +000096 writeUleb128(OS, 1, "result Count");
Sam Cleggc94d3932017-11-17 18:14:09 +000097 writeValueType(OS, Sig.ReturnType, "result type");
98 }
99}
100
101void 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));
Sam Cleggc94d3932017-11-17 18:14:09 +0000115 }
116 writeU8(OS, WASM_OPCODE_END, "opcode:end");
117}
118
119void 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
Sam Clegg1a9b7b92018-01-31 19:54:34 +0000126void wasm::writeGlobalType(raw_ostream &OS, const WasmGlobalType &Type) {
127 writeValueType(OS, Type.Type, "global type");
128 writeUleb128(OS, Type.Mutable, "global mutable");
129}
130
Sam Cleggc94d3932017-11-17 18:14:09 +0000131void wasm::writeGlobal(raw_ostream &OS, const WasmGlobal &Global) {
Sam Clegg1a9b7b92018-01-31 19:54:34 +0000132 writeGlobalType(OS, Global.Type);
Sam Cleggc94d3932017-11-17 18:14:09 +0000133 writeInitExpr(OS, Global.InitExpr);
134}
135
136void 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:
Sam Clegg1a9b7b92018-01-31 19:54:34 +0000145 writeGlobalType(OS, Import.Global);
Sam Cleggc94d3932017-11-17 18:14:09 +0000146 break;
147 case WASM_EXTERNAL_MEMORY:
148 writeLimits(OS, Import.Memory);
149 break;
150 default:
151 fatal("unsupported import type: " + Twine(Import.Kind));
Sam Cleggc94d3932017-11-17 18:14:09 +0000152 }
153}
154
155void 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));
Sam Cleggc94d3932017-11-17 18:14:09 +0000170 }
171}
172
173void 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
Sam Cleggb8621592017-11-30 01:40:08 +0000190
191std::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
205std::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}