//===- 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 types; llvm::DenseMap 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; } std::vector importedSymbols; std::vector gotSymbols; protected: bool isSealed = false; unsigned numImportedGlobals = 0; unsigned numImportedFunctions = 0; unsigned numImportedEvents = 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 inputFunctions; protected: }; class TableSection : public SyntheticSection { public: TableSection() : SyntheticSection(llvm::wasm::WASM_SEC_TABLE) {} bool isNeeded() const override { // Always output a table section (or table import), even if there are no // indirect calls. There are two reasons for this: // 1. For executables it is useful to have an empty table slot at 0 // which can be filled with a null function call handler. // 2. If we don't do this, any program that contains a call_indirect but // no address-taken function will fail at validation time since it is // a validation error to include a call_indirect instruction if there // is not table. return !config->importTable; } void writeBody() override; }; 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 inputEvents; }; class GlobalSection : public SyntheticSection { public: GlobalSection() : SyntheticSection(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); void generateRelocationCode(raw_ostream &os) const; std::vector dataAddressGlobals; std::vector inputGlobals; std::vector 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 exports; std::vector exportedSymbols; }; class StartSection : public SyntheticSection { public: StartSection(bool hasInitializedSegments) : SyntheticSection(llvm::wasm::WASM_SEC_START), hasInitializedSegments(hasInitializedSegments) {} bool isNeeded() const override; void writeBody() override; protected: bool hasInitializedSegments; }; 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 indirectFunctions; }; class DataCountSection : public SyntheticSection { public: DataCountSection(ArrayRef 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 &initFunctions, const std::vector &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 symtabEntries; llvm::StringMap sectionSymbolIndices; const std::vector &initFunctions; const std::vector &dataSegments; }; // Create the custom "name" section containing debug symbol names. class NameSection : public SyntheticSection { public: NameSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name") {} 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; }; 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, 8> languages; SmallVector, 8> tools; SmallVector, 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 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