1 //===- InputChunks.h --------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Linker 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // An InputChunks represents an indivisible opaque region of a input wasm file. 11 // i.e. a single wasm data segment or a single wasm function. 12 // 13 // They are written directly to the mmap'd output file after which relocations 14 // are applied. Because each Chunk is independent they can be written in 15 // parallel. 16 // 17 // Chunks are also unit on which garbage collection (--gc-sections) operates. 18 // 19 //===----------------------------------------------------------------------===// 20 21 #ifndef LLD_WASM_INPUT_CHUNKS_H 22 #define LLD_WASM_INPUT_CHUNKS_H 23 24 #include "Config.h" 25 #include "InputFiles.h" 26 #include "lld/Common/ErrorHandler.h" 27 #include "llvm/Object/Wasm.h" 28 29 using llvm::object::WasmSection; 30 using llvm::object::WasmSegment; 31 using llvm::wasm::WasmFunction; 32 using llvm::wasm::WasmRelocation; 33 using llvm::wasm::WasmSignature; 34 35 namespace llvm { 36 class raw_ostream; 37 } 38 39 namespace lld { 40 namespace wasm { 41 42 class ObjFile; 43 class OutputSegment; 44 45 class InputChunk { 46 public: 47 enum Kind { DataSegment, Function, SyntheticFunction, Section }; 48 49 Kind kind() const { return SectionKind; } 50 51 virtual uint32_t getSize() const { return data().size(); } 52 virtual uint32_t getInputSize() const { return getSize(); }; 53 54 virtual void writeTo(uint8_t *SectionStart) const; 55 56 ArrayRef<WasmRelocation> getRelocations() const { return Relocations; } 57 void setRelocations(ArrayRef<WasmRelocation> Rs) { Relocations = Rs; } 58 59 virtual StringRef getName() const = 0; 60 virtual StringRef getDebugName() const = 0; 61 virtual uint32_t getComdat() const = 0; 62 StringRef getComdatName() const; 63 virtual uint32_t getInputSectionOffset() const = 0; 64 65 size_t NumRelocations() const { return Relocations.size(); } 66 void writeRelocations(llvm::raw_ostream &OS) const; 67 68 ObjFile *File; 69 int32_t OutputOffset = 0; 70 71 // Signals that the section is part of the output. The garbage collector, 72 // and COMDAT handling can set a sections' Live bit. 73 // If GC is disabled, all sections start out as live by default. 74 unsigned Live : 1; 75 76 protected: 77 InputChunk(ObjFile *F, Kind K) 78 : File(F), Live(!Config->GcSections), SectionKind(K) {} 79 virtual ~InputChunk() = default; 80 virtual ArrayRef<uint8_t> data() const = 0; 81 82 // Verifies the existing data at relocation targets matches our expectations. 83 // This is performed only debug builds as an extra sanity check. 84 void verifyRelocTargets() const; 85 86 ArrayRef<WasmRelocation> Relocations; 87 Kind SectionKind; 88 }; 89 90 // Represents a WebAssembly data segment which can be included as part of 91 // an output data segments. Note that in WebAssembly, unlike ELF and other 92 // formats, used the term "data segment" to refer to the continous regions of 93 // memory that make on the data section. See: 94 // https://webassembly.github.io/spec/syntax/modules.html#syntax-data 95 // 96 // For example, by default, clang will produce a separate data section for 97 // each global variable. 98 class InputSegment : public InputChunk { 99 public: 100 InputSegment(const WasmSegment &Seg, ObjFile *F) 101 : InputChunk(F, InputChunk::DataSegment), Segment(Seg) {} 102 103 static bool classof(const InputChunk *C) { return C->kind() == DataSegment; } 104 105 uint32_t getAlignment() const { return Segment.Data.Alignment; } 106 StringRef getName() const override { return Segment.Data.Name; } 107 StringRef getDebugName() const override { return StringRef(); } 108 uint32_t getComdat() const override { return Segment.Data.Comdat; } 109 uint32_t getInputSectionOffset() const override { 110 return Segment.SectionOffset; 111 } 112 113 const OutputSegment *OutputSeg = nullptr; 114 int32_t OutputSegmentOffset = 0; 115 116 protected: 117 ArrayRef<uint8_t> data() const override { return Segment.Data.Content; } 118 119 const WasmSegment &Segment; 120 }; 121 122 // Represents a single wasm function within and input file. These are 123 // combined to create the final output CODE section. 124 class InputFunction : public InputChunk { 125 public: 126 InputFunction(const WasmSignature &S, const WasmFunction *Func, ObjFile *F) 127 : InputChunk(F, InputChunk::Function), Signature(S), Function(Func) {} 128 129 static bool classof(const InputChunk *C) { 130 return C->kind() == InputChunk::Function || 131 C->kind() == InputChunk::SyntheticFunction; 132 } 133 134 void writeTo(uint8_t *SectionStart) const override; 135 StringRef getName() const override { return Function->SymbolName; } 136 StringRef getDebugName() const override { return Function->DebugName; } 137 uint32_t getComdat() const override { return Function->Comdat; } 138 uint32_t getFunctionInputOffset() const { return getInputSectionOffset(); } 139 uint32_t getFunctionCodeOffset() const { return Function->CodeOffset; } 140 uint32_t getSize() const override { 141 if (Config->CompressRelocations && File) { 142 assert(CompressedSize); 143 return CompressedSize; 144 } 145 return data().size(); 146 } 147 uint32_t getInputSize() const override { return Function->Size; } 148 uint32_t getFunctionIndex() const { return FunctionIndex.getValue(); } 149 bool hasFunctionIndex() const { return FunctionIndex.hasValue(); } 150 void setFunctionIndex(uint32_t Index); 151 uint32_t getInputSectionOffset() const override { 152 return Function->CodeSectionOffset; 153 } 154 uint32_t getTableIndex() const { return TableIndex.getValue(); } 155 bool hasTableIndex() const { return TableIndex.hasValue(); } 156 void setTableIndex(uint32_t Index); 157 158 // The size of a given input function can depend on the values of the 159 // LEB relocations within it. This finalizeContents method is called after 160 // all the symbol values have be calcualted but before getSize() is ever 161 // called. 162 void calculateSize(); 163 164 const WasmSignature &Signature; 165 166 protected: 167 ArrayRef<uint8_t> data() const override { 168 assert(!Config->CompressRelocations); 169 return File->CodeSection->Content.slice(getInputSectionOffset(), 170 Function->Size); 171 } 172 173 const WasmFunction *Function; 174 llvm::Optional<uint32_t> FunctionIndex; 175 llvm::Optional<uint32_t> TableIndex; 176 uint32_t CompressedFuncSize = 0; 177 uint32_t CompressedSize = 0; 178 }; 179 180 class SyntheticFunction : public InputFunction { 181 public: 182 SyntheticFunction(const WasmSignature &S, StringRef Name, 183 StringRef DebugName = {}) 184 : InputFunction(S, nullptr, nullptr), Name(Name), DebugName(DebugName) { 185 SectionKind = InputChunk::SyntheticFunction; 186 } 187 188 static bool classof(const InputChunk *C) { 189 return C->kind() == InputChunk::SyntheticFunction; 190 } 191 192 StringRef getName() const override { return Name; } 193 StringRef getDebugName() const override { return DebugName; } 194 uint32_t getComdat() const override { return UINT32_MAX; } 195 196 void setBody(ArrayRef<uint8_t> Body_) { Body = Body_; } 197 198 protected: 199 ArrayRef<uint8_t> data() const override { return Body; } 200 201 StringRef Name; 202 StringRef DebugName; 203 ArrayRef<uint8_t> Body; 204 }; 205 206 // Represents a single Wasm Section within an input file. 207 class InputSection : public InputChunk { 208 public: 209 InputSection(const WasmSection &S, ObjFile *F) 210 : InputChunk(F, InputChunk::Section), Section(S) { 211 assert(Section.Type == llvm::wasm::WASM_SEC_CUSTOM); 212 } 213 214 StringRef getName() const override { return Section.Name; } 215 StringRef getDebugName() const override { return StringRef(); } 216 uint32_t getComdat() const override { return UINT32_MAX; } 217 218 protected: 219 ArrayRef<uint8_t> data() const override { return Section.Content; } 220 221 // Offset within the input section. This is only zero since this chunk 222 // type represents an entire input section, not part of one. 223 uint32_t getInputSectionOffset() const override { return 0; } 224 225 const WasmSection &Section; 226 }; 227 228 } // namespace wasm 229 230 std::string toString(const wasm::InputChunk *); 231 } // namespace lld 232 233 #endif // LLD_WASM_INPUT_CHUNKS_H 234