//===- 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/Object/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() {} 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->Pic; } 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 numImports() > 0; } void writeBody() override; void addImport(Symbol *Sym); void addGOTEntry(Symbol *Sym); void seal() { IsSealed = true; } uint32_t numImports() const; uint32_t numImportedGlobals() const { assert(IsSealed); return NumImportedGlobals; } uint32_t numImportedFunctions() const { assert(IsSealed); return NumImportedFunctions; } uint32_t numImportedEvents() const { assert(IsSealed); return NumImportedEvents; } std::vector ImportedSymbols; protected: bool IsSealed = false; unsigned NumImportedGlobals = 0; unsigned NumImportedFunctions = 0; unsigned NumImportedEvents = 0; std::vector GOTSymbols; }; 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 MemorySection : public SyntheticSection { public: MemorySection() : SyntheticSection(llvm::wasm::WASM_SEC_MEMORY) {} bool isNeeded() const override { return !Config->ImportMemory; } void writeBody() override; uint32_t NumMemoryPages = 0; uint32_t MaxMemoryPages = 0; }; 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 GlobalSection : public SyntheticSection { public: GlobalSection() : SyntheticSection(llvm::wasm::WASM_SEC_GLOBAL) {} uint32_t numGlobals() const { return InputGlobals.size() + DefinedFakeGlobals.size(); } bool isNeeded() const override { return numGlobals() > 0; } void writeBody() override; void addGlobal(InputGlobal *Global); std::vector DefinedFakeGlobals; std::vector InputGlobals; }; // 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 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; }; class ElemSection : public SyntheticSection { public: ElemSection(uint32_t Offset) : SyntheticSection(llvm::wasm::WASM_SEC_ELEM), ElemOffset(Offset) {} bool isNeeded() const override { return IndirectFunctions.size() > 0; }; void writeBody() override; void addEntry(FunctionSymbol *Sym); uint32_t numEntries() const { return IndirectFunctions.size(); } uint32_t ElemOffset; protected: std::vector IndirectFunctions; }; class DataCountSection : public SyntheticSection { public: DataCountSection(uint32_t NumSegments) : SyntheticSection(llvm::wasm::WASM_SEC_DATACOUNT), NumSegments(NumSegments) {} 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; }; 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, Name), Sec(Sec) {} void writeBody() override; bool isNeeded() const override { return Sec->numRelocations() > 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; ElemSection *ElemSec; DataCountSection *DataCountSec; LinkingSection *LinkingSec; NameSection *NameSec; ProducersSection *ProducersSec; TargetFeaturesSection *TargetFeaturesSec; }; extern OutStruct Out; } // namespace wasm } // namespace lld #endif