1//===- Writer.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#include "Writer.h"
10#include "Config.h"
11#include "InputChunks.h"
12#include "InputElement.h"
13#include "MapFile.h"
14#include "OutputSections.h"
15#include "OutputSegment.h"
16#include "Relocations.h"
17#include "SymbolTable.h"
18#include "SyntheticSections.h"
19#include "WriterUtils.h"
20#include "lld/Common/Arrays.h"
21#include "lld/Common/CommonLinkerContext.h"
22#include "lld/Common/Strings.h"
23#include "llvm/ADT/ArrayRef.h"
24#include "llvm/ADT/MapVector.h"
25#include "llvm/ADT/SmallSet.h"
26#include "llvm/ADT/SmallVector.h"
27#include "llvm/ADT/StringMap.h"
28#include "llvm/BinaryFormat/Wasm.h"
29#include "llvm/Support/FileOutputBuffer.h"
30#include "llvm/Support/FormatVariadic.h"
31#include "llvm/Support/Parallel.h"
32#include "llvm/Support/RandomNumberGenerator.h"
33#include "llvm/Support/SHA1.h"
34#include "llvm/Support/xxhash.h"
35
36#include <cstdarg>
37#include <optional>
38
39#define DEBUG_TYPE "lld"
40
41using namespace llvm;
42using namespace llvm::wasm;
43
44namespace lld::wasm {
45static constexpr int stackAlignment = 16;
46static constexpr int heapAlignment = 16;
47
48namespace {
49
50// The writer writes a SymbolTable result to a file.
51class Writer {
52public:
53 void run();
54
55private:
56 void openFile();
57
58 bool needsPassiveInitialization(const OutputSegment *segment);
59 bool hasPassiveInitializedSegments();
60
61 void createSyntheticInitFunctions();
62 void createInitMemoryFunction();
63 void createStartFunction();
64 void createApplyDataRelocationsFunction();
65 void createApplyGlobalRelocationsFunction();
66 void createApplyTLSRelocationsFunction();
67 void createApplyGlobalTLSRelocationsFunction();
68 void createCallCtorsFunction();
69 void createInitTLSFunction();
70 void createCommandExportWrappers();
71 void createCommandExportWrapper(uint32_t functionIndex, DefinedFunction *f);
72
73 void assignIndexes();
74 void populateSymtab();
75 void populateProducers();
76 void populateTargetFeatures();
77 // populateTargetFeatures happens early on so some checks are delayed
78 // until imports and exports are finalized. There are run unstead
79 // in checkImportExportTargetFeatures
80 void checkImportExportTargetFeatures();
81 void calculateInitFunctions();
82 void calculateImports();
83 void calculateExports();
84 void calculateCustomSections();
85 void calculateTypes();
86 void createOutputSegments();
87 OutputSegment *createOutputSegment(StringRef name);
88 void combineOutputSegments();
89 void layoutMemory();
90 void createHeader();
91
92 void addSection(OutputSection *sec);
93
94 void addSections();
95
96 void createCustomSections();
97 void createSyntheticSections();
98 void createSyntheticSectionsPostLayout();
99 void finalizeSections();
100
101 // Custom sections
102 void createRelocSections();
103
104 void writeHeader();
105 void writeSections();
106 void writeBuildId();
107
108 uint64_t fileSize = 0;
109
110 std::vector<WasmInitEntry> initFunctions;
111 llvm::MapVector<StringRef, std::vector<InputChunk *>> customSectionMapping;
112
113 // Stable storage for command export wrapper function name strings.
114 std::list<std::string> commandExportWrapperNames;
115
116 // Elements that are used to construct the final output
117 std::string header;
118 std::vector<OutputSection *> outputSections;
119
120 std::unique_ptr<FileOutputBuffer> buffer;
121
122 std::vector<OutputSegment *> segments;
123 llvm::SmallDenseMap<StringRef, OutputSegment *> segmentMap;
124};
125
126void writeSetTLSBase(const Ctx &ctx, raw_ostream &os) {
127 if (ctx.arg.libcallThreadContext) {
128 writeU8(os, byte: WASM_OPCODE_CALL, msg: "call");
129 writeUleb128(os, number: ctx.sym.setTLSBase->getFunctionIndex(), msg: "function index");
130 } else {
131 writeU8(os, byte: WASM_OPCODE_GLOBAL_SET, msg: "GLOBAL_SET");
132 writeUleb128(os, number: ctx.sym.tlsBase->getGlobalIndex(), msg: "__tls_base");
133 }
134}
135} // anonymous namespace
136
137void Writer::calculateCustomSections() {
138 log(msg: "calculateCustomSections");
139 bool stripDebug = ctx.arg.stripDebug || ctx.arg.stripAll;
140 for (ObjFile *file : ctx.objectFiles) {
141 for (InputChunk *section : file->customSections) {
142 // Exclude COMDAT sections that are not selected for inclusion
143 if (section->discarded)
144 continue;
145 // Ignore empty custom sections. In particular objcopy/strip will
146 // sometimes replace stripped sections with empty custom sections to
147 // avoid section re-numbering.
148 if (section->getSize() == 0)
149 continue;
150 StringRef name = section->name;
151 // These custom sections are known the linker and synthesized rather than
152 // blindly copied.
153 if (name == "linking" || name == "name" || name == "producers" ||
154 name == "target_features" || name.starts_with(Prefix: "reloc."))
155 continue;
156 // These custom sections are generated by `clang -fembed-bitcode`.
157 // These are used by the rust toolchain to ship LTO data along with
158 // compiled object code, but they don't want this included in the linker
159 // output.
160 if (name == ".llvmbc" || name == ".llvmcmd")
161 continue;
162 // Strip debug section in that option was specified.
163 if (stripDebug && name.starts_with(Prefix: ".debug_"))
164 continue;
165 // Otherwise include custom sections by default and concatenate their
166 // contents.
167 customSectionMapping[name].push_back(x: section);
168 }
169 }
170}
171
172void Writer::createCustomSections() {
173 log(msg: "createCustomSections");
174 for (auto &pair : customSectionMapping) {
175 StringRef name = pair.first;
176 LLVM_DEBUG(dbgs() << "createCustomSection: " << name << "\n");
177
178 OutputSection *sec = make<CustomSection>(args: std::string(name), args&: pair.second);
179 if (ctx.arg.relocatable || ctx.arg.emitRelocs) {
180 auto *sym = make<OutputSectionSymbol>(args&: sec);
181 out.linkingSec->addToSymtab(sym);
182 sec->sectionSym = sym;
183 }
184 addSection(sec);
185 }
186}
187
188// Create relocations sections in the final output.
189// These are only created when relocatable output is requested.
190void Writer::createRelocSections() {
191 log(msg: "createRelocSections");
192 // Don't use iterator here since we are adding to OutputSection
193 size_t origSize = outputSections.size();
194 for (size_t i = 0; i < origSize; i++) {
195 LLVM_DEBUG(dbgs() << "check section " << i << "\n");
196 OutputSection *sec = outputSections[i];
197
198 // Count the number of needed sections.
199 uint32_t count = sec->getNumRelocations();
200 if (!count)
201 continue;
202
203 StringRef name;
204 if (sec->type == WASM_SEC_DATA)
205 name = "reloc.DATA";
206 else if (sec->type == WASM_SEC_CODE)
207 name = "reloc.CODE";
208 else if (sec->type == WASM_SEC_CUSTOM)
209 name = saver().save(S: "reloc." + sec->name);
210 else
211 llvm_unreachable(
212 "relocations only supported for code, data, or custom sections");
213
214 addSection(sec: make<RelocSection>(args&: name, args&: sec));
215 }
216}
217
218void Writer::populateProducers() {
219 for (ObjFile *file : ctx.objectFiles) {
220 const WasmProducerInfo &info = file->getWasmObj()->getProducerInfo();
221 out.producersSec->addInfo(info);
222 }
223}
224
225void Writer::writeHeader() {
226 memcpy(dest: buffer->getBufferStart(), src: header.data(), n: header.size());
227}
228
229void Writer::writeSections() {
230 uint8_t *buf = buffer->getBufferStart();
231 parallelForEach(R&: outputSections, Fn: [buf](OutputSection *s) {
232 assert(s->isNeeded());
233 s->writeTo(buf);
234 });
235}
236
237// Computes a hash value of Data using a given hash function.
238// In order to utilize multiple cores, we first split data into 1MB
239// chunks, compute a hash for each chunk, and then compute a hash value
240// of the hash values.
241
242static void
243computeHash(llvm::MutableArrayRef<uint8_t> hashBuf,
244 llvm::ArrayRef<uint8_t> data,
245 std::function<void(uint8_t *dest, ArrayRef<uint8_t> arr)> hashFn) {
246 std::vector<ArrayRef<uint8_t>> chunks = split(arr: data, chunkSize: 1024 * 1024);
247 std::vector<uint8_t> hashes(chunks.size() * hashBuf.size());
248
249 // Compute hash values.
250 parallelFor(Begin: 0, End: chunks.size(), Fn: [&](size_t i) {
251 hashFn(hashes.data() + i * hashBuf.size(), chunks[i]);
252 });
253
254 // Write to the final output buffer.
255 hashFn(hashBuf.data(), hashes);
256}
257
258static void makeUUID(unsigned version, llvm::ArrayRef<uint8_t> fileHash,
259 llvm::MutableArrayRef<uint8_t> output) {
260 assert((version == 4 || version == 5) && "Unknown UUID version");
261 assert(output.size() == 16 && "Wrong size for UUID output");
262 if (version == 5) {
263 // Build a valid v5 UUID from a hardcoded (randomly-generated) namespace
264 // UUID, and the computed hash of the output.
265 std::array<uint8_t, 16> namespaceUUID{0xA1, 0xFA, 0x48, 0x2D, 0x0E, 0x22,
266 0x03, 0x8D, 0x33, 0x8B, 0x52, 0x1C,
267 0xD6, 0xD2, 0x12, 0xB2};
268 SHA1 sha;
269 sha.update(Data: namespaceUUID);
270 sha.update(Data: fileHash);
271 auto s = sha.final();
272 std::copy(first: s.data(), last: &s.data()[output.size()], result: output.data());
273 } else if (version == 4) {
274 if (auto ec = llvm::getRandomBytes(Buffer: output.data(), Size: output.size()))
275 error(msg: "entropy source failure: " + ec.message());
276 }
277 // Set the UUID version and variant fields.
278 // The version is the upper nibble of byte 6 (0b0101xxxx or 0b0100xxxx)
279 output[6] = (static_cast<uint8_t>(version) << 4) | (output[6] & 0xF);
280
281 // The variant is DCE 1.1/ISO 11578 (0b10xxxxxx)
282 output[8] &= 0xBF;
283 output[8] |= 0x80;
284}
285
286void Writer::writeBuildId() {
287 if (!out.buildIdSec->isNeeded())
288 return;
289 if (ctx.arg.buildId == BuildIdKind::Hexstring) {
290 out.buildIdSec->writeBuildId(buf: ctx.arg.buildIdVector);
291 return;
292 }
293
294 // Compute a hash of all sections of the output file.
295 size_t hashSize = out.buildIdSec->hashSize;
296 std::vector<uint8_t> buildId(hashSize);
297 llvm::ArrayRef<uint8_t> buf{buffer->getBufferStart(), size_t(fileSize)};
298
299 switch (ctx.arg.buildId) {
300 case BuildIdKind::Fast: {
301 std::vector<uint8_t> fileHash(8);
302 computeHash(hashBuf: fileHash, data: buf, hashFn: [](uint8_t *dest, ArrayRef<uint8_t> arr) {
303 support::endian::write64le(P: dest, V: xxh3_64bits(data: arr));
304 });
305 makeUUID(version: 5, fileHash, output: buildId);
306 break;
307 }
308 case BuildIdKind::Sha1:
309 computeHash(hashBuf: buildId, data: buf, hashFn: [&](uint8_t *dest, ArrayRef<uint8_t> arr) {
310 memcpy(dest: dest, src: SHA1::hash(Data: arr).data(), n: hashSize);
311 });
312 break;
313 case BuildIdKind::Uuid:
314 makeUUID(version: 4, fileHash: {}, output: buildId);
315 break;
316 default:
317 llvm_unreachable("unknown BuildIdKind");
318 }
319 out.buildIdSec->writeBuildId(buf: buildId);
320}
321
322static void setGlobalPtr(DefinedGlobal *g, uint64_t memoryPtr) {
323 LLVM_DEBUG(dbgs() << "setGlobalPtr " << g->getName() << " -> " << memoryPtr
324 << "\n");
325 g->global->setPointerValue(memoryPtr);
326}
327
328static void checkPageAligned(StringRef name, uint64_t value) {
329 if (value != alignTo(Value: value, Align: ctx.arg.pageSize))
330 error(msg: name + " must be aligned to the page size (" +
331 Twine(ctx.arg.pageSize) + " bytes)");
332}
333
334// Fix the memory layout of the output binary. This assigns memory offsets
335// to each of the input data sections as well as the explicit stack region.
336// The default memory layout is as follows, from low to high.
337//
338// - initialized data (starting at ctx.arg.globalBase)
339// - BSS data (not currently implemented in llvm)
340// - explicit stack (ctx.arg.ZStackSize)
341// - heap start / unallocated
342//
343// The --stack-first option means that stack is placed before any static data.
344// This can be useful since it means that stack overflow traps immediately
345// rather than overwriting global data, but also increases code size since all
346// static data loads and stores requires larger offsets.
347void Writer::layoutMemory() {
348 uint64_t memoryPtr = 0;
349
350 auto placeStack = [&]() {
351 if (ctx.arg.relocatable || ctx.isPic)
352 return;
353 memoryPtr = alignTo(Value: memoryPtr, Align: stackAlignment);
354 if (ctx.sym.stackLow)
355 ctx.sym.stackLow->setVA(memoryPtr);
356 if (ctx.arg.zStackSize != alignTo(Value: ctx.arg.zStackSize, Align: stackAlignment))
357 error(msg: "stack size must be " + Twine(stackAlignment) + "-byte aligned");
358 log(msg: "mem: stack size = " + Twine(ctx.arg.zStackSize));
359 log(msg: "mem: stack base = " + Twine(memoryPtr));
360 memoryPtr += ctx.arg.zStackSize;
361 setGlobalPtr(g: cast<DefinedGlobal>(Val: ctx.sym.stackPointer), memoryPtr);
362 if (ctx.sym.stackHigh)
363 ctx.sym.stackHigh->setVA(memoryPtr);
364 log(msg: "mem: stack top = " + Twine(memoryPtr));
365 };
366
367 if (ctx.arg.stackFirst) {
368 placeStack();
369 if (ctx.arg.globalBase) {
370 if (ctx.arg.globalBase < memoryPtr) {
371 error(msg: "--global-base cannot be less than stack size when --stack-first "
372 "is used");
373 return;
374 }
375 memoryPtr = ctx.arg.globalBase;
376 }
377 } else {
378 memoryPtr = ctx.arg.globalBase;
379 }
380
381 log(msg: "mem: global base = " + Twine(memoryPtr));
382 if (ctx.sym.globalBase)
383 ctx.sym.globalBase->setVA(memoryPtr);
384
385 uint64_t dataStart = memoryPtr;
386
387 // Arbitrarily set __dso_handle handle to point to the start of the data
388 // segments.
389 if (ctx.sym.dsoHandle)
390 ctx.sym.dsoHandle->setVA(dataStart);
391
392 out.dylinkSec->memAlign = 0;
393 uint64_t fixedTLSBase = memoryPtr;
394 for (OutputSegment *seg : segments) {
395 out.dylinkSec->memAlign = std::max(a: out.dylinkSec->memAlign, b: seg->alignment);
396 memoryPtr = alignTo(Value: memoryPtr, Align: 1ULL << seg->alignment);
397 seg->startVA = memoryPtr;
398 log(msg: formatv(Fmt: "mem: {0,-15} offset={1,-8} size={2,-8} align={3}", Vals&: seg->name,
399 Vals&: memoryPtr, Vals&: seg->size, Vals&: seg->alignment));
400
401 if (!ctx.arg.relocatable && seg->isTLS()) {
402 if (ctx.sym.tlsSize) {
403 setGlobalPtr(g: ctx.sym.tlsSize, memoryPtr: seg->size);
404 }
405 if (ctx.sym.tlsAlign) {
406 setGlobalPtr(g: ctx.sym.tlsAlign, memoryPtr: int64_t{1} << seg->alignment);
407 }
408 fixedTLSBase = memoryPtr;
409 }
410
411 if (ctx.sym.rodataStart && seg->name.starts_with(Prefix: ".rodata") &&
412 !ctx.sym.rodataStart->getVA())
413 ctx.sym.rodataStart->setVA(memoryPtr);
414
415 memoryPtr += seg->size;
416
417 // Might get set more than once if segment merging is not enabled.
418 if (ctx.sym.rodataEnd && seg->name.starts_with(Prefix: ".rodata"))
419 ctx.sym.rodataEnd->setVA(memoryPtr);
420 }
421
422 // In single-threaded builds we set __tls_base statically.
423 // Even in the absense of any actual TLS data, this symbol can still be
424 // referenced (for example by __builtin_thread_pointer, which should not
425 // return NULL).
426 if (!ctx.arg.isMultithreaded() && ctx.sym.tlsBase) {
427 setGlobalPtr(g: ctx.sym.tlsBase, memoryPtr: fixedTLSBase);
428 }
429
430 // Make space for the memory initialization flag
431 if (ctx.arg.sharedMemory && hasPassiveInitializedSegments()) {
432 memoryPtr = alignTo(Value: memoryPtr, Align: 4);
433 ctx.sym.initMemoryFlag = symtab->addSyntheticDataSymbol(
434 name: "__wasm_init_memory_flag", flags: WASM_SYMBOL_VISIBILITY_HIDDEN);
435 ctx.sym.initMemoryFlag->markLive();
436 ctx.sym.initMemoryFlag->setVA(memoryPtr);
437 log(msg: formatv(Fmt: "mem: {0,-15} offset={1,-8} size={2,-8} align={3}",
438 Vals: "__wasm_init_memory_flag", Vals&: memoryPtr, Vals: 4, Vals: 4));
439 memoryPtr += 4;
440 }
441
442 if (ctx.sym.dataEnd)
443 ctx.sym.dataEnd->setVA(memoryPtr);
444
445 uint64_t staticDataSize = memoryPtr - dataStart;
446 log(msg: "mem: static data = " + Twine(staticDataSize));
447 if (ctx.isPic)
448 out.dylinkSec->memSize = staticDataSize;
449
450 if (!ctx.arg.stackFirst)
451 placeStack();
452
453 if (ctx.sym.heapBase) {
454 // Set `__heap_base` to follow the end of the stack or global data. The
455 // fact that this comes last means that a malloc/brk implementation can
456 // grow the heap at runtime.
457 // We'll align the heap base here because memory allocators might expect
458 // __heap_base to be aligned already.
459 memoryPtr = alignTo(Value: memoryPtr, Align: heapAlignment);
460 log(msg: "mem: heap base = " + Twine(memoryPtr));
461 ctx.sym.heapBase->setVA(memoryPtr);
462 }
463
464 uint64_t maxMemorySetting = 1ULL << 32;
465 if (ctx.arg.is64.value_or(u: false)) {
466 // TODO: Update once we decide on a reasonable limit here:
467 // https://github.com/WebAssembly/memory64/issues/33
468 maxMemorySetting = 1ULL << 34;
469 }
470
471 if (ctx.arg.initialHeap != 0) {
472 checkPageAligned(name: "initial heap", value: ctx.arg.initialHeap);
473 uint64_t maxInitialHeap = maxMemorySetting - memoryPtr;
474 if (ctx.arg.initialHeap > maxInitialHeap)
475 error(msg: "initial heap too large, cannot be greater than " +
476 Twine(maxInitialHeap));
477 memoryPtr += ctx.arg.initialHeap;
478 }
479
480 if (ctx.arg.initialMemory != 0) {
481 checkPageAligned(name: "initial memory", value: ctx.arg.initialMemory);
482 if (memoryPtr > ctx.arg.initialMemory)
483 error(msg: "initial memory too small, " + Twine(memoryPtr) + " bytes needed");
484 if (ctx.arg.initialMemory > maxMemorySetting)
485 error(msg: "initial memory too large, cannot be greater than " +
486 Twine(maxMemorySetting));
487 memoryPtr = ctx.arg.initialMemory;
488 }
489
490 memoryPtr = alignTo(Value: memoryPtr, Align: ctx.arg.pageSize);
491
492 out.memorySec->numMemoryPages = memoryPtr / ctx.arg.pageSize;
493 log(msg: "mem: total pages = " + Twine(out.memorySec->numMemoryPages));
494
495 if (ctx.sym.heapEnd) {
496 // Set `__heap_end` to follow the end of the statically allocated linear
497 // memory. The fact that this comes last means that a malloc/brk
498 // implementation can grow the heap at runtime.
499 log(msg: "mem: heap end = " + Twine(memoryPtr));
500 ctx.sym.heapEnd->setVA(memoryPtr);
501 }
502
503 uint64_t maxMemory = 0;
504 if (ctx.arg.maxMemory != 0) {
505 checkPageAligned(name: "maximum memory", value: ctx.arg.maxMemory);
506 if (memoryPtr > ctx.arg.maxMemory)
507 error(msg: "maximum memory too small, " + Twine(memoryPtr) + " bytes needed");
508 if (ctx.arg.maxMemory > maxMemorySetting)
509 error(msg: "maximum memory too large, cannot be greater than " +
510 Twine(maxMemorySetting));
511
512 maxMemory = ctx.arg.maxMemory;
513 } else if (ctx.arg.noGrowableMemory) {
514 maxMemory = memoryPtr;
515 }
516
517 // If no maxMemory config was supplied but we are building with
518 // shared memory, we need to pick a sensible upper limit.
519 if (ctx.arg.sharedMemory && maxMemory == 0) {
520 if (ctx.isPic)
521 maxMemory = maxMemorySetting;
522 else
523 maxMemory = memoryPtr;
524 }
525
526 if (maxMemory != 0) {
527 out.memorySec->maxMemoryPages = maxMemory / ctx.arg.pageSize;
528 log(msg: "mem: max pages = " + Twine(out.memorySec->maxMemoryPages));
529 }
530}
531
532void Writer::addSection(OutputSection *sec) {
533 if (!sec->isNeeded())
534 return;
535 log(msg: "addSection: " + toString(section: *sec));
536 sec->sectionIndex = outputSections.size();
537 outputSections.push_back(x: sec);
538}
539
540// If a section name is valid as a C identifier (which is rare because of
541// the leading '.'), linkers are expected to define __start_<secname> and
542// __stop_<secname> symbols. They are at beginning and end of the section,
543// respectively. This is not requested by the ELF standard, but GNU ld and
544// gold provide the feature, and used by many programs.
545static void addStartStopSymbols(const OutputSegment *seg) {
546 StringRef name = seg->name;
547 if (!isValidCIdentifier(s: name))
548 return;
549 LLVM_DEBUG(dbgs() << "addStartStopSymbols: " << name << "\n");
550 uint64_t start = seg->startVA;
551 uint64_t stop = start + seg->size;
552 symtab->addOptionalDataSymbol(name: saver().save(S: "__start_" + name), value: start);
553 symtab->addOptionalDataSymbol(name: saver().save(S: "__stop_" + name), value: stop);
554}
555
556void Writer::addSections() {
557 addSection(sec: out.dylinkSec);
558 addSection(sec: out.typeSec);
559 addSection(sec: out.importSec);
560 addSection(sec: out.functionSec);
561 addSection(sec: out.tableSec);
562 addSection(sec: out.memorySec);
563 addSection(sec: out.tagSec);
564 addSection(sec: out.globalSec);
565 addSection(sec: out.exportSec);
566 addSection(sec: out.startSec);
567 addSection(sec: out.elemSec);
568 addSection(sec: out.dataCountSec);
569
570 addSection(sec: make<CodeSection>(args&: out.functionSec->inputFunctions));
571 addSection(sec: make<DataSection>(args&: segments));
572
573 createCustomSections();
574
575 addSection(sec: out.linkingSec);
576 if (ctx.arg.emitRelocs || ctx.arg.relocatable) {
577 createRelocSections();
578 }
579
580 addSection(sec: out.nameSec);
581 addSection(sec: out.producersSec);
582 addSection(sec: out.targetFeaturesSec);
583 addSection(sec: out.buildIdSec);
584}
585
586void Writer::finalizeSections() {
587 for (OutputSection *s : outputSections) {
588 s->setOffset(fileSize);
589 s->finalizeContents();
590 fileSize += s->getSize();
591 }
592}
593
594void Writer::populateTargetFeatures() {
595 StringMap<std::string> used;
596 StringMap<std::string> disallowed;
597 SmallSet<std::string, 8> &allowed = out.targetFeaturesSec->features;
598 bool tlsUsed = false;
599
600 if (ctx.isPic) {
601 // This should not be necessary because all PIC objects should
602 // contain the `mutable-globals` feature.
603 // TODO (https://github.com/llvm/llvm-project/issues/51681)
604 allowed.insert(V: "mutable-globals");
605 }
606
607 if (ctx.arg.extraFeatures.has_value()) {
608 auto &extraFeatures = *ctx.arg.extraFeatures;
609 allowed.insert_range(R&: extraFeatures);
610 }
611
612 // Only infer used features if user did not specify features
613 bool inferFeatures = !ctx.arg.features.has_value();
614
615 if (!inferFeatures) {
616 auto &explicitFeatures = *ctx.arg.features;
617 allowed.insert_range(R&: explicitFeatures);
618 if (!ctx.arg.checkFeatures)
619 goto done;
620 }
621
622 // Find the sets of used and disallowed features
623 for (ObjFile *file : ctx.objectFiles) {
624 StringRef fileName(file->getName());
625 for (auto &feature : file->getWasmObj()->getTargetFeatures()) {
626 switch (feature.Prefix) {
627 case WASM_FEATURE_PREFIX_USED:
628 used.insert(KV: {feature.Name, std::string(fileName)});
629 break;
630 case WASM_FEATURE_PREFIX_DISALLOWED:
631 disallowed.insert(KV: {feature.Name, std::string(fileName)});
632 break;
633 default:
634 error(msg: "Unrecognized feature policy prefix " +
635 std::to_string(val: feature.Prefix));
636 }
637 }
638
639 // Find TLS data segments
640 auto isTLS = [](InputChunk *segment) {
641 return segment->live && segment->isTLS();
642 };
643 tlsUsed = tlsUsed || llvm::any_of(Range&: file->segments, P: isTLS);
644
645 // Ensure that we're not mixing incompatible thread context models
646 if (ctx.arg.libcallThreadContext &&
647 llvm::any_of(Range: file->getSymbols(), P: [](const auto &sym) {
648 return sym && sym->getName() == "__stack_pointer" &&
649 sym->kind() == Symbol::UndefinedGlobalKind &&
650 sym->importModule && sym->importModule == "env";
651 }))
652 error(msg: fileName + ": object file uses globals for thread context, "
653 "but --cooperative-threading was specified");
654 }
655
656 if (inferFeatures)
657 for (const auto &key : used.keys())
658 allowed.insert(V: std::string(key));
659
660 if (!ctx.arg.checkFeatures)
661 goto done;
662
663 if (ctx.arg.sharedMemory) {
664 if (disallowed.contains(Key: "shared-mem"))
665 error(msg: "--shared-memory is disallowed by " + disallowed["shared-mem"] +
666 " because it was not compiled with 'atomics' or 'bulk-memory' "
667 "features.");
668
669 for (auto feature : {"atomics", "bulk-memory"})
670 if (!allowed.contains(V: feature))
671 error(msg: StringRef("'") + feature +
672 "' feature must be used in order to use shared memory");
673 }
674
675 if (tlsUsed) {
676 if (!allowed.contains(V: "bulk-memory"))
677 error(msg: "'bulk-memory' feature must be used in order to use thread-local "
678 "storage");
679 if (!allowed.contains(V: "atomics") && !ctx.arg.cooperativeThreading)
680 error(msg: "'atomics' feature must be used in order to use thread-local "
681 "storage");
682 }
683
684 // Validate that used features are allowed in output
685 if (!inferFeatures) {
686 for (const auto &feature : used.keys()) {
687 if (!allowed.contains(V: std::string(feature)))
688 error(msg: Twine("Target feature '") + feature + "' used by " +
689 used[feature] + " is not allowed.");
690 }
691 }
692
693 // Validate the disallowed constraints for each file
694 for (ObjFile *file : ctx.objectFiles) {
695 StringRef fileName(file->getName());
696 SmallSet<std::string, 8> objectFeatures;
697 for (const auto &feature : file->getWasmObj()->getTargetFeatures()) {
698 if (feature.Prefix == WASM_FEATURE_PREFIX_DISALLOWED)
699 continue;
700 objectFeatures.insert(V: feature.Name);
701 if (disallowed.contains(Key: feature.Name))
702 error(msg: Twine("Target feature '") + feature.Name + "' used in " +
703 fileName + " is disallowed by " + disallowed[feature.Name] +
704 ". Use --no-check-features to suppress.");
705 }
706 }
707
708done:
709 // Normally we don't include bss segments in the binary. In particular if
710 // memory is not being imported then we can assume its zero initialized.
711 // In the case the memory is imported, and we can use the memory.fill
712 // instruction, then we can also avoid including the segments.
713 // Finally, if we are emitting relocations, they may refer to locations within
714 // the bss segments, so these segments need to exist in the binary.
715 if (ctx.arg.emitRelocs ||
716 (ctx.arg.memoryImport.has_value() && !allowed.contains(V: "bulk-memory")))
717 ctx.emitBssSegments = true;
718
719 if (allowed.contains(V: "extended-const"))
720 ctx.arg.extendedConst = true;
721
722 for (auto &feature : allowed)
723 log(msg: "Allowed feature: " + feature);
724}
725
726void Writer::checkImportExportTargetFeatures() {
727 if (ctx.arg.relocatable || !ctx.arg.checkFeatures)
728 return;
729
730 if (!out.targetFeaturesSec->features.contains(V: "mutable-globals")) {
731 for (const Symbol *sym : out.importSec->importedSymbols) {
732 if (auto *global = dyn_cast<GlobalSymbol>(Val: sym)) {
733 if (global->getGlobalType()->Mutable) {
734 error(msg: Twine("mutable global imported but 'mutable-globals' feature "
735 "not present in inputs: `") +
736 toString(sym: *sym) + "`. Use --no-check-features to suppress.");
737 }
738 }
739 }
740 for (const Symbol *sym : out.exportSec->exportedSymbols) {
741 if (auto *global = dyn_cast<GlobalSymbol>(Val: sym)) {
742 if (global->getGlobalType()->Mutable) {
743 error(msg: Twine("mutable global exported but 'mutable-globals' feature "
744 "not present in inputs: `") +
745 toString(sym: *sym) + "`. Use --no-check-features to suppress.");
746 }
747 }
748 }
749 }
750}
751
752static bool shouldImport(Symbol *sym) {
753 // We don't generate imports for data symbols. They however can be imported
754 // as GOT entries.
755 if (isa<DataSymbol>(Val: sym))
756 return false;
757 if (!sym->isLive())
758 return false;
759 if (!sym->isUsedInRegularObj)
760 return false;
761
762 // When a symbol is weakly defined in a shared library we need to allow
763 // it to be overridden by another module so need to both import
764 // and export the symbol.
765 if (ctx.arg.shared && sym->isWeak() && !sym->isUndefined() &&
766 !sym->isHidden())
767 return true;
768 if (sym->isShared())
769 return true;
770 if (!sym->isUndefined())
771 return false;
772 if (sym->isWeak() && !ctx.arg.relocatable && !ctx.isPic)
773 return false;
774
775 // In PIC mode we only need to import functions when they are called directly.
776 // Indirect usage all goes via GOT imports.
777 if (ctx.isPic) {
778 if (auto *f = dyn_cast<UndefinedFunction>(Val: sym))
779 if (!f->isCalledDirectly)
780 return false;
781 }
782
783 if (ctx.isPic || ctx.arg.relocatable || ctx.arg.importUndefined ||
784 ctx.arg.unresolvedSymbols == UnresolvedPolicy::ImportDynamic)
785 return true;
786 if (ctx.arg.allowUndefinedSymbols.contains(key: sym->getName()))
787 return true;
788
789 return sym->isImported();
790}
791
792void Writer::calculateImports() {
793 // Some inputs require that the indirect function table be assigned to table
794 // number 0, so if it is present and is an import, allocate it before any
795 // other tables.
796 if (ctx.sym.indirectFunctionTable &&
797 shouldImport(sym: ctx.sym.indirectFunctionTable))
798 out.importSec->addImport(sym: ctx.sym.indirectFunctionTable);
799
800 for (Symbol *sym : symtab->symbols()) {
801 if (!shouldImport(sym))
802 continue;
803 if (sym == ctx.sym.indirectFunctionTable)
804 continue;
805 LLVM_DEBUG(dbgs() << "import: " << sym->getName() << "\n");
806 out.importSec->addImport(sym);
807 }
808}
809
810void Writer::calculateExports() {
811 if (ctx.arg.relocatable)
812 return;
813
814 if (!ctx.arg.relocatable && ctx.arg.memoryExport.has_value()) {
815 out.exportSec->exports.push_back(
816 x: WasmExport{.Name: *ctx.arg.memoryExport, .Kind: WASM_EXTERNAL_MEMORY, .Index: 0});
817 }
818
819 unsigned globalIndex =
820 out.importSec->getNumImportedGlobals() + out.globalSec->numGlobals();
821
822 bool hasMutableGlobals =
823 out.targetFeaturesSec->features.contains(V: "mutable-globals");
824
825 for (Symbol *sym : symtab->symbols()) {
826 if (!sym->isExported())
827 continue;
828 if (!sym->isLive())
829 continue;
830 if (isa<SharedFunctionSymbol>(Val: sym) || sym->isShared())
831 continue;
832
833 StringRef name = sym->getName();
834 LLVM_DEBUG(dbgs() << "Export: " << name << "\n");
835 WasmExport export_;
836 if (auto *f = dyn_cast<DefinedFunction>(Val: sym)) {
837 if (std::optional<StringRef> exportName = f->function->getExportName()) {
838 name = *exportName;
839 }
840 export_ = {.Name: name, .Kind: WASM_EXTERNAL_FUNCTION, .Index: f->getExportedFunctionIndex()};
841 } else if (auto *g = dyn_cast<DefinedGlobal>(Val: sym)) {
842 if (!hasMutableGlobals && g->getGlobalType()->Mutable && !g->getFile() &&
843 !g->isExportedExplicit()) {
844 // Avoid exporting mutable globals are linker synthesized (e.g.
845 // __stack_pointer or __tls_base) unless they are explicitly exported
846 // from the command line.
847 // Without this check `--export-all` would cause any program using the
848 // stack pointer to export a mutable global even if none of the input
849 // files were built with the `mutable-globals` feature.
850 continue;
851 }
852 export_ = {.Name: name, .Kind: WASM_EXTERNAL_GLOBAL, .Index: g->getGlobalIndex()};
853 } else if (auto *t = dyn_cast<DefinedTag>(Val: sym)) {
854 export_ = {.Name: name, .Kind: WASM_EXTERNAL_TAG, .Index: t->getTagIndex()};
855 } else if (auto *d = dyn_cast<DefinedData>(Val: sym)) {
856 out.globalSec->dataAddressGlobals.push_back(x: d);
857 export_ = {.Name: name, .Kind: WASM_EXTERNAL_GLOBAL, .Index: globalIndex++};
858 } else {
859 auto *t = cast<DefinedTable>(Val: sym);
860 export_ = {.Name: name, .Kind: WASM_EXTERNAL_TABLE, .Index: t->getTableNumber()};
861 }
862
863 out.exportSec->exports.push_back(x: export_);
864 out.exportSec->exportedSymbols.push_back(x: sym);
865 }
866}
867
868void Writer::populateSymtab() {
869 if (!ctx.arg.relocatable && !ctx.arg.emitRelocs)
870 return;
871
872 for (Symbol *sym : symtab->symbols())
873 if (sym->isUsedInRegularObj && sym->isLive() && !sym->isShared())
874 out.linkingSec->addToSymtab(sym);
875
876 for (ObjFile *file : ctx.objectFiles) {
877 LLVM_DEBUG(dbgs() << "Local symtab entries: " << file->getName() << "\n");
878 for (Symbol *sym : file->getSymbols())
879 if (sym->isLocal() && !isa<SectionSymbol>(Val: sym) && sym->isLive())
880 out.linkingSec->addToSymtab(sym);
881 }
882}
883
884void Writer::calculateTypes() {
885 // The output type section is the union of the following sets:
886 // 1. Any signature used in the TYPE relocation
887 // 2. The signatures of all imported functions
888 // 3. The signatures of all defined functions
889 // 4. The signatures of all imported tags
890 // 5. The signatures of all defined tags
891
892 for (ObjFile *file : ctx.objectFiles) {
893 ArrayRef<WasmSignature> types = file->getWasmObj()->types();
894 for (uint32_t i = 0; i < types.size(); i++)
895 if (file->typeIsUsed[i])
896 file->typeMap[i] = out.typeSec->registerType(sig: types[i]);
897 }
898
899 for (const Symbol *sym : out.importSec->importedSymbols) {
900 if (auto *f = dyn_cast<FunctionSymbol>(Val: sym))
901 out.typeSec->registerType(sig: *f->signature);
902 else if (auto *t = dyn_cast<TagSymbol>(Val: sym))
903 out.typeSec->registerType(sig: *t->signature);
904 }
905
906 for (const InputFunction *f : out.functionSec->inputFunctions)
907 out.typeSec->registerType(sig: f->signature);
908
909 for (const InputTag *t : out.tagSec->inputTags)
910 out.typeSec->registerType(sig: t->signature);
911}
912
913// In a command-style link, create a wrapper for each exported symbol
914// which calls the constructors and destructors.
915void Writer::createCommandExportWrappers() {
916 // This logic doesn't currently support Emscripten-style PIC mode.
917 assert(!ctx.isPic);
918
919 // If there are no ctors and there's no libc `__wasm_call_dtors` to
920 // call, don't wrap the exports.
921 if (initFunctions.empty() && ctx.sym.callDtors == nullptr)
922 return;
923
924 std::vector<DefinedFunction *> toWrap;
925
926 for (Symbol *sym : symtab->symbols())
927 if (sym->isExported())
928 if (auto *f = dyn_cast<DefinedFunction>(Val: sym))
929 toWrap.push_back(x: f);
930
931 for (auto *f : toWrap) {
932 auto funcNameStr = (f->getName() + ".command_export").str();
933 commandExportWrapperNames.push_back(x: funcNameStr);
934 const std::string &funcName = commandExportWrapperNames.back();
935
936 auto func = make<SyntheticFunction>(args: *f->getSignature(), args: funcName);
937 if (f->function->getExportName())
938 func->setExportName(f->function->getExportName()->str());
939 else
940 func->setExportName(f->getName().str());
941
942 DefinedFunction *def =
943 symtab->addSyntheticFunction(name: funcName, flags: f->flags, function: func);
944 def->markLive();
945
946 def->flags |= WASM_SYMBOL_EXPORTED;
947 def->flags &= ~WASM_SYMBOL_VISIBILITY_HIDDEN;
948 def->forceExport = f->forceExport;
949
950 f->flags |= WASM_SYMBOL_VISIBILITY_HIDDEN;
951 f->flags &= ~WASM_SYMBOL_EXPORTED;
952 f->forceExport = false;
953
954 out.functionSec->addFunction(func);
955
956 createCommandExportWrapper(functionIndex: f->getFunctionIndex(), f: def);
957 }
958}
959
960static void finalizeIndirectFunctionTable() {
961 if (!ctx.sym.indirectFunctionTable)
962 return;
963
964 if (shouldImport(sym: ctx.sym.indirectFunctionTable) &&
965 !ctx.sym.indirectFunctionTable->hasTableNumber()) {
966 // Processing -Bsymbolic relocations resulted in a late requirement that the
967 // indirect function table be present, and we are running in --import-table
968 // mode. Add the table now to the imports section. Otherwise it will be
969 // added to the tables section later in assignIndexes.
970 out.importSec->addImport(sym: ctx.sym.indirectFunctionTable);
971 }
972
973 uint32_t tableSize = ctx.arg.tableBase + out.elemSec->numEntries();
974 WasmLimits limits = {.Flags: 0, .Minimum: tableSize, .Maximum: 0, .PageSize: 0};
975 if (ctx.sym.indirectFunctionTable->isDefined() && !ctx.arg.growableTable) {
976 limits.Flags |= WASM_LIMITS_FLAG_HAS_MAX;
977 limits.Maximum = limits.Minimum;
978 }
979 if (ctx.arg.is64.value_or(u: false))
980 limits.Flags |= WASM_LIMITS_FLAG_IS_64;
981 ctx.sym.indirectFunctionTable->setLimits(limits);
982}
983
984static void scanRelocations() {
985 for (ObjFile *file : ctx.objectFiles) {
986 LLVM_DEBUG(dbgs() << "scanRelocations: " << file->getName() << "\n");
987 for (InputChunk *chunk : file->functions)
988 scanRelocations(chunk);
989 for (InputChunk *chunk : file->segments)
990 scanRelocations(chunk);
991 for (auto &p : file->customSections)
992 scanRelocations(chunk: p);
993 }
994}
995
996void Writer::assignIndexes() {
997 // Seal the import section, since other index spaces such as function and
998 // global are effected by the number of imports.
999 out.importSec->seal();
1000
1001 for (InputFunction *func : ctx.syntheticFunctions)
1002 out.functionSec->addFunction(func);
1003
1004 for (ObjFile *file : ctx.objectFiles) {
1005 LLVM_DEBUG(dbgs() << "Functions: " << file->getName() << "\n");
1006 for (InputFunction *func : file->functions)
1007 out.functionSec->addFunction(func);
1008 }
1009
1010 for (InputGlobal *global : ctx.syntheticGlobals)
1011 out.globalSec->addGlobal(global);
1012
1013 for (ObjFile *file : ctx.objectFiles) {
1014 LLVM_DEBUG(dbgs() << "Globals: " << file->getName() << "\n");
1015 for (InputGlobal *global : file->globals)
1016 out.globalSec->addGlobal(global);
1017 }
1018
1019 for (ObjFile *file : ctx.objectFiles) {
1020 LLVM_DEBUG(dbgs() << "Tags: " << file->getName() << "\n");
1021 for (InputTag *tag : file->tags)
1022 out.tagSec->addTag(tag);
1023 }
1024
1025 for (ObjFile *file : ctx.objectFiles) {
1026 LLVM_DEBUG(dbgs() << "Tables: " << file->getName() << "\n");
1027 for (InputTable *table : file->tables)
1028 out.tableSec->addTable(table);
1029 }
1030
1031 for (InputTable *table : ctx.syntheticTables)
1032 out.tableSec->addTable(table);
1033
1034 out.globalSec->assignIndexes();
1035 out.tableSec->assignIndexes();
1036}
1037
1038static StringRef getOutputDataSegmentName(const InputChunk &seg) {
1039 // We always merge .tbss and .tdata into a single TLS segment so all TLS
1040 // symbols are be relative to single __tls_base.
1041 if (seg.isTLS())
1042 return ".tdata";
1043 if (!ctx.arg.mergeDataSegments)
1044 return seg.name;
1045 if (seg.name.starts_with(Prefix: ".text."))
1046 return ".text";
1047 if (seg.name.starts_with(Prefix: ".data."))
1048 return ".data";
1049 if (seg.name.starts_with(Prefix: ".bss."))
1050 return ".bss";
1051 if (seg.name.starts_with(Prefix: ".rodata."))
1052 return ".rodata";
1053 return seg.name;
1054}
1055
1056OutputSegment *Writer::createOutputSegment(StringRef name) {
1057 LLVM_DEBUG(dbgs() << "new segment: " << name << "\n");
1058 OutputSegment *s = make<OutputSegment>(args&: name);
1059 // In the shared memory case, all data segments must be passive since they
1060 // will be initialized once by the main thread and then shared with other
1061 // threads. In the cooperative threading case, TLS segments need to exist to
1062 // be able to run TLS initialization on spawned threads, so that's managed
1063 // here by flagging TLS as passive as well.
1064 bool needsPassiveInit =
1065 ctx.arg.sharedMemory || (ctx.arg.cooperativeThreading && s->isTLS());
1066 if (needsPassiveInit)
1067 s->initFlags = WASM_DATA_SEGMENT_IS_PASSIVE;
1068 if (!ctx.arg.relocatable && name.starts_with(Prefix: ".bss"))
1069 s->isBss = true;
1070 segments.push_back(x: s);
1071 return s;
1072}
1073
1074void Writer::createOutputSegments() {
1075 for (ObjFile *file : ctx.objectFiles) {
1076 for (InputChunk *segment : file->segments) {
1077 if (!segment->live)
1078 continue;
1079 StringRef name = getOutputDataSegmentName(seg: *segment);
1080 OutputSegment *s = nullptr;
1081 // When running in relocatable mode we can't merge segments that are part
1082 // of comdat groups since the ultimate linker needs to be able exclude or
1083 // include them individually.
1084 if (ctx.arg.relocatable && !segment->getComdatName().empty()) {
1085 s = createOutputSegment(name);
1086 } else {
1087 if (!segmentMap.contains(Val: name))
1088 segmentMap[name] = createOutputSegment(name);
1089 s = segmentMap[name];
1090 }
1091 s->addInputSegment(inSeg: segment);
1092 }
1093 }
1094
1095 // Sort segments by type, placing .bss last
1096 llvm::stable_sort(Range&: segments,
1097 C: [](const OutputSegment *a, const OutputSegment *b) {
1098 auto order = [](StringRef name) {
1099 return StringSwitch<int>(name)
1100 .StartsWith(S: ".tdata", Value: 0)
1101 .StartsWith(S: ".rodata", Value: 1)
1102 .StartsWith(S: ".data", Value: 2)
1103 .StartsWith(S: ".bss", Value: 4)
1104 .Default(Value: 3);
1105 };
1106 return order(a->name) < order(b->name);
1107 });
1108
1109 for (size_t i = 0; i < segments.size(); ++i)
1110 segments[i]->index = i;
1111
1112 // Merge MergeInputSections into a single MergeSyntheticSection.
1113 LLVM_DEBUG(dbgs() << "-- finalize input semgments\n");
1114 for (OutputSegment *seg : segments)
1115 seg->finalizeInputSegments();
1116}
1117
1118void Writer::combineOutputSegments() {
1119 // With PIC code we currently only support a single active data segment since
1120 // we only have a single __memory_base to use as our base address. This pass
1121 // combines all data segments into a single .data segment.
1122 // This restriction does not apply when the extended const extension is
1123 // available: https://github.com/WebAssembly/extended-const
1124 assert(!ctx.arg.extendedConst);
1125 assert(ctx.isPic && !ctx.arg.isMultithreaded());
1126 if (segments.size() <= 1)
1127 return;
1128 OutputSegment *combined = make<OutputSegment>(args: ".data");
1129 combined->startVA = segments[0]->startVA;
1130 std::vector<OutputSegment *> newSegments = {combined};
1131 for (OutputSegment *s : segments) {
1132 if (!s->requiredInBinary()) {
1133 newSegments.push_back(x: s);
1134 continue;
1135 }
1136 bool first = true;
1137 for (InputChunk *inSeg : s->inputSegments) {
1138 if (first)
1139 inSeg->alignment = std::max(a: inSeg->alignment, b: s->alignment);
1140 first = false;
1141#ifndef NDEBUG
1142 uint64_t oldVA = inSeg->getVA();
1143#endif
1144 combined->addInputSegment(inSeg);
1145#ifndef NDEBUG
1146 uint64_t newVA = inSeg->getVA();
1147 LLVM_DEBUG(dbgs() << "added input segment. name=" << inSeg->name
1148 << " oldVA=" << oldVA << " newVA=" << newVA << "\n");
1149 assert(oldVA == newVA);
1150#endif
1151 }
1152 }
1153
1154 segments = std::move(newSegments);
1155}
1156
1157static void createFunction(DefinedFunction *func, StringRef bodyContent) {
1158 std::string functionBody;
1159 {
1160 raw_string_ostream os(functionBody);
1161 writeUleb128(os, number: bodyContent.size(), msg: "function size");
1162 os << bodyContent;
1163 }
1164 ArrayRef<uint8_t> body = arrayRefFromStringRef(Input: saver().save(S: functionBody));
1165 cast<SyntheticFunction>(Val: func->function)->setBody(body);
1166}
1167
1168bool Writer::needsPassiveInitialization(const OutputSegment *segment) {
1169 // If bulk memory features is supported then we can perform bss initialization
1170 // (via memory.fill) during `__wasm_init_memory`.
1171 if (ctx.arg.memoryImport.has_value() && !segment->requiredInBinary())
1172 return true;
1173 return segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE;
1174}
1175
1176bool Writer::hasPassiveInitializedSegments() {
1177 return llvm::any_of(Range&: segments, P: [this](const OutputSegment *s) {
1178 return this->needsPassiveInitialization(segment: s);
1179 });
1180}
1181
1182void Writer::createSyntheticInitFunctions() {
1183 if (ctx.arg.relocatable)
1184 return;
1185
1186 static WasmSignature nullSignature = {{}, {}};
1187
1188 createApplyDataRelocationsFunction();
1189
1190 // Passive segments are used to avoid memory being reinitialized on each
1191 // thread's instantiation. These passive segments are initialized and
1192 // dropped in __wasm_init_memory, which is registered as the start function
1193 // We also initialize bss segments (using memory.fill) as part of this
1194 // function.
1195 if (hasPassiveInitializedSegments()) {
1196 ctx.sym.initMemory = symtab->addSyntheticFunction(
1197 name: "__wasm_init_memory", flags: WASM_SYMBOL_VISIBILITY_HIDDEN,
1198 function: make<SyntheticFunction>(args&: nullSignature, args: "__wasm_init_memory"));
1199 ctx.sym.initMemory->markLive();
1200 // __wasm_init_memory uses __tls_base/__wasm_set_tls_base
1201 if (ctx.sym.setTLSBase)
1202 ctx.sym.setTLSBase->markLive();
1203 else if (ctx.arg.sharedMemory)
1204 ctx.sym.tlsBase->markLive();
1205 }
1206
1207 if (ctx.arg.isMultithreaded()) {
1208 if (out.globalSec->needsTLSRelocations()) {
1209 ctx.sym.applyGlobalTLSRelocs = symtab->addSyntheticFunction(
1210 name: "__wasm_apply_global_tls_relocs", flags: WASM_SYMBOL_VISIBILITY_HIDDEN,
1211 function: make<SyntheticFunction>(args&: nullSignature,
1212 args: "__wasm_apply_global_tls_relocs"));
1213 ctx.sym.applyGlobalTLSRelocs->markLive();
1214 // TLS relocations depend on the __tls_base/__wasm_get_tls_base symbols
1215 if (ctx.sym.getTLSBase)
1216 ctx.sym.getTLSBase->markLive();
1217 else if (ctx.arg.sharedMemory)
1218 ctx.sym.tlsBase->markLive();
1219 }
1220
1221 auto hasTLSRelocs = [](const OutputSegment *segment) {
1222 if (segment->isTLS())
1223 for (const auto *is : segment->inputSegments)
1224 if (is->getRelocations().size())
1225 return true;
1226 return false;
1227 };
1228 if (llvm::any_of(Range&: segments, P: hasTLSRelocs)) {
1229 ctx.sym.applyTLSRelocs = symtab->addSyntheticFunction(
1230 name: "__wasm_apply_tls_relocs", flags: WASM_SYMBOL_VISIBILITY_HIDDEN,
1231 function: make<SyntheticFunction>(args&: nullSignature, args: "__wasm_apply_tls_relocs"));
1232 ctx.sym.applyTLSRelocs->markLive();
1233 }
1234 }
1235
1236 if (ctx.isPic && out.globalSec->needsRelocations()) {
1237 ctx.sym.applyGlobalRelocs = symtab->addSyntheticFunction(
1238 name: "__wasm_apply_global_relocs", flags: WASM_SYMBOL_VISIBILITY_HIDDEN,
1239 function: make<SyntheticFunction>(args&: nullSignature, args: "__wasm_apply_global_relocs"));
1240 ctx.sym.applyGlobalRelocs->markLive();
1241 }
1242
1243 // If there is only one start function we can just use that function
1244 // itself as the Wasm start function, otherwise we need to synthesize
1245 // a new function to call them in sequence.
1246 if (ctx.sym.applyGlobalRelocs && ctx.sym.initMemory) {
1247 ctx.sym.startFunction = symtab->addSyntheticFunction(
1248 name: "__wasm_start", flags: WASM_SYMBOL_VISIBILITY_HIDDEN,
1249 function: make<SyntheticFunction>(args&: nullSignature, args: "__wasm_start"));
1250 ctx.sym.startFunction->markLive();
1251 }
1252}
1253
1254void Writer::createInitMemoryFunction() {
1255 LLVM_DEBUG(dbgs() << "createInitMemoryFunction\n");
1256 assert(ctx.sym.initMemory);
1257 assert(hasPassiveInitializedSegments());
1258 uint64_t flagAddress;
1259 if (ctx.arg.sharedMemory) {
1260 assert(ctx.sym.initMemoryFlag);
1261 flagAddress = ctx.sym.initMemoryFlag->getVA();
1262 }
1263 bool is64 = ctx.arg.is64.value_or(u: false);
1264 std::string bodyContent;
1265 {
1266 raw_string_ostream os(bodyContent);
1267 // Initialize memory in a thread-safe manner. The thread that successfully
1268 // increments the flag from 0 to 1 is responsible for performing the memory
1269 // initialization. Other threads go sleep on the flag until the first thread
1270 // finishing initializing memory, increments the flag to 2, and wakes all
1271 // the other threads. Once the flag has been set to 2, subsequently started
1272 // threads will skip the sleep. All threads unconditionally drop their
1273 // passive data segments once memory has been initialized. The generated
1274 // code is as follows:
1275 //
1276 // (func $__wasm_init_memory
1277 // (block $drop
1278 // (block $wait
1279 // (block $init
1280 // (br_table $init $wait $drop
1281 // (i32.atomic.rmw.cmpxchg align=2 offset=0
1282 // (i32.const $__init_memory_flag)
1283 // (i32.const 0)
1284 // (i32.const 1)
1285 // )
1286 // )
1287 // ) ;; $init
1288 // ( ... initialize data segments ... )
1289 // (i32.atomic.store align=2 offset=0
1290 // (i32.const $__init_memory_flag)
1291 // (i32.const 2)
1292 // )
1293 // (drop
1294 // (i32.atomic.notify align=2 offset=0
1295 // (i32.const $__init_memory_flag)
1296 // (i32.const -1u)
1297 // )
1298 // )
1299 // (br $drop)
1300 // ) ;; $wait
1301 // (drop
1302 // (i32.atomic.wait align=2 offset=0
1303 // (i32.const $__init_memory_flag)
1304 // (i32.const 1)
1305 // (i32.const -1)
1306 // )
1307 // )
1308 // ) ;; $drop
1309 // ( ... drop data segments ... )
1310 // )
1311 //
1312 // When we are building with PIC, calculate the flag location using:
1313 //
1314 // (global.get $__memory_base)
1315 // (i32.const $__init_memory_flag)
1316 // (i32.const 1)
1317
1318 auto writeGetFlagAddress = [&]() {
1319 if (ctx.isPic) {
1320 writeU8(os, byte: WASM_OPCODE_LOCAL_GET, msg: "local.get");
1321 writeUleb128(os, number: 0, msg: "local 0");
1322 } else {
1323 writePtrConst(os, number: flagAddress, is64, msg: "flag address");
1324 }
1325 };
1326
1327 if (ctx.arg.sharedMemory) {
1328 // With PIC code we cache the flag address in local 0
1329 if (ctx.isPic) {
1330 writeUleb128(os, number: 1, msg: "num local decls");
1331 writeUleb128(os, number: 2, msg: "local count");
1332 writeU8(os, byte: is64 ? WASM_TYPE_I64 : WASM_TYPE_I32, msg: "address type");
1333 writeU8(os, byte: WASM_OPCODE_GLOBAL_GET, msg: "GLOBAL_GET");
1334 writeUleb128(os, number: ctx.sym.memoryBase->getGlobalIndex(), msg: "memory_base");
1335 writePtrConst(os, number: flagAddress, is64, msg: "flag address");
1336 writeU8(os, byte: is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD, msg: "add");
1337 writeU8(os, byte: WASM_OPCODE_LOCAL_SET, msg: "local.set");
1338 writeUleb128(os, number: 0, msg: "local 0");
1339 } else {
1340 writeUleb128(os, number: 0, msg: "num locals");
1341 }
1342
1343 // Set up destination blocks
1344 writeU8(os, byte: WASM_OPCODE_BLOCK, msg: "block $drop");
1345 writeU8(os, byte: WASM_TYPE_NORESULT, msg: "block type");
1346 writeU8(os, byte: WASM_OPCODE_BLOCK, msg: "block $wait");
1347 writeU8(os, byte: WASM_TYPE_NORESULT, msg: "block type");
1348 writeU8(os, byte: WASM_OPCODE_BLOCK, msg: "block $init");
1349 writeU8(os, byte: WASM_TYPE_NORESULT, msg: "block type");
1350
1351 // Atomically check whether we win the race.
1352 writeGetFlagAddress();
1353 writeI32Const(os, number: 0, msg: "expected flag value");
1354 writeI32Const(os, number: 1, msg: "new flag value");
1355 writeU8(os, byte: WASM_OPCODE_ATOMICS_PREFIX, msg: "atomics prefix");
1356 writeUleb128(os, number: WASM_OPCODE_I32_RMW_CMPXCHG, msg: "i32.atomic.rmw.cmpxchg");
1357 writeMemArg(os, alignment: 2, offset: 0);
1358
1359 // Based on the value, decide what to do next.
1360 writeU8(os, byte: WASM_OPCODE_BR_TABLE, msg: "br_table");
1361 writeUleb128(os, number: 2, msg: "label vector length");
1362 writeUleb128(os, number: 0, msg: "label $init");
1363 writeUleb128(os, number: 1, msg: "label $wait");
1364 writeUleb128(os, number: 2, msg: "default label $drop");
1365
1366 // Initialize passive data segments
1367 writeU8(os, byte: WASM_OPCODE_END, msg: "end $init");
1368 } else {
1369 writeUleb128(os, number: 0, msg: "num local decls");
1370 }
1371
1372 for (const OutputSegment *s : segments) {
1373 if (needsPassiveInitialization(segment: s)) {
1374 // For passive BSS segments we can simple issue a memory.fill(0).
1375 // For non-BSS segments we do a memory.init. Both these
1376 // instructions take as their first argument the destination
1377 // address.
1378 writePtrConst(os, number: s->startVA, is64, msg: "destination address");
1379 if (ctx.isPic) {
1380 writeU8(os, byte: WASM_OPCODE_GLOBAL_GET, msg: "GLOBAL_GET");
1381 writeUleb128(os, number: ctx.sym.memoryBase->getGlobalIndex(),
1382 msg: "__memory_base");
1383 writeU8(os, byte: is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD,
1384 msg: "i32.add");
1385 }
1386
1387 // When we initialize the TLS segment we also set the TLS base.
1388 // This allows the runtime to use this static copy of the TLS data
1389 // for the first/main thread.
1390 if (ctx.arg.isMultithreaded() && s->isTLS()) {
1391 if (ctx.isPic) {
1392 // Cache the result of the addionion in local 0
1393 writeU8(os, byte: WASM_OPCODE_LOCAL_TEE, msg: "local.tee");
1394 writeUleb128(os, number: 1, msg: "local 1");
1395 } else {
1396 writePtrConst(os, number: s->startVA, is64, msg: "destination address");
1397 }
1398 writeSetTLSBase(ctx, os);
1399 if (ctx.isPic) {
1400 writeU8(os, byte: WASM_OPCODE_LOCAL_GET, msg: "local.tee");
1401 writeUleb128(os, number: 1, msg: "local 1");
1402 }
1403 }
1404
1405 if (s->isBss) {
1406 writeI32Const(os, number: 0, msg: "fill value");
1407 writePtrConst(os, number: s->size, is64, msg: "memory region size");
1408 writeU8(os, byte: WASM_OPCODE_MISC_PREFIX, msg: "bulk-memory prefix");
1409 writeUleb128(os, number: WASM_OPCODE_MEMORY_FILL, msg: "memory.fill");
1410 writeU8(os, byte: 0, msg: "memory index immediate");
1411 } else {
1412 writeI32Const(os, number: 0, msg: "source segment offset");
1413 writeI32Const(os, number: s->size, msg: "memory region size");
1414 writeU8(os, byte: WASM_OPCODE_MISC_PREFIX, msg: "bulk-memory prefix");
1415 writeUleb128(os, number: WASM_OPCODE_MEMORY_INIT, msg: "memory.init");
1416 writeUleb128(os, number: s->index, msg: "segment index immediate");
1417 writeU8(os, byte: 0, msg: "memory index immediate");
1418 }
1419 }
1420 }
1421
1422 if (ctx.arg.sharedMemory) {
1423 // Set flag to 2 to mark end of initialization
1424 writeGetFlagAddress();
1425 writeI32Const(os, number: 2, msg: "flag value");
1426 writeU8(os, byte: WASM_OPCODE_ATOMICS_PREFIX, msg: "atomics prefix");
1427 writeUleb128(os, number: WASM_OPCODE_I32_ATOMIC_STORE, msg: "i32.atomic.store");
1428 writeMemArg(os, alignment: 2, offset: 0);
1429
1430 // Notify any waiters that memory initialization is complete
1431 writeGetFlagAddress();
1432 writeI32Const(os, number: -1, msg: "number of waiters");
1433 writeU8(os, byte: WASM_OPCODE_ATOMICS_PREFIX, msg: "atomics prefix");
1434 writeUleb128(os, number: WASM_OPCODE_ATOMIC_NOTIFY, msg: "atomic.notify");
1435 writeMemArg(os, alignment: 2, offset: 0);
1436 writeU8(os, byte: WASM_OPCODE_DROP, msg: "drop");
1437
1438 // Branch to drop the segments
1439 writeU8(os, byte: WASM_OPCODE_BR, msg: "br");
1440 writeUleb128(os, number: 1, msg: "label $drop");
1441
1442 // Wait for the winning thread to initialize memory
1443 writeU8(os, byte: WASM_OPCODE_END, msg: "end $wait");
1444 writeGetFlagAddress();
1445 writeI32Const(os, number: 1, msg: "expected flag value");
1446 writeI64Const(os, number: -1, msg: "timeout");
1447
1448 writeU8(os, byte: WASM_OPCODE_ATOMICS_PREFIX, msg: "atomics prefix");
1449 writeUleb128(os, number: WASM_OPCODE_I32_ATOMIC_WAIT, msg: "i32.atomic.wait");
1450 writeMemArg(os, alignment: 2, offset: 0);
1451 writeU8(os, byte: WASM_OPCODE_DROP, msg: "drop");
1452
1453 // Unconditionally drop passive data segments
1454 writeU8(os, byte: WASM_OPCODE_END, msg: "end $drop");
1455 }
1456
1457 for (const OutputSegment *s : segments) {
1458 if (needsPassiveInitialization(segment: s) && !s->isBss) {
1459 // The TLS region should not be dropped since its is needed
1460 // during the initialization of each thread (__wasm_init_tls).
1461 if (ctx.arg.isMultithreaded() && s->isTLS())
1462 continue;
1463 // data.drop instruction
1464 writeU8(os, byte: WASM_OPCODE_MISC_PREFIX, msg: "bulk-memory prefix");
1465 writeUleb128(os, number: WASM_OPCODE_DATA_DROP, msg: "data.drop");
1466 writeUleb128(os, number: s->index, msg: "segment index immediate");
1467 }
1468 }
1469
1470 // End the function
1471 writeU8(os, byte: WASM_OPCODE_END, msg: "END");
1472 }
1473
1474 createFunction(func: ctx.sym.initMemory, bodyContent);
1475}
1476
1477void Writer::createStartFunction() {
1478 // If the start function exists when we have more than one function to call.
1479 if (ctx.sym.initMemory && ctx.sym.applyGlobalRelocs) {
1480 assert(ctx.sym.startFunction);
1481 std::string bodyContent;
1482 {
1483 raw_string_ostream os(bodyContent);
1484 writeUleb128(os, number: 0, msg: "num locals");
1485 writeU8(os, byte: WASM_OPCODE_CALL, msg: "CALL");
1486 writeUleb128(os, number: ctx.sym.applyGlobalRelocs->getFunctionIndex(),
1487 msg: "function index");
1488 writeU8(os, byte: WASM_OPCODE_CALL, msg: "CALL");
1489 writeUleb128(os, number: ctx.sym.initMemory->getFunctionIndex(),
1490 msg: "function index");
1491 writeU8(os, byte: WASM_OPCODE_END, msg: "END");
1492 }
1493 createFunction(func: ctx.sym.startFunction, bodyContent);
1494 } else if (ctx.sym.initMemory) {
1495 ctx.sym.startFunction = ctx.sym.initMemory;
1496 } else if (ctx.sym.applyGlobalRelocs) {
1497 ctx.sym.startFunction = ctx.sym.applyGlobalRelocs;
1498 }
1499}
1500
1501// For -shared (PIC) output, we create create a synthetic function which will
1502// apply any relocations to the data segments on startup. This function is
1503// called `__wasm_apply_data_relocs` and is expected to be called before
1504// any user code (i.e. before `__wasm_call_ctors`).
1505void Writer::createApplyDataRelocationsFunction() {
1506 LLVM_DEBUG(dbgs() << "createApplyDataRelocationsFunction\n");
1507 // First write the body's contents to a string.
1508 std::string bodyContent;
1509 {
1510 raw_string_ostream os(bodyContent);
1511 writeUleb128(os, number: 0, msg: "num locals");
1512 bool generated = false;
1513 for (const OutputSegment *seg : segments)
1514 if (!ctx.arg.isMultithreaded() || !seg->isTLS())
1515 for (const InputChunk *inSeg : seg->inputSegments)
1516 generated |= inSeg->generateRelocationCode(os);
1517
1518 if (!generated) {
1519 LLVM_DEBUG(dbgs() << "skipping empty __wasm_apply_data_relocs\n");
1520 return;
1521 }
1522 writeU8(os, byte: WASM_OPCODE_END, msg: "END");
1523 }
1524
1525 // __wasm_apply_data_relocs
1526 // Function that applies relocations to data segment post-instantiation.
1527 static WasmSignature nullSignature = {{}, {}};
1528 auto def = symtab->addSyntheticFunction(
1529 name: "__wasm_apply_data_relocs",
1530 flags: WASM_SYMBOL_VISIBILITY_DEFAULT | WASM_SYMBOL_EXPORTED,
1531 function: make<SyntheticFunction>(args&: nullSignature, args: "__wasm_apply_data_relocs"));
1532 def->markLive();
1533
1534 createFunction(func: def, bodyContent);
1535}
1536
1537void Writer::createApplyTLSRelocationsFunction() {
1538 LLVM_DEBUG(dbgs() << "createApplyTLSRelocationsFunction\n");
1539 std::string bodyContent;
1540 {
1541 raw_string_ostream os(bodyContent);
1542 writeUleb128(os, number: 0, msg: "num locals");
1543 for (const OutputSegment *seg : segments)
1544 if (seg->isTLS())
1545 for (const InputChunk *inSeg : seg->inputSegments)
1546 inSeg->generateRelocationCode(os);
1547
1548 writeU8(os, byte: WASM_OPCODE_END, msg: "END");
1549 }
1550
1551 createFunction(func: ctx.sym.applyTLSRelocs, bodyContent);
1552}
1553
1554// Similar to createApplyDataRelocationsFunction but generates relocation code
1555// for WebAssembly globals. Because these globals are not shared between threads
1556// these relocation need to run on every thread.
1557void Writer::createApplyGlobalRelocationsFunction() {
1558 // First write the body's contents to a string.
1559 std::string bodyContent;
1560 {
1561 raw_string_ostream os(bodyContent);
1562 writeUleb128(os, number: 0, msg: "num locals");
1563 out.globalSec->generateRelocationCode(os, TLS: false);
1564 writeU8(os, byte: WASM_OPCODE_END, msg: "END");
1565 }
1566
1567 createFunction(func: ctx.sym.applyGlobalRelocs, bodyContent);
1568}
1569
1570// Similar to createApplyGlobalRelocationsFunction but for
1571// TLS symbols. This cannot be run during the start function
1572// but must be delayed until __wasm_init_tls is called.
1573void Writer::createApplyGlobalTLSRelocationsFunction() {
1574 // First write the body's contents to a string.
1575 std::string bodyContent;
1576 {
1577 raw_string_ostream os(bodyContent);
1578 writeUleb128(os, number: 0, msg: "num locals");
1579 out.globalSec->generateRelocationCode(os, TLS: true);
1580 writeU8(os, byte: WASM_OPCODE_END, msg: "END");
1581 }
1582
1583 createFunction(func: ctx.sym.applyGlobalTLSRelocs, bodyContent);
1584}
1585
1586// Create synthetic "__wasm_call_ctors" function based on ctor functions
1587// in input object.
1588void Writer::createCallCtorsFunction() {
1589 // If __wasm_call_ctors isn't referenced, there aren't any ctors, don't
1590 // define the `__wasm_call_ctors` function.
1591 if (!ctx.sym.callCtors->isLive() && initFunctions.empty())
1592 return;
1593
1594 // First write the body's contents to a string.
1595 std::string bodyContent;
1596 {
1597 raw_string_ostream os(bodyContent);
1598 writeUleb128(os, number: 0, msg: "num locals");
1599
1600 // Call constructors
1601 for (const WasmInitEntry &f : initFunctions) {
1602 writeU8(os, byte: WASM_OPCODE_CALL, msg: "CALL");
1603 writeUleb128(os, number: f.sym->getFunctionIndex(), msg: "function index");
1604 for (size_t i = 0; i < f.sym->signature->Returns.size(); i++) {
1605 writeU8(os, byte: WASM_OPCODE_DROP, msg: "DROP");
1606 }
1607 }
1608
1609 writeU8(os, byte: WASM_OPCODE_END, msg: "END");
1610 }
1611
1612 createFunction(func: ctx.sym.callCtors, bodyContent);
1613}
1614
1615// Create a wrapper around a function export which calls the
1616// static constructors and destructors.
1617void Writer::createCommandExportWrapper(uint32_t functionIndex,
1618 DefinedFunction *f) {
1619 // First write the body's contents to a string.
1620 std::string bodyContent;
1621 {
1622 raw_string_ostream os(bodyContent);
1623 writeUleb128(os, number: 0, msg: "num locals");
1624
1625 // Call `__wasm_call_ctors` which call static constructors (and
1626 // applies any runtime relocations in Emscripten-style PIC mode)
1627 if (ctx.sym.callCtors->isLive()) {
1628 writeU8(os, byte: WASM_OPCODE_CALL, msg: "CALL");
1629 writeUleb128(os, number: ctx.sym.callCtors->getFunctionIndex(), msg: "function index");
1630 }
1631
1632 // Call the user's code, leaving any return values on the operand stack.
1633 for (size_t i = 0; i < f->signature->Params.size(); ++i) {
1634 writeU8(os, byte: WASM_OPCODE_LOCAL_GET, msg: "local.get");
1635 writeUleb128(os, number: i, msg: "local index");
1636 }
1637 writeU8(os, byte: WASM_OPCODE_CALL, msg: "CALL");
1638 writeUleb128(os, number: functionIndex, msg: "function index");
1639
1640 // Call the function that calls the destructors.
1641 if (DefinedFunction *callDtors = ctx.sym.callDtors) {
1642 writeU8(os, byte: WASM_OPCODE_CALL, msg: "CALL");
1643 writeUleb128(os, number: callDtors->getFunctionIndex(), msg: "function index");
1644 }
1645
1646 // End the function, returning the return values from the user's code.
1647 writeU8(os, byte: WASM_OPCODE_END, msg: "END");
1648 }
1649
1650 createFunction(func: f, bodyContent);
1651}
1652
1653void Writer::createInitTLSFunction() {
1654 std::string bodyContent;
1655 {
1656 raw_string_ostream os(bodyContent);
1657
1658 OutputSegment *tlsSeg = nullptr;
1659 for (auto *seg : segments) {
1660 if (seg->name == ".tdata") {
1661 tlsSeg = seg;
1662 break;
1663 }
1664 }
1665
1666 writeUleb128(os, number: 0, msg: "num locals");
1667 if (tlsSeg) {
1668 writeU8(os, byte: WASM_OPCODE_LOCAL_GET, msg: "local.get");
1669 writeUleb128(os, number: 0, msg: "local index");
1670 writeSetTLSBase(ctx, os);
1671
1672 // FIXME(wvo): this local needs to be I64 in wasm64, or we need an extend
1673 // op.
1674 writeU8(os, byte: WASM_OPCODE_LOCAL_GET, msg: "local.get");
1675 writeUleb128(os, number: 0, msg: "local index");
1676
1677 writeI32Const(os, number: 0, msg: "segment offset");
1678
1679 writeI32Const(os, number: tlsSeg->size, msg: "memory region size");
1680
1681 writeU8(os, byte: WASM_OPCODE_MISC_PREFIX, msg: "bulk-memory prefix");
1682 writeUleb128(os, number: WASM_OPCODE_MEMORY_INIT, msg: "MEMORY.INIT");
1683 writeUleb128(os, number: tlsSeg->index, msg: "segment index immediate");
1684 writeU8(os, byte: 0, msg: "memory index immediate");
1685 }
1686
1687 if (ctx.sym.applyTLSRelocs) {
1688 writeU8(os, byte: WASM_OPCODE_CALL, msg: "CALL");
1689 writeUleb128(os, number: ctx.sym.applyTLSRelocs->getFunctionIndex(),
1690 msg: "function index");
1691 }
1692
1693 if (ctx.sym.applyGlobalTLSRelocs) {
1694 writeU8(os, byte: WASM_OPCODE_CALL, msg: "CALL");
1695 writeUleb128(os, number: ctx.sym.applyGlobalTLSRelocs->getFunctionIndex(),
1696 msg: "function index");
1697 }
1698 writeU8(os, byte: WASM_OPCODE_END, msg: "end function");
1699 }
1700
1701 createFunction(func: ctx.sym.initTLS, bodyContent);
1702}
1703
1704// Populate InitFunctions vector with init functions from all input objects.
1705// This is then used either when creating the output linking section or to
1706// synthesize the "__wasm_call_ctors" function.
1707void Writer::calculateInitFunctions() {
1708 if (!ctx.arg.relocatable && !ctx.sym.callCtors->isLive())
1709 return;
1710
1711 for (ObjFile *file : ctx.objectFiles) {
1712 const WasmLinkingData &l = file->getWasmObj()->linkingData();
1713 for (const WasmInitFunc &f : l.InitFunctions) {
1714 FunctionSymbol *sym = file->getFunctionSymbol(index: f.Symbol);
1715 // comdat exclusions can cause init functions be discarded.
1716 if (sym->isDiscarded() || !sym->isLive())
1717 continue;
1718 if (sym->signature->Params.size() != 0)
1719 error(msg: "constructor functions cannot take arguments: " + toString(sym: *sym));
1720 LLVM_DEBUG(dbgs() << "initFunctions: " << toString(*sym) << "\n");
1721 initFunctions.emplace_back(args: WasmInitEntry{.sym: sym, .priority: f.Priority});
1722 }
1723 }
1724
1725 // Sort in order of priority (lowest first) so that they are called
1726 // in the correct order.
1727 llvm::stable_sort(Range&: initFunctions,
1728 C: [](const WasmInitEntry &l, const WasmInitEntry &r) {
1729 return l.priority < r.priority;
1730 });
1731}
1732
1733void Writer::createSyntheticSections() {
1734 out.dylinkSec = make<DylinkSection>();
1735 out.typeSec = make<TypeSection>();
1736 out.importSec = make<ImportSection>();
1737 out.functionSec = make<FunctionSection>();
1738 out.tableSec = make<TableSection>();
1739 out.memorySec = make<MemorySection>();
1740 out.tagSec = make<TagSection>();
1741 out.globalSec = make<GlobalSection>();
1742 out.exportSec = make<ExportSection>();
1743 out.startSec = make<StartSection>();
1744 out.elemSec = make<ElemSection>();
1745 out.producersSec = make<ProducersSection>();
1746 out.targetFeaturesSec = make<TargetFeaturesSection>();
1747 out.buildIdSec = make<BuildIdSection>();
1748}
1749
1750void Writer::createSyntheticSectionsPostLayout() {
1751 out.dataCountSec = make<DataCountSection>(args&: segments);
1752 out.linkingSec = make<LinkingSection>(args&: initFunctions, args&: segments);
1753 out.nameSec = make<NameSection>(args&: segments);
1754}
1755
1756void Writer::run() {
1757 // For PIC code the table base is assigned dynamically by the loader.
1758 // For non-PIC, we start at 1 so that accessing table index 0 always traps.
1759 if (!ctx.isPic && ctx.sym.tableBase)
1760 setGlobalPtr(g: cast<DefinedGlobal>(Val: ctx.sym.tableBase), memoryPtr: ctx.arg.tableBase);
1761
1762 log(msg: "-- createOutputSegments");
1763 createOutputSegments();
1764 log(msg: "-- createSyntheticSections");
1765 createSyntheticSections();
1766 log(msg: "-- layoutMemory");
1767 layoutMemory();
1768
1769 if (!ctx.arg.relocatable) {
1770 // Create linker synthesized __start_SECNAME/__stop_SECNAME symbols
1771 // This has to be done after memory layout is performed.
1772 for (const OutputSegment *seg : segments) {
1773 addStartStopSymbols(seg);
1774 }
1775 }
1776
1777 for (auto &pair : ctx.arg.exportedSymbols) {
1778 Symbol *sym = symtab->find(name: pair.first());
1779 if (sym && sym->isDefined())
1780 sym->forceExport = true;
1781 }
1782
1783 // Delay reporting errors about explicit exports until after
1784 // addStartStopSymbols which can create optional symbols.
1785 for (auto &name : ctx.arg.requiredExports) {
1786 Symbol *sym = symtab->find(name);
1787 if (!sym || !sym->isDefined()) {
1788 if (ctx.arg.unresolvedSymbols == UnresolvedPolicy::ReportError)
1789 error(msg: Twine("symbol exported via --export not found: ") + name);
1790 if (ctx.arg.unresolvedSymbols == UnresolvedPolicy::Warn)
1791 warn(msg: Twine("symbol exported via --export not found: ") + name);
1792 }
1793 }
1794
1795 log(msg: "-- populateTargetFeatures");
1796 populateTargetFeatures();
1797
1798 // When outputting PIC code each segment lives at at fixes offset from the
1799 // `__memory_base` import. Unless we support the extended const expression we
1800 // can't do addition inside the constant expression, so we much combine the
1801 // segments into a single one that can live at `__memory_base`.
1802 if (ctx.isPic && !ctx.arg.extendedConst && !ctx.arg.isMultithreaded()) {
1803 // In multithreaded modes (shared or cooperative), data segments may be
1804 // passive and must not be combined into a single active segment.
1805 log(msg: "-- combineOutputSegments");
1806 combineOutputSegments();
1807 }
1808
1809 log(msg: "-- createSyntheticSectionsPostLayout");
1810 createSyntheticSectionsPostLayout();
1811 log(msg: "-- populateProducers");
1812 populateProducers();
1813 log(msg: "-- calculateImports");
1814 calculateImports();
1815 log(msg: "-- scanRelocations");
1816 scanRelocations();
1817 log(msg: "-- finalizeIndirectFunctionTable");
1818 finalizeIndirectFunctionTable();
1819 log(msg: "-- createSyntheticInitFunctions");
1820 createSyntheticInitFunctions();
1821 log(msg: "-- assignIndexes");
1822 assignIndexes();
1823 log(msg: "-- calculateInitFunctions");
1824 calculateInitFunctions();
1825
1826 if (!ctx.arg.relocatable) {
1827 // Create linker synthesized functions
1828 if (ctx.sym.applyGlobalRelocs) {
1829 createApplyGlobalRelocationsFunction();
1830 }
1831 if (ctx.sym.applyTLSRelocs) {
1832 createApplyTLSRelocationsFunction();
1833 }
1834 if (ctx.sym.applyGlobalTLSRelocs) {
1835 createApplyGlobalTLSRelocationsFunction();
1836 }
1837 if (ctx.sym.initMemory) {
1838 createInitMemoryFunction();
1839 }
1840 createStartFunction();
1841
1842 createCallCtorsFunction();
1843
1844 // Create export wrappers for commands if needed.
1845 //
1846 // If the input contains a call to `__wasm_call_ctors`, either in one of
1847 // the input objects or an explicit export from the command-line, we
1848 // assume ctors and dtors are taken care of already.
1849 if (!ctx.arg.relocatable && !ctx.isPic &&
1850 !ctx.sym.callCtors->isUsedInRegularObj &&
1851 !ctx.sym.callCtors->isExported()) {
1852 log(msg: "-- createCommandExportWrappers");
1853 createCommandExportWrappers();
1854 }
1855 }
1856
1857 if (ctx.sym.initTLS && ctx.sym.initTLS->isLive()) {
1858 log(msg: "-- createInitTLSFunction");
1859 createInitTLSFunction();
1860 }
1861
1862 if (errorCount())
1863 return;
1864
1865 log(msg: "-- calculateTypes");
1866 calculateTypes();
1867 log(msg: "-- calculateExports");
1868 calculateExports();
1869 log(msg: "-- calculateCustomSections");
1870 calculateCustomSections();
1871 log(msg: "-- populateSymtab");
1872 populateSymtab();
1873 log(msg: "-- checkImportExportTargetFeatures");
1874 checkImportExportTargetFeatures();
1875 log(msg: "-- addSections");
1876 addSections();
1877
1878 if (errorHandler().verbose) {
1879 log(msg: "Defined Functions: " + Twine(out.functionSec->inputFunctions.size()));
1880 log(msg: "Defined Globals : " + Twine(out.globalSec->numGlobals()));
1881 log(msg: "Defined Tags : " + Twine(out.tagSec->inputTags.size()));
1882 log(msg: "Defined Tables : " + Twine(out.tableSec->inputTables.size()));
1883 log(msg: "Function Imports : " +
1884 Twine(out.importSec->getNumImportedFunctions()));
1885 log(msg: "Global Imports : " + Twine(out.importSec->getNumImportedGlobals()));
1886 log(msg: "Tag Imports : " + Twine(out.importSec->getNumImportedTags()));
1887 log(msg: "Table Imports : " + Twine(out.importSec->getNumImportedTables()));
1888 }
1889
1890 createHeader();
1891 log(msg: "-- finalizeSections");
1892 finalizeSections();
1893
1894 log(msg: "-- writeMapFile");
1895 writeMapFile(outputSections);
1896
1897 log(msg: "-- openFile");
1898 openFile();
1899 if (errorCount())
1900 return;
1901
1902 writeHeader();
1903
1904 log(msg: "-- writeSections");
1905 writeSections();
1906 writeBuildId();
1907 if (errorCount())
1908 return;
1909
1910 if (Error e = buffer->commit())
1911 fatal(msg: "failed to write output '" + buffer->getPath() +
1912 "': " + toString(E: std::move(e)));
1913}
1914
1915// Open a result file.
1916void Writer::openFile() {
1917 log(msg: "writing: " + ctx.arg.outputFile);
1918
1919 Expected<std::unique_ptr<FileOutputBuffer>> bufferOrErr =
1920 FileOutputBuffer::create(FilePath: ctx.arg.outputFile, Size: fileSize,
1921 Flags: FileOutputBuffer::F_executable);
1922
1923 if (!bufferOrErr)
1924 error(msg: "failed to open " + ctx.arg.outputFile + ": " +
1925 toString(E: bufferOrErr.takeError()));
1926 else
1927 buffer = std::move(*bufferOrErr);
1928}
1929
1930void Writer::createHeader() {
1931 raw_string_ostream os(header);
1932 writeBytes(os, bytes: WasmMagic, count: sizeof(WasmMagic), msg: "wasm magic");
1933 writeU32(os, number: WasmVersion, msg: "wasm version");
1934 fileSize += header.size();
1935}
1936
1937void writeResult() { Writer().run(); }
1938
1939} // namespace lld::wasm
1940