File: | tools/lld/wasm/InputChunks.h |
Warning: | line 169, column 12 Access to field 'CodeSection' results in a dereference of a null pointer (loaded from field 'File') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- InputChunks.cpp ----------------------------------------------------===// | |||
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 | #include "InputChunks.h" | |||
11 | #include "Config.h" | |||
12 | #include "OutputSegment.h" | |||
13 | #include "WriterUtils.h" | |||
14 | #include "lld/Common/ErrorHandler.h" | |||
15 | #include "lld/Common/LLVM.h" | |||
16 | #include "llvm/Support/LEB128.h" | |||
17 | ||||
18 | #define DEBUG_TYPE"lld" "lld" | |||
19 | ||||
20 | using namespace llvm; | |||
21 | using namespace llvm::wasm; | |||
22 | using namespace llvm::support::endian; | |||
23 | using namespace lld; | |||
24 | using namespace lld::wasm; | |||
25 | ||||
26 | static StringRef ReloctTypeToString(uint8_t RelocType) { | |||
27 | switch (RelocType) { | |||
28 | #define WASM_RELOC(NAME, REL) \ | |||
29 | case REL: \ | |||
30 | return #NAME; | |||
31 | #include "llvm/BinaryFormat/WasmRelocs.def" | |||
32 | #undef WASM_RELOC | |||
33 | } | |||
34 | llvm_unreachable("unknown reloc type")::llvm::llvm_unreachable_internal("unknown reloc type", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.cpp" , 34); | |||
35 | } | |||
36 | ||||
37 | std::string lld::toString(const InputChunk *C) { | |||
38 | return (toString(C->File) + ":(" + C->getName() + ")").str(); | |||
39 | } | |||
40 | ||||
41 | StringRef InputChunk::getComdatName() const { | |||
42 | uint32_t Index = getComdat(); | |||
43 | if (Index == UINT32_MAX(4294967295U)) | |||
44 | return StringRef(); | |||
45 | return File->getWasmObj()->linkingData().Comdats[Index]; | |||
46 | } | |||
47 | ||||
48 | void InputChunk::verifyRelocTargets() const { | |||
49 | for (const WasmRelocation &Rel : Relocations) { | |||
50 | uint32_t ExistingValue; | |||
51 | unsigned BytesRead = 0; | |||
52 | uint32_t Offset = Rel.Offset - getInputSectionOffset(); | |||
53 | const uint8_t *Loc = data().data() + Offset; | |||
54 | switch (Rel.Type) { | |||
55 | case R_WEBASSEMBLY_TYPE_INDEX_LEB: | |||
56 | case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: | |||
57 | case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: | |||
58 | case R_WEBASSEMBLY_MEMORY_ADDR_LEB: | |||
59 | ExistingValue = decodeULEB128(Loc, &BytesRead); | |||
60 | break; | |||
61 | case R_WEBASSEMBLY_TABLE_INDEX_SLEB: | |||
62 | case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: | |||
63 | ExistingValue = static_cast<uint32_t>(decodeSLEB128(Loc, &BytesRead)); | |||
64 | break; | |||
65 | case R_WEBASSEMBLY_TABLE_INDEX_I32: | |||
66 | case R_WEBASSEMBLY_MEMORY_ADDR_I32: | |||
67 | case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: | |||
68 | case R_WEBASSEMBLY_SECTION_OFFSET_I32: | |||
69 | ExistingValue = static_cast<uint32_t>(read32le(Loc)); | |||
70 | break; | |||
71 | default: | |||
72 | llvm_unreachable("unknown relocation type")::llvm::llvm_unreachable_internal("unknown relocation type", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.cpp" , 72); | |||
73 | } | |||
74 | ||||
75 | if (BytesRead && BytesRead != 5) | |||
76 | warn("expected LEB at relocation site be 5-byte padded"); | |||
77 | uint32_t ExpectedValue = File->calcExpectedValue(Rel); | |||
78 | if (ExpectedValue != ExistingValue) | |||
79 | warn("unexpected existing value for " + ReloctTypeToString(Rel.Type) + | |||
80 | ": existing=" + Twine(ExistingValue) + | |||
81 | " expected=" + Twine(ExpectedValue)); | |||
82 | } | |||
83 | } | |||
84 | ||||
85 | // Copy this input chunk to an mmap'ed output file and apply relocations. | |||
86 | void InputChunk::writeTo(uint8_t *Buf) const { | |||
87 | // Copy contents | |||
88 | memcpy(Buf + OutputOffset, data().data(), data().size()); | |||
89 | ||||
90 | // Apply relocations | |||
91 | if (Relocations.empty()) | |||
92 | return; | |||
93 | ||||
94 | #ifndef NDEBUG | |||
95 | verifyRelocTargets(); | |||
96 | #endif | |||
97 | ||||
98 | LLVM_DEBUG(dbgs() << "applying relocations: " << getName()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << "applying relocations: " << getName () << " count=" << Relocations.size() << "\n" ; } } while (false) | |||
99 | << " count=" << Relocations.size() << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << "applying relocations: " << getName () << " count=" << Relocations.size() << "\n" ; } } while (false); | |||
100 | int32_t Off = OutputOffset - getInputSectionOffset(); | |||
101 | ||||
102 | for (const WasmRelocation &Rel : Relocations) { | |||
103 | uint8_t *Loc = Buf + Rel.Offset + Off; | |||
104 | uint32_t Value = File->calcNewValue(Rel); | |||
105 | LLVM_DEBUG(dbgs() << "apply reloc: type=" << ReloctTypeToString(Rel.Type)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << "apply reloc: type=" << ReloctTypeToString (Rel.Type) << " addend=" << Rel.Addend << " index=" << Rel.Index << " value=" << Value << " offset=" << Rel.Offset << "\n"; } } while (false ) | |||
106 | << " addend=" << Rel.Addend << " index=" << Rel.Indexdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << "apply reloc: type=" << ReloctTypeToString (Rel.Type) << " addend=" << Rel.Addend << " index=" << Rel.Index << " value=" << Value << " offset=" << Rel.Offset << "\n"; } } while (false ) | |||
107 | << " value=" << Value << " offset=" << Rel.Offsetdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << "apply reloc: type=" << ReloctTypeToString (Rel.Type) << " addend=" << Rel.Addend << " index=" << Rel.Index << " value=" << Value << " offset=" << Rel.Offset << "\n"; } } while (false ) | |||
108 | << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << "apply reloc: type=" << ReloctTypeToString (Rel.Type) << " addend=" << Rel.Addend << " index=" << Rel.Index << " value=" << Value << " offset=" << Rel.Offset << "\n"; } } while (false ); | |||
109 | ||||
110 | switch (Rel.Type) { | |||
111 | case R_WEBASSEMBLY_TYPE_INDEX_LEB: | |||
112 | case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: | |||
113 | case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: | |||
114 | case R_WEBASSEMBLY_MEMORY_ADDR_LEB: | |||
115 | encodeULEB128(Value, Loc, 5); | |||
116 | break; | |||
117 | case R_WEBASSEMBLY_TABLE_INDEX_SLEB: | |||
118 | case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: | |||
119 | encodeSLEB128(static_cast<int32_t>(Value), Loc, 5); | |||
120 | break; | |||
121 | case R_WEBASSEMBLY_TABLE_INDEX_I32: | |||
122 | case R_WEBASSEMBLY_MEMORY_ADDR_I32: | |||
123 | case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: | |||
124 | case R_WEBASSEMBLY_SECTION_OFFSET_I32: | |||
125 | write32le(Loc, Value); | |||
126 | break; | |||
127 | default: | |||
128 | llvm_unreachable("unknown relocation type")::llvm::llvm_unreachable_internal("unknown relocation type", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.cpp" , 128); | |||
129 | } | |||
130 | } | |||
131 | } | |||
132 | ||||
133 | // Copy relocation entries to a given output stream. | |||
134 | // This function is used only when a user passes "-r". For a regular link, | |||
135 | // we consume relocations instead of copying them to an output file. | |||
136 | void InputChunk::writeRelocations(raw_ostream &OS) const { | |||
137 | if (Relocations.empty()) | |||
138 | return; | |||
139 | ||||
140 | int32_t Off = OutputOffset - getInputSectionOffset(); | |||
141 | LLVM_DEBUG(dbgs() << "writeRelocations: " << File->getName()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << "writeRelocations: " << File ->getName() << " offset=" << Twine(Off) << "\n"; } } while (false) | |||
142 | << " offset=" << Twine(Off) << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << "writeRelocations: " << File ->getName() << " offset=" << Twine(Off) << "\n"; } } while (false); | |||
143 | ||||
144 | for (const WasmRelocation &Rel : Relocations) { | |||
145 | writeUleb128(OS, Rel.Type, "reloc type"); | |||
146 | writeUleb128(OS, Rel.Offset + Off, "reloc offset"); | |||
147 | writeUleb128(OS, File->calcNewIndex(Rel), "reloc index"); | |||
148 | ||||
149 | switch (Rel.Type) { | |||
150 | case R_WEBASSEMBLY_MEMORY_ADDR_LEB: | |||
151 | case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: | |||
152 | case R_WEBASSEMBLY_MEMORY_ADDR_I32: | |||
153 | case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: | |||
154 | case R_WEBASSEMBLY_SECTION_OFFSET_I32: | |||
155 | writeSleb128(OS, File->calcNewAddend(Rel), "reloc addend"); | |||
156 | break; | |||
157 | } | |||
158 | } | |||
159 | } | |||
160 | ||||
161 | void InputFunction::setFunctionIndex(uint32_t Index) { | |||
162 | LLVM_DEBUG(dbgs() << "InputFunction::setFunctionIndex: " << getName()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << "InputFunction::setFunctionIndex: " << getName() << " -> " << Index << "\n"; } } while (false) | |||
163 | << " -> " << Index << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << "InputFunction::setFunctionIndex: " << getName() << " -> " << Index << "\n"; } } while (false); | |||
164 | assert(!hasFunctionIndex())((!hasFunctionIndex()) ? static_cast<void> (0) : __assert_fail ("!hasFunctionIndex()", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.cpp" , 164, __PRETTY_FUNCTION__)); | |||
165 | FunctionIndex = Index; | |||
166 | } | |||
167 | ||||
168 | void InputFunction::setTableIndex(uint32_t Index) { | |||
169 | LLVM_DEBUG(dbgs() << "InputFunction::setTableIndex: " << getName() << " -> "do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << "InputFunction::setTableIndex: " << getName() << " -> " << Index << "\n"; } } while (false) | |||
170 | << Index << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << "InputFunction::setTableIndex: " << getName() << " -> " << Index << "\n"; } } while (false); | |||
171 | assert(!hasTableIndex())((!hasTableIndex()) ? static_cast<void> (0) : __assert_fail ("!hasTableIndex()", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.cpp" , 171, __PRETTY_FUNCTION__)); | |||
172 | TableIndex = Index; | |||
173 | } | |||
174 | ||||
175 | // Write a relocation value without padding and return the number of bytes | |||
176 | // witten. | |||
177 | static unsigned writeCompressedReloc(uint8_t *Buf, const WasmRelocation &Rel, | |||
178 | uint32_t Value) { | |||
179 | switch (Rel.Type) { | |||
180 | case R_WEBASSEMBLY_TYPE_INDEX_LEB: | |||
181 | case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: | |||
182 | case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: | |||
183 | case R_WEBASSEMBLY_MEMORY_ADDR_LEB: | |||
184 | return encodeULEB128(Value, Buf); | |||
185 | case R_WEBASSEMBLY_TABLE_INDEX_SLEB: | |||
186 | case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: | |||
187 | return encodeSLEB128(static_cast<int32_t>(Value), Buf); | |||
188 | default: | |||
189 | llvm_unreachable("unexpected relocation type")::llvm::llvm_unreachable_internal("unexpected relocation type" , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.cpp" , 189); | |||
190 | } | |||
191 | } | |||
192 | ||||
193 | static unsigned getRelocWidthPadded(const WasmRelocation &Rel) { | |||
194 | switch (Rel.Type) { | |||
195 | case R_WEBASSEMBLY_TYPE_INDEX_LEB: | |||
196 | case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: | |||
197 | case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: | |||
198 | case R_WEBASSEMBLY_MEMORY_ADDR_LEB: | |||
199 | case R_WEBASSEMBLY_TABLE_INDEX_SLEB: | |||
200 | case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: | |||
201 | return 5; | |||
202 | default: | |||
203 | llvm_unreachable("unexpected relocation type")::llvm::llvm_unreachable_internal("unexpected relocation type" , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.cpp" , 203); | |||
204 | } | |||
205 | } | |||
206 | ||||
207 | static unsigned getRelocWidth(const WasmRelocation &Rel, uint32_t Value) { | |||
208 | uint8_t Buf[5]; | |||
209 | return writeCompressedReloc(Buf, Rel, Value); | |||
210 | } | |||
211 | ||||
212 | // Relocations of type LEB and SLEB in the code section are padded to 5 bytes | |||
213 | // so that a fast linker can blindly overwrite them without needing to worry | |||
214 | // about the number of bytes needed to encode the values. | |||
215 | // However, for optimal output the code section can be compressed to remove | |||
216 | // the padding then outputting non-relocatable files. | |||
217 | // In this case we need to perform a size calculation based on the value at each | |||
218 | // relocation. At best we end up saving 4 bytes for each relocation entry. | |||
219 | // | |||
220 | // This function only computes the final output size. It must be called | |||
221 | // before getSize() is used to calculate of layout of the code section. | |||
222 | void InputFunction::calculateSize() { | |||
223 | if (!File || !Config->CompressRelocations) | |||
224 | return; | |||
225 | ||||
226 | LLVM_DEBUG(dbgs() << "calculateSize: " << getName() << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << "calculateSize: " << getName () << "\n"; } } while (false); | |||
227 | ||||
228 | const uint8_t *SecStart = File->CodeSection->Content.data(); | |||
229 | const uint8_t *FuncStart = SecStart + getInputSectionOffset(); | |||
230 | uint32_t FunctionSizeLength; | |||
231 | decodeULEB128(FuncStart, &FunctionSizeLength); | |||
232 | ||||
233 | uint32_t Start = getInputSectionOffset(); | |||
234 | uint32_t End = Start + Function->Size; | |||
235 | ||||
236 | uint32_t LastRelocEnd = Start + FunctionSizeLength; | |||
237 | for (const WasmRelocation &Rel : Relocations) { | |||
238 | LLVM_DEBUG(dbgs() << " region: " << (Rel.Offset - LastRelocEnd) << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << " region: " << (Rel.Offset - LastRelocEnd) << "\n"; } } while (false); | |||
239 | CompressedFuncSize += Rel.Offset - LastRelocEnd; | |||
240 | CompressedFuncSize += getRelocWidth(Rel, File->calcNewValue(Rel)); | |||
241 | LastRelocEnd = Rel.Offset + getRelocWidthPadded(Rel); | |||
242 | } | |||
243 | LLVM_DEBUG(dbgs() << " final region: " << (End - LastRelocEnd) << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << " final region: " << (End - LastRelocEnd) << "\n"; } } while (false); | |||
244 | CompressedFuncSize += End - LastRelocEnd; | |||
245 | ||||
246 | // Now we know how long the resulting function is we can add the encoding | |||
247 | // of its length | |||
248 | uint8_t Buf[5]; | |||
249 | CompressedSize = CompressedFuncSize + encodeULEB128(CompressedFuncSize, Buf); | |||
250 | ||||
251 | LLVM_DEBUG(dbgs() << " calculateSize orig: " << Function->Size << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << " calculateSize orig: " << Function ->Size << "\n"; } } while (false); | |||
252 | LLVM_DEBUG(dbgs() << " calculateSize new: " << CompressedSize << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << " calculateSize new: " << CompressedSize << "\n"; } } while (false); | |||
253 | } | |||
254 | ||||
255 | // Override the default writeTo method so that we can (optionally) write the | |||
256 | // compressed version of the function. | |||
257 | void InputFunction::writeTo(uint8_t *Buf) const { | |||
258 | if (!File || !Config->CompressRelocations) | |||
| ||||
259 | return InputChunk::writeTo(Buf); | |||
260 | ||||
261 | Buf += OutputOffset; | |||
262 | uint8_t *Orig = Buf; | |||
263 | (void)Orig; | |||
264 | ||||
265 | const uint8_t *SecStart = File->CodeSection->Content.data(); | |||
266 | const uint8_t *FuncStart = SecStart + getInputSectionOffset(); | |||
267 | const uint8_t *End = FuncStart + Function->Size; | |||
268 | uint32_t Count; | |||
269 | decodeULEB128(FuncStart, &Count); | |||
270 | FuncStart += Count; | |||
271 | ||||
272 | LLVM_DEBUG(dbgs() << "write func: " << getName() << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << "write func: " << getName() << "\n"; } } while (false); | |||
273 | Buf += encodeULEB128(CompressedFuncSize, Buf); | |||
274 | const uint8_t *LastRelocEnd = FuncStart; | |||
275 | for (const WasmRelocation &Rel : Relocations) { | |||
276 | unsigned ChunkSize = (SecStart + Rel.Offset) - LastRelocEnd; | |||
277 | LLVM_DEBUG(dbgs() << " write chunk: " << ChunkSize << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << " write chunk: " << ChunkSize << "\n"; } } while (false); | |||
278 | memcpy(Buf, LastRelocEnd, ChunkSize); | |||
279 | Buf += ChunkSize; | |||
280 | Buf += writeCompressedReloc(Buf, Rel, File->calcNewValue(Rel)); | |||
281 | LastRelocEnd = SecStart + Rel.Offset + getRelocWidthPadded(Rel); | |||
282 | } | |||
283 | ||||
284 | unsigned ChunkSize = End - LastRelocEnd; | |||
285 | LLVM_DEBUG(dbgs() << " write final chunk: " << ChunkSize << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << " write final chunk: " << ChunkSize << "\n"; } } while (false); | |||
286 | memcpy(Buf, LastRelocEnd, ChunkSize); | |||
287 | LLVM_DEBUG(dbgs() << " total: " << (Buf + ChunkSize - Orig) << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("lld")) { dbgs() << " total: " << (Buf + ChunkSize - Orig) << "\n"; } } while (false); | |||
288 | } |
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)((CompressedSize) ? static_cast<void> (0) : __assert_fail ("CompressedSize", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.h" , 142, __PRETTY_FUNCTION__)); | |||
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)((!Config->CompressRelocations) ? static_cast<void> ( 0) : __assert_fail ("!Config->CompressRelocations", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.h" , 168, __PRETTY_FUNCTION__)); | |||
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(4294967295U); } | |||
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)((Section.Type == llvm::wasm::WASM_SEC_CUSTOM) ? static_cast< void> (0) : __assert_fail ("Section.Type == llvm::wasm::WASM_SEC_CUSTOM" , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lld/wasm/InputChunks.h" , 211, __PRETTY_FUNCTION__)); | |||
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(4294967295U); } | |||
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 |