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 = "") OutputSection(type,name)40 : OutputSection(type, name), bodyOutputStream(body) { 41 if (!name.empty()) 42 writeStr(bodyOutputStream, name, "section name"); 43 } 44 writeTo(uint8_t * buf)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 getSize()52 size_t getSize() const override { return header.size() + body.size(); } 53 writeBody()54 virtual void writeBody() {} 55 assignIndexes()56 virtual void assignIndexes() {} 57 finalizeContents()58 void finalizeContents() override { 59 writeBody(); 60 bodyOutputStream.flush(); 61 createHeader(body.size()); 62 } 63 getStream()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: DylinkSection()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: TypeSection()88 TypeSection() : SyntheticSection(llvm::wasm::WASM_SEC_TYPE) {} 89 isNeeded()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: ImportKeyImportKey116 ImportKey(T type) : type(type), state(State::Plain) {} ImportKeyImportKey117 ImportKey(T type, State state) : type(type), state(state) {} ImportKeyImportKey118 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