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