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 } 120 121 std::vector<const Symbol *> importedSymbols; 122 std::vector<const Symbol *> gotSymbols; 123 124 protected: 125 bool isSealed = false; 126 unsigned numImportedGlobals = 0; 127 unsigned numImportedFunctions = 0; 128 unsigned numImportedEvents = 0; 129 }; 130 131 class FunctionSection : public SyntheticSection { 132 public: FunctionSection()133 FunctionSection() : SyntheticSection(llvm::wasm::WASM_SEC_FUNCTION) {} 134 isNeeded()135 bool isNeeded() const override { return inputFunctions.size() > 0; }; 136 void writeBody() override; 137 void addFunction(InputFunction *func); 138 139 std::vector<InputFunction *> inputFunctions; 140 141 protected: 142 }; 143 144 class TableSection : public SyntheticSection { 145 public: TableSection()146 TableSection() : SyntheticSection(llvm::wasm::WASM_SEC_TABLE) {} 147 isNeeded()148 bool isNeeded() const override { 149 // Always output a table section (or table import), even if there are no 150 // indirect calls. There are two reasons for this: 151 // 1. For executables it is useful to have an empty table slot at 0 152 // which can be filled with a null function call handler. 153 // 2. If we don't do this, any program that contains a call_indirect but 154 // no address-taken function will fail at validation time since it is 155 // a validation error to include a call_indirect instruction if there 156 // is not table. 157 return !config->importTable; 158 } 159 160 void writeBody() override; 161 }; 162 163 class MemorySection : public SyntheticSection { 164 public: MemorySection()165 MemorySection() : SyntheticSection(llvm::wasm::WASM_SEC_MEMORY) {} 166 isNeeded()167 bool isNeeded() const override { return !config->importMemory; } 168 void writeBody() override; 169 170 uint64_t numMemoryPages = 0; 171 uint64_t maxMemoryPages = 0; 172 }; 173 174 // The event section contains a list of declared wasm events associated with the 175 // module. Currently the only supported event kind is exceptions. A single event 176 // entry represents a single event with an event tag. All C++ exceptions are 177 // represented by a single event. An event entry in this section contains 178 // information on what kind of event it is (e.g. exception) and the type of 179 // values contained in a single event object. (In wasm, an event can contain 180 // multiple values of primitive types. But for C++ exceptions, we just throw a 181 // pointer which is an i32 value (for wasm32 architecture), so the signature of 182 // C++ exception is (i32)->(void), because all event types are assumed to have 183 // void return type to share WasmSignature with functions.) 184 class EventSection : public SyntheticSection { 185 public: EventSection()186 EventSection() : SyntheticSection(llvm::wasm::WASM_SEC_EVENT) {} 187 void writeBody() override; isNeeded()188 bool isNeeded() const override { return inputEvents.size() > 0; } 189 void addEvent(InputEvent *event); 190 191 std::vector<InputEvent *> inputEvents; 192 }; 193 194 class GlobalSection : public SyntheticSection { 195 public: GlobalSection()196 GlobalSection() : SyntheticSection(llvm::wasm::WASM_SEC_GLOBAL) {} numGlobals()197 uint32_t numGlobals() const { 198 assert(isSealed); 199 return inputGlobals.size() + dataAddressGlobals.size() + 200 internalGotSymbols.size(); 201 } isNeeded()202 bool isNeeded() const override { return numGlobals() > 0; } 203 void assignIndexes() override; 204 void writeBody() override; 205 void addGlobal(InputGlobal *global); 206 207 // Add an internal GOT entry global that corresponds to the given symbol. 208 // Normally GOT entries are imported and assigned by the external dynamic 209 // linker. However, when linking PIC code statically or when linking with 210 // -Bsymbolic we can internalize GOT entries by declaring globals the hold 211 // symbol addresses. 212 // 213 // For the static linking case these internal globals can be completely 214 // eliminated by a post-link optimizer such as wasm-opt. 215 // 216 // TODO(sbc): Another approach to optimizing these away could be to use 217 // specific relocation types combined with linker relaxation which could 218 // transform a `global.get` to an `i32.const`. 219 void addInternalGOTEntry(Symbol *sym); 220 void generateRelocationCode(raw_ostream &os) const; 221 222 std::vector<const DefinedData *> dataAddressGlobals; 223 std::vector<InputGlobal *> inputGlobals; 224 std::vector<Symbol *> internalGotSymbols; 225 226 protected: 227 bool isSealed = false; 228 }; 229 230 class ExportSection : public SyntheticSection { 231 public: ExportSection()232 ExportSection() : SyntheticSection(llvm::wasm::WASM_SEC_EXPORT) {} isNeeded()233 bool isNeeded() const override { return exports.size() > 0; } 234 void writeBody() override; 235 236 std::vector<llvm::wasm::WasmExport> exports; 237 std::vector<const Symbol *> exportedSymbols; 238 }; 239 240 class StartSection : public SyntheticSection { 241 public: StartSection(bool hasInitializedSegments)242 StartSection(bool hasInitializedSegments) 243 : SyntheticSection(llvm::wasm::WASM_SEC_START), 244 hasInitializedSegments(hasInitializedSegments) {} 245 bool isNeeded() const override; 246 void writeBody() override; 247 248 protected: 249 bool hasInitializedSegments; 250 }; 251 252 class ElemSection : public SyntheticSection { 253 public: ElemSection()254 ElemSection() 255 : SyntheticSection(llvm::wasm::WASM_SEC_ELEM) {} isNeeded()256 bool isNeeded() const override { return indirectFunctions.size() > 0; }; 257 void writeBody() override; 258 void addEntry(FunctionSymbol *sym); numEntries()259 uint32_t numEntries() const { return indirectFunctions.size(); } 260 261 protected: 262 std::vector<const FunctionSymbol *> indirectFunctions; 263 }; 264 265 class DataCountSection : public SyntheticSection { 266 public: 267 DataCountSection(ArrayRef<OutputSegment *> segments); 268 bool isNeeded() const override; 269 void writeBody() override; 270 271 protected: 272 uint32_t numSegments; 273 }; 274 275 // Create the custom "linking" section containing linker metadata. 276 // This is only created when relocatable output is requested. 277 class LinkingSection : public SyntheticSection { 278 public: LinkingSection(const std::vector<WasmInitEntry> & initFunctions,const std::vector<OutputSegment * > & dataSegments)279 LinkingSection(const std::vector<WasmInitEntry> &initFunctions, 280 const std::vector<OutputSegment *> &dataSegments) 281 : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "linking"), 282 initFunctions(initFunctions), dataSegments(dataSegments) {} isNeeded()283 bool isNeeded() const override { 284 return config->relocatable || config->emitRelocs; 285 } 286 void writeBody() override; 287 void addToSymtab(Symbol *sym); 288 289 protected: 290 std::vector<const Symbol *> symtabEntries; 291 llvm::StringMap<uint32_t> sectionSymbolIndices; 292 const std::vector<WasmInitEntry> &initFunctions; 293 const std::vector<OutputSegment *> &dataSegments; 294 }; 295 296 // Create the custom "name" section containing debug symbol names. 297 class NameSection : public SyntheticSection { 298 public: NameSection()299 NameSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name") {} isNeeded()300 bool isNeeded() const override { 301 return !config->stripDebug && !config->stripAll && numNames() > 0; 302 } 303 void writeBody() override; numNames()304 unsigned numNames() const { return numNamedGlobals() + numNamedFunctions(); } 305 unsigned numNamedGlobals() const; 306 unsigned numNamedFunctions() const; 307 }; 308 309 class ProducersSection : public SyntheticSection { 310 public: ProducersSection()311 ProducersSection() 312 : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "producers") {} isNeeded()313 bool isNeeded() const override { 314 return !config->stripAll && fieldCount() > 0; 315 } 316 void writeBody() override; 317 void addInfo(const llvm::wasm::WasmProducerInfo &info); 318 319 protected: fieldCount()320 int fieldCount() const { 321 return int(!languages.empty()) + int(!tools.empty()) + int(!sDKs.empty()); 322 } 323 SmallVector<std::pair<std::string, std::string>, 8> languages; 324 SmallVector<std::pair<std::string, std::string>, 8> tools; 325 SmallVector<std::pair<std::string, std::string>, 8> sDKs; 326 }; 327 328 class TargetFeaturesSection : public SyntheticSection { 329 public: TargetFeaturesSection()330 TargetFeaturesSection() 331 : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "target_features") {} isNeeded()332 bool isNeeded() const override { 333 return !config->stripAll && features.size() > 0; 334 } 335 void writeBody() override; 336 337 llvm::SmallSet<std::string, 8> features; 338 }; 339 340 class RelocSection : public SyntheticSection { 341 public: RelocSection(StringRef name,OutputSection * sec)342 RelocSection(StringRef name, OutputSection *sec) 343 : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, std::string(name)), 344 sec(sec) {} 345 void writeBody() override; isNeeded()346 bool isNeeded() const override { return sec->getNumRelocations() > 0; }; 347 348 protected: 349 OutputSection *sec; 350 }; 351 352 // Linker generated output sections 353 struct OutStruct { 354 DylinkSection *dylinkSec; 355 TypeSection *typeSec; 356 FunctionSection *functionSec; 357 ImportSection *importSec; 358 TableSection *tableSec; 359 MemorySection *memorySec; 360 GlobalSection *globalSec; 361 EventSection *eventSec; 362 ExportSection *exportSec; 363 StartSection *startSec; 364 ElemSection *elemSec; 365 DataCountSection *dataCountSec; 366 LinkingSection *linkingSec; 367 NameSection *nameSec; 368 ProducersSection *producersSec; 369 TargetFeaturesSection *targetFeaturesSec; 370 }; 371 372 extern OutStruct out; 373 374 } // namespace wasm 375 } // namespace lld 376 377 #endif 378