| //===- SyntheticSection.h ---------------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Synthetic sections represent chunks of linker-created data. If you |
| // need to create a chunk of data that to be included in some section |
| // in the result, you probably want to create that as a synthetic section. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLD_WASM_SYNTHETIC_SECTIONS_H |
| #define LLD_WASM_SYNTHETIC_SECTIONS_H |
| |
| #include "OutputSections.h" |
| |
| #include "llvm/ADT/SmallSet.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/BinaryFormat/WasmTraits.h" |
| |
| #define DEBUG_TYPE "lld" |
| |
| namespace lld { |
| namespace wasm { |
| |
| // An init entry to be written to either the synthetic init func or the |
| // linking metadata. |
| struct WasmInitEntry { |
| const FunctionSymbol *sym; |
| uint32_t priority; |
| }; |
| |
| class SyntheticSection : public OutputSection { |
| public: |
| SyntheticSection(uint32_t type, std::string name = "") |
| : OutputSection(type, name), bodyOutputStream(body) { |
| if (!name.empty()) |
| writeStr(bodyOutputStream, name, "section name"); |
| } |
| |
| void writeTo(uint8_t *buf) override { |
| assert(offset); |
| log("writing " + toString(*this)); |
| memcpy(buf + offset, header.data(), header.size()); |
| memcpy(buf + offset + header.size(), body.data(), body.size()); |
| } |
| |
| size_t getSize() const override { return header.size() + body.size(); } |
| |
| virtual void writeBody() {} |
| |
| virtual void assignIndexes() {} |
| |
| void finalizeContents() override { |
| writeBody(); |
| bodyOutputStream.flush(); |
| createHeader(body.size()); |
| } |
| |
| raw_ostream &getStream() { return bodyOutputStream; } |
| |
| std::string body; |
| |
| protected: |
| llvm::raw_string_ostream bodyOutputStream; |
| }; |
| |
| // Create the custom "dylink" section containing information for the dynamic |
| // linker. |
| // See |
| // https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md |
| class DylinkSection : public SyntheticSection { |
| public: |
| DylinkSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "dylink") {} |
| bool isNeeded() const override { return config->isPic; } |
| void writeBody() override; |
| |
| uint32_t memAlign = 0; |
| uint32_t memSize = 0; |
| }; |
| |
| class TypeSection : public SyntheticSection { |
| public: |
| TypeSection() : SyntheticSection(llvm::wasm::WASM_SEC_TYPE) {} |
| |
| bool isNeeded() const override { return types.size() > 0; }; |
| void writeBody() override; |
| uint32_t registerType(const WasmSignature &sig); |
| uint32_t lookupType(const WasmSignature &sig); |
| |
| protected: |
| std::vector<const WasmSignature *> types; |
| llvm::DenseMap<WasmSignature, int32_t> typeIndices; |
| }; |
| |
| class ImportSection : public SyntheticSection { |
| public: |
| ImportSection() : SyntheticSection(llvm::wasm::WASM_SEC_IMPORT) {} |
| bool isNeeded() const override { return getNumImports() > 0; } |
| void writeBody() override; |
| void addImport(Symbol *sym); |
| void addGOTEntry(Symbol *sym); |
| void seal() { isSealed = true; } |
| uint32_t getNumImports() const; |
| uint32_t getNumImportedGlobals() const { |
| assert(isSealed); |
| return numImportedGlobals; |
| } |
| uint32_t getNumImportedFunctions() const { |
| assert(isSealed); |
| return numImportedFunctions; |
| } |
| uint32_t getNumImportedEvents() const { |
| assert(isSealed); |
| return numImportedEvents; |
| } |
| uint32_t getNumImportedTables() const { |
| assert(isSealed); |
| return numImportedTables; |
| } |
| |
| std::vector<const Symbol *> importedSymbols; |
| std::vector<const Symbol *> gotSymbols; |
| |
| protected: |
| bool isSealed = false; |
| unsigned numImportedGlobals = 0; |
| unsigned numImportedFunctions = 0; |
| unsigned numImportedEvents = 0; |
| unsigned numImportedTables = 0; |
| }; |
| |
| class FunctionSection : public SyntheticSection { |
| public: |
| FunctionSection() : SyntheticSection(llvm::wasm::WASM_SEC_FUNCTION) {} |
| |
| bool isNeeded() const override { return inputFunctions.size() > 0; }; |
| void writeBody() override; |
| void addFunction(InputFunction *func); |
| |
| std::vector<InputFunction *> inputFunctions; |
| |
| protected: |
| }; |
| |
| class TableSection : public SyntheticSection { |
| public: |
| TableSection() : SyntheticSection(llvm::wasm::WASM_SEC_TABLE) {} |
| |
| bool isNeeded() const override { return inputTables.size() > 0; }; |
| void assignIndexes() override; |
| void writeBody() override; |
| void addTable(InputTable *table); |
| |
| std::vector<InputTable *> inputTables; |
| }; |
| |
| class MemorySection : public SyntheticSection { |
| public: |
| MemorySection() : SyntheticSection(llvm::wasm::WASM_SEC_MEMORY) {} |
| |
| bool isNeeded() const override { return !config->importMemory; } |
| void writeBody() override; |
| |
| uint64_t numMemoryPages = 0; |
| uint64_t maxMemoryPages = 0; |
| }; |
| |
| // The event section contains a list of declared wasm events associated with the |
| // module. Currently the only supported event kind is exceptions. A single event |
| // entry represents a single event with an event tag. All C++ exceptions are |
| // represented by a single event. An event entry in this section contains |
| // information on what kind of event it is (e.g. exception) and the type of |
| // values contained in a single event object. (In wasm, an event can contain |
| // multiple values of primitive types. But for C++ exceptions, we just throw a |
| // pointer which is an i32 value (for wasm32 architecture), so the signature of |
| // C++ exception is (i32)->(void), because all event types are assumed to have |
| // void return type to share WasmSignature with functions.) |
| class EventSection : public SyntheticSection { |
| public: |
| EventSection() : SyntheticSection(llvm::wasm::WASM_SEC_EVENT) {} |
| void writeBody() override; |
| bool isNeeded() const override { return inputEvents.size() > 0; } |
| void addEvent(InputEvent *event); |
| |
| std::vector<InputEvent *> inputEvents; |
| }; |
| |
| class GlobalSection : public SyntheticSection { |
| public: |
| GlobalSection() : SyntheticSection(llvm::wasm::WASM_SEC_GLOBAL) {} |
| |
| static bool classof(const OutputSection *sec) { |
| return sec->type == llvm::wasm::WASM_SEC_GLOBAL; |
| } |
| |
| uint32_t numGlobals() const { |
| assert(isSealed); |
| return inputGlobals.size() + dataAddressGlobals.size() + |
| internalGotSymbols.size(); |
| } |
| bool isNeeded() const override { return numGlobals() > 0; } |
| void assignIndexes() override; |
| void writeBody() override; |
| void addGlobal(InputGlobal *global); |
| |
| // Add an internal GOT entry global that corresponds to the given symbol. |
| // Normally GOT entries are imported and assigned by the external dynamic |
| // linker. However, when linking PIC code statically or when linking with |
| // -Bsymbolic we can internalize GOT entries by declaring globals the hold |
| // symbol addresses. |
| // |
| // For the static linking case these internal globals can be completely |
| // eliminated by a post-link optimizer such as wasm-opt. |
| // |
| // TODO(sbc): Another approach to optimizing these away could be to use |
| // specific relocation types combined with linker relaxation which could |
| // transform a `global.get` to an `i32.const`. |
| void addInternalGOTEntry(Symbol *sym); |
| bool needsRelocations() { return internalGotSymbols.size(); } |
| void generateRelocationCode(raw_ostream &os) const; |
| |
| std::vector<const DefinedData *> dataAddressGlobals; |
| std::vector<InputGlobal *> inputGlobals; |
| std::vector<Symbol *> internalGotSymbols; |
| |
| protected: |
| bool isSealed = false; |
| }; |
| |
| class ExportSection : public SyntheticSection { |
| public: |
| ExportSection() : SyntheticSection(llvm::wasm::WASM_SEC_EXPORT) {} |
| bool isNeeded() const override { return exports.size() > 0; } |
| void writeBody() override; |
| |
| std::vector<llvm::wasm::WasmExport> exports; |
| std::vector<const Symbol *> exportedSymbols; |
| }; |
| |
| class StartSection : public SyntheticSection { |
| public: |
| StartSection() : SyntheticSection(llvm::wasm::WASM_SEC_START) {} |
| bool isNeeded() const override; |
| void writeBody() override; |
| }; |
| |
| class ElemSection : public SyntheticSection { |
| public: |
| ElemSection() |
| : SyntheticSection(llvm::wasm::WASM_SEC_ELEM) {} |
| bool isNeeded() const override { return indirectFunctions.size() > 0; }; |
| void writeBody() override; |
| void addEntry(FunctionSymbol *sym); |
| uint32_t numEntries() const { return indirectFunctions.size(); } |
| |
| protected: |
| std::vector<const FunctionSymbol *> indirectFunctions; |
| }; |
| |
| class DataCountSection : public SyntheticSection { |
| public: |
| DataCountSection(ArrayRef<OutputSegment *> segments); |
| bool isNeeded() const override; |
| void writeBody() override; |
| |
| protected: |
| uint32_t numSegments; |
| }; |
| |
| // Create the custom "linking" section containing linker metadata. |
| // This is only created when relocatable output is requested. |
| class LinkingSection : public SyntheticSection { |
| public: |
| LinkingSection(const std::vector<WasmInitEntry> &initFunctions, |
| const std::vector<OutputSegment *> &dataSegments) |
| : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "linking"), |
| initFunctions(initFunctions), dataSegments(dataSegments) {} |
| bool isNeeded() const override { |
| return config->relocatable || config->emitRelocs; |
| } |
| void writeBody() override; |
| void addToSymtab(Symbol *sym); |
| |
| protected: |
| std::vector<const Symbol *> symtabEntries; |
| llvm::StringMap<uint32_t> sectionSymbolIndices; |
| const std::vector<WasmInitEntry> &initFunctions; |
| const std::vector<OutputSegment *> &dataSegments; |
| }; |
| |
| // Create the custom "name" section containing debug symbol names. |
| class NameSection : public SyntheticSection { |
| public: |
| NameSection(ArrayRef<OutputSegment *> segments) |
| : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name"), |
| segments(segments) {} |
| bool isNeeded() const override { |
| return !config->stripDebug && !config->stripAll && numNames() > 0; |
| } |
| void writeBody() override; |
| unsigned numNames() const { return numNamedGlobals() + numNamedFunctions(); } |
| unsigned numNamedGlobals() const; |
| unsigned numNamedFunctions() const; |
| unsigned numNamedDataSegments() const; |
| |
| protected: |
| ArrayRef<OutputSegment *> segments; |
| }; |
| |
| class ProducersSection : public SyntheticSection { |
| public: |
| ProducersSection() |
| : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "producers") {} |
| bool isNeeded() const override { |
| return !config->stripAll && fieldCount() > 0; |
| } |
| void writeBody() override; |
| void addInfo(const llvm::wasm::WasmProducerInfo &info); |
| |
| protected: |
| int fieldCount() const { |
| return int(!languages.empty()) + int(!tools.empty()) + int(!sDKs.empty()); |
| } |
| SmallVector<std::pair<std::string, std::string>, 8> languages; |
| SmallVector<std::pair<std::string, std::string>, 8> tools; |
| SmallVector<std::pair<std::string, std::string>, 8> sDKs; |
| }; |
| |
| class TargetFeaturesSection : public SyntheticSection { |
| public: |
| TargetFeaturesSection() |
| : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "target_features") {} |
| bool isNeeded() const override { |
| return !config->stripAll && features.size() > 0; |
| } |
| void writeBody() override; |
| |
| llvm::SmallSet<std::string, 8> features; |
| }; |
| |
| class RelocSection : public SyntheticSection { |
| public: |
| RelocSection(StringRef name, OutputSection *sec) |
| : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, std::string(name)), |
| sec(sec) {} |
| void writeBody() override; |
| bool isNeeded() const override { return sec->getNumRelocations() > 0; }; |
| |
| protected: |
| OutputSection *sec; |
| }; |
| |
| // Linker generated output sections |
| struct OutStruct { |
| DylinkSection *dylinkSec; |
| TypeSection *typeSec; |
| FunctionSection *functionSec; |
| ImportSection *importSec; |
| TableSection *tableSec; |
| MemorySection *memorySec; |
| GlobalSection *globalSec; |
| EventSection *eventSec; |
| ExportSection *exportSec; |
| StartSection *startSec; |
| ElemSection *elemSec; |
| DataCountSection *dataCountSec; |
| LinkingSection *linkingSec; |
| NameSection *nameSec; |
| ProducersSection *producersSec; |
| TargetFeaturesSection *targetFeaturesSec; |
| }; |
| |
| extern OutStruct out; |
| |
| } // namespace wasm |
| } // namespace lld |
| |
| #endif |