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