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