1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
//===- 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));
break;
}
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));
break;
}
}
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));
break;
}
}
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
|