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 
24 #define DEBUG_TYPE "lld"
25 
26 namespace lld {
27 namespace 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 = "")
OutputSection(type,name)39       : OutputSection(type, name), bodyOutputStream(body) {
40     if (!name.empty())
41       writeStr(bodyOutputStream, name, "section name");
42   }
43 
writeTo(uint8_t * buf)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 
getSize()51   size_t getSize() const override { return header.size() + body.size(); }
52 
writeBody()53   virtual void writeBody() {}
54 
assignIndexes()55   virtual void assignIndexes() {}
56 
finalizeContents()57   void finalizeContents() override {
58     writeBody();
59     bodyOutputStream.flush();
60     createHeader(body.size());
61   }
62 
getStream()63   raw_ostream &getStream() { return bodyOutputStream; }
64 
65   std::string body;
66 
67 protected:
68   llvm::raw_string_ostream bodyOutputStream;
69 };
70 
71 // Create the custom "dylink" section containing information for the dynamic
72 // linker.
73 // See
74 // https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
75 class DylinkSection : public SyntheticSection {
76 public:
DylinkSection()77   DylinkSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "dylink") {}
isNeeded()78   bool isNeeded() const override { return config->isPic; }
79   void writeBody() override;
80 
81   uint32_t memAlign = 0;
82   uint32_t memSize = 0;
83 };
84 
85 class TypeSection : public SyntheticSection {
86 public:
TypeSection()87   TypeSection() : SyntheticSection(llvm::wasm::WASM_SEC_TYPE) {}
88 
isNeeded()89   bool isNeeded() const override { return types.size() > 0; };
90   void writeBody() override;
91   uint32_t registerType(const WasmSignature &sig);
92   uint32_t lookupType(const WasmSignature &sig);
93 
94 protected:
95   std::vector<const WasmSignature *> types;
96   llvm::DenseMap<WasmSignature, int32_t> typeIndices;
97 };
98 
99 class ImportSection : public SyntheticSection {
100 public:
ImportSection()101   ImportSection() : SyntheticSection(llvm::wasm::WASM_SEC_IMPORT) {}
isNeeded()102   bool isNeeded() const override { return getNumImports() > 0; }
103   void writeBody() override;
104   void addImport(Symbol *sym);
105   void addGOTEntry(Symbol *sym);
seal()106   void seal() { isSealed = true; }
107   uint32_t getNumImports() const;
getNumImportedGlobals()108   uint32_t getNumImportedGlobals() const {
109     assert(isSealed);
110     return numImportedGlobals;
111   }
getNumImportedFunctions()112   uint32_t getNumImportedFunctions() const {
113     assert(isSealed);
114     return numImportedFunctions;
115   }
getNumImportedEvents()116   uint32_t getNumImportedEvents() const {
117     assert(isSealed);
118     return numImportedEvents;
119   }
getNumImportedTables()120   uint32_t getNumImportedTables() const {
121     assert(isSealed);
122     return numImportedTables;
123   }
124 
125   std::vector<const Symbol *> importedSymbols;
126   std::vector<const Symbol *> gotSymbols;
127 
128 protected:
129   bool isSealed = false;
130   unsigned numImportedGlobals = 0;
131   unsigned numImportedFunctions = 0;
132   unsigned numImportedEvents = 0;
133   unsigned numImportedTables = 0;
134 };
135 
136 class FunctionSection : public SyntheticSection {
137 public:
FunctionSection()138   FunctionSection() : SyntheticSection(llvm::wasm::WASM_SEC_FUNCTION) {}
139 
isNeeded()140   bool isNeeded() const override { return inputFunctions.size() > 0; };
141   void writeBody() override;
142   void addFunction(InputFunction *func);
143 
144   std::vector<InputFunction *> inputFunctions;
145 
146 protected:
147 };
148 
149 class TableSection : public SyntheticSection {
150 public:
TableSection()151   TableSection() : SyntheticSection(llvm::wasm::WASM_SEC_TABLE) {}
152 
isNeeded()153   bool isNeeded() const override { return inputTables.size() > 0; };
154   void writeBody() override;
155   void addTable(InputTable *table);
156 
157   std::vector<InputTable *> inputTables;
158 };
159 
160 class MemorySection : public SyntheticSection {
161 public:
MemorySection()162   MemorySection() : SyntheticSection(llvm::wasm::WASM_SEC_MEMORY) {}
163 
isNeeded()164   bool isNeeded() const override { return !config->importMemory; }
165   void writeBody() override;
166 
167   uint64_t numMemoryPages = 0;
168   uint64_t maxMemoryPages = 0;
169 };
170 
171 // The event section contains a list of declared wasm events associated with the
172 // module. Currently the only supported event kind is exceptions. A single event
173 // entry represents a single event with an event tag. All C++ exceptions are
174 // represented by a single event. An event entry in this section contains
175 // information on what kind of event it is (e.g. exception) and the type of
176 // values contained in a single event object. (In wasm, an event can contain
177 // multiple values of primitive types. But for C++ exceptions, we just throw a
178 // pointer which is an i32 value (for wasm32 architecture), so the signature of
179 // C++ exception is (i32)->(void), because all event types are assumed to have
180 // void return type to share WasmSignature with functions.)
181 class EventSection : public SyntheticSection {
182 public:
EventSection()183   EventSection() : SyntheticSection(llvm::wasm::WASM_SEC_EVENT) {}
184   void writeBody() override;
isNeeded()185   bool isNeeded() const override { return inputEvents.size() > 0; }
186   void addEvent(InputEvent *event);
187 
188   std::vector<InputEvent *> inputEvents;
189 };
190 
191 class GlobalSection : public SyntheticSection {
192 public:
GlobalSection()193   GlobalSection() : SyntheticSection(llvm::wasm::WASM_SEC_GLOBAL) {}
numGlobals()194   uint32_t numGlobals() const {
195     assert(isSealed);
196     return inputGlobals.size() + dataAddressGlobals.size() +
197            internalGotSymbols.size();
198   }
isNeeded()199   bool isNeeded() const override { return numGlobals() > 0; }
200   void assignIndexes() override;
201   void writeBody() override;
202   void addGlobal(InputGlobal *global);
203 
204   // Add an internal GOT entry global that corresponds to the given symbol.
205   // Normally GOT entries are imported and assigned by the external dynamic
206   // linker.  However, when linking PIC code statically or when linking with
207   // -Bsymbolic we can internalize GOT entries by declaring globals the hold
208   // symbol addresses.
209   //
210   // For the static linking case these internal globals can be completely
211   // eliminated by a post-link optimizer such as wasm-opt.
212   //
213   // TODO(sbc): Another approach to optimizing these away could be to use
214   // specific relocation types combined with linker relaxation which could
215   // transform a `global.get` to an `i32.const`.
216   void addInternalGOTEntry(Symbol *sym);
needsRelocations()217   bool needsRelocations() { return internalGotSymbols.size(); }
218   void generateRelocationCode(raw_ostream &os) const;
219 
220   std::vector<const DefinedData *> dataAddressGlobals;
221   std::vector<InputGlobal *> inputGlobals;
222   std::vector<Symbol *> internalGotSymbols;
223 
224 protected:
225   bool isSealed = false;
226 };
227 
228 class ExportSection : public SyntheticSection {
229 public:
ExportSection()230   ExportSection() : SyntheticSection(llvm::wasm::WASM_SEC_EXPORT) {}
isNeeded()231   bool isNeeded() const override { return exports.size() > 0; }
232   void writeBody() override;
233 
234   std::vector<llvm::wasm::WasmExport> exports;
235   std::vector<const Symbol *> exportedSymbols;
236 };
237 
238 class StartSection : public SyntheticSection {
239 public:
StartSection()240   StartSection() : SyntheticSection(llvm::wasm::WASM_SEC_START) {}
241   bool isNeeded() const override;
242   void writeBody() override;
243 };
244 
245 class ElemSection : public SyntheticSection {
246 public:
ElemSection()247   ElemSection()
248       : SyntheticSection(llvm::wasm::WASM_SEC_ELEM) {}
isNeeded()249   bool isNeeded() const override { return indirectFunctions.size() > 0; };
250   void writeBody() override;
251   void addEntry(FunctionSymbol *sym);
numEntries()252   uint32_t numEntries() const { return indirectFunctions.size(); }
253 
254 protected:
255   std::vector<const FunctionSymbol *> indirectFunctions;
256 };
257 
258 class DataCountSection : public SyntheticSection {
259 public:
260   DataCountSection(ArrayRef<OutputSegment *> segments);
261   bool isNeeded() const override;
262   void writeBody() override;
263 
264 protected:
265   uint32_t numSegments;
266 };
267 
268 // Create the custom "linking" section containing linker metadata.
269 // This is only created when relocatable output is requested.
270 class LinkingSection : public SyntheticSection {
271 public:
LinkingSection(const std::vector<WasmInitEntry> & initFunctions,const std::vector<OutputSegment * > & dataSegments)272   LinkingSection(const std::vector<WasmInitEntry> &initFunctions,
273                  const std::vector<OutputSegment *> &dataSegments)
274       : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "linking"),
275         initFunctions(initFunctions), dataSegments(dataSegments) {}
isNeeded()276   bool isNeeded() const override {
277     return config->relocatable || config->emitRelocs;
278   }
279   void writeBody() override;
280   void addToSymtab(Symbol *sym);
281 
282 protected:
283   std::vector<const Symbol *> symtabEntries;
284   llvm::StringMap<uint32_t> sectionSymbolIndices;
285   const std::vector<WasmInitEntry> &initFunctions;
286   const std::vector<OutputSegment *> &dataSegments;
287 };
288 
289 // Create the custom "name" section containing debug symbol names.
290 class NameSection : public SyntheticSection {
291 public:
NameSection(ArrayRef<OutputSegment * > segments)292   NameSection(ArrayRef<OutputSegment *> segments)
293       : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name"),
294         segments(segments) {}
isNeeded()295   bool isNeeded() const override {
296     return !config->stripDebug && !config->stripAll && numNames() > 0;
297   }
298   void writeBody() override;
numNames()299   unsigned numNames() const { return numNamedGlobals() + numNamedFunctions(); }
300   unsigned numNamedGlobals() const;
301   unsigned numNamedFunctions() const;
302   unsigned numNamedDataSegments() const;
303 
304 protected:
305   ArrayRef<OutputSegment *> segments;
306 };
307 
308 class ProducersSection : public SyntheticSection {
309 public:
ProducersSection()310   ProducersSection()
311       : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "producers") {}
isNeeded()312   bool isNeeded() const override {
313     return !config->stripAll && fieldCount() > 0;
314   }
315   void writeBody() override;
316   void addInfo(const llvm::wasm::WasmProducerInfo &info);
317 
318 protected:
fieldCount()319   int fieldCount() const {
320     return int(!languages.empty()) + int(!tools.empty()) + int(!sDKs.empty());
321   }
322   SmallVector<std::pair<std::string, std::string>, 8> languages;
323   SmallVector<std::pair<std::string, std::string>, 8> tools;
324   SmallVector<std::pair<std::string, std::string>, 8> sDKs;
325 };
326 
327 class TargetFeaturesSection : public SyntheticSection {
328 public:
TargetFeaturesSection()329   TargetFeaturesSection()
330       : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "target_features") {}
isNeeded()331   bool isNeeded() const override {
332     return !config->stripAll && features.size() > 0;
333   }
334   void writeBody() override;
335 
336   llvm::SmallSet<std::string, 8> features;
337 };
338 
339 class RelocSection : public SyntheticSection {
340 public:
RelocSection(StringRef name,OutputSection * sec)341   RelocSection(StringRef name, OutputSection *sec)
342       : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, std::string(name)),
343         sec(sec) {}
344   void writeBody() override;
isNeeded()345   bool isNeeded() const override { return sec->getNumRelocations() > 0; };
346 
347 protected:
348   OutputSection *sec;
349 };
350 
351 // Linker generated output sections
352 struct OutStruct {
353   DylinkSection *dylinkSec;
354   TypeSection *typeSec;
355   FunctionSection *functionSec;
356   ImportSection *importSec;
357   TableSection *tableSec;
358   MemorySection *memorySec;
359   GlobalSection *globalSec;
360   EventSection *eventSec;
361   ExportSection *exportSec;
362   StartSection *startSec;
363   ElemSection *elemSec;
364   DataCountSection *dataCountSec;
365   LinkingSection *linkingSec;
366   NameSection *nameSec;
367   ProducersSection *producersSec;
368   TargetFeaturesSection *targetFeaturesSec;
369 };
370 
371 extern OutStruct out;
372 
373 } // namespace wasm
374 } // namespace lld
375 
376 #endif
377