1 | //===- SyntheticSections.cpp ----------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file contains linker-synthesized sections. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "SyntheticSections.h" |
14 | |
15 | #include "InputChunks.h" |
16 | #include "InputElement.h" |
17 | #include "OutputSegment.h" |
18 | #include "SymbolTable.h" |
19 | #include "llvm/Support/Path.h" |
20 | #include <optional> |
21 | |
22 | using namespace llvm; |
23 | using namespace llvm::wasm; |
24 | |
25 | namespace lld::wasm { |
26 | |
27 | OutStruct out; |
28 | |
29 | namespace { |
30 | |
31 | // Some synthetic sections (e.g. "name" and "linking") have subsections. |
32 | // Just like the synthetic sections themselves these need to be created before |
33 | // they can be written out (since they are preceded by their length). This |
34 | // class is used to create subsections and then write them into the stream |
35 | // of the parent section. |
36 | class SubSection { |
37 | public: |
38 | explicit SubSection(uint32_t type) : type(type) {} |
39 | |
40 | void writeTo(raw_ostream &to) { |
41 | os.flush(); |
42 | writeUleb128(os&: to, number: type, msg: "subsection type" ); |
43 | writeUleb128(os&: to, number: body.size(), msg: "subsection size" ); |
44 | to.write(Ptr: body.data(), Size: body.size()); |
45 | } |
46 | |
47 | private: |
48 | uint32_t type; |
49 | std::string body; |
50 | |
51 | public: |
52 | raw_string_ostream os{body}; |
53 | }; |
54 | |
55 | } // namespace |
56 | |
57 | bool DylinkSection::isNeeded() const { |
58 | return ctx.isPic || |
59 | config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic || |
60 | !ctx.sharedFiles.empty(); |
61 | } |
62 | |
63 | void DylinkSection::writeBody() { |
64 | raw_ostream &os = bodyOutputStream; |
65 | |
66 | { |
67 | SubSection sub(WASM_DYLINK_MEM_INFO); |
68 | writeUleb128(os&: sub.os, number: memSize, msg: "MemSize" ); |
69 | writeUleb128(os&: sub.os, number: memAlign, msg: "MemAlign" ); |
70 | writeUleb128(os&: sub.os, number: out.elemSec->numEntries(), msg: "TableSize" ); |
71 | writeUleb128(os&: sub.os, number: 0, msg: "TableAlign" ); |
72 | sub.writeTo(to&: os); |
73 | } |
74 | |
75 | if (ctx.sharedFiles.size()) { |
76 | SubSection sub(WASM_DYLINK_NEEDED); |
77 | writeUleb128(os&: sub.os, number: ctx.sharedFiles.size(), msg: "Needed" ); |
78 | for (auto *so : ctx.sharedFiles) |
79 | writeStr(os&: sub.os, string: llvm::sys::path::filename(path: so->getName()), msg: "so name" ); |
80 | sub.writeTo(to&: os); |
81 | } |
82 | |
83 | // Under certain circumstances we need to include extra information about our |
84 | // exports and/or imports to the dynamic linker. |
85 | // For exports we need to notify the linker when an export is TLS since the |
86 | // exported value is relative to __tls_base rather than __memory_base. |
87 | // For imports we need to notify the dynamic linker when an import is weak |
88 | // so that knows not to report an error for such symbols. |
89 | std::vector<const Symbol *> importInfo; |
90 | std::vector<const Symbol *> exportInfo; |
91 | for (const Symbol *sym : symtab->symbols()) { |
92 | if (sym->isLive()) { |
93 | if (sym->isExported() && sym->isTLS() && isa<DefinedData>(Val: sym)) { |
94 | exportInfo.push_back(x: sym); |
95 | } |
96 | if (sym->isUndefWeak()) { |
97 | importInfo.push_back(x: sym); |
98 | } |
99 | } |
100 | } |
101 | |
102 | if (!exportInfo.empty()) { |
103 | SubSection sub(WASM_DYLINK_EXPORT_INFO); |
104 | writeUleb128(os&: sub.os, number: exportInfo.size(), msg: "num exports" ); |
105 | |
106 | for (const Symbol *sym : exportInfo) { |
107 | LLVM_DEBUG(llvm::dbgs() << "export info: " << toString(*sym) << "\n" ); |
108 | StringRef name = sym->getName(); |
109 | if (auto *f = dyn_cast<DefinedFunction>(Val: sym)) { |
110 | if (std::optional<StringRef> exportName = |
111 | f->function->getExportName()) { |
112 | name = *exportName; |
113 | } |
114 | } |
115 | writeStr(os&: sub.os, string: name, msg: "sym name" ); |
116 | writeUleb128(os&: sub.os, number: sym->flags, msg: "sym flags" ); |
117 | } |
118 | |
119 | sub.writeTo(to&: os); |
120 | } |
121 | |
122 | if (!importInfo.empty()) { |
123 | SubSection sub(WASM_DYLINK_IMPORT_INFO); |
124 | writeUleb128(os&: sub.os, number: importInfo.size(), msg: "num imports" ); |
125 | |
126 | for (const Symbol *sym : importInfo) { |
127 | LLVM_DEBUG(llvm::dbgs() << "imports info: " << toString(*sym) << "\n" ); |
128 | StringRef module = sym->importModule.value_or(u&: defaultModule); |
129 | StringRef name = sym->importName.value_or(u: sym->getName()); |
130 | writeStr(os&: sub.os, string: module, msg: "import module" ); |
131 | writeStr(os&: sub.os, string: name, msg: "import name" ); |
132 | writeUleb128(os&: sub.os, number: sym->flags, msg: "sym flags" ); |
133 | } |
134 | |
135 | sub.writeTo(to&: os); |
136 | } |
137 | } |
138 | |
139 | uint32_t TypeSection::registerType(const WasmSignature &sig) { |
140 | auto pair = typeIndices.insert(KV: std::make_pair(x: sig, y: types.size())); |
141 | if (pair.second) { |
142 | LLVM_DEBUG(llvm::dbgs() << "type " << toString(sig) << "\n" ); |
143 | types.push_back(x: &sig); |
144 | } |
145 | return pair.first->second; |
146 | } |
147 | |
148 | uint32_t TypeSection::lookupType(const WasmSignature &sig) { |
149 | auto it = typeIndices.find(Val: sig); |
150 | if (it == typeIndices.end()) { |
151 | error(msg: "type not found: " + toString(sig)); |
152 | return 0; |
153 | } |
154 | return it->second; |
155 | } |
156 | |
157 | void TypeSection::writeBody() { |
158 | writeUleb128(os&: bodyOutputStream, number: types.size(), msg: "type count" ); |
159 | for (const WasmSignature *sig : types) |
160 | writeSig(os&: bodyOutputStream, sig: *sig); |
161 | } |
162 | |
163 | uint32_t ImportSection::getNumImports() const { |
164 | assert(isSealed); |
165 | uint32_t numImports = importedSymbols.size() + gotSymbols.size(); |
166 | if (config->memoryImport.has_value()) |
167 | ++numImports; |
168 | return numImports; |
169 | } |
170 | |
171 | void ImportSection::addGOTEntry(Symbol *sym) { |
172 | assert(!isSealed); |
173 | if (sym->hasGOTIndex()) |
174 | return; |
175 | LLVM_DEBUG(dbgs() << "addGOTEntry: " << toString(*sym) << "\n" ); |
176 | sym->setGOTIndex(numImportedGlobals++); |
177 | if (ctx.isPic) { |
178 | // Any symbol that is assigned an normal GOT entry must be exported |
179 | // otherwise the dynamic linker won't be able create the entry that contains |
180 | // it. |
181 | sym->forceExport = true; |
182 | } |
183 | gotSymbols.push_back(x: sym); |
184 | } |
185 | |
186 | void ImportSection::addImport(Symbol *sym) { |
187 | assert(!isSealed); |
188 | StringRef module = sym->importModule.value_or(u&: defaultModule); |
189 | StringRef name = sym->importName.value_or(u: sym->getName()); |
190 | if (auto *f = dyn_cast<FunctionSymbol>(Val: sym)) { |
191 | ImportKey<WasmSignature> key(*(f->getSignature()), module, name); |
192 | auto entry = importedFunctions.try_emplace(Key: key, Args&: numImportedFunctions); |
193 | if (entry.second) { |
194 | importedSymbols.emplace_back(args&: sym); |
195 | f->setFunctionIndex(numImportedFunctions++); |
196 | } else { |
197 | f->setFunctionIndex(entry.first->second); |
198 | } |
199 | } else if (auto *g = dyn_cast<GlobalSymbol>(Val: sym)) { |
200 | ImportKey<WasmGlobalType> key(*(g->getGlobalType()), module, name); |
201 | auto entry = importedGlobals.try_emplace(Key: key, Args&: numImportedGlobals); |
202 | if (entry.second) { |
203 | importedSymbols.emplace_back(args&: sym); |
204 | g->setGlobalIndex(numImportedGlobals++); |
205 | } else { |
206 | g->setGlobalIndex(entry.first->second); |
207 | } |
208 | } else if (auto *t = dyn_cast<TagSymbol>(Val: sym)) { |
209 | ImportKey<WasmSignature> key(*(t->getSignature()), module, name); |
210 | auto entry = importedTags.try_emplace(Key: key, Args&: numImportedTags); |
211 | if (entry.second) { |
212 | importedSymbols.emplace_back(args&: sym); |
213 | t->setTagIndex(numImportedTags++); |
214 | } else { |
215 | t->setTagIndex(entry.first->second); |
216 | } |
217 | } else { |
218 | assert(TableSymbol::classof(sym)); |
219 | auto *table = cast<TableSymbol>(Val: sym); |
220 | ImportKey<WasmTableType> key(*(table->getTableType()), module, name); |
221 | auto entry = importedTables.try_emplace(Key: key, Args&: numImportedTables); |
222 | if (entry.second) { |
223 | importedSymbols.emplace_back(args&: sym); |
224 | table->setTableNumber(numImportedTables++); |
225 | } else { |
226 | table->setTableNumber(entry.first->second); |
227 | } |
228 | } |
229 | } |
230 | |
231 | void ImportSection::writeBody() { |
232 | raw_ostream &os = bodyOutputStream; |
233 | |
234 | writeUleb128(os, number: getNumImports(), msg: "import count" ); |
235 | |
236 | bool is64 = config->is64.value_or(u: false); |
237 | |
238 | if (config->memoryImport) { |
239 | WasmImport import; |
240 | import.Module = config->memoryImport->first; |
241 | import.Field = config->memoryImport->second; |
242 | import.Kind = WASM_EXTERNAL_MEMORY; |
243 | import.Memory.Flags = 0; |
244 | import.Memory.Minimum = out.memorySec->numMemoryPages; |
245 | if (out.memorySec->maxMemoryPages != 0 || config->sharedMemory) { |
246 | import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX; |
247 | import.Memory.Maximum = out.memorySec->maxMemoryPages; |
248 | } |
249 | if (config->sharedMemory) |
250 | import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED; |
251 | if (is64) |
252 | import.Memory.Flags |= WASM_LIMITS_FLAG_IS_64; |
253 | writeImport(os, import); |
254 | } |
255 | |
256 | for (const Symbol *sym : importedSymbols) { |
257 | WasmImport import; |
258 | import.Field = sym->importName.value_or(u: sym->getName()); |
259 | import.Module = sym->importModule.value_or(u&: defaultModule); |
260 | |
261 | if (auto *functionSym = dyn_cast<FunctionSymbol>(Val: sym)) { |
262 | import.Kind = WASM_EXTERNAL_FUNCTION; |
263 | import.SigIndex = out.typeSec->lookupType(sig: *functionSym->signature); |
264 | } else if (auto *globalSym = dyn_cast<GlobalSymbol>(Val: sym)) { |
265 | import.Kind = WASM_EXTERNAL_GLOBAL; |
266 | import.Global = *globalSym->getGlobalType(); |
267 | } else if (auto *tagSym = dyn_cast<TagSymbol>(Val: sym)) { |
268 | import.Kind = WASM_EXTERNAL_TAG; |
269 | import.SigIndex = out.typeSec->lookupType(sig: *tagSym->signature); |
270 | } else { |
271 | auto *tableSym = cast<TableSymbol>(Val: sym); |
272 | import.Kind = WASM_EXTERNAL_TABLE; |
273 | import.Table = *tableSym->getTableType(); |
274 | } |
275 | writeImport(os, import); |
276 | } |
277 | |
278 | for (const Symbol *sym : gotSymbols) { |
279 | WasmImport import; |
280 | import.Kind = WASM_EXTERNAL_GLOBAL; |
281 | auto ptrType = is64 ? WASM_TYPE_I64 : WASM_TYPE_I32; |
282 | import.Global = {.Type: static_cast<uint8_t>(ptrType), .Mutable: true}; |
283 | if (isa<DataSymbol>(Val: sym)) |
284 | import.Module = "GOT.mem" ; |
285 | else |
286 | import.Module = "GOT.func" ; |
287 | import.Field = sym->getName(); |
288 | writeImport(os, import); |
289 | } |
290 | } |
291 | |
292 | void FunctionSection::writeBody() { |
293 | raw_ostream &os = bodyOutputStream; |
294 | |
295 | writeUleb128(os, number: inputFunctions.size(), msg: "function count" ); |
296 | for (const InputFunction *func : inputFunctions) |
297 | writeUleb128(os, number: out.typeSec->lookupType(sig: func->signature), msg: "sig index" ); |
298 | } |
299 | |
300 | void FunctionSection::addFunction(InputFunction *func) { |
301 | if (!func->live) |
302 | return; |
303 | uint32_t functionIndex = |
304 | out.importSec->getNumImportedFunctions() + inputFunctions.size(); |
305 | inputFunctions.emplace_back(args&: func); |
306 | func->setFunctionIndex(functionIndex); |
307 | } |
308 | |
309 | void TableSection::writeBody() { |
310 | raw_ostream &os = bodyOutputStream; |
311 | |
312 | writeUleb128(os, number: inputTables.size(), msg: "table count" ); |
313 | for (const InputTable *table : inputTables) |
314 | writeTableType(os, type: table->getType()); |
315 | } |
316 | |
317 | void TableSection::addTable(InputTable *table) { |
318 | if (!table->live) |
319 | return; |
320 | // Some inputs require that the indirect function table be assigned to table |
321 | // number 0. |
322 | if (ctx.legacyFunctionTable && |
323 | isa<DefinedTable>(Val: WasmSym::indirectFunctionTable) && |
324 | cast<DefinedTable>(Val: WasmSym::indirectFunctionTable)->table == table) { |
325 | if (out.importSec->getNumImportedTables()) { |
326 | // Alack! Some other input imported a table, meaning that we are unable |
327 | // to assign table number 0 to the indirect function table. |
328 | for (const auto *culprit : out.importSec->importedSymbols) { |
329 | if (isa<UndefinedTable>(Val: culprit)) { |
330 | error(msg: "object file not built with 'reference-types' feature " |
331 | "conflicts with import of table " + |
332 | culprit->getName() + " by file " + |
333 | toString(file: culprit->getFile())); |
334 | return; |
335 | } |
336 | } |
337 | llvm_unreachable("failed to find conflicting table import" ); |
338 | } |
339 | inputTables.insert(position: inputTables.begin(), x: table); |
340 | return; |
341 | } |
342 | inputTables.push_back(x: table); |
343 | } |
344 | |
345 | void TableSection::assignIndexes() { |
346 | uint32_t tableNumber = out.importSec->getNumImportedTables(); |
347 | for (InputTable *t : inputTables) |
348 | t->assignIndex(index: tableNumber++); |
349 | } |
350 | |
351 | void MemorySection::writeBody() { |
352 | raw_ostream &os = bodyOutputStream; |
353 | |
354 | bool hasMax = maxMemoryPages != 0 || config->sharedMemory; |
355 | writeUleb128(os, number: 1, msg: "memory count" ); |
356 | unsigned flags = 0; |
357 | if (hasMax) |
358 | flags |= WASM_LIMITS_FLAG_HAS_MAX; |
359 | if (config->sharedMemory) |
360 | flags |= WASM_LIMITS_FLAG_IS_SHARED; |
361 | if (config->is64.value_or(u: false)) |
362 | flags |= WASM_LIMITS_FLAG_IS_64; |
363 | writeUleb128(os, number: flags, msg: "memory limits flags" ); |
364 | writeUleb128(os, number: numMemoryPages, msg: "initial pages" ); |
365 | if (hasMax) |
366 | writeUleb128(os, number: maxMemoryPages, msg: "max pages" ); |
367 | } |
368 | |
369 | void TagSection::writeBody() { |
370 | raw_ostream &os = bodyOutputStream; |
371 | |
372 | writeUleb128(os, number: inputTags.size(), msg: "tag count" ); |
373 | for (InputTag *t : inputTags) { |
374 | writeUleb128(os, number: 0, msg: "tag attribute" ); // Reserved "attribute" field |
375 | writeUleb128(os, number: out.typeSec->lookupType(sig: t->signature), msg: "sig index" ); |
376 | } |
377 | } |
378 | |
379 | void TagSection::addTag(InputTag *tag) { |
380 | if (!tag->live) |
381 | return; |
382 | uint32_t tagIndex = out.importSec->getNumImportedTags() + inputTags.size(); |
383 | LLVM_DEBUG(dbgs() << "addTag: " << tagIndex << "\n" ); |
384 | tag->assignIndex(index: tagIndex); |
385 | inputTags.push_back(x: tag); |
386 | } |
387 | |
388 | void GlobalSection::assignIndexes() { |
389 | uint32_t globalIndex = out.importSec->getNumImportedGlobals(); |
390 | for (InputGlobal *g : inputGlobals) |
391 | g->assignIndex(index: globalIndex++); |
392 | for (Symbol *sym : internalGotSymbols) |
393 | sym->setGOTIndex(globalIndex++); |
394 | isSealed = true; |
395 | } |
396 | |
397 | static void ensureIndirectFunctionTable() { |
398 | if (!WasmSym::indirectFunctionTable) |
399 | WasmSym::indirectFunctionTable = |
400 | symtab->resolveIndirectFunctionTable(/*required =*/true); |
401 | } |
402 | |
403 | void GlobalSection::addInternalGOTEntry(Symbol *sym) { |
404 | assert(!isSealed); |
405 | if (sym->requiresGOT) |
406 | return; |
407 | LLVM_DEBUG(dbgs() << "addInternalGOTEntry: " << sym->getName() << " " |
408 | << toString(sym->kind()) << "\n" ); |
409 | sym->requiresGOT = true; |
410 | if (auto *F = dyn_cast<FunctionSymbol>(Val: sym)) { |
411 | ensureIndirectFunctionTable(); |
412 | out.elemSec->addEntry(sym: F); |
413 | } |
414 | internalGotSymbols.push_back(x: sym); |
415 | } |
416 | |
417 | void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const { |
418 | assert(!config->extendedConst); |
419 | bool is64 = config->is64.value_or(u: false); |
420 | unsigned opcode_ptr_const = is64 ? WASM_OPCODE_I64_CONST |
421 | : WASM_OPCODE_I32_CONST; |
422 | unsigned opcode_ptr_add = is64 ? WASM_OPCODE_I64_ADD |
423 | : WASM_OPCODE_I32_ADD; |
424 | |
425 | for (const Symbol *sym : internalGotSymbols) { |
426 | if (TLS != sym->isTLS()) |
427 | continue; |
428 | |
429 | if (auto *d = dyn_cast<DefinedData>(Val: sym)) { |
430 | // Get __memory_base |
431 | writeU8(os, byte: WASM_OPCODE_GLOBAL_GET, msg: "GLOBAL_GET" ); |
432 | if (sym->isTLS()) |
433 | writeUleb128(os, number: WasmSym::tlsBase->getGlobalIndex(), msg: "__tls_base" ); |
434 | else |
435 | writeUleb128(os, number: WasmSym::memoryBase->getGlobalIndex(), |
436 | msg: "__memory_base" ); |
437 | |
438 | // Add the virtual address of the data symbol |
439 | writeU8(os, byte: opcode_ptr_const, msg: "CONST" ); |
440 | writeSleb128(os, number: d->getVA(), msg: "offset" ); |
441 | } else if (auto *f = dyn_cast<FunctionSymbol>(Val: sym)) { |
442 | if (f->isStub) |
443 | continue; |
444 | // Get __table_base |
445 | writeU8(os, byte: WASM_OPCODE_GLOBAL_GET, msg: "GLOBAL_GET" ); |
446 | writeUleb128(os, number: WasmSym::tableBase->getGlobalIndex(), msg: "__table_base" ); |
447 | |
448 | // Add the table index to __table_base |
449 | writeU8(os, byte: opcode_ptr_const, msg: "CONST" ); |
450 | writeSleb128(os, number: f->getTableIndex(), msg: "offset" ); |
451 | } else { |
452 | assert(isa<UndefinedData>(sym)); |
453 | continue; |
454 | } |
455 | writeU8(os, byte: opcode_ptr_add, msg: "ADD" ); |
456 | writeU8(os, byte: WASM_OPCODE_GLOBAL_SET, msg: "GLOBAL_SET" ); |
457 | writeUleb128(os, number: sym->getGOTIndex(), msg: "got_entry" ); |
458 | } |
459 | } |
460 | |
461 | void GlobalSection::writeBody() { |
462 | raw_ostream &os = bodyOutputStream; |
463 | |
464 | writeUleb128(os, number: numGlobals(), msg: "global count" ); |
465 | for (InputGlobal *g : inputGlobals) { |
466 | writeGlobalType(os, type: g->getType()); |
467 | writeInitExpr(os, initExpr: g->getInitExpr()); |
468 | } |
469 | bool is64 = config->is64.value_or(u: false); |
470 | uint8_t itype = is64 ? WASM_TYPE_I64 : WASM_TYPE_I32; |
471 | for (const Symbol *sym : internalGotSymbols) { |
472 | bool mutable_ = false; |
473 | if (!sym->isStub) { |
474 | // In the case of dynamic linking, unless we have 'extended-const' |
475 | // available, these global must to be mutable since they get updated to |
476 | // the correct runtime value during `__wasm_apply_global_relocs`. |
477 | if (!config->extendedConst && ctx.isPic && !sym->isTLS()) |
478 | mutable_ = true; |
479 | // With multi-theadeding any TLS globals must be mutable since they get |
480 | // set during `__wasm_apply_global_tls_relocs` |
481 | if (config->sharedMemory && sym->isTLS()) |
482 | mutable_ = true; |
483 | } |
484 | WasmGlobalType type{.Type: itype, .Mutable: mutable_}; |
485 | writeGlobalType(os, type); |
486 | |
487 | bool useExtendedConst = false; |
488 | uint32_t globalIdx; |
489 | int64_t offset; |
490 | if (config->extendedConst && ctx.isPic) { |
491 | if (auto *d = dyn_cast<DefinedData>(Val: sym)) { |
492 | if (!sym->isTLS()) { |
493 | globalIdx = WasmSym::memoryBase->getGlobalIndex(); |
494 | offset = d->getVA(); |
495 | useExtendedConst = true; |
496 | } |
497 | } else if (auto *f = dyn_cast<FunctionSymbol>(Val: sym)) { |
498 | if (!sym->isStub) { |
499 | globalIdx = WasmSym::tableBase->getGlobalIndex(); |
500 | offset = f->getTableIndex(); |
501 | useExtendedConst = true; |
502 | } |
503 | } |
504 | } |
505 | if (useExtendedConst) { |
506 | // We can use an extended init expression to add a constant |
507 | // offset of __memory_base/__table_base. |
508 | writeU8(os, byte: WASM_OPCODE_GLOBAL_GET, msg: "global get" ); |
509 | writeUleb128(os, number: globalIdx, msg: "literal (global index)" ); |
510 | if (offset) { |
511 | writePtrConst(os, number: offset, is64, msg: "offset" ); |
512 | writeU8(os, byte: is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD, msg: "add" ); |
513 | } |
514 | writeU8(os, byte: WASM_OPCODE_END, msg: "opcode:end" ); |
515 | } else { |
516 | WasmInitExpr initExpr; |
517 | if (auto *d = dyn_cast<DefinedData>(Val: sym)) |
518 | initExpr = intConst(value: d->getVA(), is64); |
519 | else if (auto *f = dyn_cast<FunctionSymbol>(Val: sym)) |
520 | initExpr = intConst(value: f->isStub ? 0 : f->getTableIndex(), is64); |
521 | else { |
522 | assert(isa<UndefinedData>(sym)); |
523 | initExpr = intConst(value: 0, is64); |
524 | } |
525 | writeInitExpr(os, initExpr); |
526 | } |
527 | } |
528 | for (const DefinedData *sym : dataAddressGlobals) { |
529 | WasmGlobalType type{.Type: itype, .Mutable: false}; |
530 | writeGlobalType(os, type); |
531 | writeInitExpr(os, initExpr: intConst(value: sym->getVA(), is64)); |
532 | } |
533 | } |
534 | |
535 | void GlobalSection::addGlobal(InputGlobal *global) { |
536 | assert(!isSealed); |
537 | if (!global->live) |
538 | return; |
539 | inputGlobals.push_back(x: global); |
540 | } |
541 | |
542 | void ExportSection::writeBody() { |
543 | raw_ostream &os = bodyOutputStream; |
544 | |
545 | writeUleb128(os, number: exports.size(), msg: "export count" ); |
546 | for (const WasmExport &export_ : exports) |
547 | writeExport(os, export_); |
548 | } |
549 | |
550 | bool StartSection::isNeeded() const { |
551 | return WasmSym::startFunction != nullptr; |
552 | } |
553 | |
554 | void StartSection::writeBody() { |
555 | raw_ostream &os = bodyOutputStream; |
556 | writeUleb128(os, number: WasmSym::startFunction->getFunctionIndex(), |
557 | msg: "function index" ); |
558 | } |
559 | |
560 | void ElemSection::addEntry(FunctionSymbol *sym) { |
561 | // Don't add stub functions to the wasm table. The address of all stub |
562 | // functions should be zero and they should they don't appear in the table. |
563 | // They only exist so that the calls to missing functions can validate. |
564 | if (sym->hasTableIndex() || sym->isStub) |
565 | return; |
566 | sym->setTableIndex(config->tableBase + indirectFunctions.size()); |
567 | indirectFunctions.emplace_back(args&: sym); |
568 | } |
569 | |
570 | void ElemSection::writeBody() { |
571 | raw_ostream &os = bodyOutputStream; |
572 | |
573 | assert(WasmSym::indirectFunctionTable); |
574 | writeUleb128(os, number: 1, msg: "segment count" ); |
575 | uint32_t tableNumber = WasmSym::indirectFunctionTable->getTableNumber(); |
576 | uint32_t flags = 0; |
577 | if (tableNumber) |
578 | flags |= WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER; |
579 | writeUleb128(os, number: flags, msg: "elem segment flags" ); |
580 | if (flags & WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER) |
581 | writeUleb128(os, number: tableNumber, msg: "table number" ); |
582 | |
583 | WasmInitExpr initExpr; |
584 | initExpr.Extended = false; |
585 | if (ctx.isPic) { |
586 | initExpr.Inst.Opcode = WASM_OPCODE_GLOBAL_GET; |
587 | initExpr.Inst.Value.Global = |
588 | (config->is64.value_or(u: false) ? WasmSym::tableBase32 |
589 | : WasmSym::tableBase) |
590 | ->getGlobalIndex(); |
591 | } else { |
592 | initExpr.Inst.Opcode = WASM_OPCODE_I32_CONST; |
593 | initExpr.Inst.Value.Int32 = config->tableBase; |
594 | } |
595 | writeInitExpr(os, initExpr); |
596 | |
597 | if (flags & WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) { |
598 | // We only write active function table initializers, for which the elem kind |
599 | // is specified to be written as 0x00 and interpreted to mean "funcref". |
600 | const uint8_t elemKind = 0; |
601 | writeU8(os, byte: elemKind, msg: "elem kind" ); |
602 | } |
603 | |
604 | writeUleb128(os, number: indirectFunctions.size(), msg: "elem count" ); |
605 | uint32_t tableIndex = config->tableBase; |
606 | for (const FunctionSymbol *sym : indirectFunctions) { |
607 | assert(sym->getTableIndex() == tableIndex); |
608 | (void) tableIndex; |
609 | writeUleb128(os, number: sym->getFunctionIndex(), msg: "function index" ); |
610 | ++tableIndex; |
611 | } |
612 | } |
613 | |
614 | DataCountSection::DataCountSection(ArrayRef<OutputSegment *> segments) |
615 | : SyntheticSection(llvm::wasm::WASM_SEC_DATACOUNT), |
616 | numSegments(llvm::count_if(Range&: segments, P: [](OutputSegment *const segment) { |
617 | return segment->requiredInBinary(); |
618 | })) {} |
619 | |
620 | void DataCountSection::writeBody() { |
621 | writeUleb128(os&: bodyOutputStream, number: numSegments, msg: "data count" ); |
622 | } |
623 | |
624 | bool DataCountSection::isNeeded() const { |
625 | return numSegments && config->sharedMemory; |
626 | } |
627 | |
628 | void LinkingSection::writeBody() { |
629 | raw_ostream &os = bodyOutputStream; |
630 | |
631 | writeUleb128(os, number: WasmMetadataVersion, msg: "Version" ); |
632 | |
633 | if (!symtabEntries.empty()) { |
634 | SubSection sub(WASM_SYMBOL_TABLE); |
635 | writeUleb128(os&: sub.os, number: symtabEntries.size(), msg: "num symbols" ); |
636 | |
637 | for (const Symbol *sym : symtabEntries) { |
638 | assert(sym->isDefined() || sym->isUndefined()); |
639 | WasmSymbolType kind = sym->getWasmType(); |
640 | uint32_t flags = sym->flags; |
641 | |
642 | writeU8(os&: sub.os, byte: kind, msg: "sym kind" ); |
643 | writeUleb128(os&: sub.os, number: flags, msg: "sym flags" ); |
644 | |
645 | if (auto *f = dyn_cast<FunctionSymbol>(Val: sym)) { |
646 | if (auto *d = dyn_cast<DefinedFunction>(Val: sym)) { |
647 | writeUleb128(os&: sub.os, number: d->getExportedFunctionIndex(), msg: "index" ); |
648 | } else { |
649 | writeUleb128(os&: sub.os, number: f->getFunctionIndex(), msg: "index" ); |
650 | } |
651 | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) |
652 | writeStr(os&: sub.os, string: sym->getName(), msg: "sym name" ); |
653 | } else if (auto *g = dyn_cast<GlobalSymbol>(Val: sym)) { |
654 | writeUleb128(os&: sub.os, number: g->getGlobalIndex(), msg: "index" ); |
655 | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) |
656 | writeStr(os&: sub.os, string: sym->getName(), msg: "sym name" ); |
657 | } else if (auto *t = dyn_cast<TagSymbol>(Val: sym)) { |
658 | writeUleb128(os&: sub.os, number: t->getTagIndex(), msg: "index" ); |
659 | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) |
660 | writeStr(os&: sub.os, string: sym->getName(), msg: "sym name" ); |
661 | } else if (auto *t = dyn_cast<TableSymbol>(Val: sym)) { |
662 | writeUleb128(os&: sub.os, number: t->getTableNumber(), msg: "table number" ); |
663 | if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0) |
664 | writeStr(os&: sub.os, string: sym->getName(), msg: "sym name" ); |
665 | } else if (isa<DataSymbol>(Val: sym)) { |
666 | writeStr(os&: sub.os, string: sym->getName(), msg: "sym name" ); |
667 | if (auto *dataSym = dyn_cast<DefinedData>(Val: sym)) { |
668 | if (dataSym->segment) { |
669 | writeUleb128(os&: sub.os, number: dataSym->getOutputSegmentIndex(), msg: "index" ); |
670 | writeUleb128(os&: sub.os, number: dataSym->getOutputSegmentOffset(), |
671 | msg: "data offset" ); |
672 | } else { |
673 | writeUleb128(os&: sub.os, number: 0, msg: "index" ); |
674 | writeUleb128(os&: sub.os, number: dataSym->getVA(), msg: "data offset" ); |
675 | } |
676 | writeUleb128(os&: sub.os, number: dataSym->getSize(), msg: "data size" ); |
677 | } |
678 | } else { |
679 | auto *s = cast<OutputSectionSymbol>(Val: sym); |
680 | writeUleb128(os&: sub.os, number: s->section->sectionIndex, msg: "sym section index" ); |
681 | } |
682 | } |
683 | |
684 | sub.writeTo(to&: os); |
685 | } |
686 | |
687 | if (dataSegments.size()) { |
688 | SubSection sub(WASM_SEGMENT_INFO); |
689 | writeUleb128(os&: sub.os, number: dataSegments.size(), msg: "num data segments" ); |
690 | for (const OutputSegment *s : dataSegments) { |
691 | writeStr(os&: sub.os, string: s->name, msg: "segment name" ); |
692 | writeUleb128(os&: sub.os, number: s->alignment, msg: "alignment" ); |
693 | writeUleb128(os&: sub.os, number: s->linkingFlags, msg: "flags" ); |
694 | } |
695 | sub.writeTo(to&: os); |
696 | } |
697 | |
698 | if (!initFunctions.empty()) { |
699 | SubSection sub(WASM_INIT_FUNCS); |
700 | writeUleb128(os&: sub.os, number: initFunctions.size(), msg: "num init functions" ); |
701 | for (const WasmInitEntry &f : initFunctions) { |
702 | writeUleb128(os&: sub.os, number: f.priority, msg: "priority" ); |
703 | writeUleb128(os&: sub.os, number: f.sym->getOutputSymbolIndex(), msg: "function index" ); |
704 | } |
705 | sub.writeTo(to&: os); |
706 | } |
707 | |
708 | struct ComdatEntry { |
709 | unsigned kind; |
710 | uint32_t index; |
711 | }; |
712 | std::map<StringRef, std::vector<ComdatEntry>> comdats; |
713 | |
714 | for (const InputFunction *f : out.functionSec->inputFunctions) { |
715 | StringRef comdat = f->getComdatName(); |
716 | if (!comdat.empty()) |
717 | comdats[comdat].emplace_back( |
718 | args: ComdatEntry{.kind: WASM_COMDAT_FUNCTION, .index: f->getFunctionIndex()}); |
719 | } |
720 | for (uint32_t i = 0; i < dataSegments.size(); ++i) { |
721 | const auto &inputSegments = dataSegments[i]->inputSegments; |
722 | if (inputSegments.empty()) |
723 | continue; |
724 | StringRef comdat = inputSegments[0]->getComdatName(); |
725 | #ifndef NDEBUG |
726 | for (const InputChunk *isec : inputSegments) |
727 | assert(isec->getComdatName() == comdat); |
728 | #endif |
729 | if (!comdat.empty()) |
730 | comdats[comdat].emplace_back(args: ComdatEntry{.kind: WASM_COMDAT_DATA, .index: i}); |
731 | } |
732 | |
733 | if (!comdats.empty()) { |
734 | SubSection sub(WASM_COMDAT_INFO); |
735 | writeUleb128(os&: sub.os, number: comdats.size(), msg: "num comdats" ); |
736 | for (const auto &c : comdats) { |
737 | writeStr(os&: sub.os, string: c.first, msg: "comdat name" ); |
738 | writeUleb128(os&: sub.os, number: 0, msg: "comdat flags" ); // flags for future use |
739 | writeUleb128(os&: sub.os, number: c.second.size(), msg: "num entries" ); |
740 | for (const ComdatEntry &entry : c.second) { |
741 | writeU8(os&: sub.os, byte: entry.kind, msg: "entry kind" ); |
742 | writeUleb128(os&: sub.os, number: entry.index, msg: "entry index" ); |
743 | } |
744 | } |
745 | sub.writeTo(to&: os); |
746 | } |
747 | } |
748 | |
749 | void LinkingSection::addToSymtab(Symbol *sym) { |
750 | sym->setOutputSymbolIndex(symtabEntries.size()); |
751 | symtabEntries.emplace_back(args&: sym); |
752 | } |
753 | |
754 | unsigned NameSection::numNamedFunctions() const { |
755 | unsigned numNames = out.importSec->getNumImportedFunctions(); |
756 | |
757 | for (const InputFunction *f : out.functionSec->inputFunctions) |
758 | if (!f->name.empty() || !f->debugName.empty()) |
759 | ++numNames; |
760 | |
761 | return numNames; |
762 | } |
763 | |
764 | unsigned NameSection::numNamedGlobals() const { |
765 | unsigned numNames = out.importSec->getNumImportedGlobals(); |
766 | |
767 | for (const InputGlobal *g : out.globalSec->inputGlobals) |
768 | if (!g->getName().empty()) |
769 | ++numNames; |
770 | |
771 | numNames += out.globalSec->internalGotSymbols.size(); |
772 | return numNames; |
773 | } |
774 | |
775 | unsigned NameSection::numNamedDataSegments() const { |
776 | unsigned numNames = 0; |
777 | |
778 | for (const OutputSegment *s : segments) |
779 | if (!s->name.empty() && s->requiredInBinary()) |
780 | ++numNames; |
781 | |
782 | return numNames; |
783 | } |
784 | |
785 | // Create the custom "name" section containing debug symbol names. |
786 | void NameSection::writeBody() { |
787 | { |
788 | SubSection sub(WASM_NAMES_MODULE); |
789 | StringRef moduleName = config->soName; |
790 | if (config->soName.empty()) |
791 | moduleName = llvm::sys::path::filename(path: config->outputFile); |
792 | writeStr(os&: sub.os, string: moduleName, msg: "module name" ); |
793 | sub.writeTo(to&: bodyOutputStream); |
794 | } |
795 | |
796 | unsigned count = numNamedFunctions(); |
797 | if (count) { |
798 | SubSection sub(WASM_NAMES_FUNCTION); |
799 | writeUleb128(os&: sub.os, number: count, msg: "name count" ); |
800 | |
801 | // Function names appear in function index order. As it happens |
802 | // importedSymbols and inputFunctions are numbered in order with imported |
803 | // functions coming first. |
804 | for (const Symbol *s : out.importSec->importedSymbols) { |
805 | if (auto *f = dyn_cast<FunctionSymbol>(Val: s)) { |
806 | writeUleb128(os&: sub.os, number: f->getFunctionIndex(), msg: "func index" ); |
807 | writeStr(os&: sub.os, string: toString(sym: *s), msg: "symbol name" ); |
808 | } |
809 | } |
810 | for (const InputFunction *f : out.functionSec->inputFunctions) { |
811 | if (!f->name.empty()) { |
812 | writeUleb128(os&: sub.os, number: f->getFunctionIndex(), msg: "func index" ); |
813 | if (!f->debugName.empty()) { |
814 | writeStr(os&: sub.os, string: f->debugName, msg: "symbol name" ); |
815 | } else { |
816 | writeStr(os&: sub.os, string: maybeDemangleSymbol(name: f->name), msg: "symbol name" ); |
817 | } |
818 | } |
819 | } |
820 | sub.writeTo(to&: bodyOutputStream); |
821 | } |
822 | |
823 | count = numNamedGlobals(); |
824 | if (count) { |
825 | SubSection sub(WASM_NAMES_GLOBAL); |
826 | writeUleb128(os&: sub.os, number: count, msg: "name count" ); |
827 | |
828 | for (const Symbol *s : out.importSec->importedSymbols) { |
829 | if (auto *g = dyn_cast<GlobalSymbol>(Val: s)) { |
830 | writeUleb128(os&: sub.os, number: g->getGlobalIndex(), msg: "global index" ); |
831 | writeStr(os&: sub.os, string: toString(sym: *s), msg: "symbol name" ); |
832 | } |
833 | } |
834 | for (const Symbol *s : out.importSec->gotSymbols) { |
835 | writeUleb128(os&: sub.os, number: s->getGOTIndex(), msg: "global index" ); |
836 | writeStr(os&: sub.os, string: toString(sym: *s), msg: "symbol name" ); |
837 | } |
838 | for (const InputGlobal *g : out.globalSec->inputGlobals) { |
839 | if (!g->getName().empty()) { |
840 | writeUleb128(os&: sub.os, number: g->getAssignedIndex(), msg: "global index" ); |
841 | writeStr(os&: sub.os, string: maybeDemangleSymbol(name: g->getName()), msg: "symbol name" ); |
842 | } |
843 | } |
844 | for (Symbol *s : out.globalSec->internalGotSymbols) { |
845 | writeUleb128(os&: sub.os, number: s->getGOTIndex(), msg: "global index" ); |
846 | if (isa<FunctionSymbol>(Val: s)) |
847 | writeStr(os&: sub.os, string: "GOT.func.internal." + toString(sym: *s), msg: "symbol name" ); |
848 | else |
849 | writeStr(os&: sub.os, string: "GOT.data.internal." + toString(sym: *s), msg: "symbol name" ); |
850 | } |
851 | |
852 | sub.writeTo(to&: bodyOutputStream); |
853 | } |
854 | |
855 | count = numNamedDataSegments(); |
856 | if (count) { |
857 | SubSection sub(WASM_NAMES_DATA_SEGMENT); |
858 | writeUleb128(os&: sub.os, number: count, msg: "name count" ); |
859 | |
860 | for (OutputSegment *s : segments) { |
861 | if (!s->name.empty() && s->requiredInBinary()) { |
862 | writeUleb128(os&: sub.os, number: s->index, msg: "global index" ); |
863 | writeStr(os&: sub.os, string: s->name, msg: "segment name" ); |
864 | } |
865 | } |
866 | |
867 | sub.writeTo(to&: bodyOutputStream); |
868 | } |
869 | } |
870 | |
871 | void ProducersSection::(const WasmProducerInfo &info) { |
872 | for (auto &producers : |
873 | {std::make_pair(x: &info.Languages, y: &languages), |
874 | std::make_pair(x: &info.Tools, y: &tools), std::make_pair(x: &info.SDKs, y: &sDKs)}) |
875 | for (auto &producer : *producers.first) |
876 | if (llvm::none_of(Range&: *producers.second, |
877 | P: [&](std::pair<std::string, std::string> seen) { |
878 | return seen.first == producer.first; |
879 | })) |
880 | producers.second->push_back(Elt: producer); |
881 | } |
882 | |
883 | void ProducersSection::writeBody() { |
884 | auto &os = bodyOutputStream; |
885 | writeUleb128(os, number: fieldCount(), msg: "field count" ); |
886 | for (auto &field : |
887 | {std::make_pair(x: "language" , y&: languages), |
888 | std::make_pair(x: "processed-by" , y&: tools), std::make_pair(x: "sdk" , y&: sDKs)}) { |
889 | if (field.second.empty()) |
890 | continue; |
891 | writeStr(os, string: field.first, msg: "field name" ); |
892 | writeUleb128(os, number: field.second.size(), msg: "number of entries" ); |
893 | for (auto &entry : field.second) { |
894 | writeStr(os, string: entry.first, msg: "producer name" ); |
895 | writeStr(os, string: entry.second, msg: "producer version" ); |
896 | } |
897 | } |
898 | } |
899 | |
900 | void TargetFeaturesSection::writeBody() { |
901 | SmallVector<std::string, 8> emitted(features.begin(), features.end()); |
902 | llvm::sort(C&: emitted); |
903 | auto &os = bodyOutputStream; |
904 | writeUleb128(os, number: emitted.size(), msg: "feature count" ); |
905 | for (auto &feature : emitted) { |
906 | writeU8(os, byte: WASM_FEATURE_PREFIX_USED, msg: "feature used prefix" ); |
907 | writeStr(os, string: feature, msg: "feature name" ); |
908 | } |
909 | } |
910 | |
911 | void RelocSection::writeBody() { |
912 | uint32_t count = sec->getNumRelocations(); |
913 | assert(sec->sectionIndex != UINT32_MAX); |
914 | writeUleb128(os&: bodyOutputStream, number: sec->sectionIndex, msg: "reloc section" ); |
915 | writeUleb128(os&: bodyOutputStream, number: count, msg: "reloc count" ); |
916 | sec->writeRelocations(os&: bodyOutputStream); |
917 | } |
918 | |
919 | static size_t getHashSize() { |
920 | switch (config->buildId) { |
921 | case BuildIdKind::Fast: |
922 | case BuildIdKind::Uuid: |
923 | return 16; |
924 | case BuildIdKind::Sha1: |
925 | return 20; |
926 | case BuildIdKind::Hexstring: |
927 | return config->buildIdVector.size(); |
928 | case BuildIdKind::None: |
929 | return 0; |
930 | } |
931 | llvm_unreachable("build id kind not implemented" ); |
932 | } |
933 | |
934 | BuildIdSection::BuildIdSection() |
935 | : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, buildIdSectionName), |
936 | hashSize(getHashSize()) {} |
937 | |
938 | void BuildIdSection::writeBody() { |
939 | LLVM_DEBUG(llvm::dbgs() << "BuildId writebody\n" ); |
940 | // Write hash size |
941 | auto &os = bodyOutputStream; |
942 | writeUleb128(os, number: hashSize, msg: "build id size" ); |
943 | writeBytes(os, bytes: std::vector<char>(hashSize, ' ').data(), count: hashSize, |
944 | msg: "placeholder" ); |
945 | } |
946 | |
947 | void BuildIdSection::writeBuildId(llvm::ArrayRef<uint8_t> buf) { |
948 | assert(buf.size() == hashSize); |
949 | LLVM_DEBUG(dbgs() << "buildid write " << buf.size() << " " |
950 | << hashPlaceholderPtr << '\n'); |
951 | memcpy(dest: hashPlaceholderPtr, src: buf.data(), n: hashSize); |
952 | } |
953 | |
954 | } // namespace wasm::lld |
955 | |