|  | //===- InputChunks.h --------------------------------------------*- C++ -*-===// | 
|  | // | 
|  | //                             The LLVM Linker | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // An InputChunks represents an indivisible opaque region of a input wasm file. | 
|  | // i.e. a single wasm data segment or a single wasm function. | 
|  | // | 
|  | // They are written directly to the mmap'd output file after which relocations | 
|  | // are applied.  Because each Chunk is independent they can be written in | 
|  | // parallel. | 
|  | // | 
|  | // Chunks are also unit on which garbage collection (--gc-sections) operates. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef LLD_WASM_INPUT_CHUNKS_H | 
|  | #define LLD_WASM_INPUT_CHUNKS_H | 
|  |  | 
|  | #include "Config.h" | 
|  | #include "InputFiles.h" | 
|  | #include "lld/Common/ErrorHandler.h" | 
|  | #include "llvm/Object/Wasm.h" | 
|  |  | 
|  | using llvm::object::WasmSection; | 
|  | using llvm::object::WasmSegment; | 
|  | using llvm::wasm::WasmFunction; | 
|  | using llvm::wasm::WasmRelocation; | 
|  | using llvm::wasm::WasmSignature; | 
|  |  | 
|  | namespace llvm { | 
|  | class raw_ostream; | 
|  | } | 
|  |  | 
|  | namespace lld { | 
|  | namespace wasm { | 
|  |  | 
|  | class ObjFile; | 
|  | class OutputSegment; | 
|  |  | 
|  | class InputChunk { | 
|  | public: | 
|  | enum Kind { DataSegment, Function, SyntheticFunction, Section }; | 
|  |  | 
|  | Kind kind() const { return SectionKind; } | 
|  |  | 
|  | virtual uint32_t getSize() const { return data().size(); } | 
|  |  | 
|  | void copyRelocations(const WasmSection &Section); | 
|  |  | 
|  | virtual void writeTo(uint8_t *SectionStart) const; | 
|  |  | 
|  | ArrayRef<WasmRelocation> getRelocations() const { return Relocations; } | 
|  |  | 
|  | virtual StringRef getName() const = 0; | 
|  | virtual StringRef getDebugName() const = 0; | 
|  | virtual uint32_t getComdat() const = 0; | 
|  | StringRef getComdatName() const; | 
|  |  | 
|  | size_t NumRelocations() const { return Relocations.size(); } | 
|  | void writeRelocations(llvm::raw_ostream &OS) const; | 
|  |  | 
|  | ObjFile *File; | 
|  | int32_t OutputOffset = 0; | 
|  |  | 
|  | // Signals that the section is part of the output.  The garbage collector, | 
|  | // and COMDAT handling can set a sections' Live bit. | 
|  | // If GC is disabled, all sections start out as live by default. | 
|  | unsigned Live : 1; | 
|  |  | 
|  | protected: | 
|  | InputChunk(ObjFile *F, Kind K) | 
|  | : File(F), Live(!Config->GcSections), SectionKind(K) {} | 
|  | virtual ~InputChunk() = default; | 
|  | virtual ArrayRef<uint8_t> data() const = 0; | 
|  | virtual uint32_t getInputSectionOffset() const = 0; | 
|  | virtual uint32_t getInputSize() const { return getSize(); }; | 
|  |  | 
|  | // Verifies the existing data at relocation targets matches our expectations. | 
|  | // This is performed only debug builds as an extra sanity check. | 
|  | void verifyRelocTargets() const; | 
|  |  | 
|  | std::vector<WasmRelocation> Relocations; | 
|  | Kind SectionKind; | 
|  | }; | 
|  |  | 
|  | // Represents a WebAssembly data segment which can be included as part of | 
|  | // an output data segments.  Note that in WebAssembly, unlike ELF and other | 
|  | // formats, used the term "data segment" to refer to the continous regions of | 
|  | // memory that make on the data section. See: | 
|  | // https://webassembly.github.io/spec/syntax/modules.html#syntax-data | 
|  | // | 
|  | // For example, by default, clang will produce a separate data section for | 
|  | // each global variable. | 
|  | class InputSegment : public InputChunk { | 
|  | public: | 
|  | InputSegment(const WasmSegment &Seg, ObjFile *F) | 
|  | : InputChunk(F, InputChunk::DataSegment), Segment(Seg) {} | 
|  |  | 
|  | static bool classof(const InputChunk *C) { return C->kind() == DataSegment; } | 
|  |  | 
|  | uint32_t getAlignment() const { return Segment.Data.Alignment; } | 
|  | StringRef getName() const override { return Segment.Data.Name; } | 
|  | StringRef getDebugName() const override { return StringRef(); } | 
|  | uint32_t getComdat() const override { return Segment.Data.Comdat; } | 
|  |  | 
|  | const OutputSegment *OutputSeg = nullptr; | 
|  | int32_t OutputSegmentOffset = 0; | 
|  |  | 
|  | protected: | 
|  | ArrayRef<uint8_t> data() const override { return Segment.Data.Content; } | 
|  | uint32_t getInputSectionOffset() const override { | 
|  | return Segment.SectionOffset; | 
|  | } | 
|  |  | 
|  | const WasmSegment &Segment; | 
|  | }; | 
|  |  | 
|  | // Represents a single wasm function within and input file.  These are | 
|  | // combined to create the final output CODE section. | 
|  | class InputFunction : public InputChunk { | 
|  | public: | 
|  | InputFunction(const WasmSignature &S, const WasmFunction *Func, ObjFile *F) | 
|  | : InputChunk(F, InputChunk::Function), Signature(S), Function(Func) {} | 
|  |  | 
|  | static bool classof(const InputChunk *C) { | 
|  | return C->kind() == InputChunk::Function || | 
|  | C->kind() == InputChunk::SyntheticFunction; | 
|  | } | 
|  |  | 
|  | void writeTo(uint8_t *SectionStart) const override; | 
|  | StringRef getName() const override { return Function->SymbolName; } | 
|  | StringRef getDebugName() const override { return Function->DebugName; } | 
|  | uint32_t getComdat() const override { return Function->Comdat; } | 
|  | uint32_t getFunctionInputOffset() const { return getInputSectionOffset(); } | 
|  | uint32_t getFunctionCodeOffset() const { return Function->CodeOffset; } | 
|  | uint32_t getSize() const override { | 
|  | if (Config->CompressRelocTargets && File) { | 
|  | assert(CompressedSize); | 
|  | return CompressedSize; | 
|  | } | 
|  | return data().size(); | 
|  | } | 
|  | uint32_t getFunctionIndex() const { return FunctionIndex.getValue(); } | 
|  | bool hasFunctionIndex() const { return FunctionIndex.hasValue(); } | 
|  | void setFunctionIndex(uint32_t Index); | 
|  | uint32_t getTableIndex() const { return TableIndex.getValue(); } | 
|  | bool hasTableIndex() const { return TableIndex.hasValue(); } | 
|  | void setTableIndex(uint32_t Index); | 
|  |  | 
|  | // The size of a given input function can depend on the values of the | 
|  | // LEB relocations within it.  This finalizeContents method is called after | 
|  | // all the symbol values have be calcualted but before getSize() is ever | 
|  | // called. | 
|  | void calculateSize(); | 
|  |  | 
|  | const WasmSignature &Signature; | 
|  |  | 
|  | protected: | 
|  | ArrayRef<uint8_t> data() const override { | 
|  | assert(!Config->CompressRelocTargets); | 
|  | return File->CodeSection->Content.slice(getInputSectionOffset(), | 
|  | Function->Size); | 
|  | } | 
|  |  | 
|  | uint32_t getInputSize() const override { return Function->Size; } | 
|  |  | 
|  | uint32_t getInputSectionOffset() const override { | 
|  | return Function->CodeSectionOffset; | 
|  | } | 
|  |  | 
|  | const WasmFunction *Function; | 
|  | llvm::Optional<uint32_t> FunctionIndex; | 
|  | llvm::Optional<uint32_t> TableIndex; | 
|  | uint32_t CompressedFuncSize = 0; | 
|  | uint32_t CompressedSize = 0; | 
|  | }; | 
|  |  | 
|  | class SyntheticFunction : public InputFunction { | 
|  | public: | 
|  | SyntheticFunction(const WasmSignature &S, StringRef Name, | 
|  | StringRef DebugName = {}) | 
|  | : InputFunction(S, nullptr, nullptr), Name(Name), DebugName(DebugName) { | 
|  | SectionKind = InputChunk::SyntheticFunction; | 
|  | } | 
|  |  | 
|  | static bool classof(const InputChunk *C) { | 
|  | return C->kind() == InputChunk::SyntheticFunction; | 
|  | } | 
|  |  | 
|  | StringRef getName() const override { return Name; } | 
|  | StringRef getDebugName() const override { return DebugName; } | 
|  | uint32_t getComdat() const override { return UINT32_MAX; } | 
|  |  | 
|  | void setBody(ArrayRef<uint8_t> Body_) { Body = Body_; } | 
|  |  | 
|  | protected: | 
|  | ArrayRef<uint8_t> data() const override { return Body; } | 
|  |  | 
|  | StringRef Name; | 
|  | StringRef DebugName; | 
|  | ArrayRef<uint8_t> Body; | 
|  | }; | 
|  |  | 
|  | // Represents a single Wasm Section within an input file. | 
|  | class InputSection : public InputChunk { | 
|  | public: | 
|  | InputSection(const WasmSection &S, ObjFile *F) | 
|  | : InputChunk(F, InputChunk::Section), Section(S) { | 
|  | assert(Section.Type == llvm::wasm::WASM_SEC_CUSTOM); | 
|  | } | 
|  |  | 
|  | StringRef getName() const override { return Section.Name; } | 
|  | StringRef getDebugName() const override { return StringRef(); } | 
|  | uint32_t getComdat() const override { return UINT32_MAX; } | 
|  |  | 
|  | protected: | 
|  | ArrayRef<uint8_t> data() const override { return Section.Content; } | 
|  |  | 
|  | // Offset within the input section.  This is only zero since this chunk | 
|  | // type represents an entire input section, not part of one. | 
|  | uint32_t getInputSectionOffset() const override { return 0; } | 
|  |  | 
|  | const WasmSection &Section; | 
|  | }; | 
|  |  | 
|  | } // namespace wasm | 
|  |  | 
|  | std::string toString(const wasm::InputChunk *); | 
|  | } // namespace lld | 
|  |  | 
|  | #endif // LLD_WASM_INPUT_CHUNKS_H |