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