File: | build/source/lld/COFF/Writer.cpp |
Warning: | line 1073, column 44 Forming reference to null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- Writer.cpp ---------------------------------------------------------===// | |||
2 | // | |||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
6 | // | |||
7 | //===----------------------------------------------------------------------===// | |||
8 | ||||
9 | #include "Writer.h" | |||
10 | #include "COFFLinkerContext.h" | |||
11 | #include "CallGraphSort.h" | |||
12 | #include "Config.h" | |||
13 | #include "DLL.h" | |||
14 | #include "InputFiles.h" | |||
15 | #include "LLDMapFile.h" | |||
16 | #include "MapFile.h" | |||
17 | #include "PDB.h" | |||
18 | #include "SymbolTable.h" | |||
19 | #include "Symbols.h" | |||
20 | #include "lld/Common/ErrorHandler.h" | |||
21 | #include "lld/Common/Memory.h" | |||
22 | #include "lld/Common/Timer.h" | |||
23 | #include "llvm/ADT/DenseMap.h" | |||
24 | #include "llvm/ADT/STLExtras.h" | |||
25 | #include "llvm/ADT/StringSet.h" | |||
26 | #include "llvm/BinaryFormat/COFF.h" | |||
27 | #include "llvm/Support/BinaryStreamReader.h" | |||
28 | #include "llvm/Support/Debug.h" | |||
29 | #include "llvm/Support/Endian.h" | |||
30 | #include "llvm/Support/FileOutputBuffer.h" | |||
31 | #include "llvm/Support/Parallel.h" | |||
32 | #include "llvm/Support/Path.h" | |||
33 | #include "llvm/Support/RandomNumberGenerator.h" | |||
34 | #include "llvm/Support/xxhash.h" | |||
35 | #include <algorithm> | |||
36 | #include <cstdio> | |||
37 | #include <map> | |||
38 | #include <memory> | |||
39 | #include <utility> | |||
40 | ||||
41 | using namespace llvm; | |||
42 | using namespace llvm::COFF; | |||
43 | using namespace llvm::object; | |||
44 | using namespace llvm::support; | |||
45 | using namespace llvm::support::endian; | |||
46 | using namespace lld; | |||
47 | using namespace lld::coff; | |||
48 | ||||
49 | /* To re-generate DOSProgram: | |||
50 | $ cat > /tmp/DOSProgram.asm | |||
51 | org 0 | |||
52 | ; Copy cs to ds. | |||
53 | push cs | |||
54 | pop ds | |||
55 | ; Point ds:dx at the $-terminated string. | |||
56 | mov dx, str | |||
57 | ; Int 21/AH=09h: Write string to standard output. | |||
58 | mov ah, 0x9 | |||
59 | int 0x21 | |||
60 | ; Int 21/AH=4Ch: Exit with return code (in AL). | |||
61 | mov ax, 0x4C01 | |||
62 | int 0x21 | |||
63 | str: | |||
64 | db 'This program cannot be run in DOS mode.$' | |||
65 | align 8, db 0 | |||
66 | $ nasm -fbin /tmp/DOSProgram.asm -o /tmp/DOSProgram.bin | |||
67 | $ xxd -i /tmp/DOSProgram.bin | |||
68 | */ | |||
69 | static unsigned char dosProgram[] = { | |||
70 | 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, | |||
71 | 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, | |||
72 | 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, | |||
73 | 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, | |||
74 | 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x24, 0x00, 0x00 | |||
75 | }; | |||
76 | static_assert(sizeof(dosProgram) % 8 == 0, | |||
77 | "DOSProgram size must be multiple of 8"); | |||
78 | ||||
79 | static const int dosStubSize = sizeof(dos_header) + sizeof(dosProgram); | |||
80 | static_assert(dosStubSize % 8 == 0, "DOSStub size must be multiple of 8"); | |||
81 | ||||
82 | static const int numberOfDataDirectory = 16; | |||
83 | ||||
84 | namespace { | |||
85 | ||||
86 | class DebugDirectoryChunk : public NonSectionChunk { | |||
87 | public: | |||
88 | DebugDirectoryChunk(COFFLinkerContext &c, | |||
89 | const std::vector<std::pair<COFF::DebugType, Chunk *>> &r, | |||
90 | bool writeRepro) | |||
91 | : records(r), writeRepro(writeRepro), ctx(c) {} | |||
92 | ||||
93 | size_t getSize() const override { | |||
94 | return (records.size() + int(writeRepro)) * sizeof(debug_directory); | |||
95 | } | |||
96 | ||||
97 | void writeTo(uint8_t *b) const override { | |||
98 | auto *d = reinterpret_cast<debug_directory *>(b); | |||
99 | ||||
100 | for (const std::pair<COFF::DebugType, Chunk *>& record : records) { | |||
101 | Chunk *c = record.second; | |||
102 | OutputSection *os = ctx.getOutputSection(c); | |||
103 | uint64_t offs = os->getFileOff() + (c->getRVA() - os->getRVA()); | |||
104 | fillEntry(d, record.first, c->getSize(), c->getRVA(), offs); | |||
105 | ++d; | |||
106 | } | |||
107 | ||||
108 | if (writeRepro) { | |||
109 | // FIXME: The COFF spec allows either a 0-sized entry to just say | |||
110 | // "the timestamp field is really a hash", or a 4-byte size field | |||
111 | // followed by that many bytes containing a longer hash (with the | |||
112 | // lowest 4 bytes usually being the timestamp in little-endian order). | |||
113 | // Consider storing the full 8 bytes computed by xxHash64 here. | |||
114 | fillEntry(d, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0); | |||
115 | } | |||
116 | } | |||
117 | ||||
118 | void setTimeDateStamp(uint32_t timeDateStamp) { | |||
119 | for (support::ulittle32_t *tds : timeDateStamps) | |||
120 | *tds = timeDateStamp; | |||
121 | } | |||
122 | ||||
123 | private: | |||
124 | void fillEntry(debug_directory *d, COFF::DebugType debugType, size_t size, | |||
125 | uint64_t rva, uint64_t offs) const { | |||
126 | d->Characteristics = 0; | |||
127 | d->TimeDateStamp = 0; | |||
128 | d->MajorVersion = 0; | |||
129 | d->MinorVersion = 0; | |||
130 | d->Type = debugType; | |||
131 | d->SizeOfData = size; | |||
132 | d->AddressOfRawData = rva; | |||
133 | d->PointerToRawData = offs; | |||
134 | ||||
135 | timeDateStamps.push_back(&d->TimeDateStamp); | |||
136 | } | |||
137 | ||||
138 | mutable std::vector<support::ulittle32_t *> timeDateStamps; | |||
139 | const std::vector<std::pair<COFF::DebugType, Chunk *>> &records; | |||
140 | bool writeRepro; | |||
141 | ||||
142 | COFFLinkerContext &ctx; | |||
143 | }; | |||
144 | ||||
145 | class CVDebugRecordChunk : public NonSectionChunk { | |||
146 | public: | |||
147 | size_t getSize() const override { | |||
148 | return sizeof(codeview::DebugInfo) + config->pdbAltPath.size() + 1; | |||
149 | } | |||
150 | ||||
151 | void writeTo(uint8_t *b) const override { | |||
152 | // Save off the DebugInfo entry to backfill the file signature (build id) | |||
153 | // in Writer::writeBuildId | |||
154 | buildId = reinterpret_cast<codeview::DebugInfo *>(b); | |||
155 | ||||
156 | // variable sized field (PDB Path) | |||
157 | char *p = reinterpret_cast<char *>(b + sizeof(*buildId)); | |||
158 | if (!config->pdbAltPath.empty()) | |||
159 | memcpy(p, config->pdbAltPath.data(), config->pdbAltPath.size()); | |||
160 | p[config->pdbAltPath.size()] = '\0'; | |||
161 | } | |||
162 | ||||
163 | mutable codeview::DebugInfo *buildId = nullptr; | |||
164 | }; | |||
165 | ||||
166 | class ExtendedDllCharacteristicsChunk : public NonSectionChunk { | |||
167 | public: | |||
168 | ExtendedDllCharacteristicsChunk(uint32_t c) : characteristics(c) {} | |||
169 | ||||
170 | size_t getSize() const override { return 4; } | |||
171 | ||||
172 | void writeTo(uint8_t *buf) const override { write32le(buf, characteristics); } | |||
173 | ||||
174 | uint32_t characteristics = 0; | |||
175 | }; | |||
176 | ||||
177 | // PartialSection represents a group of chunks that contribute to an | |||
178 | // OutputSection. Collating a collection of PartialSections of same name and | |||
179 | // characteristics constitutes the OutputSection. | |||
180 | class PartialSectionKey { | |||
181 | public: | |||
182 | StringRef name; | |||
183 | unsigned characteristics; | |||
184 | ||||
185 | bool operator<(const PartialSectionKey &other) const { | |||
186 | int c = name.compare(other.name); | |||
187 | if (c == 1) | |||
188 | return false; | |||
189 | if (c == 0) | |||
190 | return characteristics < other.characteristics; | |||
191 | return true; | |||
192 | } | |||
193 | }; | |||
194 | ||||
195 | // The writer writes a SymbolTable result to a file. | |||
196 | class Writer { | |||
197 | public: | |||
198 | Writer(COFFLinkerContext &c) : buffer(errorHandler().outputBuffer), ctx(c) {} | |||
199 | void run(); | |||
200 | ||||
201 | private: | |||
202 | void createSections(); | |||
203 | void createMiscChunks(); | |||
204 | void createImportTables(); | |||
205 | void appendImportThunks(); | |||
206 | void locateImportTables(); | |||
207 | void createExportTable(); | |||
208 | void mergeSections(); | |||
209 | void removeUnusedSections(); | |||
210 | void assignAddresses(); | |||
211 | void finalizeAddresses(); | |||
212 | void removeEmptySections(); | |||
213 | void assignOutputSectionIndices(); | |||
214 | void createSymbolAndStringTable(); | |||
215 | void openFile(StringRef outputPath); | |||
216 | template <typename PEHeaderTy> void writeHeader(); | |||
217 | void createSEHTable(); | |||
218 | void createRuntimePseudoRelocs(); | |||
219 | void insertCtorDtorSymbols(); | |||
220 | void createGuardCFTables(); | |||
221 | void markSymbolsForRVATable(ObjFile *file, | |||
222 | ArrayRef<SectionChunk *> symIdxChunks, | |||
223 | SymbolRVASet &tableSymbols); | |||
224 | void getSymbolsFromSections(ObjFile *file, | |||
225 | ArrayRef<SectionChunk *> symIdxChunks, | |||
226 | std::vector<Symbol *> &symbols); | |||
227 | void maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym, | |||
228 | StringRef countSym, bool hasFlag=false); | |||
229 | void setSectionPermissions(); | |||
230 | void writeSections(); | |||
231 | void writeBuildId(); | |||
232 | void writePEChecksum(); | |||
233 | void sortSections(); | |||
234 | void sortExceptionTable(); | |||
235 | void sortCRTSectionChunks(std::vector<Chunk *> &chunks); | |||
236 | void addSyntheticIdata(); | |||
237 | void fixPartialSectionChars(StringRef name, uint32_t chars); | |||
238 | bool fixGnuImportChunks(); | |||
239 | void fixTlsAlignment(); | |||
240 | PartialSection *createPartialSection(StringRef name, uint32_t outChars); | |||
241 | PartialSection *findPartialSection(StringRef name, uint32_t outChars); | |||
242 | ||||
243 | std::optional<coff_symbol16> createSymbol(Defined *d); | |||
244 | size_t addEntryToStringTable(StringRef str); | |||
245 | ||||
246 | OutputSection *findSection(StringRef name); | |||
247 | void addBaserels(); | |||
248 | void addBaserelBlocks(std::vector<Baserel> &v); | |||
249 | ||||
250 | uint32_t getSizeOfInitializedData(); | |||
251 | ||||
252 | void checkLoadConfig(); | |||
253 | template <typename T> void checkLoadConfigGuardData(const T *loadConfig); | |||
254 | ||||
255 | std::unique_ptr<FileOutputBuffer> &buffer; | |||
256 | std::map<PartialSectionKey, PartialSection *> partialSections; | |||
257 | std::vector<char> strtab; | |||
258 | std::vector<llvm::object::coff_symbol16> outputSymtab; | |||
259 | IdataContents idata; | |||
260 | Chunk *importTableStart = nullptr; | |||
261 | uint64_t importTableSize = 0; | |||
262 | Chunk *edataStart = nullptr; | |||
263 | Chunk *edataEnd = nullptr; | |||
264 | Chunk *iatStart = nullptr; | |||
265 | uint64_t iatSize = 0; | |||
266 | DelayLoadContents delayIdata; | |||
267 | EdataContents edata; | |||
268 | bool setNoSEHCharacteristic = false; | |||
269 | uint32_t tlsAlignment = 0; | |||
270 | ||||
271 | DebugDirectoryChunk *debugDirectory = nullptr; | |||
272 | std::vector<std::pair<COFF::DebugType, Chunk *>> debugRecords; | |||
273 | CVDebugRecordChunk *buildId = nullptr; | |||
274 | ArrayRef<uint8_t> sectionTable; | |||
275 | ||||
276 | uint64_t fileSize; | |||
277 | uint32_t pointerToSymbolTable = 0; | |||
278 | uint64_t sizeOfImage; | |||
279 | uint64_t sizeOfHeaders; | |||
280 | ||||
281 | OutputSection *textSec; | |||
282 | OutputSection *rdataSec; | |||
283 | OutputSection *buildidSec; | |||
284 | OutputSection *dataSec; | |||
285 | OutputSection *pdataSec; | |||
286 | OutputSection *idataSec; | |||
287 | OutputSection *edataSec; | |||
288 | OutputSection *didatSec; | |||
289 | OutputSection *rsrcSec; | |||
290 | OutputSection *relocSec; | |||
291 | OutputSection *ctorsSec; | |||
292 | OutputSection *dtorsSec; | |||
293 | ||||
294 | // The first and last .pdata sections in the output file. | |||
295 | // | |||
296 | // We need to keep track of the location of .pdata in whichever section it | |||
297 | // gets merged into so that we can sort its contents and emit a correct data | |||
298 | // directory entry for the exception table. This is also the case for some | |||
299 | // other sections (such as .edata) but because the contents of those sections | |||
300 | // are entirely linker-generated we can keep track of their locations using | |||
301 | // the chunks that the linker creates. All .pdata chunks come from input | |||
302 | // files, so we need to keep track of them separately. | |||
303 | Chunk *firstPdata = nullptr; | |||
304 | Chunk *lastPdata; | |||
305 | ||||
306 | COFFLinkerContext &ctx; | |||
307 | }; | |||
308 | } // anonymous namespace | |||
309 | ||||
310 | void lld::coff::writeResult(COFFLinkerContext &ctx) { Writer(ctx).run(); } | |||
| ||||
311 | ||||
312 | void OutputSection::addChunk(Chunk *c) { | |||
313 | chunks.push_back(c); | |||
314 | } | |||
315 | ||||
316 | void OutputSection::insertChunkAtStart(Chunk *c) { | |||
317 | chunks.insert(chunks.begin(), c); | |||
318 | } | |||
319 | ||||
320 | void OutputSection::setPermissions(uint32_t c) { | |||
321 | header.Characteristics &= ~permMask; | |||
322 | header.Characteristics |= c; | |||
323 | } | |||
324 | ||||
325 | void OutputSection::merge(OutputSection *other) { | |||
326 | chunks.insert(chunks.end(), other->chunks.begin(), other->chunks.end()); | |||
327 | other->chunks.clear(); | |||
328 | contribSections.insert(contribSections.end(), other->contribSections.begin(), | |||
329 | other->contribSections.end()); | |||
330 | other->contribSections.clear(); | |||
331 | } | |||
332 | ||||
333 | // Write the section header to a given buffer. | |||
334 | void OutputSection::writeHeaderTo(uint8_t *buf) { | |||
335 | auto *hdr = reinterpret_cast<coff_section *>(buf); | |||
336 | *hdr = header; | |||
337 | if (stringTableOff) { | |||
338 | // If name is too long, write offset into the string table as a name. | |||
339 | encodeSectionName(hdr->Name, stringTableOff); | |||
340 | } else { | |||
341 | assert(!config->debug || name.size() <= COFF::NameSize ||(static_cast <bool> (!config->debug || name.size() <= COFF::NameSize || (hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE ) == 0) ? void (0) : __assert_fail ("!config->debug || name.size() <= COFF::NameSize || (hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0" , "lld/COFF/Writer.cpp", 342, __extension__ __PRETTY_FUNCTION__ )) | |||
342 | (hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)(static_cast <bool> (!config->debug || name.size() <= COFF::NameSize || (hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE ) == 0) ? void (0) : __assert_fail ("!config->debug || name.size() <= COFF::NameSize || (hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0" , "lld/COFF/Writer.cpp", 342, __extension__ __PRETTY_FUNCTION__ )); | |||
343 | strncpy(hdr->Name, name.data(), | |||
344 | std::min(name.size(), (size_t)COFF::NameSize)); | |||
345 | } | |||
346 | } | |||
347 | ||||
348 | void OutputSection::addContributingPartialSection(PartialSection *sec) { | |||
349 | contribSections.push_back(sec); | |||
350 | } | |||
351 | ||||
352 | // Check whether the target address S is in range from a relocation | |||
353 | // of type relType at address P. | |||
354 | static bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin) { | |||
355 | if (config->machine == ARMNT) { | |||
356 | int64_t diff = AbsoluteDifference(s, p + 4) + margin; | |||
357 | switch (relType) { | |||
358 | case IMAGE_REL_ARM_BRANCH20T: | |||
359 | return isInt<21>(diff); | |||
360 | case IMAGE_REL_ARM_BRANCH24T: | |||
361 | case IMAGE_REL_ARM_BLX23T: | |||
362 | return isInt<25>(diff); | |||
363 | default: | |||
364 | return true; | |||
365 | } | |||
366 | } else if (config->machine == ARM64) { | |||
367 | int64_t diff = AbsoluteDifference(s, p) + margin; | |||
368 | switch (relType) { | |||
369 | case IMAGE_REL_ARM64_BRANCH26: | |||
370 | return isInt<28>(diff); | |||
371 | case IMAGE_REL_ARM64_BRANCH19: | |||
372 | return isInt<21>(diff); | |||
373 | case IMAGE_REL_ARM64_BRANCH14: | |||
374 | return isInt<16>(diff); | |||
375 | default: | |||
376 | return true; | |||
377 | } | |||
378 | } else { | |||
379 | llvm_unreachable("Unexpected architecture")::llvm::llvm_unreachable_internal("Unexpected architecture", "lld/COFF/Writer.cpp" , 379); | |||
380 | } | |||
381 | } | |||
382 | ||||
383 | // Return the last thunk for the given target if it is in range, | |||
384 | // or create a new one. | |||
385 | static std::pair<Defined *, bool> | |||
386 | getThunk(DenseMap<uint64_t, Defined *> &lastThunks, Defined *target, uint64_t p, | |||
387 | uint16_t type, int margin) { | |||
388 | Defined *&lastThunk = lastThunks[target->getRVA()]; | |||
389 | if (lastThunk && isInRange(type, lastThunk->getRVA(), p, margin)) | |||
390 | return {lastThunk, false}; | |||
391 | Chunk *c; | |||
392 | switch (config->machine) { | |||
393 | case ARMNT: | |||
394 | c = make<RangeExtensionThunkARM>(target); | |||
395 | break; | |||
396 | case ARM64: | |||
397 | c = make<RangeExtensionThunkARM64>(target); | |||
398 | break; | |||
399 | default: | |||
400 | llvm_unreachable("Unexpected architecture")::llvm::llvm_unreachable_internal("Unexpected architecture", "lld/COFF/Writer.cpp" , 400); | |||
401 | } | |||
402 | Defined *d = make<DefinedSynthetic>("range_extension_thunk", c); | |||
403 | lastThunk = d; | |||
404 | return {d, true}; | |||
405 | } | |||
406 | ||||
407 | // This checks all relocations, and for any relocation which isn't in range | |||
408 | // it adds a thunk after the section chunk that contains the relocation. | |||
409 | // If the latest thunk for the specific target is in range, that is used | |||
410 | // instead of creating a new thunk. All range checks are done with the | |||
411 | // specified margin, to make sure that relocations that originally are in | |||
412 | // range, but only barely, also get thunks - in case other added thunks makes | |||
413 | // the target go out of range. | |||
414 | // | |||
415 | // After adding thunks, we verify that all relocations are in range (with | |||
416 | // no extra margin requirements). If this failed, we restart (throwing away | |||
417 | // the previously created thunks) and retry with a wider margin. | |||
418 | static bool createThunks(OutputSection *os, int margin) { | |||
419 | bool addressesChanged = false; | |||
420 | DenseMap<uint64_t, Defined *> lastThunks; | |||
421 | DenseMap<std::pair<ObjFile *, Defined *>, uint32_t> thunkSymtabIndices; | |||
422 | size_t thunksSize = 0; | |||
423 | // Recheck Chunks.size() each iteration, since we can insert more | |||
424 | // elements into it. | |||
425 | for (size_t i = 0; i != os->chunks.size(); ++i) { | |||
426 | SectionChunk *sc = dyn_cast_or_null<SectionChunk>(os->chunks[i]); | |||
427 | if (!sc) | |||
428 | continue; | |||
429 | size_t thunkInsertionSpot = i + 1; | |||
430 | ||||
431 | // Try to get a good enough estimate of where new thunks will be placed. | |||
432 | // Offset this by the size of the new thunks added so far, to make the | |||
433 | // estimate slightly better. | |||
434 | size_t thunkInsertionRVA = sc->getRVA() + sc->getSize() + thunksSize; | |||
435 | ObjFile *file = sc->file; | |||
436 | std::vector<std::pair<uint32_t, uint32_t>> relocReplacements; | |||
437 | ArrayRef<coff_relocation> originalRelocs = | |||
438 | file->getCOFFObj()->getRelocations(sc->header); | |||
439 | for (size_t j = 0, e = originalRelocs.size(); j < e; ++j) { | |||
440 | const coff_relocation &rel = originalRelocs[j]; | |||
441 | Symbol *relocTarget = file->getSymbol(rel.SymbolTableIndex); | |||
442 | ||||
443 | // The estimate of the source address P should be pretty accurate, | |||
444 | // but we don't know whether the target Symbol address should be | |||
445 | // offset by thunksSize or not (or by some of thunksSize but not all of | |||
446 | // it), giving us some uncertainty once we have added one thunk. | |||
447 | uint64_t p = sc->getRVA() + rel.VirtualAddress + thunksSize; | |||
448 | ||||
449 | Defined *sym = dyn_cast_or_null<Defined>(relocTarget); | |||
450 | if (!sym) | |||
451 | continue; | |||
452 | ||||
453 | uint64_t s = sym->getRVA(); | |||
454 | ||||
455 | if (isInRange(rel.Type, s, p, margin)) | |||
456 | continue; | |||
457 | ||||
458 | // If the target isn't in range, hook it up to an existing or new thunk. | |||
459 | auto [thunk, wasNew] = getThunk(lastThunks, sym, p, rel.Type, margin); | |||
460 | if (wasNew) { | |||
461 | Chunk *thunkChunk = thunk->getChunk(); | |||
462 | thunkChunk->setRVA( | |||
463 | thunkInsertionRVA); // Estimate of where it will be located. | |||
464 | os->chunks.insert(os->chunks.begin() + thunkInsertionSpot, thunkChunk); | |||
465 | thunkInsertionSpot++; | |||
466 | thunksSize += thunkChunk->getSize(); | |||
467 | thunkInsertionRVA += thunkChunk->getSize(); | |||
468 | addressesChanged = true; | |||
469 | } | |||
470 | ||||
471 | // To redirect the relocation, add a symbol to the parent object file's | |||
472 | // symbol table, and replace the relocation symbol table index with the | |||
473 | // new index. | |||
474 | auto insertion = thunkSymtabIndices.insert({{file, thunk}, ~0U}); | |||
475 | uint32_t &thunkSymbolIndex = insertion.first->second; | |||
476 | if (insertion.second) | |||
477 | thunkSymbolIndex = file->addRangeThunkSymbol(thunk); | |||
478 | relocReplacements.push_back({j, thunkSymbolIndex}); | |||
479 | } | |||
480 | ||||
481 | // Get a writable copy of this section's relocations so they can be | |||
482 | // modified. If the relocations point into the object file, allocate new | |||
483 | // memory. Otherwise, this must be previously allocated memory that can be | |||
484 | // modified in place. | |||
485 | ArrayRef<coff_relocation> curRelocs = sc->getRelocs(); | |||
486 | MutableArrayRef<coff_relocation> newRelocs; | |||
487 | if (originalRelocs.data() == curRelocs.data()) { | |||
488 | newRelocs = makeMutableArrayRef( | |||
489 | bAlloc().Allocate<coff_relocation>(originalRelocs.size()), | |||
490 | originalRelocs.size()); | |||
491 | } else { | |||
492 | newRelocs = makeMutableArrayRef( | |||
493 | const_cast<coff_relocation *>(curRelocs.data()), curRelocs.size()); | |||
494 | } | |||
495 | ||||
496 | // Copy each relocation, but replace the symbol table indices which need | |||
497 | // thunks. | |||
498 | auto nextReplacement = relocReplacements.begin(); | |||
499 | auto endReplacement = relocReplacements.end(); | |||
500 | for (size_t i = 0, e = originalRelocs.size(); i != e; ++i) { | |||
501 | newRelocs[i] = originalRelocs[i]; | |||
502 | if (nextReplacement != endReplacement && nextReplacement->first == i) { | |||
503 | newRelocs[i].SymbolTableIndex = nextReplacement->second; | |||
504 | ++nextReplacement; | |||
505 | } | |||
506 | } | |||
507 | ||||
508 | sc->setRelocs(newRelocs); | |||
509 | } | |||
510 | return addressesChanged; | |||
511 | } | |||
512 | ||||
513 | // Verify that all relocations are in range, with no extra margin requirements. | |||
514 | static bool verifyRanges(const std::vector<Chunk *> chunks) { | |||
515 | for (Chunk *c : chunks) { | |||
516 | SectionChunk *sc = dyn_cast_or_null<SectionChunk>(c); | |||
517 | if (!sc) | |||
518 | continue; | |||
519 | ||||
520 | ArrayRef<coff_relocation> relocs = sc->getRelocs(); | |||
521 | for (size_t j = 0, e = relocs.size(); j < e; ++j) { | |||
522 | const coff_relocation &rel = relocs[j]; | |||
523 | Symbol *relocTarget = sc->file->getSymbol(rel.SymbolTableIndex); | |||
524 | ||||
525 | Defined *sym = dyn_cast_or_null<Defined>(relocTarget); | |||
526 | if (!sym) | |||
527 | continue; | |||
528 | ||||
529 | uint64_t p = sc->getRVA() + rel.VirtualAddress; | |||
530 | uint64_t s = sym->getRVA(); | |||
531 | ||||
532 | if (!isInRange(rel.Type, s, p, 0)) | |||
533 | return false; | |||
534 | } | |||
535 | } | |||
536 | return true; | |||
537 | } | |||
538 | ||||
539 | // Assign addresses and add thunks if necessary. | |||
540 | void Writer::finalizeAddresses() { | |||
541 | assignAddresses(); | |||
542 | if (config->machine != ARMNT && config->machine != ARM64) | |||
543 | return; | |||
544 | ||||
545 | size_t origNumChunks = 0; | |||
546 | for (OutputSection *sec : ctx.outputSections) { | |||
547 | sec->origChunks = sec->chunks; | |||
548 | origNumChunks += sec->chunks.size(); | |||
549 | } | |||
550 | ||||
551 | int pass = 0; | |||
552 | int margin = 1024 * 100; | |||
553 | while (true) { | |||
554 | // First check whether we need thunks at all, or if the previous pass of | |||
555 | // adding them turned out ok. | |||
556 | bool rangesOk = true; | |||
557 | size_t numChunks = 0; | |||
558 | for (OutputSection *sec : ctx.outputSections) { | |||
559 | if (!verifyRanges(sec->chunks)) { | |||
560 | rangesOk = false; | |||
561 | break; | |||
562 | } | |||
563 | numChunks += sec->chunks.size(); | |||
564 | } | |||
565 | if (rangesOk) { | |||
566 | if (pass > 0) | |||
567 | log("Added " + Twine(numChunks - origNumChunks) + " thunks with " + | |||
568 | "margin " + Twine(margin) + " in " + Twine(pass) + " passes"); | |||
569 | return; | |||
570 | } | |||
571 | ||||
572 | if (pass >= 10) | |||
573 | fatal("adding thunks hasn't converged after " + Twine(pass) + " passes"); | |||
574 | ||||
575 | if (pass > 0) { | |||
576 | // If the previous pass didn't work out, reset everything back to the | |||
577 | // original conditions before retrying with a wider margin. This should | |||
578 | // ideally never happen under real circumstances. | |||
579 | for (OutputSection *sec : ctx.outputSections) | |||
580 | sec->chunks = sec->origChunks; | |||
581 | margin *= 2; | |||
582 | } | |||
583 | ||||
584 | // Try adding thunks everywhere where it is needed, with a margin | |||
585 | // to avoid things going out of range due to the added thunks. | |||
586 | bool addressesChanged = false; | |||
587 | for (OutputSection *sec : ctx.outputSections) | |||
588 | addressesChanged |= createThunks(sec, margin); | |||
589 | // If the verification above thought we needed thunks, we should have | |||
590 | // added some. | |||
591 | assert(addressesChanged)(static_cast <bool> (addressesChanged) ? void (0) : __assert_fail ("addressesChanged", "lld/COFF/Writer.cpp", 591, __extension__ __PRETTY_FUNCTION__)); | |||
592 | (void)addressesChanged; | |||
593 | ||||
594 | // Recalculate the layout for the whole image (and verify the ranges at | |||
595 | // the start of the next round). | |||
596 | assignAddresses(); | |||
597 | ||||
598 | pass++; | |||
599 | } | |||
600 | } | |||
601 | ||||
602 | void Writer::writePEChecksum() { | |||
603 | if (!config->writeCheckSum) { | |||
604 | return; | |||
605 | } | |||
606 | ||||
607 | // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#checksum | |||
608 | uint32_t *buf = (uint32_t *)buffer->getBufferStart(); | |||
609 | uint32_t size = (uint32_t)(buffer->getBufferSize()); | |||
610 | ||||
611 | coff_file_header *coffHeader = | |||
612 | (coff_file_header *)((uint8_t *)buf + dosStubSize + sizeof(PEMagic)); | |||
613 | pe32_header *peHeader = | |||
614 | (pe32_header *)((uint8_t *)coffHeader + sizeof(coff_file_header)); | |||
615 | ||||
616 | uint64_t sum = 0; | |||
617 | uint32_t count = size; | |||
618 | ulittle16_t *addr = (ulittle16_t *)buf; | |||
619 | ||||
620 | // The PE checksum algorithm, implemented as suggested in RFC1071 | |||
621 | while (count > 1) { | |||
622 | sum += *addr++; | |||
623 | count -= 2; | |||
624 | } | |||
625 | ||||
626 | // Add left-over byte, if any | |||
627 | if (count > 0) | |||
628 | sum += *(unsigned char *)addr; | |||
629 | ||||
630 | // Fold 32-bit sum to 16 bits | |||
631 | while (sum >> 16) { | |||
632 | sum = (sum & 0xffff) + (sum >> 16); | |||
633 | } | |||
634 | ||||
635 | sum += size; | |||
636 | peHeader->CheckSum = sum; | |||
637 | } | |||
638 | ||||
639 | // The main function of the writer. | |||
640 | void Writer::run() { | |||
641 | ScopedTimer t1(ctx.codeLayoutTimer); | |||
642 | ||||
643 | createImportTables(); | |||
644 | createSections(); | |||
645 | appendImportThunks(); | |||
646 | // Import thunks must be added before the Control Flow Guard tables are added. | |||
647 | createMiscChunks(); | |||
648 | createExportTable(); | |||
649 | mergeSections(); | |||
650 | removeUnusedSections(); | |||
651 | finalizeAddresses(); | |||
652 | removeEmptySections(); | |||
653 | assignOutputSectionIndices(); | |||
654 | setSectionPermissions(); | |||
655 | createSymbolAndStringTable(); | |||
656 | ||||
657 | if (fileSize > UINT32_MAX(4294967295U)) | |||
658 | fatal("image size (" + Twine(fileSize) + ") " + | |||
659 | "exceeds maximum allowable size (" + Twine(UINT32_MAX(4294967295U)) + ")"); | |||
660 | ||||
661 | openFile(config->outputFile); | |||
662 | if (config->is64()) { | |||
663 | writeHeader<pe32plus_header>(); | |||
664 | } else { | |||
665 | writeHeader<pe32_header>(); | |||
666 | } | |||
667 | writeSections(); | |||
668 | checkLoadConfig(); | |||
669 | sortExceptionTable(); | |||
670 | ||||
671 | // Fix up the alignment in the TLS Directory's characteristic field, | |||
672 | // if a specific alignment value is needed | |||
673 | if (tlsAlignment) | |||
674 | fixTlsAlignment(); | |||
675 | ||||
676 | t1.stop(); | |||
677 | ||||
678 | if (!config->pdbPath.empty() && config->debug) { | |||
679 | assert(buildId)(static_cast <bool> (buildId) ? void (0) : __assert_fail ("buildId", "lld/COFF/Writer.cpp", 679, __extension__ __PRETTY_FUNCTION__ )); | |||
680 | createPDB(ctx, sectionTable, buildId->buildId); | |||
681 | } | |||
682 | writeBuildId(); | |||
683 | ||||
684 | writeLLDMapFile(ctx); | |||
685 | writeMapFile(ctx); | |||
686 | ||||
687 | writePEChecksum(); | |||
688 | ||||
689 | if (errorCount()) | |||
690 | return; | |||
691 | ||||
692 | ScopedTimer t2(ctx.outputCommitTimer); | |||
693 | if (auto e = buffer->commit()) | |||
694 | fatal("failed to write output '" + buffer->getPath() + | |||
695 | "': " + toString(std::move(e))); | |||
696 | } | |||
697 | ||||
698 | static StringRef getOutputSectionName(StringRef name) { | |||
699 | StringRef s = name.split('$').first; | |||
700 | ||||
701 | // Treat a later period as a separator for MinGW, for sections like | |||
702 | // ".ctors.01234". | |||
703 | return s.substr(0, s.find('.', 1)); | |||
704 | } | |||
705 | ||||
706 | // For /order. | |||
707 | static void sortBySectionOrder(std::vector<Chunk *> &chunks) { | |||
708 | auto getPriority = [](const Chunk *c) { | |||
709 | if (auto *sec = dyn_cast<SectionChunk>(c)) | |||
710 | if (sec->sym) | |||
711 | return config->order.lookup(sec->sym->getName()); | |||
712 | return 0; | |||
713 | }; | |||
714 | ||||
715 | llvm::stable_sort(chunks, [=](const Chunk *a, const Chunk *b) { | |||
716 | return getPriority(a) < getPriority(b); | |||
717 | }); | |||
718 | } | |||
719 | ||||
720 | // Change the characteristics of existing PartialSections that belong to the | |||
721 | // section Name to Chars. | |||
722 | void Writer::fixPartialSectionChars(StringRef name, uint32_t chars) { | |||
723 | for (auto it : partialSections) { | |||
724 | PartialSection *pSec = it.second; | |||
725 | StringRef curName = pSec->name; | |||
726 | if (!curName.consume_front(name) || | |||
727 | (!curName.empty() && !curName.startswith("$"))) | |||
728 | continue; | |||
729 | if (pSec->characteristics == chars) | |||
730 | continue; | |||
731 | PartialSection *destSec = createPartialSection(pSec->name, chars); | |||
732 | destSec->chunks.insert(destSec->chunks.end(), pSec->chunks.begin(), | |||
733 | pSec->chunks.end()); | |||
734 | pSec->chunks.clear(); | |||
735 | } | |||
736 | } | |||
737 | ||||
738 | // Sort concrete section chunks from GNU import libraries. | |||
739 | // | |||
740 | // GNU binutils doesn't use short import files, but instead produces import | |||
741 | // libraries that consist of object files, with section chunks for the .idata$* | |||
742 | // sections. These are linked just as regular static libraries. Each import | |||
743 | // library consists of one header object, one object file for every imported | |||
744 | // symbol, and one trailer object. In order for the .idata tables/lists to | |||
745 | // be formed correctly, the section chunks within each .idata$* section need | |||
746 | // to be grouped by library, and sorted alphabetically within each library | |||
747 | // (which makes sure the header comes first and the trailer last). | |||
748 | bool Writer::fixGnuImportChunks() { | |||
749 | uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; | |||
750 | ||||
751 | // Make sure all .idata$* section chunks are mapped as RDATA in order to | |||
752 | // be sorted into the same sections as our own synthesized .idata chunks. | |||
753 | fixPartialSectionChars(".idata", rdata); | |||
754 | ||||
755 | bool hasIdata = false; | |||
756 | // Sort all .idata$* chunks, grouping chunks from the same library, | |||
757 | // with alphabetical ordering of the object files within a library. | |||
758 | for (auto it : partialSections) { | |||
759 | PartialSection *pSec = it.second; | |||
760 | if (!pSec->name.startswith(".idata")) | |||
761 | continue; | |||
762 | ||||
763 | if (!pSec->chunks.empty()) | |||
764 | hasIdata = true; | |||
765 | llvm::stable_sort(pSec->chunks, [&](Chunk *s, Chunk *t) { | |||
766 | SectionChunk *sc1 = dyn_cast_or_null<SectionChunk>(s); | |||
767 | SectionChunk *sc2 = dyn_cast_or_null<SectionChunk>(t); | |||
768 | if (!sc1 || !sc2) { | |||
769 | // if SC1, order them ascending. If SC2 or both null, | |||
770 | // S is not less than T. | |||
771 | return sc1 != nullptr; | |||
772 | } | |||
773 | // Make a string with "libraryname/objectfile" for sorting, achieving | |||
774 | // both grouping by library and sorting of objects within a library, | |||
775 | // at once. | |||
776 | std::string key1 = | |||
777 | (sc1->file->parentName + "/" + sc1->file->getName()).str(); | |||
778 | std::string key2 = | |||
779 | (sc2->file->parentName + "/" + sc2->file->getName()).str(); | |||
780 | return key1 < key2; | |||
781 | }); | |||
782 | } | |||
783 | return hasIdata; | |||
784 | } | |||
785 | ||||
786 | // Add generated idata chunks, for imported symbols and DLLs, and a | |||
787 | // terminator in .idata$2. | |||
788 | void Writer::addSyntheticIdata() { | |||
789 | uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; | |||
790 | idata.create(); | |||
791 | ||||
792 | // Add the .idata content in the right section groups, to allow | |||
793 | // chunks from other linked in object files to be grouped together. | |||
794 | // See Microsoft PE/COFF spec 5.4 for details. | |||
795 | auto add = [&](StringRef n, std::vector<Chunk *> &v) { | |||
796 | PartialSection *pSec = createPartialSection(n, rdata); | |||
797 | pSec->chunks.insert(pSec->chunks.end(), v.begin(), v.end()); | |||
798 | }; | |||
799 | ||||
800 | // The loader assumes a specific order of data. | |||
801 | // Add each type in the correct order. | |||
802 | add(".idata$2", idata.dirs); | |||
803 | add(".idata$4", idata.lookups); | |||
804 | add(".idata$5", idata.addresses); | |||
805 | if (!idata.hints.empty()) | |||
806 | add(".idata$6", idata.hints); | |||
807 | add(".idata$7", idata.dllNames); | |||
808 | } | |||
809 | ||||
810 | // Locate the first Chunk and size of the import directory list and the | |||
811 | // IAT. | |||
812 | void Writer::locateImportTables() { | |||
813 | uint32_t rdata = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; | |||
814 | ||||
815 | if (PartialSection *importDirs = findPartialSection(".idata$2", rdata)) { | |||
816 | if (!importDirs->chunks.empty()) | |||
817 | importTableStart = importDirs->chunks.front(); | |||
818 | for (Chunk *c : importDirs->chunks) | |||
819 | importTableSize += c->getSize(); | |||
820 | } | |||
821 | ||||
822 | if (PartialSection *importAddresses = findPartialSection(".idata$5", rdata)) { | |||
823 | if (!importAddresses->chunks.empty()) | |||
824 | iatStart = importAddresses->chunks.front(); | |||
825 | for (Chunk *c : importAddresses->chunks) | |||
826 | iatSize += c->getSize(); | |||
827 | } | |||
828 | } | |||
829 | ||||
830 | // Return whether a SectionChunk's suffix (the dollar and any trailing | |||
831 | // suffix) should be removed and sorted into the main suffixless | |||
832 | // PartialSection. | |||
833 | static bool shouldStripSectionSuffix(SectionChunk *sc, StringRef name) { | |||
834 | // On MinGW, comdat groups are formed by putting the comdat group name | |||
835 | // after the '$' in the section name. For .eh_frame$<symbol>, that must | |||
836 | // still be sorted before the .eh_frame trailer from crtend.o, thus just | |||
837 | // strip the section name trailer. For other sections, such as | |||
838 | // .tls$$<symbol> (where non-comdat .tls symbols are otherwise stored in | |||
839 | // ".tls$"), they must be strictly sorted after .tls. And for the | |||
840 | // hypothetical case of comdat .CRT$XCU, we definitely need to keep the | |||
841 | // suffix for sorting. Thus, to play it safe, only strip the suffix for | |||
842 | // the standard sections. | |||
843 | if (!config->mingw) | |||
844 | return false; | |||
845 | if (!sc || !sc->isCOMDAT()) | |||
846 | return false; | |||
847 | return name.startswith(".text$") || name.startswith(".data$") || | |||
848 | name.startswith(".rdata$") || name.startswith(".pdata$") || | |||
849 | name.startswith(".xdata$") || name.startswith(".eh_frame$"); | |||
850 | } | |||
851 | ||||
852 | void Writer::sortSections() { | |||
853 | if (!config->callGraphProfile.empty()) { | |||
854 | DenseMap<const SectionChunk *, int> order = | |||
855 | computeCallGraphProfileOrder(ctx); | |||
856 | for (auto it : order) { | |||
857 | if (DefinedRegular *sym = it.first->sym) | |||
858 | config->order[sym->getName()] = it.second; | |||
859 | } | |||
860 | } | |||
861 | if (!config->order.empty()) | |||
862 | for (auto it : partialSections) | |||
863 | sortBySectionOrder(it.second->chunks); | |||
864 | } | |||
865 | ||||
866 | // Create output section objects and add them to OutputSections. | |||
867 | void Writer::createSections() { | |||
868 | // First, create the builtin sections. | |||
869 | const uint32_t data = IMAGE_SCN_CNT_INITIALIZED_DATA; | |||
870 | const uint32_t bss = IMAGE_SCN_CNT_UNINITIALIZED_DATA; | |||
871 | const uint32_t code = IMAGE_SCN_CNT_CODE; | |||
872 | const uint32_t discardable = IMAGE_SCN_MEM_DISCARDABLE; | |||
873 | const uint32_t r = IMAGE_SCN_MEM_READ; | |||
874 | const uint32_t w = IMAGE_SCN_MEM_WRITE; | |||
875 | const uint32_t x = IMAGE_SCN_MEM_EXECUTE; | |||
876 | ||||
877 | SmallDenseMap<std::pair<StringRef, uint32_t>, OutputSection *> sections; | |||
878 | auto createSection = [&](StringRef name, uint32_t outChars) { | |||
879 | OutputSection *&sec = sections[{name, outChars}]; | |||
880 | if (!sec) { | |||
881 | sec = make<OutputSection>(name, outChars); | |||
882 | ctx.outputSections.push_back(sec); | |||
883 | } | |||
884 | return sec; | |||
885 | }; | |||
886 | ||||
887 | // Try to match the section order used by link.exe. | |||
888 | textSec = createSection(".text", code | r | x); | |||
889 | createSection(".bss", bss | r | w); | |||
890 | rdataSec = createSection(".rdata", data | r); | |||
891 | buildidSec = createSection(".buildid", data | r); | |||
892 | dataSec = createSection(".data", data | r | w); | |||
893 | pdataSec = createSection(".pdata", data | r); | |||
894 | idataSec = createSection(".idata", data | r); | |||
895 | edataSec = createSection(".edata", data | r); | |||
896 | didatSec = createSection(".didat", data | r); | |||
897 | rsrcSec = createSection(".rsrc", data | r); | |||
898 | relocSec = createSection(".reloc", data | discardable | r); | |||
899 | ctorsSec = createSection(".ctors", data | r | w); | |||
900 | dtorsSec = createSection(".dtors", data | r | w); | |||
901 | ||||
902 | // Then bin chunks by name and output characteristics. | |||
903 | for (Chunk *c : ctx.symtab.getChunks()) { | |||
904 | auto *sc = dyn_cast<SectionChunk>(c); | |||
905 | if (sc && !sc->live) { | |||
906 | if (config->verbose) | |||
907 | sc->printDiscardedMessage(); | |||
908 | continue; | |||
909 | } | |||
910 | StringRef name = c->getSectionName(); | |||
911 | if (shouldStripSectionSuffix(sc, name)) | |||
912 | name = name.split('$').first; | |||
913 | ||||
914 | if (name.startswith(".tls")) | |||
915 | tlsAlignment = std::max(tlsAlignment, c->getAlignment()); | |||
916 | ||||
917 | PartialSection *pSec = createPartialSection(name, | |||
918 | c->getOutputCharacteristics()); | |||
919 | pSec->chunks.push_back(c); | |||
920 | } | |||
921 | ||||
922 | fixPartialSectionChars(".rsrc", data | r); | |||
923 | fixPartialSectionChars(".edata", data | r); | |||
924 | // Even in non MinGW cases, we might need to link against GNU import | |||
925 | // libraries. | |||
926 | bool hasIdata = fixGnuImportChunks(); | |||
927 | if (!idata.empty()) | |||
928 | hasIdata = true; | |||
929 | ||||
930 | if (hasIdata) | |||
931 | addSyntheticIdata(); | |||
932 | ||||
933 | sortSections(); | |||
934 | ||||
935 | if (hasIdata) | |||
936 | locateImportTables(); | |||
937 | ||||
938 | // Then create an OutputSection for each section. | |||
939 | // '$' and all following characters in input section names are | |||
940 | // discarded when determining output section. So, .text$foo | |||
941 | // contributes to .text, for example. See PE/COFF spec 3.2. | |||
942 | for (auto it : partialSections) { | |||
943 | PartialSection *pSec = it.second; | |||
944 | StringRef name = getOutputSectionName(pSec->name); | |||
945 | uint32_t outChars = pSec->characteristics; | |||
946 | ||||
947 | if (name == ".CRT") { | |||
948 | // In link.exe, there is a special case for the I386 target where .CRT | |||
949 | // sections are treated as if they have output characteristics DATA | R if | |||
950 | // their characteristics are DATA | R | W. This implements the same | |||
951 | // special case for all architectures. | |||
952 | outChars = data | r; | |||
953 | ||||
954 | log("Processing section " + pSec->name + " -> " + name); | |||
955 | ||||
956 | sortCRTSectionChunks(pSec->chunks); | |||
957 | } | |||
958 | ||||
959 | OutputSection *sec = createSection(name, outChars); | |||
960 | for (Chunk *c : pSec->chunks) | |||
961 | sec->addChunk(c); | |||
962 | ||||
963 | sec->addContributingPartialSection(pSec); | |||
964 | } | |||
965 | ||||
966 | // Finally, move some output sections to the end. | |||
967 | auto sectionOrder = [&](const OutputSection *s) { | |||
968 | // Move DISCARDABLE (or non-memory-mapped) sections to the end of file | |||
969 | // because the loader cannot handle holes. Stripping can remove other | |||
970 | // discardable ones than .reloc, which is first of them (created early). | |||
971 | if (s->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) { | |||
972 | // Move discardable sections named .debug_ to the end, after other | |||
973 | // discardable sections. Stripping only removes the sections named | |||
974 | // .debug_* - thus try to avoid leaving holes after stripping. | |||
975 | if (s->name.startswith(".debug_")) | |||
976 | return 3; | |||
977 | return 2; | |||
978 | } | |||
979 | // .rsrc should come at the end of the non-discardable sections because its | |||
980 | // size may change by the Win32 UpdateResources() function, causing | |||
981 | // subsequent sections to move (see https://crbug.com/827082). | |||
982 | if (s == rsrcSec) | |||
983 | return 1; | |||
984 | return 0; | |||
985 | }; | |||
986 | llvm::stable_sort(ctx.outputSections, | |||
987 | [&](const OutputSection *s, const OutputSection *t) { | |||
988 | return sectionOrder(s) < sectionOrder(t); | |||
989 | }); | |||
990 | } | |||
991 | ||||
992 | void Writer::createMiscChunks() { | |||
993 | for (MergeChunk *p : ctx.mergeChunkInstances) { | |||
994 | if (p) { | |||
995 | p->finalizeContents(); | |||
996 | rdataSec->addChunk(p); | |||
997 | } | |||
998 | } | |||
999 | ||||
1000 | // Create thunks for locally-dllimported symbols. | |||
1001 | if (!ctx.symtab.localImportChunks.empty()) { | |||
1002 | for (Chunk *c : ctx.symtab.localImportChunks) | |||
1003 | rdataSec->addChunk(c); | |||
1004 | } | |||
1005 | ||||
1006 | // Create Debug Information Chunks | |||
1007 | OutputSection *debugInfoSec = config->mingw ? buildidSec : rdataSec; | |||
1008 | if (config->debug || config->repro || config->cetCompat) { | |||
1009 | debugDirectory = | |||
1010 | make<DebugDirectoryChunk>(ctx, debugRecords, config->repro); | |||
1011 | debugDirectory->setAlignment(4); | |||
1012 | debugInfoSec->addChunk(debugDirectory); | |||
1013 | } | |||
1014 | ||||
1015 | if (config->debug) { | |||
1016 | // Make a CVDebugRecordChunk even when /DEBUG:CV is not specified. We | |||
1017 | // output a PDB no matter what, and this chunk provides the only means of | |||
1018 | // allowing a debugger to match a PDB and an executable. So we need it even | |||
1019 | // if we're ultimately not going to write CodeView data to the PDB. | |||
1020 | buildId = make<CVDebugRecordChunk>(); | |||
1021 | debugRecords.push_back({COFF::IMAGE_DEBUG_TYPE_CODEVIEW, buildId}); | |||
1022 | } | |||
1023 | ||||
1024 | if (config->cetCompat) { | |||
1025 | debugRecords.push_back({COFF::IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS, | |||
1026 | make<ExtendedDllCharacteristicsChunk>( | |||
1027 | IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT)}); | |||
1028 | } | |||
1029 | ||||
1030 | // Align and add each chunk referenced by the debug data directory. | |||
1031 | for (std::pair<COFF::DebugType, Chunk *> r : debugRecords) { | |||
1032 | r.second->setAlignment(4); | |||
1033 | debugInfoSec->addChunk(r.second); | |||
1034 | } | |||
1035 | ||||
1036 | // Create SEH table. x86-only. | |||
1037 | if (config->safeSEH) | |||
1038 | createSEHTable(); | |||
1039 | ||||
1040 | // Create /guard:cf tables if requested. | |||
1041 | if (config->guardCF != GuardCFLevel::Off) | |||
1042 | createGuardCFTables(); | |||
1043 | ||||
1044 | if (config->autoImport) | |||
1045 | createRuntimePseudoRelocs(); | |||
1046 | ||||
1047 | if (config->mingw) | |||
1048 | insertCtorDtorSymbols(); | |||
1049 | } | |||
1050 | ||||
1051 | // Create .idata section for the DLL-imported symbol table. | |||
1052 | // The format of this section is inherently Windows-specific. | |||
1053 | // IdataContents class abstracted away the details for us, | |||
1054 | // so we just let it create chunks and add them to the section. | |||
1055 | void Writer::createImportTables() { | |||
1056 | // Initialize DLLOrder so that import entries are ordered in | |||
1057 | // the same order as in the command line. (That affects DLL | |||
1058 | // initialization order, and this ordering is MSVC-compatible.) | |||
1059 | for (ImportFile *file : ctx.importFileInstances) { | |||
1060 | if (!file->live) | |||
1061 | continue; | |||
1062 | ||||
1063 | std::string dll = StringRef(file->dllName).lower(); | |||
1064 | if (config->dllOrder.count(dll) == 0) | |||
1065 | config->dllOrder[dll] = config->dllOrder.size(); | |||
1066 | ||||
1067 | if (file->impSym && !isa<DefinedImportData>(file->impSym)) | |||
1068 | fatal(toString(*file->impSym) + " was replaced"); | |||
1069 | DefinedImportData *impSym = cast_or_null<DefinedImportData>(file->impSym); | |||
1070 | if (config->delayLoads.count(StringRef(file->dllName).lower())) { | |||
1071 | if (!file->thunkSym) | |||
1072 | fatal("cannot delay-load " + toString(file) + | |||
1073 | " due to import of data: " + toString(*impSym)); | |||
| ||||
1074 | delayIdata.add(impSym); | |||
1075 | } else { | |||
1076 | idata.add(impSym); | |||
1077 | } | |||
1078 | } | |||
1079 | } | |||
1080 | ||||
1081 | void Writer::appendImportThunks() { | |||
1082 | if (ctx.importFileInstances.empty()) | |||
1083 | return; | |||
1084 | ||||
1085 | for (ImportFile *file : ctx.importFileInstances) { | |||
1086 | if (!file->live) | |||
1087 | continue; | |||
1088 | ||||
1089 | if (!file->thunkSym) | |||
1090 | continue; | |||
1091 | ||||
1092 | if (!isa<DefinedImportThunk>(file->thunkSym)) | |||
1093 | fatal(toString(*file->thunkSym) + " was replaced"); | |||
1094 | DefinedImportThunk *thunk = cast<DefinedImportThunk>(file->thunkSym); | |||
1095 | if (file->thunkLive) | |||
1096 | textSec->addChunk(thunk->getChunk()); | |||
1097 | } | |||
1098 | ||||
1099 | if (!delayIdata.empty()) { | |||
1100 | Defined *helper = cast<Defined>(config->delayLoadHelper); | |||
1101 | delayIdata.create(ctx, helper); | |||
1102 | for (Chunk *c : delayIdata.getChunks()) | |||
1103 | didatSec->addChunk(c); | |||
1104 | for (Chunk *c : delayIdata.getDataChunks()) | |||
1105 | dataSec->addChunk(c); | |||
1106 | for (Chunk *c : delayIdata.getCodeChunks()) | |||
1107 | textSec->addChunk(c); | |||
1108 | } | |||
1109 | } | |||
1110 | ||||
1111 | void Writer::createExportTable() { | |||
1112 | if (!edataSec->chunks.empty()) { | |||
1113 | // Allow using a custom built export table from input object files, instead | |||
1114 | // of having the linker synthesize the tables. | |||
1115 | if (config->hadExplicitExports) | |||
1116 | warn("literal .edata sections override exports"); | |||
1117 | } else if (!config->exports.empty()) { | |||
1118 | for (Chunk *c : edata.chunks) | |||
1119 | edataSec->addChunk(c); | |||
1120 | } | |||
1121 | if (!edataSec->chunks.empty()) { | |||
1122 | edataStart = edataSec->chunks.front(); | |||
1123 | edataEnd = edataSec->chunks.back(); | |||
1124 | } | |||
1125 | // Warn on exported deleting destructor. | |||
1126 | for (auto e : config->exports) | |||
1127 | if (e.sym && e.sym->getName().startswith("??_G")) | |||
1128 | warn("export of deleting dtor: " + toString(*e.sym)); | |||
1129 | } | |||
1130 | ||||
1131 | void Writer::removeUnusedSections() { | |||
1132 | // Remove sections that we can be sure won't get content, to avoid | |||
1133 | // allocating space for their section headers. | |||
1134 | auto isUnused = [this](OutputSection *s) { | |||
1135 | if (s == relocSec) | |||
1136 | return false; // This section is populated later. | |||
1137 | // MergeChunks have zero size at this point, as their size is finalized | |||
1138 | // later. Only remove sections that have no Chunks at all. | |||
1139 | return s->chunks.empty(); | |||
1140 | }; | |||
1141 | llvm::erase_if(ctx.outputSections, isUnused); | |||
1142 | } | |||
1143 | ||||
1144 | // The Windows loader doesn't seem to like empty sections, | |||
1145 | // so we remove them if any. | |||
1146 | void Writer::removeEmptySections() { | |||
1147 | auto isEmpty = [](OutputSection *s) { return s->getVirtualSize() == 0; }; | |||
1148 | llvm::erase_if(ctx.outputSections, isEmpty); | |||
1149 | } | |||
1150 | ||||
1151 | void Writer::assignOutputSectionIndices() { | |||
1152 | // Assign final output section indices, and assign each chunk to its output | |||
1153 | // section. | |||
1154 | uint32_t idx = 1; | |||
1155 | for (OutputSection *os : ctx.outputSections) { | |||
1156 | os->sectionIndex = idx; | |||
1157 | for (Chunk *c : os->chunks) | |||
1158 | c->setOutputSectionIdx(idx); | |||
1159 | ++idx; | |||
1160 | } | |||
1161 | ||||
1162 | // Merge chunks are containers of chunks, so assign those an output section | |||
1163 | // too. | |||
1164 | for (MergeChunk *mc : ctx.mergeChunkInstances) | |||
1165 | if (mc) | |||
1166 | for (SectionChunk *sc : mc->sections) | |||
1167 | if (sc && sc->live) | |||
1168 | sc->setOutputSectionIdx(mc->getOutputSectionIdx()); | |||
1169 | } | |||
1170 | ||||
1171 | size_t Writer::addEntryToStringTable(StringRef str) { | |||
1172 | assert(str.size() > COFF::NameSize)(static_cast <bool> (str.size() > COFF::NameSize) ? void (0) : __assert_fail ("str.size() > COFF::NameSize", "lld/COFF/Writer.cpp" , 1172, __extension__ __PRETTY_FUNCTION__)); | |||
1173 | size_t offsetOfEntry = strtab.size() + 4; // +4 for the size field | |||
1174 | strtab.insert(strtab.end(), str.begin(), str.end()); | |||
1175 | strtab.push_back('\0'); | |||
1176 | return offsetOfEntry; | |||
1177 | } | |||
1178 | ||||
1179 | std::optional<coff_symbol16> Writer::createSymbol(Defined *def) { | |||
1180 | coff_symbol16 sym; | |||
1181 | switch (def->kind()) { | |||
1182 | case Symbol::DefinedAbsoluteKind: { | |||
1183 | auto *da = dyn_cast<DefinedAbsolute>(def); | |||
1184 | // Note: COFF symbol can only store 32-bit values, so 64-bit absolute | |||
1185 | // values will be truncated. | |||
1186 | sym.Value = da->getVA(); | |||
1187 | sym.SectionNumber = IMAGE_SYM_ABSOLUTE; | |||
1188 | break; | |||
1189 | } | |||
1190 | default: { | |||
1191 | // Don't write symbols that won't be written to the output to the symbol | |||
1192 | // table. | |||
1193 | // We also try to write DefinedSynthetic as a normal symbol. Some of these | |||
1194 | // symbols do point to an actual chunk, like __safe_se_handler_table. Others | |||
1195 | // like __ImageBase are outside of sections and thus cannot be represented. | |||
1196 | Chunk *c = def->getChunk(); | |||
1197 | if (!c) | |||
1198 | return std::nullopt; | |||
1199 | OutputSection *os = ctx.getOutputSection(c); | |||
1200 | if (!os) | |||
1201 | return std::nullopt; | |||
1202 | ||||
1203 | sym.Value = def->getRVA() - os->getRVA(); | |||
1204 | sym.SectionNumber = os->sectionIndex; | |||
1205 | break; | |||
1206 | } | |||
1207 | } | |||
1208 | ||||
1209 | // Symbols that are runtime pseudo relocations don't point to the actual | |||
1210 | // symbol data itself (as they are imported), but points to the IAT entry | |||
1211 | // instead. Avoid emitting them to the symbol table, as they can confuse | |||
1212 | // debuggers. | |||
1213 | if (def->isRuntimePseudoReloc) | |||
1214 | return std::nullopt; | |||
1215 | ||||
1216 | StringRef name = def->getName(); | |||
1217 | if (name.size() > COFF::NameSize) { | |||
1218 | sym.Name.Offset.Zeroes = 0; | |||
1219 | sym.Name.Offset.Offset = addEntryToStringTable(name); | |||
1220 | } else { | |||
1221 | memset(sym.Name.ShortName, 0, COFF::NameSize); | |||
1222 | memcpy(sym.Name.ShortName, name.data(), name.size()); | |||
1223 | } | |||
1224 | ||||
1225 | if (auto *d = dyn_cast<DefinedCOFF>(def)) { | |||
1226 | COFFSymbolRef ref = d->getCOFFSymbol(); | |||
1227 | sym.Type = ref.getType(); | |||
1228 | sym.StorageClass = ref.getStorageClass(); | |||
1229 | } else if (def->kind() == Symbol::DefinedImportThunkKind) { | |||
1230 | sym.Type = (IMAGE_SYM_DTYPE_FUNCTION << SCT_COMPLEX_TYPE_SHIFT) | | |||
1231 | IMAGE_SYM_TYPE_NULL; | |||
1232 | sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; | |||
1233 | } else { | |||
1234 | sym.Type = IMAGE_SYM_TYPE_NULL; | |||
1235 | sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; | |||
1236 | } | |||
1237 | sym.NumberOfAuxSymbols = 0; | |||
1238 | return sym; | |||
1239 | } | |||
1240 | ||||
1241 | void Writer::createSymbolAndStringTable() { | |||
1242 | // PE/COFF images are limited to 8 byte section names. Longer names can be | |||
1243 | // supported by writing a non-standard string table, but this string table is | |||
1244 | // not mapped at runtime and the long names will therefore be inaccessible. | |||
1245 | // link.exe always truncates section names to 8 bytes, whereas binutils always | |||
1246 | // preserves long section names via the string table. LLD adopts a hybrid | |||
1247 | // solution where discardable sections have long names preserved and | |||
1248 | // non-discardable sections have their names truncated, to ensure that any | |||
1249 | // section which is mapped at runtime also has its name mapped at runtime. | |||
1250 | for (OutputSection *sec : ctx.outputSections) { | |||
1251 | if (sec->name.size() <= COFF::NameSize) | |||
1252 | continue; | |||
1253 | if ((sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) | |||
1254 | continue; | |||
1255 | if (config->warnLongSectionNames) { | |||
1256 | warn("section name " + sec->name + | |||
1257 | " is longer than 8 characters and will use a non-standard string " | |||
1258 | "table"); | |||
1259 | } | |||
1260 | sec->setStringTableOff(addEntryToStringTable(sec->name)); | |||
1261 | } | |||
1262 | ||||
1263 | if (config->debugDwarf || config->debugSymtab) { | |||
1264 | for (ObjFile *file : ctx.objFileInstances) { | |||
1265 | for (Symbol *b : file->getSymbols()) { | |||
1266 | auto *d = dyn_cast_or_null<Defined>(b); | |||
1267 | if (!d || d->writtenToSymtab) | |||
1268 | continue; | |||
1269 | d->writtenToSymtab = true; | |||
1270 | if (auto *dc = dyn_cast_or_null<DefinedCOFF>(d)) { | |||
1271 | COFFSymbolRef symRef = dc->getCOFFSymbol(); | |||
1272 | if (symRef.isSectionDefinition() || | |||
1273 | symRef.getStorageClass() == COFF::IMAGE_SYM_CLASS_LABEL) | |||
1274 | continue; | |||
1275 | } | |||
1276 | ||||
1277 | if (std::optional<coff_symbol16> sym = createSymbol(d)) | |||
1278 | outputSymtab.push_back(*sym); | |||
1279 | ||||
1280 | if (auto *dthunk = dyn_cast<DefinedImportThunk>(d)) { | |||
1281 | if (!dthunk->wrappedSym->writtenToSymtab) { | |||
1282 | dthunk->wrappedSym->writtenToSymtab = true; | |||
1283 | if (std::optional<coff_symbol16> sym = | |||
1284 | createSymbol(dthunk->wrappedSym)) | |||
1285 | outputSymtab.push_back(*sym); | |||
1286 | } | |||
1287 | } | |||
1288 | } | |||
1289 | } | |||
1290 | } | |||
1291 | ||||
1292 | if (outputSymtab.empty() && strtab.empty()) | |||
1293 | return; | |||
1294 | ||||
1295 | // We position the symbol table to be adjacent to the end of the last section. | |||
1296 | uint64_t fileOff = fileSize; | |||
1297 | pointerToSymbolTable = fileOff; | |||
1298 | fileOff += outputSymtab.size() * sizeof(coff_symbol16); | |||
1299 | fileOff += 4 + strtab.size(); | |||
1300 | fileSize = alignTo(fileOff, config->fileAlign); | |||
1301 | } | |||
1302 | ||||
1303 | void Writer::mergeSections() { | |||
1304 | if (!pdataSec->chunks.empty()) { | |||
1305 | firstPdata = pdataSec->chunks.front(); | |||
1306 | lastPdata = pdataSec->chunks.back(); | |||
1307 | } | |||
1308 | ||||
1309 | for (auto &p : config->merge) { | |||
1310 | StringRef toName = p.second; | |||
1311 | if (p.first == toName) | |||
1312 | continue; | |||
1313 | StringSet<> names; | |||
1314 | while (true) { | |||
1315 | if (!names.insert(toName).second) | |||
1316 | fatal("/merge: cycle found for section '" + p.first + "'"); | |||
1317 | auto i = config->merge.find(toName); | |||
1318 | if (i == config->merge.end()) | |||
1319 | break; | |||
1320 | toName = i->second; | |||
1321 | } | |||
1322 | OutputSection *from = findSection(p.first); | |||
1323 | OutputSection *to = findSection(toName); | |||
1324 | if (!from) | |||
1325 | continue; | |||
1326 | if (!to) { | |||
1327 | from->name = toName; | |||
1328 | continue; | |||
1329 | } | |||
1330 | to->merge(from); | |||
1331 | } | |||
1332 | } | |||
1333 | ||||
1334 | // Visits all sections to assign incremental, non-overlapping RVAs and | |||
1335 | // file offsets. | |||
1336 | void Writer::assignAddresses() { | |||
1337 | sizeOfHeaders = dosStubSize + sizeof(PEMagic) + sizeof(coff_file_header) + | |||
1338 | sizeof(data_directory) * numberOfDataDirectory + | |||
1339 | sizeof(coff_section) * ctx.outputSections.size(); | |||
1340 | sizeOfHeaders += | |||
1341 | config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); | |||
1342 | sizeOfHeaders = alignTo(sizeOfHeaders, config->fileAlign); | |||
1343 | fileSize = sizeOfHeaders; | |||
1344 | ||||
1345 | // The first page is kept unmapped. | |||
1346 | uint64_t rva = alignTo(sizeOfHeaders, config->align); | |||
1347 | ||||
1348 | for (OutputSection *sec : ctx.outputSections) { | |||
1349 | if (sec == relocSec) | |||
1350 | addBaserels(); | |||
1351 | uint64_t rawSize = 0, virtualSize = 0; | |||
1352 | sec->header.VirtualAddress = rva; | |||
1353 | ||||
1354 | // If /FUNCTIONPADMIN is used, functions are padded in order to create a | |||
1355 | // hotpatchable image. | |||
1356 | const bool isCodeSection = | |||
1357 | (sec->header.Characteristics & IMAGE_SCN_CNT_CODE) && | |||
1358 | (sec->header.Characteristics & IMAGE_SCN_MEM_READ) && | |||
1359 | (sec->header.Characteristics & IMAGE_SCN_MEM_EXECUTE); | |||
1360 | uint32_t padding = isCodeSection ? config->functionPadMin : 0; | |||
1361 | ||||
1362 | for (Chunk *c : sec->chunks) { | |||
1363 | if (padding && c->isHotPatchable()) | |||
1364 | virtualSize += padding; | |||
1365 | virtualSize = alignTo(virtualSize, c->getAlignment()); | |||
1366 | c->setRVA(rva + virtualSize); | |||
1367 | virtualSize += c->getSize(); | |||
1368 | if (c->hasData) | |||
1369 | rawSize = alignTo(virtualSize, config->fileAlign); | |||
1370 | } | |||
1371 | if (virtualSize > UINT32_MAX(4294967295U)) | |||
1372 | error("section larger than 4 GiB: " + sec->name); | |||
1373 | sec->header.VirtualSize = virtualSize; | |||
1374 | sec->header.SizeOfRawData = rawSize; | |||
1375 | if (rawSize != 0) | |||
1376 | sec->header.PointerToRawData = fileSize; | |||
1377 | rva += alignTo(virtualSize, config->align); | |||
1378 | fileSize += alignTo(rawSize, config->fileAlign); | |||
1379 | } | |||
1380 | sizeOfImage = alignTo(rva, config->align); | |||
1381 | ||||
1382 | // Assign addresses to sections in MergeChunks. | |||
1383 | for (MergeChunk *mc : ctx.mergeChunkInstances) | |||
1384 | if (mc) | |||
1385 | mc->assignSubsectionRVAs(); | |||
1386 | } | |||
1387 | ||||
1388 | template <typename PEHeaderTy> void Writer::writeHeader() { | |||
1389 | // Write DOS header. For backwards compatibility, the first part of a PE/COFF | |||
1390 | // executable consists of an MS-DOS MZ executable. If the executable is run | |||
1391 | // under DOS, that program gets run (usually to just print an error message). | |||
1392 | // When run under Windows, the loader looks at AddressOfNewExeHeader and uses | |||
1393 | // the PE header instead. | |||
1394 | uint8_t *buf = buffer->getBufferStart(); | |||
1395 | auto *dos = reinterpret_cast<dos_header *>(buf); | |||
1396 | buf += sizeof(dos_header); | |||
1397 | dos->Magic[0] = 'M'; | |||
1398 | dos->Magic[1] = 'Z'; | |||
1399 | dos->UsedBytesInTheLastPage = dosStubSize % 512; | |||
1400 | dos->FileSizeInPages = divideCeil(dosStubSize, 512); | |||
1401 | dos->HeaderSizeInParagraphs = sizeof(dos_header) / 16; | |||
1402 | ||||
1403 | dos->AddressOfRelocationTable = sizeof(dos_header); | |||
1404 | dos->AddressOfNewExeHeader = dosStubSize; | |||
1405 | ||||
1406 | // Write DOS program. | |||
1407 | memcpy(buf, dosProgram, sizeof(dosProgram)); | |||
1408 | buf += sizeof(dosProgram); | |||
1409 | ||||
1410 | // Write PE magic | |||
1411 | memcpy(buf, PEMagic, sizeof(PEMagic)); | |||
1412 | buf += sizeof(PEMagic); | |||
1413 | ||||
1414 | // Write COFF header | |||
1415 | auto *coff = reinterpret_cast<coff_file_header *>(buf); | |||
1416 | buf += sizeof(*coff); | |||
1417 | coff->Machine = config->machine; | |||
1418 | coff->NumberOfSections = ctx.outputSections.size(); | |||
1419 | coff->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; | |||
1420 | if (config->largeAddressAware) | |||
1421 | coff->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; | |||
1422 | if (!config->is64()) | |||
1423 | coff->Characteristics |= IMAGE_FILE_32BIT_MACHINE; | |||
1424 | if (config->dll) | |||
1425 | coff->Characteristics |= IMAGE_FILE_DLL; | |||
1426 | if (config->driverUponly) | |||
1427 | coff->Characteristics |= IMAGE_FILE_UP_SYSTEM_ONLY; | |||
1428 | if (!config->relocatable) | |||
1429 | coff->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; | |||
1430 | if (config->swaprunCD) | |||
1431 | coff->Characteristics |= IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP; | |||
1432 | if (config->swaprunNet) | |||
1433 | coff->Characteristics |= IMAGE_FILE_NET_RUN_FROM_SWAP; | |||
1434 | coff->SizeOfOptionalHeader = | |||
1435 | sizeof(PEHeaderTy) + sizeof(data_directory) * numberOfDataDirectory; | |||
1436 | ||||
1437 | // Write PE header | |||
1438 | auto *pe = reinterpret_cast<PEHeaderTy *>(buf); | |||
1439 | buf += sizeof(*pe); | |||
1440 | pe->Magic = config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32; | |||
1441 | ||||
1442 | // If {Major,Minor}LinkerVersion is left at 0.0, then for some | |||
1443 | // reason signing the resulting PE file with Authenticode produces a | |||
1444 | // signature that fails to validate on Windows 7 (but is OK on 10). | |||
1445 | // Set it to 14.0, which is what VS2015 outputs, and which avoids | |||
1446 | // that problem. | |||
1447 | pe->MajorLinkerVersion = 14; | |||
1448 | pe->MinorLinkerVersion = 0; | |||
1449 | ||||
1450 | pe->ImageBase = config->imageBase; | |||
1451 | pe->SectionAlignment = config->align; | |||
1452 | pe->FileAlignment = config->fileAlign; | |||
1453 | pe->MajorImageVersion = config->majorImageVersion; | |||
1454 | pe->MinorImageVersion = config->minorImageVersion; | |||
1455 | pe->MajorOperatingSystemVersion = config->majorOSVersion; | |||
1456 | pe->MinorOperatingSystemVersion = config->minorOSVersion; | |||
1457 | pe->MajorSubsystemVersion = config->majorSubsystemVersion; | |||
1458 | pe->MinorSubsystemVersion = config->minorSubsystemVersion; | |||
1459 | pe->Subsystem = config->subsystem; | |||
1460 | pe->SizeOfImage = sizeOfImage; | |||
1461 | pe->SizeOfHeaders = sizeOfHeaders; | |||
1462 | if (!config->noEntry) { | |||
1463 | Defined *entry = cast<Defined>(config->entry); | |||
1464 | pe->AddressOfEntryPoint = entry->getRVA(); | |||
1465 | // Pointer to thumb code must have the LSB set, so adjust it. | |||
1466 | if (config->machine == ARMNT) | |||
1467 | pe->AddressOfEntryPoint |= 1; | |||
1468 | } | |||
1469 | pe->SizeOfStackReserve = config->stackReserve; | |||
1470 | pe->SizeOfStackCommit = config->stackCommit; | |||
1471 | pe->SizeOfHeapReserve = config->heapReserve; | |||
1472 | pe->SizeOfHeapCommit = config->heapCommit; | |||
1473 | if (config->appContainer) | |||
1474 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER; | |||
1475 | if (config->driverWdm) | |||
1476 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER; | |||
1477 | if (config->dynamicBase) | |||
1478 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; | |||
1479 | if (config->highEntropyVA) | |||
1480 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA; | |||
1481 | if (!config->allowBind) | |||
1482 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND; | |||
1483 | if (config->nxCompat) | |||
1484 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; | |||
1485 | if (!config->allowIsolation) | |||
1486 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION; | |||
1487 | if (config->guardCF != GuardCFLevel::Off) | |||
1488 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF; | |||
1489 | if (config->integrityCheck) | |||
1490 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY; | |||
1491 | if (setNoSEHCharacteristic || config->noSEH) | |||
1492 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH; | |||
1493 | if (config->terminalServerAware) | |||
1494 | pe->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE; | |||
1495 | pe->NumberOfRvaAndSize = numberOfDataDirectory; | |||
1496 | if (textSec->getVirtualSize()) { | |||
1497 | pe->BaseOfCode = textSec->getRVA(); | |||
1498 | pe->SizeOfCode = textSec->getRawSize(); | |||
1499 | } | |||
1500 | pe->SizeOfInitializedData = getSizeOfInitializedData(); | |||
1501 | ||||
1502 | // Write data directory | |||
1503 | auto *dir = reinterpret_cast<data_directory *>(buf); | |||
1504 | buf += sizeof(*dir) * numberOfDataDirectory; | |||
1505 | if (edataStart) { | |||
1506 | dir[EXPORT_TABLE].RelativeVirtualAddress = edataStart->getRVA(); | |||
1507 | dir[EXPORT_TABLE].Size = | |||
1508 | edataEnd->getRVA() + edataEnd->getSize() - edataStart->getRVA(); | |||
1509 | } | |||
1510 | if (importTableStart) { | |||
1511 | dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA(); | |||
1512 | dir[IMPORT_TABLE].Size = importTableSize; | |||
1513 | } | |||
1514 | if (iatStart) { | |||
1515 | dir[IAT].RelativeVirtualAddress = iatStart->getRVA(); | |||
1516 | dir[IAT].Size = iatSize; | |||
1517 | } | |||
1518 | if (rsrcSec->getVirtualSize()) { | |||
1519 | dir[RESOURCE_TABLE].RelativeVirtualAddress = rsrcSec->getRVA(); | |||
1520 | dir[RESOURCE_TABLE].Size = rsrcSec->getVirtualSize(); | |||
1521 | } | |||
1522 | if (firstPdata) { | |||
1523 | dir[EXCEPTION_TABLE].RelativeVirtualAddress = firstPdata->getRVA(); | |||
1524 | dir[EXCEPTION_TABLE].Size = | |||
1525 | lastPdata->getRVA() + lastPdata->getSize() - firstPdata->getRVA(); | |||
1526 | } | |||
1527 | if (relocSec->getVirtualSize()) { | |||
1528 | dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = relocSec->getRVA(); | |||
1529 | dir[BASE_RELOCATION_TABLE].Size = relocSec->getVirtualSize(); | |||
1530 | } | |||
1531 | if (Symbol *sym = ctx.symtab.findUnderscore("_tls_used")) { | |||
1532 | if (Defined *b = dyn_cast<Defined>(sym)) { | |||
1533 | dir[TLS_TABLE].RelativeVirtualAddress = b->getRVA(); | |||
1534 | dir[TLS_TABLE].Size = config->is64() | |||
1535 | ? sizeof(object::coff_tls_directory64) | |||
1536 | : sizeof(object::coff_tls_directory32); | |||
1537 | } | |||
1538 | } | |||
1539 | if (debugDirectory) { | |||
1540 | dir[DEBUG_DIRECTORY].RelativeVirtualAddress = debugDirectory->getRVA(); | |||
1541 | dir[DEBUG_DIRECTORY].Size = debugDirectory->getSize(); | |||
1542 | } | |||
1543 | if (Symbol *sym = ctx.symtab.findUnderscore("_load_config_used")) { | |||
1544 | if (auto *b = dyn_cast<DefinedRegular>(sym)) { | |||
1545 | SectionChunk *sc = b->getChunk(); | |||
1546 | assert(b->getRVA() >= sc->getRVA())(static_cast <bool> (b->getRVA() >= sc->getRVA ()) ? void (0) : __assert_fail ("b->getRVA() >= sc->getRVA()" , "lld/COFF/Writer.cpp", 1546, __extension__ __PRETTY_FUNCTION__ )); | |||
1547 | uint64_t offsetInChunk = b->getRVA() - sc->getRVA(); | |||
1548 | if (!sc->hasData || offsetInChunk + 4 > sc->getSize()) | |||
1549 | fatal("_load_config_used is malformed"); | |||
1550 | ||||
1551 | ArrayRef<uint8_t> secContents = sc->getContents(); | |||
1552 | uint32_t loadConfigSize = | |||
1553 | *reinterpret_cast<const ulittle32_t *>(&secContents[offsetInChunk]); | |||
1554 | if (offsetInChunk + loadConfigSize > sc->getSize()) | |||
1555 | fatal("_load_config_used is too large"); | |||
1556 | dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = b->getRVA(); | |||
1557 | dir[LOAD_CONFIG_TABLE].Size = loadConfigSize; | |||
1558 | } | |||
1559 | } | |||
1560 | if (!delayIdata.empty()) { | |||
1561 | dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress = | |||
1562 | delayIdata.getDirRVA(); | |||
1563 | dir[DELAY_IMPORT_DESCRIPTOR].Size = delayIdata.getDirSize(); | |||
1564 | } | |||
1565 | ||||
1566 | // Write section table | |||
1567 | for (OutputSection *sec : ctx.outputSections) { | |||
1568 | sec->writeHeaderTo(buf); | |||
1569 | buf += sizeof(coff_section); | |||
1570 | } | |||
1571 | sectionTable = ArrayRef<uint8_t>( | |||
1572 | buf - ctx.outputSections.size() * sizeof(coff_section), buf); | |||
1573 | ||||
1574 | if (outputSymtab.empty() && strtab.empty()) | |||
1575 | return; | |||
1576 | ||||
1577 | coff->PointerToSymbolTable = pointerToSymbolTable; | |||
1578 | uint32_t numberOfSymbols = outputSymtab.size(); | |||
1579 | coff->NumberOfSymbols = numberOfSymbols; | |||
1580 | auto *symbolTable = reinterpret_cast<coff_symbol16 *>( | |||
1581 | buffer->getBufferStart() + coff->PointerToSymbolTable); | |||
1582 | for (size_t i = 0; i != numberOfSymbols; ++i) | |||
1583 | symbolTable[i] = outputSymtab[i]; | |||
1584 | // Create the string table, it follows immediately after the symbol table. | |||
1585 | // The first 4 bytes is length including itself. | |||
1586 | buf = reinterpret_cast<uint8_t *>(&symbolTable[numberOfSymbols]); | |||
1587 | write32le(buf, strtab.size() + 4); | |||
1588 | if (!strtab.empty()) | |||
1589 | memcpy(buf + 4, strtab.data(), strtab.size()); | |||
1590 | } | |||
1591 | ||||
1592 | void Writer::openFile(StringRef path) { | |||
1593 | buffer = CHECK(check2((FileOutputBuffer::create(path, fileSize, FileOutputBuffer ::F_executable)), [&] { return toString("failed to open " + path); }) | |||
1594 | FileOutputBuffer::create(path, fileSize, FileOutputBuffer::F_executable),check2((FileOutputBuffer::create(path, fileSize, FileOutputBuffer ::F_executable)), [&] { return toString("failed to open " + path); }) | |||
1595 | "failed to open " + path)check2((FileOutputBuffer::create(path, fileSize, FileOutputBuffer ::F_executable)), [&] { return toString("failed to open " + path); }); | |||
1596 | } | |||
1597 | ||||
1598 | void Writer::createSEHTable() { | |||
1599 | SymbolRVASet handlers; | |||
1600 | for (ObjFile *file : ctx.objFileInstances) { | |||
1601 | if (!file->hasSafeSEH()) | |||
1602 | error("/safeseh: " + file->getName() + " is not compatible with SEH"); | |||
1603 | markSymbolsForRVATable(file, file->getSXDataChunks(), handlers); | |||
1604 | } | |||
1605 | ||||
1606 | // Set the "no SEH" characteristic if there really were no handlers, or if | |||
1607 | // there is no load config object to point to the table of handlers. | |||
1608 | setNoSEHCharacteristic = | |||
1609 | handlers.empty() || !ctx.symtab.findUnderscore("_load_config_used"); | |||
1610 | ||||
1611 | maybeAddRVATable(std::move(handlers), "__safe_se_handler_table", | |||
1612 | "__safe_se_handler_count"); | |||
1613 | } | |||
1614 | ||||
1615 | // Add a symbol to an RVA set. Two symbols may have the same RVA, but an RVA set | |||
1616 | // cannot contain duplicates. Therefore, the set is uniqued by Chunk and the | |||
1617 | // symbol's offset into that Chunk. | |||
1618 | static void addSymbolToRVASet(SymbolRVASet &rvaSet, Defined *s) { | |||
1619 | Chunk *c = s->getChunk(); | |||
1620 | if (auto *sc = dyn_cast<SectionChunk>(c)) | |||
1621 | c = sc->repl; // Look through ICF replacement. | |||
1622 | uint32_t off = s->getRVA() - (c ? c->getRVA() : 0); | |||
1623 | rvaSet.insert({c, off}); | |||
1624 | } | |||
1625 | ||||
1626 | // Given a symbol, add it to the GFIDs table if it is a live, defined, function | |||
1627 | // symbol in an executable section. | |||
1628 | static void maybeAddAddressTakenFunction(SymbolRVASet &addressTakenSyms, | |||
1629 | Symbol *s) { | |||
1630 | if (!s) | |||
1631 | return; | |||
1632 | ||||
1633 | switch (s->kind()) { | |||
1634 | case Symbol::DefinedLocalImportKind: | |||
1635 | case Symbol::DefinedImportDataKind: | |||
1636 | // Defines an __imp_ pointer, so it is data, so it is ignored. | |||
1637 | break; | |||
1638 | case Symbol::DefinedCommonKind: | |||
1639 | // Common is always data, so it is ignored. | |||
1640 | break; | |||
1641 | case Symbol::DefinedAbsoluteKind: | |||
1642 | case Symbol::DefinedSyntheticKind: | |||
1643 | // Absolute is never code, synthetic generally isn't and usually isn't | |||
1644 | // determinable. | |||
1645 | break; | |||
1646 | case Symbol::LazyArchiveKind: | |||
1647 | case Symbol::LazyObjectKind: | |||
1648 | case Symbol::LazyDLLSymbolKind: | |||
1649 | case Symbol::UndefinedKind: | |||
1650 | // Undefined symbols resolve to zero, so they don't have an RVA. Lazy | |||
1651 | // symbols shouldn't have relocations. | |||
1652 | break; | |||
1653 | ||||
1654 | case Symbol::DefinedImportThunkKind: | |||
1655 | // Thunks are always code, include them. | |||
1656 | addSymbolToRVASet(addressTakenSyms, cast<Defined>(s)); | |||
1657 | break; | |||
1658 | ||||
1659 | case Symbol::DefinedRegularKind: { | |||
1660 | // This is a regular, defined, symbol from a COFF file. Mark the symbol as | |||
1661 | // address taken if the symbol type is function and it's in an executable | |||
1662 | // section. | |||
1663 | auto *d = cast<DefinedRegular>(s); | |||
1664 | if (d->getCOFFSymbol().getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) { | |||
1665 | SectionChunk *sc = dyn_cast<SectionChunk>(d->getChunk()); | |||
1666 | if (sc && sc->live && | |||
1667 | sc->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) | |||
1668 | addSymbolToRVASet(addressTakenSyms, d); | |||
1669 | } | |||
1670 | break; | |||
1671 | } | |||
1672 | } | |||
1673 | } | |||
1674 | ||||
1675 | // Visit all relocations from all section contributions of this object file and | |||
1676 | // mark the relocation target as address-taken. | |||
1677 | static void markSymbolsWithRelocations(ObjFile *file, | |||
1678 | SymbolRVASet &usedSymbols) { | |||
1679 | for (Chunk *c : file->getChunks()) { | |||
1680 | // We only care about live section chunks. Common chunks and other chunks | |||
1681 | // don't generally contain relocations. | |||
1682 | SectionChunk *sc = dyn_cast<SectionChunk>(c); | |||
1683 | if (!sc || !sc->live) | |||
1684 | continue; | |||
1685 | ||||
1686 | for (const coff_relocation &reloc : sc->getRelocs()) { | |||
1687 | if (config->machine == I386 && reloc.Type == COFF::IMAGE_REL_I386_REL32) | |||
1688 | // Ignore relative relocations on x86. On x86_64 they can't be ignored | |||
1689 | // since they're also used to compute absolute addresses. | |||
1690 | continue; | |||
1691 | ||||
1692 | Symbol *ref = sc->file->getSymbol(reloc.SymbolTableIndex); | |||
1693 | maybeAddAddressTakenFunction(usedSymbols, ref); | |||
1694 | } | |||
1695 | } | |||
1696 | } | |||
1697 | ||||
1698 | // Create the guard function id table. This is a table of RVAs of all | |||
1699 | // address-taken functions. It is sorted and uniqued, just like the safe SEH | |||
1700 | // table. | |||
1701 | void Writer::createGuardCFTables() { | |||
1702 | SymbolRVASet addressTakenSyms; | |||
1703 | SymbolRVASet giatsRVASet; | |||
1704 | std::vector<Symbol *> giatsSymbols; | |||
1705 | SymbolRVASet longJmpTargets; | |||
1706 | SymbolRVASet ehContTargets; | |||
1707 | for (ObjFile *file : ctx.objFileInstances) { | |||
1708 | // If the object was compiled with /guard:cf, the address taken symbols | |||
1709 | // are in .gfids$y sections, the longjmp targets are in .gljmp$y sections, | |||
1710 | // and ehcont targets are in .gehcont$y sections. If the object was not | |||
1711 | // compiled with /guard:cf, we assume there were no setjmp and ehcont | |||
1712 | // targets, and that all code symbols with relocations are possibly | |||
1713 | // address-taken. | |||
1714 | if (file->hasGuardCF()) { | |||
1715 | markSymbolsForRVATable(file, file->getGuardFidChunks(), addressTakenSyms); | |||
1716 | markSymbolsForRVATable(file, file->getGuardIATChunks(), giatsRVASet); | |||
1717 | getSymbolsFromSections(file, file->getGuardIATChunks(), giatsSymbols); | |||
1718 | markSymbolsForRVATable(file, file->getGuardLJmpChunks(), longJmpTargets); | |||
1719 | markSymbolsForRVATable(file, file->getGuardEHContChunks(), ehContTargets); | |||
1720 | } else { | |||
1721 | markSymbolsWithRelocations(file, addressTakenSyms); | |||
1722 | } | |||
1723 | } | |||
1724 | ||||
1725 | // Mark the image entry as address-taken. | |||
1726 | if (config->entry) | |||
1727 | maybeAddAddressTakenFunction(addressTakenSyms, config->entry); | |||
1728 | ||||
1729 | // Mark exported symbols in executable sections as address-taken. | |||
1730 | for (Export &e : config->exports) | |||
1731 | maybeAddAddressTakenFunction(addressTakenSyms, e.sym); | |||
1732 | ||||
1733 | // For each entry in the .giats table, check if it has a corresponding load | |||
1734 | // thunk (e.g. because the DLL that defines it will be delay-loaded) and, if | |||
1735 | // so, add the load thunk to the address taken (.gfids) table. | |||
1736 | for (Symbol *s : giatsSymbols) { | |||
1737 | if (auto *di = dyn_cast<DefinedImportData>(s)) { | |||
1738 | if (di->loadThunkSym) | |||
1739 | addSymbolToRVASet(addressTakenSyms, di->loadThunkSym); | |||
1740 | } | |||
1741 | } | |||
1742 | ||||
1743 | // Ensure sections referenced in the gfid table are 16-byte aligned. | |||
1744 | for (const ChunkAndOffset &c : addressTakenSyms) | |||
1745 | if (c.inputChunk->getAlignment() < 16) | |||
1746 | c.inputChunk->setAlignment(16); | |||
1747 | ||||
1748 | maybeAddRVATable(std::move(addressTakenSyms), "__guard_fids_table", | |||
1749 | "__guard_fids_count"); | |||
1750 | ||||
1751 | // Add the Guard Address Taken IAT Entry Table (.giats). | |||
1752 | maybeAddRVATable(std::move(giatsRVASet), "__guard_iat_table", | |||
1753 | "__guard_iat_count"); | |||
1754 | ||||
1755 | // Add the longjmp target table unless the user told us not to. | |||
1756 | if (config->guardCF & GuardCFLevel::LongJmp) | |||
1757 | maybeAddRVATable(std::move(longJmpTargets), "__guard_longjmp_table", | |||
1758 | "__guard_longjmp_count"); | |||
1759 | ||||
1760 | // Add the ehcont target table unless the user told us not to. | |||
1761 | if (config->guardCF & GuardCFLevel::EHCont) | |||
1762 | maybeAddRVATable(std::move(ehContTargets), "__guard_eh_cont_table", | |||
1763 | "__guard_eh_cont_count", true); | |||
1764 | ||||
1765 | // Set __guard_flags, which will be used in the load config to indicate that | |||
1766 | // /guard:cf was enabled. | |||
1767 | uint32_t guardFlags = uint32_t(GuardFlags::CF_INSTRUMENTED) | | |||
1768 | uint32_t(GuardFlags::CF_FUNCTION_TABLE_PRESENT); | |||
1769 | if (config->guardCF & GuardCFLevel::LongJmp) | |||
1770 | guardFlags |= uint32_t(GuardFlags::CF_LONGJUMP_TABLE_PRESENT); | |||
1771 | if (config->guardCF & GuardCFLevel::EHCont) | |||
1772 | guardFlags |= uint32_t(GuardFlags::EH_CONTINUATION_TABLE_PRESENT); | |||
1773 | Symbol *flagSym = ctx.symtab.findUnderscore("__guard_flags"); | |||
1774 | cast<DefinedAbsolute>(flagSym)->setVA(guardFlags); | |||
1775 | } | |||
1776 | ||||
1777 | // Take a list of input sections containing symbol table indices and add those | |||
1778 | // symbols to a vector. The challenge is that symbol RVAs are not known and | |||
1779 | // depend on the table size, so we can't directly build a set of integers. | |||
1780 | void Writer::getSymbolsFromSections(ObjFile *file, | |||
1781 | ArrayRef<SectionChunk *> symIdxChunks, | |||
1782 | std::vector<Symbol *> &symbols) { | |||
1783 | for (SectionChunk *c : symIdxChunks) { | |||
1784 | // Skip sections discarded by linker GC. This comes up when a .gfids section | |||
1785 | // is associated with something like a vtable and the vtable is discarded. | |||
1786 | // In this case, the associated gfids section is discarded, and we don't | |||
1787 | // mark the virtual member functions as address-taken by the vtable. | |||
1788 | if (!c->live) | |||
1789 | continue; | |||
1790 | ||||
1791 | // Validate that the contents look like symbol table indices. | |||
1792 | ArrayRef<uint8_t> data = c->getContents(); | |||
1793 | if (data.size() % 4 != 0) { | |||
1794 | warn("ignoring " + c->getSectionName() + | |||
1795 | " symbol table index section in object " + toString(file)); | |||
1796 | continue; | |||
1797 | } | |||
1798 | ||||
1799 | // Read each symbol table index and check if that symbol was included in the | |||
1800 | // final link. If so, add it to the vector of symbols. | |||
1801 | ArrayRef<ulittle32_t> symIndices( | |||
1802 | reinterpret_cast<const ulittle32_t *>(data.data()), data.size() / 4); | |||
1803 | ArrayRef<Symbol *> objSymbols = file->getSymbols(); | |||
1804 | for (uint32_t symIndex : symIndices) { | |||
1805 | if (symIndex >= objSymbols.size()) { | |||
1806 | warn("ignoring invalid symbol table index in section " + | |||
1807 | c->getSectionName() + " in object " + toString(file)); | |||
1808 | continue; | |||
1809 | } | |||
1810 | if (Symbol *s = objSymbols[symIndex]) { | |||
1811 | if (s->isLive()) | |||
1812 | symbols.push_back(cast<Symbol>(s)); | |||
1813 | } | |||
1814 | } | |||
1815 | } | |||
1816 | } | |||
1817 | ||||
1818 | // Take a list of input sections containing symbol table indices and add those | |||
1819 | // symbols to an RVA table. | |||
1820 | void Writer::markSymbolsForRVATable(ObjFile *file, | |||
1821 | ArrayRef<SectionChunk *> symIdxChunks, | |||
1822 | SymbolRVASet &tableSymbols) { | |||
1823 | std::vector<Symbol *> syms; | |||
1824 | getSymbolsFromSections(file, symIdxChunks, syms); | |||
1825 | ||||
1826 | for (Symbol *s : syms) | |||
1827 | addSymbolToRVASet(tableSymbols, cast<Defined>(s)); | |||
1828 | } | |||
1829 | ||||
1830 | // Replace the absolute table symbol with a synthetic symbol pointing to | |||
1831 | // tableChunk so that we can emit base relocations for it and resolve section | |||
1832 | // relative relocations. | |||
1833 | void Writer::maybeAddRVATable(SymbolRVASet tableSymbols, StringRef tableSym, | |||
1834 | StringRef countSym, bool hasFlag) { | |||
1835 | if (tableSymbols.empty()) | |||
1836 | return; | |||
1837 | ||||
1838 | NonSectionChunk *tableChunk; | |||
1839 | if (hasFlag) | |||
1840 | tableChunk = make<RVAFlagTableChunk>(std::move(tableSymbols)); | |||
1841 | else | |||
1842 | tableChunk = make<RVATableChunk>(std::move(tableSymbols)); | |||
1843 | rdataSec->addChunk(tableChunk); | |||
1844 | ||||
1845 | Symbol *t = ctx.symtab.findUnderscore(tableSym); | |||
1846 | Symbol *c = ctx.symtab.findUnderscore(countSym); | |||
1847 | replaceSymbol<DefinedSynthetic>(t, t->getName(), tableChunk); | |||
1848 | cast<DefinedAbsolute>(c)->setVA(tableChunk->getSize() / (hasFlag ? 5 : 4)); | |||
1849 | } | |||
1850 | ||||
1851 | // MinGW specific. Gather all relocations that are imported from a DLL even | |||
1852 | // though the code didn't expect it to, produce the table that the runtime | |||
1853 | // uses for fixing them up, and provide the synthetic symbols that the | |||
1854 | // runtime uses for finding the table. | |||
1855 | void Writer::createRuntimePseudoRelocs() { | |||
1856 | std::vector<RuntimePseudoReloc> rels; | |||
1857 | ||||
1858 | for (Chunk *c : ctx.symtab.getChunks()) { | |||
1859 | auto *sc = dyn_cast<SectionChunk>(c); | |||
1860 | if (!sc || !sc->live) | |||
1861 | continue; | |||
1862 | sc->getRuntimePseudoRelocs(rels); | |||
1863 | } | |||
1864 | ||||
1865 | if (!config->pseudoRelocs) { | |||
1866 | // Not writing any pseudo relocs; if some were needed, error out and | |||
1867 | // indicate what required them. | |||
1868 | for (const RuntimePseudoReloc &rpr : rels) | |||
1869 | error("automatic dllimport of " + rpr.sym->getName() + " in " + | |||
1870 | toString(rpr.target->file) + " requires pseudo relocations"); | |||
1871 | return; | |||
1872 | } | |||
1873 | ||||
1874 | if (!rels.empty()) | |||
1875 | log("Writing " + Twine(rels.size()) + " runtime pseudo relocations"); | |||
1876 | PseudoRelocTableChunk *table = make<PseudoRelocTableChunk>(rels); | |||
1877 | rdataSec->addChunk(table); | |||
1878 | EmptyChunk *endOfList = make<EmptyChunk>(); | |||
1879 | rdataSec->addChunk(endOfList); | |||
1880 | ||||
1881 | Symbol *headSym = ctx.symtab.findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__"); | |||
1882 | Symbol *endSym = | |||
1883 | ctx.symtab.findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__"); | |||
1884 | replaceSymbol<DefinedSynthetic>(headSym, headSym->getName(), table); | |||
1885 | replaceSymbol<DefinedSynthetic>(endSym, endSym->getName(), endOfList); | |||
1886 | } | |||
1887 | ||||
1888 | // MinGW specific. | |||
1889 | // The MinGW .ctors and .dtors lists have sentinels at each end; | |||
1890 | // a (uintptr_t)-1 at the start and a (uintptr_t)0 at the end. | |||
1891 | // There's a symbol pointing to the start sentinel pointer, __CTOR_LIST__ | |||
1892 | // and __DTOR_LIST__ respectively. | |||
1893 | void Writer::insertCtorDtorSymbols() { | |||
1894 | AbsolutePointerChunk *ctorListHead = make<AbsolutePointerChunk>(-1); | |||
1895 | AbsolutePointerChunk *ctorListEnd = make<AbsolutePointerChunk>(0); | |||
1896 | AbsolutePointerChunk *dtorListHead = make<AbsolutePointerChunk>(-1); | |||
1897 | AbsolutePointerChunk *dtorListEnd = make<AbsolutePointerChunk>(0); | |||
1898 | ctorsSec->insertChunkAtStart(ctorListHead); | |||
1899 | ctorsSec->addChunk(ctorListEnd); | |||
1900 | dtorsSec->insertChunkAtStart(dtorListHead); | |||
1901 | dtorsSec->addChunk(dtorListEnd); | |||
1902 | ||||
1903 | Symbol *ctorListSym = ctx.symtab.findUnderscore("__CTOR_LIST__"); | |||
1904 | Symbol *dtorListSym = ctx.symtab.findUnderscore("__DTOR_LIST__"); | |||
1905 | replaceSymbol<DefinedSynthetic>(ctorListSym, ctorListSym->getName(), | |||
1906 | ctorListHead); | |||
1907 | replaceSymbol<DefinedSynthetic>(dtorListSym, dtorListSym->getName(), | |||
1908 | dtorListHead); | |||
1909 | } | |||
1910 | ||||
1911 | // Handles /section options to allow users to overwrite | |||
1912 | // section attributes. | |||
1913 | void Writer::setSectionPermissions() { | |||
1914 | for (auto &p : config->section) { | |||
1915 | StringRef name = p.first; | |||
1916 | uint32_t perm = p.second; | |||
1917 | for (OutputSection *sec : ctx.outputSections) | |||
1918 | if (sec->name == name) | |||
1919 | sec->setPermissions(perm); | |||
1920 | } | |||
1921 | } | |||
1922 | ||||
1923 | // Write section contents to a mmap'ed file. | |||
1924 | void Writer::writeSections() { | |||
1925 | // Record the number of sections to apply section index relocations | |||
1926 | // against absolute symbols. See applySecIdx in Chunks.cpp.. | |||
1927 | DefinedAbsolute::numOutputSections = ctx.outputSections.size(); | |||
1928 | ||||
1929 | uint8_t *buf = buffer->getBufferStart(); | |||
1930 | for (OutputSection *sec : ctx.outputSections) { | |||
1931 | uint8_t *secBuf = buf + sec->getFileOff(); | |||
1932 | // Fill gaps between functions in .text with INT3 instructions | |||
1933 | // instead of leaving as NUL bytes (which can be interpreted as | |||
1934 | // ADD instructions). | |||
1935 | if (sec->header.Characteristics & IMAGE_SCN_CNT_CODE) | |||
1936 | memset(secBuf, 0xCC, sec->getRawSize()); | |||
1937 | parallelForEach(sec->chunks, [&](Chunk *c) { | |||
1938 | c->writeTo(secBuf + c->getRVA() - sec->getRVA()); | |||
1939 | }); | |||
1940 | } | |||
1941 | } | |||
1942 | ||||
1943 | void Writer::writeBuildId() { | |||
1944 | // There are two important parts to the build ID. | |||
1945 | // 1) If building with debug info, the COFF debug directory contains a | |||
1946 | // timestamp as well as a Guid and Age of the PDB. | |||
1947 | // 2) In all cases, the PE COFF file header also contains a timestamp. | |||
1948 | // For reproducibility, instead of a timestamp we want to use a hash of the | |||
1949 | // PE contents. | |||
1950 | if (config->debug) { | |||
1951 | assert(buildId && "BuildId is not set!")(static_cast <bool> (buildId && "BuildId is not set!" ) ? void (0) : __assert_fail ("buildId && \"BuildId is not set!\"" , "lld/COFF/Writer.cpp", 1951, __extension__ __PRETTY_FUNCTION__ )); | |||
1952 | // BuildId->BuildId was filled in when the PDB was written. | |||
1953 | } | |||
1954 | ||||
1955 | // At this point the only fields in the COFF file which remain unset are the | |||
1956 | // "timestamp" in the COFF file header, and the ones in the coff debug | |||
1957 | // directory. Now we can hash the file and write that hash to the various | |||
1958 | // timestamp fields in the file. | |||
1959 | StringRef outputFileData( | |||
1960 | reinterpret_cast<const char *>(buffer->getBufferStart()), | |||
1961 | buffer->getBufferSize()); | |||
1962 | ||||
1963 | uint32_t timestamp = config->timestamp; | |||
1964 | uint64_t hash = 0; | |||
1965 | bool generateSyntheticBuildId = | |||
1966 | config->mingw && config->debug && config->pdbPath.empty(); | |||
1967 | ||||
1968 | if (config->repro || generateSyntheticBuildId) | |||
1969 | hash = xxHash64(outputFileData); | |||
1970 | ||||
1971 | if (config->repro) | |||
1972 | timestamp = static_cast<uint32_t>(hash); | |||
1973 | ||||
1974 | if (generateSyntheticBuildId) { | |||
1975 | // For MinGW builds without a PDB file, we still generate a build id | |||
1976 | // to allow associating a crash dump to the executable. | |||
1977 | buildId->buildId->PDB70.CVSignature = OMF::Signature::PDB70; | |||
1978 | buildId->buildId->PDB70.Age = 1; | |||
1979 | memcpy(buildId->buildId->PDB70.Signature, &hash, 8); | |||
1980 | // xxhash only gives us 8 bytes, so put some fixed data in the other half. | |||
1981 | memcpy(&buildId->buildId->PDB70.Signature[8], "LLD PDB.", 8); | |||
1982 | } | |||
1983 | ||||
1984 | if (debugDirectory) | |||
1985 | debugDirectory->setTimeDateStamp(timestamp); | |||
1986 | ||||
1987 | uint8_t *buf = buffer->getBufferStart(); | |||
1988 | buf += dosStubSize + sizeof(PEMagic); | |||
1989 | object::coff_file_header *coffHeader = | |||
1990 | reinterpret_cast<coff_file_header *>(buf); | |||
1991 | coffHeader->TimeDateStamp = timestamp; | |||
1992 | } | |||
1993 | ||||
1994 | // Sort .pdata section contents according to PE/COFF spec 5.5. | |||
1995 | void Writer::sortExceptionTable() { | |||
1996 | if (!firstPdata) | |||
1997 | return; | |||
1998 | // We assume .pdata contains function table entries only. | |||
1999 | auto bufAddr = [&](Chunk *c) { | |||
2000 | OutputSection *os = ctx.getOutputSection(c); | |||
2001 | return buffer->getBufferStart() + os->getFileOff() + c->getRVA() - | |||
2002 | os->getRVA(); | |||
2003 | }; | |||
2004 | uint8_t *begin = bufAddr(firstPdata); | |||
2005 | uint8_t *end = bufAddr(lastPdata) + lastPdata->getSize(); | |||
2006 | if (config->machine == AMD64) { | |||
2007 | struct Entry { ulittle32_t begin, end, unwind; }; | |||
2008 | if ((end - begin) % sizeof(Entry) != 0) { | |||
2009 | fatal("unexpected .pdata size: " + Twine(end - begin) + | |||
2010 | " is not a multiple of " + Twine(sizeof(Entry))); | |||
2011 | } | |||
2012 | parallelSort( | |||
2013 | MutableArrayRef<Entry>((Entry *)begin, (Entry *)end), | |||
2014 | [](const Entry &a, const Entry &b) { return a.begin < b.begin; }); | |||
2015 | return; | |||
2016 | } | |||
2017 | if (config->machine == ARMNT || config->machine == ARM64) { | |||
2018 | struct Entry { ulittle32_t begin, unwind; }; | |||
2019 | if ((end - begin) % sizeof(Entry) != 0) { | |||
2020 | fatal("unexpected .pdata size: " + Twine(end - begin) + | |||
2021 | " is not a multiple of " + Twine(sizeof(Entry))); | |||
2022 | } | |||
2023 | parallelSort( | |||
2024 | MutableArrayRef<Entry>((Entry *)begin, (Entry *)end), | |||
2025 | [](const Entry &a, const Entry &b) { return a.begin < b.begin; }); | |||
2026 | return; | |||
2027 | } | |||
2028 | lld::errs() << "warning: don't know how to handle .pdata.\n"; | |||
2029 | } | |||
2030 | ||||
2031 | // The CRT section contains, among other things, the array of function | |||
2032 | // pointers that initialize every global variable that is not trivially | |||
2033 | // constructed. The CRT calls them one after the other prior to invoking | |||
2034 | // main(). | |||
2035 | // | |||
2036 | // As per C++ spec, 3.6.2/2.3, | |||
2037 | // "Variables with ordered initialization defined within a single | |||
2038 | // translation unit shall be initialized in the order of their definitions | |||
2039 | // in the translation unit" | |||
2040 | // | |||
2041 | // It is therefore critical to sort the chunks containing the function | |||
2042 | // pointers in the order that they are listed in the object file (top to | |||
2043 | // bottom), otherwise global objects might not be initialized in the | |||
2044 | // correct order. | |||
2045 | void Writer::sortCRTSectionChunks(std::vector<Chunk *> &chunks) { | |||
2046 | auto sectionChunkOrder = [](const Chunk *a, const Chunk *b) { | |||
2047 | auto sa = dyn_cast<SectionChunk>(a); | |||
2048 | auto sb = dyn_cast<SectionChunk>(b); | |||
2049 | assert(sa && sb && "Non-section chunks in CRT section!")(static_cast <bool> (sa && sb && "Non-section chunks in CRT section!" ) ? void (0) : __assert_fail ("sa && sb && \"Non-section chunks in CRT section!\"" , "lld/COFF/Writer.cpp", 2049, __extension__ __PRETTY_FUNCTION__ )); | |||
2050 | ||||
2051 | StringRef sAObj = sa->file->mb.getBufferIdentifier(); | |||
2052 | StringRef sBObj = sb->file->mb.getBufferIdentifier(); | |||
2053 | ||||
2054 | return sAObj == sBObj && sa->getSectionNumber() < sb->getSectionNumber(); | |||
2055 | }; | |||
2056 | llvm::stable_sort(chunks, sectionChunkOrder); | |||
2057 | ||||
2058 | if (config->verbose) { | |||
2059 | for (auto &c : chunks) { | |||
2060 | auto sc = dyn_cast<SectionChunk>(c); | |||
2061 | log(" " + sc->file->mb.getBufferIdentifier().str() + | |||
2062 | ", SectionID: " + Twine(sc->getSectionNumber())); | |||
2063 | } | |||
2064 | } | |||
2065 | } | |||
2066 | ||||
2067 | OutputSection *Writer::findSection(StringRef name) { | |||
2068 | for (OutputSection *sec : ctx.outputSections) | |||
2069 | if (sec->name == name) | |||
2070 | return sec; | |||
2071 | return nullptr; | |||
2072 | } | |||
2073 | ||||
2074 | uint32_t Writer::getSizeOfInitializedData() { | |||
2075 | uint32_t res = 0; | |||
2076 | for (OutputSection *s : ctx.outputSections) | |||
2077 | if (s->header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) | |||
2078 | res += s->getRawSize(); | |||
2079 | return res; | |||
2080 | } | |||
2081 | ||||
2082 | // Add base relocations to .reloc section. | |||
2083 | void Writer::addBaserels() { | |||
2084 | if (!config->relocatable) | |||
2085 | return; | |||
2086 | relocSec->chunks.clear(); | |||
2087 | std::vector<Baserel> v; | |||
2088 | for (OutputSection *sec : ctx.outputSections) { | |||
2089 | if (sec->header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) | |||
2090 | continue; | |||
2091 | // Collect all locations for base relocations. | |||
2092 | for (Chunk *c : sec->chunks) | |||
2093 | c->getBaserels(&v); | |||
2094 | // Add the addresses to .reloc section. | |||
2095 | if (!v.empty()) | |||
2096 | addBaserelBlocks(v); | |||
2097 | v.clear(); | |||
2098 | } | |||
2099 | } | |||
2100 | ||||
2101 | // Add addresses to .reloc section. Note that addresses are grouped by page. | |||
2102 | void Writer::addBaserelBlocks(std::vector<Baserel> &v) { | |||
2103 | const uint32_t mask = ~uint32_t(pageSize - 1); | |||
2104 | uint32_t page = v[0].rva & mask; | |||
2105 | size_t i = 0, j = 1; | |||
2106 | for (size_t e = v.size(); j < e; ++j) { | |||
2107 | uint32_t p = v[j].rva & mask; | |||
2108 | if (p == page) | |||
2109 | continue; | |||
2110 | relocSec->addChunk(make<BaserelChunk>(page, &v[i], &v[0] + j)); | |||
2111 | i = j; | |||
2112 | page = p; | |||
2113 | } | |||
2114 | if (i == j) | |||
2115 | return; | |||
2116 | relocSec->addChunk(make<BaserelChunk>(page, &v[i], &v[0] + j)); | |||
2117 | } | |||
2118 | ||||
2119 | PartialSection *Writer::createPartialSection(StringRef name, | |||
2120 | uint32_t outChars) { | |||
2121 | PartialSection *&pSec = partialSections[{name, outChars}]; | |||
2122 | if (pSec) | |||
2123 | return pSec; | |||
2124 | pSec = make<PartialSection>(name, outChars); | |||
2125 | return pSec; | |||
2126 | } | |||
2127 | ||||
2128 | PartialSection *Writer::findPartialSection(StringRef name, uint32_t outChars) { | |||
2129 | auto it = partialSections.find({name, outChars}); | |||
2130 | if (it != partialSections.end()) | |||
2131 | return it->second; | |||
2132 | return nullptr; | |||
2133 | } | |||
2134 | ||||
2135 | void Writer::fixTlsAlignment() { | |||
2136 | Defined *tlsSym = | |||
2137 | dyn_cast_or_null<Defined>(ctx.symtab.findUnderscore("_tls_used")); | |||
2138 | if (!tlsSym) | |||
2139 | return; | |||
2140 | ||||
2141 | OutputSection *sec = ctx.getOutputSection(tlsSym->getChunk()); | |||
2142 | assert(sec && tlsSym->getRVA() >= sec->getRVA() &&(static_cast <bool> (sec && tlsSym->getRVA() >= sec->getRVA() && "no output section for _tls_used" ) ? void (0) : __assert_fail ("sec && tlsSym->getRVA() >= sec->getRVA() && \"no output section for _tls_used\"" , "lld/COFF/Writer.cpp", 2143, __extension__ __PRETTY_FUNCTION__ )) | |||
2143 | "no output section for _tls_used")(static_cast <bool> (sec && tlsSym->getRVA() >= sec->getRVA() && "no output section for _tls_used" ) ? void (0) : __assert_fail ("sec && tlsSym->getRVA() >= sec->getRVA() && \"no output section for _tls_used\"" , "lld/COFF/Writer.cpp", 2143, __extension__ __PRETTY_FUNCTION__ )); | |||
2144 | ||||
2145 | uint8_t *secBuf = buffer->getBufferStart() + sec->getFileOff(); | |||
2146 | uint64_t tlsOffset = tlsSym->getRVA() - sec->getRVA(); | |||
2147 | uint64_t directorySize = config->is64() | |||
2148 | ? sizeof(object::coff_tls_directory64) | |||
2149 | : sizeof(object::coff_tls_directory32); | |||
2150 | ||||
2151 | if (tlsOffset + directorySize > sec->getRawSize()) | |||
2152 | fatal("_tls_used sym is malformed"); | |||
2153 | ||||
2154 | if (config->is64()) { | |||
2155 | object::coff_tls_directory64 *tlsDir = | |||
2156 | reinterpret_cast<object::coff_tls_directory64 *>(&secBuf[tlsOffset]); | |||
2157 | tlsDir->setAlignment(tlsAlignment); | |||
2158 | } else { | |||
2159 | object::coff_tls_directory32 *tlsDir = | |||
2160 | reinterpret_cast<object::coff_tls_directory32 *>(&secBuf[tlsOffset]); | |||
2161 | tlsDir->setAlignment(tlsAlignment); | |||
2162 | } | |||
2163 | } | |||
2164 | ||||
2165 | void Writer::checkLoadConfig() { | |||
2166 | Symbol *sym = ctx.symtab.findUnderscore("_load_config_used"); | |||
2167 | auto *b = cast_if_present<DefinedRegular>(sym); | |||
2168 | if (!b) { | |||
2169 | if (config->guardCF != GuardCFLevel::Off) | |||
2170 | warn("Control Flow Guard is enabled but '_load_config_used' is missing"); | |||
2171 | return; | |||
2172 | } | |||
2173 | ||||
2174 | OutputSection *sec = ctx.getOutputSection(b->getChunk()); | |||
2175 | uint8_t *buf = buffer->getBufferStart(); | |||
2176 | uint8_t *secBuf = buf + sec->getFileOff(); | |||
2177 | uint8_t *symBuf = secBuf + (b->getRVA() - sec->getRVA()); | |||
2178 | uint32_t expectedAlign = config->is64() ? 8 : 4; | |||
2179 | if (b->getChunk()->getAlignment() < expectedAlign) | |||
2180 | warn("'_load_config_used' is misaligned (expected alignment to be " + | |||
2181 | Twine(expectedAlign) + " bytes, got " + | |||
2182 | Twine(b->getChunk()->getAlignment()) + " instead)"); | |||
2183 | else if (!isAligned(Align(expectedAlign), b->getRVA())) | |||
2184 | warn("'_load_config_used' is misaligned (RVA is 0x" + | |||
2185 | Twine::utohexstr(b->getRVA()) + " not aligned to " + | |||
2186 | Twine(expectedAlign) + " bytes)"); | |||
2187 | ||||
2188 | if (config->is64()) | |||
2189 | checkLoadConfigGuardData( | |||
2190 | reinterpret_cast<const coff_load_configuration64 *>(symBuf)); | |||
2191 | else | |||
2192 | checkLoadConfigGuardData( | |||
2193 | reinterpret_cast<const coff_load_configuration32 *>(symBuf)); | |||
2194 | } | |||
2195 | ||||
2196 | template <typename T> | |||
2197 | void Writer::checkLoadConfigGuardData(const T *loadConfig) { | |||
2198 | size_t loadConfigSize = loadConfig->Size; | |||
2199 | ||||
2200 | #define RETURN_IF_NOT_CONTAINS(field) \ | |||
2201 | if (loadConfigSize < offsetof(T, field)__builtin_offsetof(T, field) + sizeof(T::field)) { \ | |||
2202 | warn("'_load_config_used' structure too small to include " #field); \ | |||
2203 | return; \ | |||
2204 | } | |||
2205 | ||||
2206 | #define IF_CONTAINS(field) \ | |||
2207 | if (loadConfigSize >= offsetof(T, field)__builtin_offsetof(T, field) + sizeof(T::field)) | |||
2208 | ||||
2209 | #define CHECK_VA(field, sym) \ | |||
2210 | if (auto *s = dyn_cast<DefinedSynthetic>(ctx.symtab.findUnderscore(sym))) \ | |||
2211 | if (loadConfig->field != config->imageBase + s->getRVA()) \ | |||
2212 | warn(#field " not set correctly in '_load_config_used'"); | |||
2213 | ||||
2214 | #define CHECK_ABSOLUTE(field, sym) \ | |||
2215 | if (auto *s = dyn_cast<DefinedAbsolute>(ctx.symtab.findUnderscore(sym))) \ | |||
2216 | if (loadConfig->field != s->getVA()) \ | |||
2217 | warn(#field " not set correctly in '_load_config_used'"); | |||
2218 | ||||
2219 | if (config->guardCF == GuardCFLevel::Off) | |||
2220 | return; | |||
2221 | RETURN_IF_NOT_CONTAINS(GuardFlags) | |||
2222 | CHECK_VA(GuardCFFunctionTable, "__guard_fids_table") | |||
2223 | CHECK_ABSOLUTE(GuardCFFunctionCount, "__guard_fids_count") | |||
2224 | CHECK_ABSOLUTE(GuardFlags, "__guard_flags") | |||
2225 | IF_CONTAINS(GuardAddressTakenIatEntryCount) { | |||
2226 | CHECK_VA(GuardAddressTakenIatEntryTable, "__guard_iat_table") | |||
2227 | CHECK_ABSOLUTE(GuardAddressTakenIatEntryCount, "__guard_iat_count") | |||
2228 | } | |||
2229 | ||||
2230 | if (!(config->guardCF & GuardCFLevel::LongJmp)) | |||
2231 | return; | |||
2232 | RETURN_IF_NOT_CONTAINS(GuardLongJumpTargetCount) | |||
2233 | CHECK_VA(GuardLongJumpTargetTable, "__guard_longjmp_table") | |||
2234 | CHECK_ABSOLUTE(GuardLongJumpTargetCount, "__guard_longjmp_count") | |||
2235 | ||||
2236 | if (!(config->guardCF & GuardCFLevel::EHCont)) | |||
2237 | return; | |||
2238 | RETURN_IF_NOT_CONTAINS(GuardEHContinuationCount) | |||
2239 | CHECK_VA(GuardEHContinuationTable, "__guard_eh_cont_table") | |||
2240 | CHECK_ABSOLUTE(GuardEHContinuationCount, "__guard_eh_cont_count") | |||
2241 | ||||
2242 | #undef RETURN_IF_NOT_CONTAINS | |||
2243 | #undef IF_CONTAINS | |||
2244 | #undef CHECK_VA | |||
2245 | #undef CHECK_ABSOLUTE | |||
2246 | } |