1//===- SyntheticSection.h ---------------------------------------*- C++ -*-===//
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// Synthetic sections represent chunks of linker-created data. If you
10// need to create a chunk of data that to be included in some section
11// in the result, you probably want to create that as a synthetic section.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLD_WASM_SYNTHETIC_SECTIONS_H
16#define LLD_WASM_SYNTHETIC_SECTIONS_H
17
18#include "OutputSections.h"
19
20#include "llvm/ADT/SmallSet.h"
21#include "llvm/ADT/StringMap.h"
22#include "llvm/BinaryFormat/WasmTraits.h"
23#include <optional>
24
25#define DEBUG_TYPE "lld"
26
27namespace lld::wasm {
28
29// An init entry to be written to either the synthetic init func or the
30// linking metadata.
31struct WasmInitEntry {
32 const FunctionSymbol *sym;
33 uint32_t priority;
34};
35
36class SyntheticSection : public OutputSection {
37public:
38 SyntheticSection(uint32_t type, std::string name = "")
39 : OutputSection(type, name), bodyOutputStream(body) {
40 if (!name.empty())
41 writeStr(os&: bodyOutputStream, string: name, msg: "section name");
42 }
43
44 void writeTo(uint8_t *buf) override {
45 assert(offset);
46 log(msg: "writing " + toString(section: *this));
47 memcpy(dest: buf + offset, src: header.data(), n: header.size());
48 memcpy(dest: buf + offset + header.size(), src: body.data(), n: body.size());
49 }
50
51 size_t getSize() const override { return header.size() + body.size(); }
52
53 virtual void writeBody() {}
54
55 virtual void assignIndexes() {}
56
57 void finalizeContents() override {
58 writeBody();
59 createHeader(bodySize: body.size());
60 }
61
62 raw_ostream &getStream() { return bodyOutputStream; }
63
64 std::string body;
65
66protected:
67 llvm::raw_string_ostream bodyOutputStream;
68};
69
70// Create the custom "dylink" section containing information for the dynamic
71// linker.
72// See
73// https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md
74class DylinkSection : public SyntheticSection {
75public:
76 DylinkSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "dylink.0") {}
77 bool isNeeded() const override;
78 void writeBody() override;
79
80 uint32_t memAlign = 0;
81 uint32_t memSize = 0;
82};
83
84class TypeSection : public SyntheticSection {
85public:
86 TypeSection() : SyntheticSection(llvm::wasm::WASM_SEC_TYPE) {}
87
88 bool isNeeded() const override { return types.size() > 0; };
89 void writeBody() override;
90 uint32_t registerType(const WasmSignature &sig);
91 uint32_t lookupType(const WasmSignature &sig);
92
93protected:
94 std::vector<const WasmSignature *> types;
95 llvm::DenseMap<WasmSignature, int32_t> typeIndices;
96};
97
98/**
99 * A key for some kind of imported entity of type `T`.
100 *
101 * Used when de-duplicating imports.
102 */
103template <typename T> struct ImportKey {
104public:
105 T type;
106 std::optional<StringRef> importModule;
107 std::optional<StringRef> importName;
108
109public:
110 ImportKey(T type) : type(type) {}
111 ImportKey(T type, std::optional<StringRef> importModule,
112 std::optional<StringRef> importName)
113 : type(type), importModule(importModule), importName(importName) {}
114};
115
116template <typename T>
117inline bool operator==(const ImportKey<T> &lhs, const ImportKey<T> &rhs) {
118 return lhs.importModule == rhs.importModule &&
119 lhs.importName == rhs.importName && lhs.type == rhs.type;
120}
121
122} // namespace lld::wasm
123
124// `ImportKey<T>` can be used as a key in a `DenseMap` if `T` can be used as a
125// key in a `DenseMap`.
126namespace llvm {
127template <typename T> struct DenseMapInfo<lld::wasm::ImportKey<T>> {
128 static unsigned getHashValue(const lld::wasm::ImportKey<T> &key) {
129 uintptr_t hash = hash_value(key.importModule);
130 hash = hash_combine(hash, key.importName);
131 hash = hash_combine(hash, llvm::DenseMapInfo<T>::getHashValue(key.type));
132 return hash;
133 }
134 static bool isEqual(const lld::wasm::ImportKey<T> &lhs,
135 const lld::wasm::ImportKey<T> &rhs) {
136 return lhs == rhs;
137 }
138};
139} // end namespace llvm
140
141namespace lld {
142namespace wasm {
143
144class ImportSection : public SyntheticSection {
145public:
146 ImportSection() : SyntheticSection(llvm::wasm::WASM_SEC_IMPORT) {}
147 bool isNeeded() const override { return getNumImports() > 0; }
148 void writeBody() override;
149 void addImport(Symbol *sym);
150 void addGOTEntry(Symbol *sym);
151 void seal() { isSealed = true; }
152 uint32_t getNumImports() const;
153 uint32_t getNumImportedGlobals() const {
154 assert(isSealed);
155 return numImportedGlobals;
156 }
157 uint32_t getNumImportedFunctions() const {
158 assert(isSealed);
159 return numImportedFunctions;
160 }
161 uint32_t getNumImportedTags() const {
162 assert(isSealed);
163 return numImportedTags;
164 }
165 uint32_t getNumImportedTables() const {
166 assert(isSealed);
167 return numImportedTables;
168 }
169
170 std::vector<const Symbol *> importedSymbols;
171 std::vector<const Symbol *> gotSymbols;
172
173protected:
174 bool isSealed = false;
175 unsigned numImportedGlobals = 0;
176 unsigned numImportedFunctions = 0;
177 unsigned numImportedTags = 0;
178 unsigned numImportedTables = 0;
179 llvm::DenseMap<ImportKey<WasmGlobalType>, uint32_t> importedGlobals;
180 llvm::DenseMap<ImportKey<WasmSignature>, uint32_t> importedFunctions;
181 llvm::DenseMap<ImportKey<WasmTableType>, uint32_t> importedTables;
182 llvm::DenseMap<ImportKey<WasmSignature>, uint32_t> importedTags;
183};
184
185class FunctionSection : public SyntheticSection {
186public:
187 FunctionSection() : SyntheticSection(llvm::wasm::WASM_SEC_FUNCTION) {}
188
189 bool isNeeded() const override { return inputFunctions.size() > 0; };
190 void writeBody() override;
191 void addFunction(InputFunction *func);
192
193 std::vector<InputFunction *> inputFunctions;
194
195protected:
196};
197
198class TableSection : public SyntheticSection {
199public:
200 TableSection() : SyntheticSection(llvm::wasm::WASM_SEC_TABLE) {}
201
202 bool isNeeded() const override { return inputTables.size() > 0; };
203 void assignIndexes() override;
204 void writeBody() override;
205 void addTable(InputTable *table);
206
207 std::vector<InputTable *> inputTables;
208};
209
210class MemorySection : public SyntheticSection {
211public:
212 MemorySection() : SyntheticSection(llvm::wasm::WASM_SEC_MEMORY) {}
213
214 bool isNeeded() const override { return !ctx.arg.memoryImport.has_value(); }
215 void writeBody() override;
216
217 uint64_t numMemoryPages = 0;
218 uint64_t maxMemoryPages = 0;
219};
220
221// The tag section contains a list of declared wasm tags associated with the
222// module. Currently the only supported tag kind is exceptions. All C++
223// exceptions are represented by a single tag. A tag entry in this section
224// contains information on what kind of tag it is (e.g. exception) and the type
225// of values associated with the tag. (In Wasm, a tag can contain multiple
226// values of primitive types. But for C++ exceptions, we just throw a pointer
227// which is an i32 value (for wasm32 architecture), so the signature of C++
228// exception is (i32)->(void), because all exception tag types are assumed to
229// have void return type to share WasmSignature with functions.)
230class TagSection : public SyntheticSection {
231public:
232 TagSection() : SyntheticSection(llvm::wasm::WASM_SEC_TAG) {}
233 void writeBody() override;
234 bool isNeeded() const override { return inputTags.size() > 0; }
235 void addTag(InputTag *tag);
236
237 std::vector<InputTag *> inputTags;
238};
239
240class GlobalSection : public SyntheticSection {
241public:
242 GlobalSection() : SyntheticSection(llvm::wasm::WASM_SEC_GLOBAL) {}
243
244 static bool classof(const OutputSection *sec) {
245 return sec->type == llvm::wasm::WASM_SEC_GLOBAL;
246 }
247
248 uint32_t numGlobals() const {
249 assert(isSealed);
250 return inputGlobals.size() + dataAddressGlobals.size() +
251 internalGotSymbols.size();
252 }
253 bool isNeeded() const override { return numGlobals() > 0; }
254 void assignIndexes() override;
255 void writeBody() override;
256 void addGlobal(InputGlobal *global);
257
258 // Add an internal GOT entry global that corresponds to the given symbol.
259 // Normally GOT entries are imported and assigned by the external dynamic
260 // linker. However, when linking PIC code statically or when linking with
261 // -Bsymbolic we can internalize GOT entries by declaring globals the hold
262 // symbol addresses.
263 //
264 // For the static linking case these internal globals can be completely
265 // eliminated by a post-link optimizer such as wasm-opt.
266 //
267 // TODO(sbc): Another approach to optimizing these away could be to use
268 // specific relocation types combined with linker relaxation which could
269 // transform a `global.get` to an `i32.const`.
270 void addInternalGOTEntry(Symbol *sym);
271 bool needsRelocations() {
272 if (ctx.arg.extendedConst)
273 return false;
274 return llvm::any_of(Range&: internalGotSymbols,
275 P: [=](Symbol *sym) { return !sym->isTLS(); });
276 }
277 bool needsTLSRelocations() {
278 return llvm::any_of(Range&: internalGotSymbols,
279 P: [=](Symbol *sym) { return sym->isTLS(); });
280 }
281 void generateRelocationCode(raw_ostream &os, bool TLS) const;
282
283 std::vector<DefinedData *> dataAddressGlobals;
284 std::vector<InputGlobal *> inputGlobals;
285 std::vector<Symbol *> internalGotSymbols;
286
287protected:
288 bool isSealed = false;
289};
290
291class ExportSection : public SyntheticSection {
292public:
293 ExportSection() : SyntheticSection(llvm::wasm::WASM_SEC_EXPORT) {}
294 bool isNeeded() const override { return exports.size() > 0; }
295 void writeBody() override;
296
297 std::vector<llvm::wasm::WasmExport> exports;
298 std::vector<const Symbol *> exportedSymbols;
299};
300
301class StartSection : public SyntheticSection {
302public:
303 StartSection() : SyntheticSection(llvm::wasm::WASM_SEC_START) {}
304 bool isNeeded() const override;
305 void writeBody() override;
306};
307
308class ElemSection : public SyntheticSection {
309public:
310 ElemSection() : SyntheticSection(llvm::wasm::WASM_SEC_ELEM) {}
311 bool isNeeded() const override { return indirectFunctions.size() > 0; };
312 void writeBody() override;
313 void addEntry(FunctionSymbol *sym);
314 uint32_t numEntries() const { return indirectFunctions.size(); }
315
316protected:
317 std::vector<const FunctionSymbol *> indirectFunctions;
318};
319
320class DataCountSection : public SyntheticSection {
321public:
322 DataCountSection(ArrayRef<OutputSegment *> segments);
323 bool isNeeded() const override;
324 void writeBody() override;
325
326protected:
327 uint32_t numSegments;
328};
329
330// Create the custom "linking" section containing linker metadata.
331// This is only created when relocatable output is requested.
332class LinkingSection : public SyntheticSection {
333public:
334 LinkingSection(const std::vector<WasmInitEntry> &initFunctions,
335 const std::vector<OutputSegment *> &dataSegments)
336 : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "linking"),
337 initFunctions(initFunctions), dataSegments(dataSegments) {}
338 bool isNeeded() const override {
339 return ctx.arg.relocatable || ctx.arg.emitRelocs;
340 }
341 void writeBody() override;
342 void addToSymtab(Symbol *sym);
343
344protected:
345 std::vector<const Symbol *> symtabEntries;
346 llvm::StringMap<uint32_t> sectionSymbolIndices;
347 const std::vector<WasmInitEntry> &initFunctions;
348 const std::vector<OutputSegment *> &dataSegments;
349};
350
351// Create the custom "name" section containing debug symbol names.
352class NameSection : public SyntheticSection {
353public:
354 NameSection(ArrayRef<OutputSegment *> segments)
355 : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name"),
356 segments(segments) {}
357 bool isNeeded() const override {
358 if (ctx.arg.stripAll && !ctx.arg.keepSections.contains(key: name))
359 return false;
360 return numNames() > 0;
361 }
362 void writeBody() override;
363 unsigned numNames() const {
364 // We always write at least one name which is the name of the
365 // module itself.
366 return 1 + numNamedGlobals() + numNamedFunctions();
367 }
368 unsigned numNamedGlobals() const;
369 unsigned numNamedFunctions() const;
370 unsigned numNamedDataSegments() const;
371
372protected:
373 ArrayRef<OutputSegment *> segments;
374};
375
376class ProducersSection : public SyntheticSection {
377public:
378 ProducersSection()
379 : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "producers") {}
380 bool isNeeded() const override {
381 if (ctx.arg.stripAll && !ctx.arg.keepSections.contains(key: name))
382 return false;
383 return fieldCount() > 0;
384 }
385 void writeBody() override;
386 void addInfo(const llvm::wasm::WasmProducerInfo &info);
387
388protected:
389 int fieldCount() const {
390 return int(!languages.empty()) + int(!tools.empty()) + int(!sDKs.empty());
391 }
392 SmallVector<std::pair<std::string, std::string>, 8> languages;
393 SmallVector<std::pair<std::string, std::string>, 8> tools;
394 SmallVector<std::pair<std::string, std::string>, 8> sDKs;
395};
396
397class TargetFeaturesSection : public SyntheticSection {
398public:
399 TargetFeaturesSection()
400 : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "target_features") {}
401 bool isNeeded() const override {
402 if (ctx.arg.stripAll && !ctx.arg.keepSections.contains(key: name))
403 return false;
404 return features.size() > 0;
405 }
406 void writeBody() override;
407
408 llvm::SmallSet<std::string, 8> features;
409};
410
411class RelocSection : public SyntheticSection {
412public:
413 RelocSection(StringRef name, OutputSection *sec)
414 : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, std::string(name)),
415 sec(sec) {}
416 void writeBody() override;
417 bool isNeeded() const override { return sec->getNumRelocations() > 0; };
418
419protected:
420 OutputSection *sec;
421};
422
423class BuildIdSection : public SyntheticSection {
424public:
425 BuildIdSection();
426 void writeBody() override;
427 bool isNeeded() const override {
428 return ctx.arg.buildId != BuildIdKind::None;
429 }
430 void writeBuildId(llvm::ArrayRef<uint8_t> buf);
431 void writeTo(uint8_t *buf) override {
432 LLVM_DEBUG(llvm::dbgs()
433 << "BuildId writeto buf " << buf << " offset " << offset
434 << " headersize " << header.size() << '\n');
435 // The actual build ID is derived from a hash of all of the output
436 // sections, so it can't be calculated until they are written. Here
437 // we write the section leaving zeros in place of the hash.
438 SyntheticSection::writeTo(buf);
439 // Calculate and store the location where the hash will be written.
440 hashPlaceholderPtr = buf + offset + header.size() +
441 +sizeof(buildIdSectionName) /*name string*/ +
442 1 /* hash size */;
443 }
444
445 const uint32_t hashSize;
446
447private:
448 static constexpr char buildIdSectionName[] = "build_id";
449 uint8_t *hashPlaceholderPtr = nullptr;
450};
451
452// Linker generated output sections
453struct OutStruct {
454 DylinkSection *dylinkSec;
455 TypeSection *typeSec;
456 FunctionSection *functionSec;
457 ImportSection *importSec;
458 TableSection *tableSec;
459 MemorySection *memorySec;
460 GlobalSection *globalSec;
461 TagSection *tagSec;
462 ExportSection *exportSec;
463 StartSection *startSec;
464 ElemSection *elemSec;
465 DataCountSection *dataCountSec;
466 LinkingSection *linkingSec;
467 NameSection *nameSec;
468 ProducersSection *producersSec;
469 TargetFeaturesSection *targetFeaturesSec;
470 BuildIdSection *buildIdSec;
471};
472
473extern OutStruct out;
474
475} // namespace wasm
476} // namespace lld
477
478#endif
479