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 must be passive
1062 // so they can be re-initialized per-thread via memory.init, and .bss
1063 // segments are passive to avoid serializing their zero bytes into the binary;
1064 // they are still present as passive segment entries and zero-filled via
1065 // memory.fill in __wasm_init_memory.
1066 bool needsPassiveInit =
1067 ctx.arg.sharedMemory || (ctx.arg.cooperativeThreading &&
1068 (s->isTLS() || s->name.starts_with(Prefix: ".bss")));
1069 if (needsPassiveInit)
1070 s->initFlags = WASM_DATA_SEGMENT_IS_PASSIVE;
1071 if (!ctx.arg.relocatable && name.starts_with(Prefix: ".bss"))
1072 s->isBss = true;
1073 segments.push_back(x: s);
1074 return s;
1075}
1076
1077void Writer::createOutputSegments() {
1078 for (ObjFile *file : ctx.objectFiles) {
1079 for (InputChunk *segment : file->segments) {
1080 if (!segment->live)
1081 continue;
1082 StringRef name = getOutputDataSegmentName(seg: *segment);
1083 OutputSegment *s = nullptr;
1084 // When running in relocatable mode we can't merge segments that are part
1085 // of comdat groups since the ultimate linker needs to be able exclude or
1086 // include them individually.
1087 if (ctx.arg.relocatable && !segment->getComdatName().empty()) {
1088 s = createOutputSegment(name);
1089 } else {
1090 if (!segmentMap.contains(Val: name))
1091 segmentMap[name] = createOutputSegment(name);
1092 s = segmentMap[name];
1093 }
1094 s->addInputSegment(inSeg: segment);
1095 }
1096 }
1097
1098 // Sort segments by type, placing .bss last
1099 llvm::stable_sort(Range&: segments,
1100 C: [](const OutputSegment *a, const OutputSegment *b) {
1101 auto order = [](StringRef name) {
1102 return StringSwitch<int>(name)
1103 .StartsWith(S: ".tdata", Value: 0)
1104 .StartsWith(S: ".rodata", Value: 1)
1105 .StartsWith(S: ".data", Value: 2)
1106 .StartsWith(S: ".bss", Value: 4)
1107 .Default(Value: 3);
1108 };
1109 return order(a->name) < order(b->name);
1110 });
1111
1112 for (size_t i = 0; i < segments.size(); ++i)
1113 segments[i]->index = i;
1114
1115 // Merge MergeInputSections into a single MergeSyntheticSection.
1116 LLVM_DEBUG(dbgs() << "-- finalize input semgments\n");
1117 for (OutputSegment *seg : segments)
1118 seg->finalizeInputSegments();
1119}
1120
1121void Writer::combineOutputSegments() {
1122 // With PIC code we currently only support a single active data segment since
1123 // we only have a single __memory_base to use as our base address. This pass
1124 // combines all data segments into a single .data segment.
1125 // This restriction does not apply when the extended const extension is
1126 // available: https://github.com/WebAssembly/extended-const
1127 assert(!ctx.arg.extendedConst);
1128 assert(ctx.isPic && !ctx.arg.isMultithreaded());
1129 if (segments.size() <= 1)
1130 return;
1131 OutputSegment *combined = make<OutputSegment>(args: ".data");
1132 combined->startVA = segments[0]->startVA;
1133 std::vector<OutputSegment *> newSegments = {combined};
1134 for (OutputSegment *s : segments) {
1135 if (!s->requiredInBinary()) {
1136 newSegments.push_back(x: s);
1137 continue;
1138 }
1139 bool first = true;
1140 for (InputChunk *inSeg : s->inputSegments) {
1141 if (first)
1142 inSeg->alignment = std::max(a: inSeg->alignment, b: s->alignment);
1143 first = false;
1144#ifndef NDEBUG
1145 uint64_t oldVA = inSeg->getVA();
1146#endif
1147 combined->addInputSegment(inSeg);
1148#ifndef NDEBUG
1149 uint64_t newVA = inSeg->getVA();
1150 LLVM_DEBUG(dbgs() << "added input segment. name=" << inSeg->name
1151 << " oldVA=" << oldVA << " newVA=" << newVA << "\n");
1152 assert(oldVA == newVA);
1153#endif
1154 }
1155 }
1156
1157 segments = std::move(newSegments);
1158}
1159
1160static void createFunction(DefinedFunction *func, StringRef bodyContent) {
1161 std::string functionBody;
1162 {
1163 raw_string_ostream os(functionBody);
1164 writeUleb128(os, number: bodyContent.size(), msg: "function size");
1165 os << bodyContent;
1166 }
1167 ArrayRef<uint8_t> body = arrayRefFromStringRef(Input: saver().save(S: functionBody));
1168 cast<SyntheticFunction>(Val: func->function)->setBody(body);
1169}
1170
1171bool Writer::needsPassiveInitialization(const OutputSegment *segment) {
1172 // If bulk memory features is supported then we can perform bss initialization
1173 // (via memory.fill) during `__wasm_init_memory`.
1174 if (ctx.arg.memoryImport.has_value() && !segment->requiredInBinary())
1175 return true;
1176 return segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE;
1177}
1178
1179bool Writer::hasPassiveInitializedSegments() {
1180 return llvm::any_of(Range&: segments, P: [this](const OutputSegment *s) {
1181 return this->needsPassiveInitialization(segment: s);
1182 });
1183}
1184
1185void Writer::createSyntheticInitFunctions() {
1186 if (ctx.arg.relocatable)
1187 return;
1188
1189 static WasmSignature nullSignature = {{}, {}};
1190
1191 createApplyDataRelocationsFunction();
1192
1193 // Passive segments are used to avoid memory being reinitialized on each
1194 // thread's instantiation. These passive segments are initialized and
1195 // dropped in __wasm_init_memory, which is registered as the start function
1196 // We also initialize bss segments (using memory.fill) as part of this
1197 // function.
1198 if (hasPassiveInitializedSegments()) {
1199 ctx.sym.initMemory = symtab->addSyntheticFunction(
1200 name: "__wasm_init_memory", flags: WASM_SYMBOL_VISIBILITY_HIDDEN,
1201 function: make<SyntheticFunction>(args&: nullSignature, args: "__wasm_init_memory"));
1202 ctx.sym.initMemory->markLive();
1203 // __wasm_init_memory uses __tls_base/__wasm_set_tls_base
1204 if (ctx.sym.setTLSBase)
1205 ctx.sym.setTLSBase->markLive();
1206 else if (ctx.arg.sharedMemory)
1207 ctx.sym.tlsBase->markLive();
1208 }
1209
1210 if (ctx.arg.isMultithreaded()) {
1211 if (out.globalSec->needsTLSRelocations()) {
1212 ctx.sym.applyGlobalTLSRelocs = symtab->addSyntheticFunction(
1213 name: "__wasm_apply_global_tls_relocs", flags: WASM_SYMBOL_VISIBILITY_HIDDEN,
1214 function: make<SyntheticFunction>(args&: nullSignature,
1215 args: "__wasm_apply_global_tls_relocs"));
1216 ctx.sym.applyGlobalTLSRelocs->markLive();
1217 // TLS relocations depend on the __tls_base/__wasm_get_tls_base symbols
1218 if (ctx.sym.getTLSBase)
1219 ctx.sym.getTLSBase->markLive();
1220 else if (ctx.arg.sharedMemory)
1221 ctx.sym.tlsBase->markLive();
1222 }
1223
1224 auto hasTLSRelocs = [](const OutputSegment *segment) {
1225 if (segment->isTLS())
1226 for (const auto *is : segment->inputSegments)
1227 if (is->getRelocations().size())
1228 return true;
1229 return false;
1230 };
1231 if (llvm::any_of(Range&: segments, P: hasTLSRelocs)) {
1232 ctx.sym.applyTLSRelocs = symtab->addSyntheticFunction(
1233 name: "__wasm_apply_tls_relocs", flags: WASM_SYMBOL_VISIBILITY_HIDDEN,
1234 function: make<SyntheticFunction>(args&: nullSignature, args: "__wasm_apply_tls_relocs"));
1235 ctx.sym.applyTLSRelocs->markLive();
1236 }
1237 }
1238
1239 if (ctx.isPic && out.globalSec->needsRelocations()) {
1240 ctx.sym.applyGlobalRelocs = symtab->addSyntheticFunction(
1241 name: "__wasm_apply_global_relocs", flags: WASM_SYMBOL_VISIBILITY_HIDDEN,
1242 function: make<SyntheticFunction>(args&: nullSignature, args: "__wasm_apply_global_relocs"));
1243 ctx.sym.applyGlobalRelocs->markLive();
1244 }
1245
1246 // If there is only one start function we can just use that function
1247 // itself as the Wasm start function, otherwise we need to synthesize
1248 // a new function to call them in sequence.
1249 if (ctx.sym.applyGlobalRelocs && ctx.sym.initMemory) {
1250 ctx.sym.startFunction = symtab->addSyntheticFunction(
1251 name: "__wasm_start", flags: WASM_SYMBOL_VISIBILITY_HIDDEN,
1252 function: make<SyntheticFunction>(args&: nullSignature, args: "__wasm_start"));
1253 ctx.sym.startFunction->markLive();
1254 }
1255}
1256
1257void Writer::createInitMemoryFunction() {
1258 LLVM_DEBUG(dbgs() << "createInitMemoryFunction\n");
1259 assert(ctx.sym.initMemory);
1260 assert(hasPassiveInitializedSegments());
1261 uint64_t flagAddress;
1262 if (ctx.arg.sharedMemory) {
1263 assert(ctx.sym.initMemoryFlag);
1264 flagAddress = ctx.sym.initMemoryFlag->getVA();
1265 }
1266 bool is64 = ctx.arg.is64.value_or(u: false);
1267 std::string bodyContent;
1268 {
1269 raw_string_ostream os(bodyContent);
1270 // Initialize memory in a thread-safe manner. The thread that successfully
1271 // increments the flag from 0 to 1 is responsible for performing the memory
1272 // initialization. Other threads go sleep on the flag until the first thread
1273 // finishing initializing memory, increments the flag to 2, and wakes all
1274 // the other threads. Once the flag has been set to 2, subsequently started
1275 // threads will skip the sleep. All threads unconditionally drop their
1276 // passive data segments once memory has been initialized. The generated
1277 // code is as follows:
1278 //
1279 // (func $__wasm_init_memory
1280 // (block $drop
1281 // (block $wait
1282 // (block $init
1283 // (br_table $init $wait $drop
1284 // (i32.atomic.rmw.cmpxchg align=2 offset=0
1285 // (i32.const $__init_memory_flag)
1286 // (i32.const 0)
1287 // (i32.const 1)
1288 // )
1289 // )
1290 // ) ;; $init
1291 // ( ... initialize data segments ... )
1292 // (i32.atomic.store align=2 offset=0
1293 // (i32.const $__init_memory_flag)
1294 // (i32.const 2)
1295 // )
1296 // (drop
1297 // (i32.atomic.notify align=2 offset=0
1298 // (i32.const $__init_memory_flag)
1299 // (i32.const -1u)
1300 // )
1301 // )
1302 // (br $drop)
1303 // ) ;; $wait
1304 // (drop
1305 // (i32.atomic.wait align=2 offset=0
1306 // (i32.const $__init_memory_flag)
1307 // (i32.const 1)
1308 // (i32.const -1)
1309 // )
1310 // )
1311 // ) ;; $drop
1312 // ( ... drop data segments ... )
1313 // )
1314 //
1315 // When we are building with PIC, calculate the flag location using:
1316 //
1317 // (global.get $__memory_base)
1318 // (i32.const $__init_memory_flag)
1319 // (i32.const 1)
1320
1321 auto writeGetFlagAddress = [&]() {
1322 if (ctx.isPic) {
1323 writeU8(os, byte: WASM_OPCODE_LOCAL_GET, msg: "local.get");
1324 writeUleb128(os, number: 0, msg: "local 0");
1325 } else {
1326 writePtrConst(os, number: flagAddress, is64, msg: "flag address");
1327 }
1328 };
1329
1330 if (ctx.arg.sharedMemory) {
1331 // With PIC code we cache the flag address in local 0
1332 if (ctx.isPic) {
1333 writeUleb128(os, number: 1, msg: "num local decls");
1334 writeUleb128(os, number: 2, msg: "local count");
1335 writeU8(os, byte: is64 ? WASM_TYPE_I64 : WASM_TYPE_I32, msg: "address type");
1336 writeU8(os, byte: WASM_OPCODE_GLOBAL_GET, msg: "GLOBAL_GET");
1337 writeUleb128(os, number: ctx.sym.memoryBase->getGlobalIndex(), msg: "memory_base");
1338 writePtrConst(os, number: flagAddress, is64, msg: "flag address");
1339 writeU8(os, byte: is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD, msg: "add");
1340 writeU8(os, byte: WASM_OPCODE_LOCAL_SET, msg: "local.set");
1341 writeUleb128(os, number: 0, msg: "local 0");
1342 } else {
1343 writeUleb128(os, number: 0, msg: "num locals");
1344 }
1345
1346 // Set up destination blocks
1347 writeU8(os, byte: WASM_OPCODE_BLOCK, msg: "block $drop");
1348 writeU8(os, byte: WASM_TYPE_NORESULT, msg: "block type");
1349 writeU8(os, byte: WASM_OPCODE_BLOCK, msg: "block $wait");
1350 writeU8(os, byte: WASM_TYPE_NORESULT, msg: "block type");
1351 writeU8(os, byte: WASM_OPCODE_BLOCK, msg: "block $init");
1352 writeU8(os, byte: WASM_TYPE_NORESULT, msg: "block type");
1353
1354 // Atomically check whether we win the race.
1355 writeGetFlagAddress();
1356 writeI32Const(os, number: 0, msg: "expected flag value");
1357 writeI32Const(os, number: 1, msg: "new flag value");
1358 writeU8(os, byte: WASM_OPCODE_ATOMICS_PREFIX, msg: "atomics prefix");
1359 writeUleb128(os, number: WASM_OPCODE_I32_RMW_CMPXCHG, msg: "i32.atomic.rmw.cmpxchg");
1360 writeMemArg(os, alignment: 2, offset: 0);
1361
1362 // Based on the value, decide what to do next.
1363 writeU8(os, byte: WASM_OPCODE_BR_TABLE, msg: "br_table");
1364 writeUleb128(os, number: 2, msg: "label vector length");
1365 writeUleb128(os, number: 0, msg: "label $init");
1366 writeUleb128(os, number: 1, msg: "label $wait");
1367 writeUleb128(os, number: 2, msg: "default label $drop");
1368
1369 // Initialize passive data segments
1370 writeU8(os, byte: WASM_OPCODE_END, msg: "end $init");
1371 } else {
1372 writeUleb128(os, number: 0, msg: "num local decls");
1373 }
1374
1375 for (const OutputSegment *s : segments) {
1376 if (needsPassiveInitialization(segment: s)) {
1377 // For passive BSS segments we can simple issue a memory.fill(0).
1378 // For non-BSS segments we do a memory.init. Both these
1379 // instructions take as their first argument the destination
1380 // address.
1381 writePtrConst(os, number: s->startVA, is64, msg: "destination address");
1382 if (ctx.isPic) {
1383 writeU8(os, byte: WASM_OPCODE_GLOBAL_GET, msg: "GLOBAL_GET");
1384 writeUleb128(os, number: ctx.sym.memoryBase->getGlobalIndex(),
1385 msg: "__memory_base");
1386 writeU8(os, byte: is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD,
1387 msg: "i32.add");
1388 }
1389
1390 // When we initialize the TLS segment we also set the TLS base.
1391 // This allows the runtime to use this static copy of the TLS data
1392 // for the first/main thread.
1393 if (ctx.arg.isMultithreaded() && s->isTLS()) {
1394 if (ctx.isPic) {
1395 // Cache the result of the addionion in local 0
1396 writeU8(os, byte: WASM_OPCODE_LOCAL_TEE, msg: "local.tee");
1397 writeUleb128(os, number: 1, msg: "local 1");
1398 } else {
1399 writePtrConst(os, number: s->startVA, is64, msg: "destination address");
1400 }
1401 writeSetTLSBase(ctx, os);
1402 if (ctx.isPic) {
1403 writeU8(os, byte: WASM_OPCODE_LOCAL_GET, msg: "local.tee");
1404 writeUleb128(os, number: 1, msg: "local 1");
1405 }
1406 }
1407
1408 if (s->isBss) {
1409 writeI32Const(os, number: 0, msg: "fill value");
1410 writePtrConst(os, number: s->size, is64, msg: "memory region size");
1411 writeU8(os, byte: WASM_OPCODE_MISC_PREFIX, msg: "bulk-memory prefix");
1412 writeUleb128(os, number: WASM_OPCODE_MEMORY_FILL, msg: "memory.fill");
1413 writeU8(os, byte: 0, msg: "memory index immediate");
1414 } else {
1415 writeI32Const(os, number: 0, msg: "source segment offset");
1416 writeI32Const(os, number: s->size, msg: "memory region size");
1417 writeU8(os, byte: WASM_OPCODE_MISC_PREFIX, msg: "bulk-memory prefix");
1418 writeUleb128(os, number: WASM_OPCODE_MEMORY_INIT, msg: "memory.init");
1419 writeUleb128(os, number: s->index, msg: "segment index immediate");
1420 writeU8(os, byte: 0, msg: "memory index immediate");
1421 }
1422 }
1423 }
1424
1425 if (ctx.arg.sharedMemory) {
1426 // Set flag to 2 to mark end of initialization
1427 writeGetFlagAddress();
1428 writeI32Const(os, number: 2, msg: "flag value");
1429 writeU8(os, byte: WASM_OPCODE_ATOMICS_PREFIX, msg: "atomics prefix");
1430 writeUleb128(os, number: WASM_OPCODE_I32_ATOMIC_STORE, msg: "i32.atomic.store");
1431 writeMemArg(os, alignment: 2, offset: 0);
1432
1433 // Notify any waiters that memory initialization is complete
1434 writeGetFlagAddress();
1435 writeI32Const(os, number: -1, msg: "number of waiters");
1436 writeU8(os, byte: WASM_OPCODE_ATOMICS_PREFIX, msg: "atomics prefix");
1437 writeUleb128(os, number: WASM_OPCODE_ATOMIC_NOTIFY, msg: "atomic.notify");
1438 writeMemArg(os, alignment: 2, offset: 0);
1439 writeU8(os, byte: WASM_OPCODE_DROP, msg: "drop");
1440
1441 // Branch to drop the segments
1442 writeU8(os, byte: WASM_OPCODE_BR, msg: "br");
1443 writeUleb128(os, number: 1, msg: "label $drop");
1444
1445 // Wait for the winning thread to initialize memory
1446 writeU8(os, byte: WASM_OPCODE_END, msg: "end $wait");
1447 writeGetFlagAddress();
1448 writeI32Const(os, number: 1, msg: "expected flag value");
1449 writeI64Const(os, number: -1, msg: "timeout");
1450
1451 writeU8(os, byte: WASM_OPCODE_ATOMICS_PREFIX, msg: "atomics prefix");
1452 writeUleb128(os, number: WASM_OPCODE_I32_ATOMIC_WAIT, msg: "i32.atomic.wait");
1453 writeMemArg(os, alignment: 2, offset: 0);
1454 writeU8(os, byte: WASM_OPCODE_DROP, msg: "drop");
1455
1456 // Unconditionally drop passive data segments
1457 writeU8(os, byte: WASM_OPCODE_END, msg: "end $drop");
1458 }
1459
1460 for (const OutputSegment *s : segments) {
1461 if (needsPassiveInitialization(segment: s) && !s->isBss) {
1462 // The TLS region should not be dropped since its is needed
1463 // during the initialization of each thread (__wasm_init_tls).
1464 if (ctx.arg.isMultithreaded() && s->isTLS())
1465 continue;
1466 // data.drop instruction
1467 writeU8(os, byte: WASM_OPCODE_MISC_PREFIX, msg: "bulk-memory prefix");
1468 writeUleb128(os, number: WASM_OPCODE_DATA_DROP, msg: "data.drop");
1469 writeUleb128(os, number: s->index, msg: "segment index immediate");
1470 }
1471 }
1472
1473 // End the function
1474 writeU8(os, byte: WASM_OPCODE_END, msg: "END");
1475 }
1476
1477 createFunction(func: ctx.sym.initMemory, bodyContent);
1478}
1479
1480void Writer::createStartFunction() {
1481 // If the start function exists when we have more than one function to call.
1482 if (ctx.sym.initMemory && ctx.sym.applyGlobalRelocs) {
1483 assert(ctx.sym.startFunction);
1484 std::string bodyContent;
1485 {
1486 raw_string_ostream os(bodyContent);
1487 writeUleb128(os, number: 0, msg: "num locals");
1488 writeU8(os, byte: WASM_OPCODE_CALL, msg: "CALL");
1489 writeUleb128(os, number: ctx.sym.applyGlobalRelocs->getFunctionIndex(),
1490 msg: "function index");
1491 writeU8(os, byte: WASM_OPCODE_CALL, msg: "CALL");
1492 writeUleb128(os, number: ctx.sym.initMemory->getFunctionIndex(),
1493 msg: "function index");
1494 writeU8(os, byte: WASM_OPCODE_END, msg: "END");
1495 }
1496 createFunction(func: ctx.sym.startFunction, bodyContent);
1497 } else if (ctx.sym.initMemory) {
1498 ctx.sym.startFunction = ctx.sym.initMemory;
1499 } else if (ctx.sym.applyGlobalRelocs) {
1500 ctx.sym.startFunction = ctx.sym.applyGlobalRelocs;
1501 }
1502}
1503
1504// For -shared (PIC) output, we create create a synthetic function which will
1505// apply any relocations to the data segments on startup. This function is
1506// called `__wasm_apply_data_relocs` and is expected to be called before
1507// any user code (i.e. before `__wasm_call_ctors`).
1508void Writer::createApplyDataRelocationsFunction() {
1509 LLVM_DEBUG(dbgs() << "createApplyDataRelocationsFunction\n");
1510 // First write the body's contents to a string.
1511 std::string bodyContent;
1512 {
1513 raw_string_ostream os(bodyContent);
1514 writeUleb128(os, number: 0, msg: "num locals");
1515 bool generated = false;
1516 for (const OutputSegment *seg : segments)
1517 if (!ctx.arg.isMultithreaded() || !seg->isTLS())
1518 for (const InputChunk *inSeg : seg->inputSegments)
1519 generated |= inSeg->generateRelocationCode(os);
1520
1521 if (!generated) {
1522 LLVM_DEBUG(dbgs() << "skipping empty __wasm_apply_data_relocs\n");
1523 return;
1524 }
1525 writeU8(os, byte: WASM_OPCODE_END, msg: "END");
1526 }
1527
1528 // __wasm_apply_data_relocs
1529 // Function that applies relocations to data segment post-instantiation.
1530 static WasmSignature nullSignature = {{}, {}};
1531 auto def = symtab->addSyntheticFunction(
1532 name: "__wasm_apply_data_relocs",
1533 flags: WASM_SYMBOL_VISIBILITY_DEFAULT | WASM_SYMBOL_EXPORTED,
1534 function: make<SyntheticFunction>(args&: nullSignature, args: "__wasm_apply_data_relocs"));
1535 def->markLive();
1536
1537 createFunction(func: def, bodyContent);
1538}
1539
1540void Writer::createApplyTLSRelocationsFunction() {
1541 LLVM_DEBUG(dbgs() << "createApplyTLSRelocationsFunction\n");
1542 std::string bodyContent;
1543 {
1544 raw_string_ostream os(bodyContent);
1545 writeUleb128(os, number: 0, msg: "num locals");
1546 for (const OutputSegment *seg : segments)
1547 if (seg->isTLS())
1548 for (const InputChunk *inSeg : seg->inputSegments)
1549 inSeg->generateRelocationCode(os);
1550
1551 writeU8(os, byte: WASM_OPCODE_END, msg: "END");
1552 }
1553
1554 createFunction(func: ctx.sym.applyTLSRelocs, bodyContent);
1555}
1556
1557// Similar to createApplyDataRelocationsFunction but generates relocation code
1558// for WebAssembly globals. Because these globals are not shared between threads
1559// these relocation need to run on every thread.
1560void Writer::createApplyGlobalRelocationsFunction() {
1561 // First write the body's contents to a string.
1562 std::string bodyContent;
1563 {
1564 raw_string_ostream os(bodyContent);
1565 writeUleb128(os, number: 0, msg: "num locals");
1566 out.globalSec->generateRelocationCode(os, TLS: false);
1567 writeU8(os, byte: WASM_OPCODE_END, msg: "END");
1568 }
1569
1570 createFunction(func: ctx.sym.applyGlobalRelocs, bodyContent);
1571}
1572
1573// Similar to createApplyGlobalRelocationsFunction but for
1574// TLS symbols. This cannot be run during the start function
1575// but must be delayed until __wasm_init_tls is called.
1576void Writer::createApplyGlobalTLSRelocationsFunction() {
1577 // First write the body's contents to a string.
1578 std::string bodyContent;
1579 {
1580 raw_string_ostream os(bodyContent);
1581 writeUleb128(os, number: 0, msg: "num locals");
1582 out.globalSec->generateRelocationCode(os, TLS: true);
1583 writeU8(os, byte: WASM_OPCODE_END, msg: "END");
1584 }
1585
1586 createFunction(func: ctx.sym.applyGlobalTLSRelocs, bodyContent);
1587}
1588
1589// Create synthetic "__wasm_call_ctors" function based on ctor functions
1590// in input object.
1591void Writer::createCallCtorsFunction() {
1592 // If __wasm_call_ctors isn't referenced, there aren't any ctors, don't
1593 // define the `__wasm_call_ctors` function.
1594 if (!ctx.sym.callCtors->isLive() && initFunctions.empty())
1595 return;
1596
1597 // First write the body's contents to a string.
1598 std::string bodyContent;
1599 {
1600 raw_string_ostream os(bodyContent);
1601 writeUleb128(os, number: 0, msg: "num locals");
1602
1603 // Call constructors
1604 for (const WasmInitEntry &f : initFunctions) {
1605 writeU8(os, byte: WASM_OPCODE_CALL, msg: "CALL");
1606 writeUleb128(os, number: f.sym->getFunctionIndex(), msg: "function index");
1607 for (size_t i = 0; i < f.sym->signature->Returns.size(); i++) {
1608 writeU8(os, byte: WASM_OPCODE_DROP, msg: "DROP");
1609 }
1610 }
1611
1612 writeU8(os, byte: WASM_OPCODE_END, msg: "END");
1613 }
1614
1615 createFunction(func: ctx.sym.callCtors, bodyContent);
1616}
1617
1618// Create a wrapper around a function export which calls the
1619// static constructors and destructors.
1620void Writer::createCommandExportWrapper(uint32_t functionIndex,
1621 DefinedFunction *f) {
1622 // First write the body's contents to a string.
1623 std::string bodyContent;
1624 {
1625 raw_string_ostream os(bodyContent);
1626 writeUleb128(os, number: 0, msg: "num locals");
1627
1628 // Call `__wasm_call_ctors` which call static constructors (and
1629 // applies any runtime relocations in Emscripten-style PIC mode)
1630 if (ctx.sym.callCtors->isLive()) {
1631 writeU8(os, byte: WASM_OPCODE_CALL, msg: "CALL");
1632 writeUleb128(os, number: ctx.sym.callCtors->getFunctionIndex(), msg: "function index");
1633 }
1634
1635 // Call the user's code, leaving any return values on the operand stack.
1636 for (size_t i = 0; i < f->signature->Params.size(); ++i) {
1637 writeU8(os, byte: WASM_OPCODE_LOCAL_GET, msg: "local.get");
1638 writeUleb128(os, number: i, msg: "local index");
1639 }
1640 writeU8(os, byte: WASM_OPCODE_CALL, msg: "CALL");
1641 writeUleb128(os, number: functionIndex, msg: "function index");
1642
1643 // Call the function that calls the destructors.
1644 if (DefinedFunction *callDtors = ctx.sym.callDtors) {
1645 writeU8(os, byte: WASM_OPCODE_CALL, msg: "CALL");
1646 writeUleb128(os, number: callDtors->getFunctionIndex(), msg: "function index");
1647 }
1648
1649 // End the function, returning the return values from the user's code.
1650 writeU8(os, byte: WASM_OPCODE_END, msg: "END");
1651 }
1652
1653 createFunction(func: f, bodyContent);
1654}
1655
1656void Writer::createInitTLSFunction() {
1657 std::string bodyContent;
1658 {
1659 raw_string_ostream os(bodyContent);
1660
1661 OutputSegment *tlsSeg = nullptr;
1662 for (auto *seg : segments) {
1663 if (seg->name == ".tdata") {
1664 tlsSeg = seg;
1665 break;
1666 }
1667 }
1668
1669 writeUleb128(os, number: 0, msg: "num locals");
1670 if (tlsSeg) {
1671 writeU8(os, byte: WASM_OPCODE_LOCAL_GET, msg: "local.get");
1672 writeUleb128(os, number: 0, msg: "local index");
1673 writeSetTLSBase(ctx, os);
1674
1675 // FIXME(wvo): this local needs to be I64 in wasm64, or we need an extend
1676 // op.
1677 writeU8(os, byte: WASM_OPCODE_LOCAL_GET, msg: "local.get");
1678 writeUleb128(os, number: 0, msg: "local index");
1679
1680 writeI32Const(os, number: 0, msg: "segment offset");
1681
1682 writeI32Const(os, number: tlsSeg->size, msg: "memory region size");
1683
1684 writeU8(os, byte: WASM_OPCODE_MISC_PREFIX, msg: "bulk-memory prefix");
1685 writeUleb128(os, number: WASM_OPCODE_MEMORY_INIT, msg: "MEMORY.INIT");
1686 writeUleb128(os, number: tlsSeg->index, msg: "segment index immediate");
1687 writeU8(os, byte: 0, msg: "memory index immediate");
1688 }
1689
1690 if (ctx.sym.applyTLSRelocs) {
1691 writeU8(os, byte: WASM_OPCODE_CALL, msg: "CALL");
1692 writeUleb128(os, number: ctx.sym.applyTLSRelocs->getFunctionIndex(),
1693 msg: "function index");
1694 }
1695
1696 if (ctx.sym.applyGlobalTLSRelocs) {
1697 writeU8(os, byte: WASM_OPCODE_CALL, msg: "CALL");
1698 writeUleb128(os, number: ctx.sym.applyGlobalTLSRelocs->getFunctionIndex(),
1699 msg: "function index");
1700 }
1701 writeU8(os, byte: WASM_OPCODE_END, msg: "end function");
1702 }
1703
1704 createFunction(func: ctx.sym.initTLS, bodyContent);
1705}
1706
1707// Populate InitFunctions vector with init functions from all input objects.
1708// This is then used either when creating the output linking section or to
1709// synthesize the "__wasm_call_ctors" function.
1710void Writer::calculateInitFunctions() {
1711 if (!ctx.arg.relocatable && !ctx.sym.callCtors->isLive())
1712 return;
1713
1714 for (ObjFile *file : ctx.objectFiles) {
1715 const WasmLinkingData &l = file->getWasmObj()->linkingData();
1716 for (const WasmInitFunc &f : l.InitFunctions) {
1717 FunctionSymbol *sym = file->getFunctionSymbol(index: f.Symbol);
1718 // comdat exclusions can cause init functions be discarded.
1719 if (sym->isDiscarded() || !sym->isLive())
1720 continue;
1721 if (sym->signature->Params.size() != 0)
1722 error(msg: "constructor functions cannot take arguments: " + toString(sym: *sym));
1723 LLVM_DEBUG(dbgs() << "initFunctions: " << toString(*sym) << "\n");
1724 initFunctions.emplace_back(args: WasmInitEntry{.sym: sym, .priority: f.Priority});
1725 }
1726 }
1727
1728 // Sort in order of priority (lowest first) so that they are called
1729 // in the correct order.
1730 llvm::stable_sort(Range&: initFunctions,
1731 C: [](const WasmInitEntry &l, const WasmInitEntry &r) {
1732 return l.priority < r.priority;
1733 });
1734}
1735
1736void Writer::createSyntheticSections() {
1737 out.dylinkSec = make<DylinkSection>();
1738 out.typeSec = make<TypeSection>();
1739 out.importSec = make<ImportSection>();
1740 out.functionSec = make<FunctionSection>();
1741 out.tableSec = make<TableSection>();
1742 out.memorySec = make<MemorySection>();
1743 out.tagSec = make<TagSection>();
1744 out.globalSec = make<GlobalSection>();
1745 out.exportSec = make<ExportSection>();
1746 out.startSec = make<StartSection>();
1747 out.elemSec = make<ElemSection>();
1748 out.producersSec = make<ProducersSection>();
1749 out.targetFeaturesSec = make<TargetFeaturesSection>();
1750 out.buildIdSec = make<BuildIdSection>();
1751}
1752
1753void Writer::createSyntheticSectionsPostLayout() {
1754 out.dataCountSec = make<DataCountSection>(args&: segments);
1755 out.linkingSec = make<LinkingSection>(args&: initFunctions, args&: segments);
1756 out.nameSec = make<NameSection>(args&: segments);
1757}
1758
1759void Writer::run() {
1760 // For PIC code the table base is assigned dynamically by the loader.
1761 // For non-PIC, we start at 1 so that accessing table index 0 always traps.
1762 if (!ctx.isPic && ctx.sym.tableBase)
1763 setGlobalPtr(g: cast<DefinedGlobal>(Val: ctx.sym.tableBase), memoryPtr: ctx.arg.tableBase);
1764
1765 log(msg: "-- createOutputSegments");
1766 createOutputSegments();
1767 log(msg: "-- createSyntheticSections");
1768 createSyntheticSections();
1769 log(msg: "-- layoutMemory");
1770 layoutMemory();
1771
1772 if (!ctx.arg.relocatable) {
1773 // Create linker synthesized __start_SECNAME/__stop_SECNAME symbols
1774 // This has to be done after memory layout is performed.
1775 for (const OutputSegment *seg : segments) {
1776 addStartStopSymbols(seg);
1777 }
1778 }
1779
1780 for (auto &pair : ctx.arg.exportedSymbols) {
1781 Symbol *sym = symtab->find(name: pair.first());
1782 if (sym && sym->isDefined())
1783 sym->forceExport = true;
1784 }
1785
1786 // Delay reporting errors about explicit exports until after
1787 // addStartStopSymbols which can create optional symbols.
1788 for (auto &name : ctx.arg.requiredExports) {
1789 Symbol *sym = symtab->find(name);
1790 if (!sym || !sym->isDefined()) {
1791 if (ctx.arg.unresolvedSymbols == UnresolvedPolicy::ReportError)
1792 error(msg: Twine("symbol exported via --export not found: ") + name);
1793 if (ctx.arg.unresolvedSymbols == UnresolvedPolicy::Warn)
1794 warn(msg: Twine("symbol exported via --export not found: ") + name);
1795 }
1796 }
1797
1798 log(msg: "-- populateTargetFeatures");
1799 populateTargetFeatures();
1800
1801 // When outputting PIC code each segment lives at at fixes offset from the
1802 // `__memory_base` import. Unless we support the extended const expression we
1803 // can't do addition inside the constant expression, so we much combine the
1804 // segments into a single one that can live at `__memory_base`.
1805 if (ctx.isPic && !ctx.arg.extendedConst && !ctx.arg.isMultithreaded()) {
1806 // In multithreaded modes (shared or cooperative), data segments may be
1807 // passive and must not be combined into a single active segment.
1808 log(msg: "-- combineOutputSegments");
1809 combineOutputSegments();
1810 }
1811
1812 log(msg: "-- createSyntheticSectionsPostLayout");
1813 createSyntheticSectionsPostLayout();
1814 log(msg: "-- populateProducers");
1815 populateProducers();
1816 log(msg: "-- calculateImports");
1817 calculateImports();
1818 log(msg: "-- scanRelocations");
1819 scanRelocations();
1820 log(msg: "-- finalizeIndirectFunctionTable");
1821 finalizeIndirectFunctionTable();
1822 log(msg: "-- createSyntheticInitFunctions");
1823 createSyntheticInitFunctions();
1824 log(msg: "-- assignIndexes");
1825 assignIndexes();
1826 log(msg: "-- calculateInitFunctions");
1827 calculateInitFunctions();
1828
1829 if (!ctx.arg.relocatable) {
1830 // Create linker synthesized functions
1831 if (ctx.sym.applyGlobalRelocs) {
1832 createApplyGlobalRelocationsFunction();
1833 }
1834 if (ctx.sym.applyTLSRelocs) {
1835 createApplyTLSRelocationsFunction();
1836 }
1837 if (ctx.sym.applyGlobalTLSRelocs) {
1838 createApplyGlobalTLSRelocationsFunction();
1839 }
1840 if (ctx.sym.initMemory) {
1841 createInitMemoryFunction();
1842 }
1843 createStartFunction();
1844
1845 createCallCtorsFunction();
1846
1847 // Create export wrappers for commands if needed.
1848 //
1849 // If the input contains a call to `__wasm_call_ctors`, either in one of
1850 // the input objects or an explicit export from the command-line, we
1851 // assume ctors and dtors are taken care of already.
1852 if (!ctx.arg.relocatable && !ctx.isPic &&
1853 !ctx.sym.callCtors->isUsedInRegularObj &&
1854 !ctx.sym.callCtors->isExported()) {
1855 log(msg: "-- createCommandExportWrappers");
1856 createCommandExportWrappers();
1857 }
1858 }
1859
1860 if (ctx.sym.initTLS && ctx.sym.initTLS->isLive()) {
1861 log(msg: "-- createInitTLSFunction");
1862 createInitTLSFunction();
1863 }
1864
1865 if (errorCount())
1866 return;
1867
1868 log(msg: "-- calculateTypes");
1869 calculateTypes();
1870 log(msg: "-- calculateExports");
1871 calculateExports();
1872 log(msg: "-- calculateCustomSections");
1873 calculateCustomSections();
1874 log(msg: "-- populateSymtab");
1875 populateSymtab();
1876 log(msg: "-- checkImportExportTargetFeatures");
1877 checkImportExportTargetFeatures();
1878 log(msg: "-- addSections");
1879 addSections();
1880
1881 if (errorHandler().verbose) {
1882 log(msg: "Defined Functions: " + Twine(out.functionSec->inputFunctions.size()));
1883 log(msg: "Defined Globals : " + Twine(out.globalSec->numGlobals()));
1884 log(msg: "Defined Tags : " + Twine(out.tagSec->inputTags.size()));
1885 log(msg: "Defined Tables : " + Twine(out.tableSec->inputTables.size()));
1886 log(msg: "Function Imports : " +
1887 Twine(out.importSec->getNumImportedFunctions()));
1888 log(msg: "Global Imports : " + Twine(out.importSec->getNumImportedGlobals()));
1889 log(msg: "Tag Imports : " + Twine(out.importSec->getNumImportedTags()));
1890 log(msg: "Table Imports : " + Twine(out.importSec->getNumImportedTables()));
1891 }
1892
1893 createHeader();
1894 log(msg: "-- finalizeSections");
1895 finalizeSections();
1896
1897 log(msg: "-- writeMapFile");
1898 writeMapFile(outputSections);
1899
1900 log(msg: "-- openFile");
1901 openFile();
1902 if (errorCount())
1903 return;
1904
1905 writeHeader();
1906
1907 log(msg: "-- writeSections");
1908 writeSections();
1909 writeBuildId();
1910 if (errorCount())
1911 return;
1912
1913 if (Error e = buffer->commit())
1914 fatal(msg: "failed to write output '" + buffer->getPath() +
1915 "': " + toString(E: std::move(e)));
1916}
1917
1918// Open a result file.
1919void Writer::openFile() {
1920 log(msg: "writing: " + ctx.arg.outputFile);
1921
1922 Expected<std::unique_ptr<FileOutputBuffer>> bufferOrErr =
1923 FileOutputBuffer::create(FilePath: ctx.arg.outputFile, Size: fileSize,
1924 Flags: FileOutputBuffer::F_executable);
1925
1926 if (!bufferOrErr)
1927 error(msg: "failed to open " + ctx.arg.outputFile + ": " +
1928 toString(E: bufferOrErr.takeError()));
1929 else
1930 buffer = std::move(*bufferOrErr);
1931}
1932
1933void Writer::createHeader() {
1934 raw_string_ostream os(header);
1935 writeBytes(os, bytes: WasmMagic, count: sizeof(WasmMagic), msg: "wasm magic");
1936 writeU32(os, number: WasmVersion, msg: "wasm version");
1937 fileSize += header.size();
1938}
1939
1940void writeResult() { Writer().run(); }
1941
1942} // namespace lld::wasm
1943