Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lld/COFF/Chunks.h
34870 views
1
//===- Chunks.h -------------------------------------------------*- C++ -*-===//
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
#ifndef LLD_COFF_CHUNKS_H
10
#define LLD_COFF_CHUNKS_H
11
12
#include "Config.h"
13
#include "InputFiles.h"
14
#include "lld/Common/LLVM.h"
15
#include "llvm/ADT/ArrayRef.h"
16
#include "llvm/ADT/PointerIntPair.h"
17
#include "llvm/ADT/iterator.h"
18
#include "llvm/ADT/iterator_range.h"
19
#include "llvm/MC/StringTableBuilder.h"
20
#include "llvm/Object/COFF.h"
21
#include "llvm/Object/WindowsMachineFlag.h"
22
#include <utility>
23
#include <vector>
24
25
namespace lld::coff {
26
27
using llvm::COFF::ImportDirectoryTableEntry;
28
using llvm::object::chpe_range_type;
29
using llvm::object::coff_relocation;
30
using llvm::object::coff_section;
31
using llvm::object::COFFSymbolRef;
32
using llvm::object::SectionRef;
33
34
class Baserel;
35
class Defined;
36
class DefinedImportData;
37
class DefinedRegular;
38
class ObjFile;
39
class OutputSection;
40
class RuntimePseudoReloc;
41
class Symbol;
42
43
// Mask for permissions (discardable, writable, readable, executable, etc).
44
const uint32_t permMask = 0xFE000000;
45
46
// Mask for section types (code, data, bss).
47
const uint32_t typeMask = 0x000000E0;
48
49
// The log base 2 of the largest section alignment, which is log2(8192), or 13.
50
enum : unsigned { Log2MaxSectionAlignment = 13 };
51
52
// A Chunk represents a chunk of data that will occupy space in the
53
// output (if the resolver chose that). It may or may not be backed by
54
// a section of an input file. It could be linker-created data, or
55
// doesn't even have actual data (if common or bss).
56
class Chunk {
57
public:
58
enum Kind : uint8_t {
59
SectionKind,
60
SectionECKind,
61
OtherKind,
62
ImportThunkKind
63
};
64
Kind kind() const { return chunkKind; }
65
66
// Returns the size of this chunk (even if this is a common or BSS.)
67
size_t getSize() const;
68
69
// Returns chunk alignment in power of two form. Value values are powers of
70
// two from 1 to 8192.
71
uint32_t getAlignment() const { return 1U << p2Align; }
72
73
// Update the chunk section alignment measured in bytes. Internally alignment
74
// is stored in log2.
75
void setAlignment(uint32_t align) {
76
// Treat zero byte alignment as 1 byte alignment.
77
align = align ? align : 1;
78
assert(llvm::isPowerOf2_32(align) && "alignment is not a power of 2");
79
p2Align = llvm::Log2_32(align);
80
assert(p2Align <= Log2MaxSectionAlignment &&
81
"impossible requested alignment");
82
}
83
84
// Write this chunk to a mmap'ed file, assuming Buf is pointing to
85
// beginning of the file. Because this function may use RVA values
86
// of other chunks for relocations, you need to set them properly
87
// before calling this function.
88
void writeTo(uint8_t *buf) const;
89
90
// The writer sets and uses the addresses. In practice, PE images cannot be
91
// larger than 2GB. Chunks are always laid as part of the image, so Chunk RVAs
92
// can be stored with 32 bits.
93
uint32_t getRVA() const { return rva; }
94
void setRVA(uint64_t v) {
95
// This may truncate. The writer checks for overflow later.
96
rva = (uint32_t)v;
97
}
98
99
// Returns readable/writable/executable bits.
100
uint32_t getOutputCharacteristics() const;
101
102
// Returns the section name if this is a section chunk.
103
// It is illegal to call this function on non-section chunks.
104
StringRef getSectionName() const;
105
106
// An output section has pointers to chunks in the section, and each
107
// chunk has a back pointer to an output section.
108
void setOutputSectionIdx(uint16_t o) { osidx = o; }
109
uint16_t getOutputSectionIdx() const { return osidx; }
110
111
// Windows-specific.
112
// Collect all locations that contain absolute addresses for base relocations.
113
void getBaserels(std::vector<Baserel> *res);
114
115
// Returns a human-readable name of this chunk. Chunks are unnamed chunks of
116
// bytes, so this is used only for logging or debugging.
117
StringRef getDebugName() const;
118
119
// Return true if this file has the hotpatch flag set to true in the
120
// S_COMPILE3 record in codeview debug info. Also returns true for some thunks
121
// synthesized by the linker.
122
bool isHotPatchable() const;
123
124
MachineTypes getMachine() const;
125
llvm::Triple::ArchType getArch() const;
126
std::optional<chpe_range_type> getArm64ECRangeType() const;
127
128
// ARM64EC entry thunk associated with the chunk.
129
Defined *getEntryThunk() const;
130
void setEntryThunk(Defined *entryThunk);
131
132
protected:
133
Chunk(Kind k = OtherKind) : chunkKind(k), hasData(true), p2Align(0) {}
134
135
const Kind chunkKind;
136
137
public:
138
// Returns true if this has non-zero data. BSS chunks return
139
// false. If false is returned, the space occupied by this chunk
140
// will be filled with zeros. Corresponds to the
141
// IMAGE_SCN_CNT_UNINITIALIZED_DATA section characteristic bit.
142
uint8_t hasData : 1;
143
144
public:
145
// The alignment of this chunk, stored in log2 form. The writer uses the
146
// value.
147
uint8_t p2Align : 7;
148
149
// The output section index for this chunk. The first valid section number is
150
// one.
151
uint16_t osidx = 0;
152
153
// The RVA of this chunk in the output. The writer sets a value.
154
uint32_t rva = 0;
155
};
156
157
class NonSectionChunk : public Chunk {
158
public:
159
virtual ~NonSectionChunk() = default;
160
161
// Returns the size of this chunk (even if this is a common or BSS.)
162
virtual size_t getSize() const = 0;
163
164
virtual uint32_t getOutputCharacteristics() const { return 0; }
165
166
// Write this chunk to a mmap'ed file, assuming Buf is pointing to
167
// beginning of the file. Because this function may use RVA values
168
// of other chunks for relocations, you need to set them properly
169
// before calling this function.
170
virtual void writeTo(uint8_t *buf) const {}
171
172
// Returns the section name if this is a section chunk.
173
// It is illegal to call this function on non-section chunks.
174
virtual StringRef getSectionName() const {
175
llvm_unreachable("unimplemented getSectionName");
176
}
177
178
// Windows-specific.
179
// Collect all locations that contain absolute addresses for base relocations.
180
virtual void getBaserels(std::vector<Baserel> *res) {}
181
182
virtual MachineTypes getMachine() const { return IMAGE_FILE_MACHINE_UNKNOWN; }
183
184
// Returns a human-readable name of this chunk. Chunks are unnamed chunks of
185
// bytes, so this is used only for logging or debugging.
186
virtual StringRef getDebugName() const { return ""; }
187
188
static bool classof(const Chunk *c) { return c->kind() >= OtherKind; }
189
190
protected:
191
NonSectionChunk(Kind k = OtherKind) : Chunk(k) {}
192
};
193
194
class NonSectionCodeChunk : public NonSectionChunk {
195
public:
196
virtual uint32_t getOutputCharacteristics() const override {
197
return llvm::COFF::IMAGE_SCN_MEM_READ | llvm::COFF::IMAGE_SCN_MEM_EXECUTE;
198
}
199
200
protected:
201
NonSectionCodeChunk(Kind k = OtherKind) : NonSectionChunk(k) {}
202
};
203
204
// MinGW specific; information about one individual location in the image
205
// that needs to be fixed up at runtime after loading. This represents
206
// one individual element in the PseudoRelocTableChunk table.
207
class RuntimePseudoReloc {
208
public:
209
RuntimePseudoReloc(Defined *sym, SectionChunk *target, uint32_t targetOffset,
210
int flags)
211
: sym(sym), target(target), targetOffset(targetOffset), flags(flags) {}
212
213
Defined *sym;
214
SectionChunk *target;
215
uint32_t targetOffset;
216
// The Flags field contains the size of the relocation, in bits. No other
217
// flags are currently defined.
218
int flags;
219
};
220
221
// A chunk corresponding a section of an input file.
222
class SectionChunk : public Chunk {
223
// Identical COMDAT Folding feature accesses section internal data.
224
friend class ICF;
225
226
public:
227
class symbol_iterator : public llvm::iterator_adaptor_base<
228
symbol_iterator, const coff_relocation *,
229
std::random_access_iterator_tag, Symbol *> {
230
friend SectionChunk;
231
232
ObjFile *file;
233
234
symbol_iterator(ObjFile *file, const coff_relocation *i)
235
: symbol_iterator::iterator_adaptor_base(i), file(file) {}
236
237
public:
238
symbol_iterator() = default;
239
240
Symbol *operator*() const { return file->getSymbol(I->SymbolTableIndex); }
241
};
242
243
SectionChunk(ObjFile *file, const coff_section *header, Kind k = SectionKind);
244
static bool classof(const Chunk *c) { return c->kind() <= SectionECKind; }
245
size_t getSize() const { return header->SizeOfRawData; }
246
ArrayRef<uint8_t> getContents() const;
247
void writeTo(uint8_t *buf) const;
248
249
MachineTypes getMachine() const { return file->getMachineType(); }
250
251
// Defend against unsorted relocations. This may be overly conservative.
252
void sortRelocations();
253
254
// Write and relocate a portion of the section. This is intended to be called
255
// in a loop. Relocations must be sorted first.
256
void writeAndRelocateSubsection(ArrayRef<uint8_t> sec,
257
ArrayRef<uint8_t> subsec,
258
uint32_t &nextRelocIndex, uint8_t *buf) const;
259
260
uint32_t getOutputCharacteristics() const {
261
return header->Characteristics & (permMask | typeMask);
262
}
263
StringRef getSectionName() const {
264
return StringRef(sectionNameData, sectionNameSize);
265
}
266
void getBaserels(std::vector<Baserel> *res);
267
bool isCOMDAT() const;
268
void applyRelocation(uint8_t *off, const coff_relocation &rel) const;
269
void applyRelX64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
270
uint64_t p, uint64_t imageBase) const;
271
void applyRelX86(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
272
uint64_t p, uint64_t imageBase) const;
273
void applyRelARM(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
274
uint64_t p, uint64_t imageBase) const;
275
void applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,
276
uint64_t p, uint64_t imageBase) const;
277
278
void getRuntimePseudoRelocs(std::vector<RuntimePseudoReloc> &res);
279
280
// Called if the garbage collector decides to not include this chunk
281
// in a final output. It's supposed to print out a log message to stdout.
282
void printDiscardedMessage() const;
283
284
// Adds COMDAT associative sections to this COMDAT section. A chunk
285
// and its children are treated as a group by the garbage collector.
286
void addAssociative(SectionChunk *child);
287
288
StringRef getDebugName() const;
289
290
// True if this is a codeview debug info chunk. These will not be laid out in
291
// the image. Instead they will end up in the PDB, if one is requested.
292
bool isCodeView() const {
293
return getSectionName() == ".debug" || getSectionName().starts_with(".debug$");
294
}
295
296
// True if this is a DWARF debug info or exception handling chunk.
297
bool isDWARF() const {
298
return getSectionName().starts_with(".debug_") || getSectionName() == ".eh_frame";
299
}
300
301
// Allow iteration over the bodies of this chunk's relocated symbols.
302
llvm::iterator_range<symbol_iterator> symbols() const {
303
return llvm::make_range(symbol_iterator(file, relocsData),
304
symbol_iterator(file, relocsData + relocsSize));
305
}
306
307
ArrayRef<coff_relocation> getRelocs() const {
308
return llvm::ArrayRef(relocsData, relocsSize);
309
}
310
311
// Reloc setter used by ARM range extension thunk insertion.
312
void setRelocs(ArrayRef<coff_relocation> newRelocs) {
313
relocsData = newRelocs.data();
314
relocsSize = newRelocs.size();
315
assert(relocsSize == newRelocs.size() && "reloc size truncation");
316
}
317
318
// Single linked list iterator for associated comdat children.
319
class AssociatedIterator
320
: public llvm::iterator_facade_base<
321
AssociatedIterator, std::forward_iterator_tag, SectionChunk> {
322
public:
323
AssociatedIterator() = default;
324
AssociatedIterator(SectionChunk *head) : cur(head) {}
325
bool operator==(const AssociatedIterator &r) const { return cur == r.cur; }
326
// FIXME: Wrong const-ness, but it makes filter ranges work.
327
SectionChunk &operator*() const { return *cur; }
328
SectionChunk &operator*() { return *cur; }
329
AssociatedIterator &operator++() {
330
cur = cur->assocChildren;
331
return *this;
332
}
333
334
private:
335
SectionChunk *cur = nullptr;
336
};
337
338
// Allow iteration over the associated child chunks for this section.
339
llvm::iterator_range<AssociatedIterator> children() const {
340
// Associated sections do not have children. The assocChildren field is
341
// part of the parent's list of children.
342
bool isAssoc = selection == llvm::COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE;
343
return llvm::make_range(
344
AssociatedIterator(isAssoc ? nullptr : assocChildren),
345
AssociatedIterator(nullptr));
346
}
347
348
// The section ID this chunk belongs to in its Obj.
349
uint32_t getSectionNumber() const;
350
351
ArrayRef<uint8_t> consumeDebugMagic();
352
353
static ArrayRef<uint8_t> consumeDebugMagic(ArrayRef<uint8_t> data,
354
StringRef sectionName);
355
356
static SectionChunk *findByName(ArrayRef<SectionChunk *> sections,
357
StringRef name);
358
359
// The file that this chunk was created from.
360
ObjFile *file;
361
362
// Pointer to the COFF section header in the input file.
363
const coff_section *header;
364
365
// The COMDAT leader symbol if this is a COMDAT chunk.
366
DefinedRegular *sym = nullptr;
367
368
// The CRC of the contents as described in the COFF spec 4.5.5.
369
// Auxiliary Format 5: Section Definitions. Used for ICF.
370
uint32_t checksum = 0;
371
372
// Used by the garbage collector.
373
bool live;
374
375
// Whether this section needs to be kept distinct from other sections during
376
// ICF. This is set by the driver using address-significance tables.
377
bool keepUnique = false;
378
379
// The COMDAT selection if this is a COMDAT chunk.
380
llvm::COFF::COMDATType selection = (llvm::COFF::COMDATType)0;
381
382
// A pointer pointing to a replacement for this chunk.
383
// Initially it points to "this" object. If this chunk is merged
384
// with other chunk by ICF, it points to another chunk,
385
// and this chunk is considered as dead.
386
SectionChunk *repl;
387
388
private:
389
SectionChunk *assocChildren = nullptr;
390
391
// Used for ICF (Identical COMDAT Folding)
392
void replace(SectionChunk *other);
393
uint32_t eqClass[2] = {0, 0};
394
395
// Relocations for this section. Size is stored below.
396
const coff_relocation *relocsData;
397
398
// Section name string. Size is stored below.
399
const char *sectionNameData;
400
401
uint32_t relocsSize = 0;
402
uint32_t sectionNameSize = 0;
403
};
404
405
// A section chunk corresponding a section of an EC input file.
406
class SectionChunkEC final : public SectionChunk {
407
public:
408
static bool classof(const Chunk *c) { return c->kind() == SectionECKind; }
409
410
SectionChunkEC(ObjFile *file, const coff_section *header)
411
: SectionChunk(file, header, SectionECKind) {}
412
Defined *entryThunk = nullptr;
413
};
414
415
// Inline methods to implement faux-virtual dispatch for SectionChunk.
416
417
inline size_t Chunk::getSize() const {
418
if (isa<SectionChunk>(this))
419
return static_cast<const SectionChunk *>(this)->getSize();
420
return static_cast<const NonSectionChunk *>(this)->getSize();
421
}
422
423
inline uint32_t Chunk::getOutputCharacteristics() const {
424
if (isa<SectionChunk>(this))
425
return static_cast<const SectionChunk *>(this)->getOutputCharacteristics();
426
return static_cast<const NonSectionChunk *>(this)->getOutputCharacteristics();
427
}
428
429
inline void Chunk::writeTo(uint8_t *buf) const {
430
if (isa<SectionChunk>(this))
431
static_cast<const SectionChunk *>(this)->writeTo(buf);
432
else
433
static_cast<const NonSectionChunk *>(this)->writeTo(buf);
434
}
435
436
inline StringRef Chunk::getSectionName() const {
437
if (isa<SectionChunk>(this))
438
return static_cast<const SectionChunk *>(this)->getSectionName();
439
return static_cast<const NonSectionChunk *>(this)->getSectionName();
440
}
441
442
inline void Chunk::getBaserels(std::vector<Baserel> *res) {
443
if (isa<SectionChunk>(this))
444
static_cast<SectionChunk *>(this)->getBaserels(res);
445
else
446
static_cast<NonSectionChunk *>(this)->getBaserels(res);
447
}
448
449
inline StringRef Chunk::getDebugName() const {
450
if (isa<SectionChunk>(this))
451
return static_cast<const SectionChunk *>(this)->getDebugName();
452
return static_cast<const NonSectionChunk *>(this)->getDebugName();
453
}
454
455
inline MachineTypes Chunk::getMachine() const {
456
if (isa<SectionChunk>(this))
457
return static_cast<const SectionChunk *>(this)->getMachine();
458
return static_cast<const NonSectionChunk *>(this)->getMachine();
459
}
460
461
inline llvm::Triple::ArchType Chunk::getArch() const {
462
return llvm::getMachineArchType(getMachine());
463
}
464
465
inline std::optional<chpe_range_type> Chunk::getArm64ECRangeType() const {
466
// Data sections don't need codemap entries.
467
if (!(getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE))
468
return std::nullopt;
469
470
switch (getMachine()) {
471
case AMD64:
472
return chpe_range_type::Amd64;
473
case ARM64EC:
474
return chpe_range_type::Arm64EC;
475
default:
476
return chpe_range_type::Arm64;
477
}
478
}
479
480
// This class is used to implement an lld-specific feature (not implemented in
481
// MSVC) that minimizes the output size by finding string literals sharing tail
482
// parts and merging them.
483
//
484
// If string tail merging is enabled and a section is identified as containing a
485
// string literal, it is added to a MergeChunk with an appropriate alignment.
486
// The MergeChunk then tail merges the strings using the StringTableBuilder
487
// class and assigns RVAs and section offsets to each of the member chunks based
488
// on the offsets assigned by the StringTableBuilder.
489
class MergeChunk : public NonSectionChunk {
490
public:
491
MergeChunk(uint32_t alignment);
492
static void addSection(COFFLinkerContext &ctx, SectionChunk *c);
493
void finalizeContents();
494
void assignSubsectionRVAs();
495
496
uint32_t getOutputCharacteristics() const override;
497
StringRef getSectionName() const override { return ".rdata"; }
498
size_t getSize() const override;
499
void writeTo(uint8_t *buf) const override;
500
501
std::vector<SectionChunk *> sections;
502
503
private:
504
llvm::StringTableBuilder builder;
505
bool finalized = false;
506
};
507
508
// A chunk for common symbols. Common chunks don't have actual data.
509
class CommonChunk : public NonSectionChunk {
510
public:
511
CommonChunk(const COFFSymbolRef sym);
512
size_t getSize() const override { return sym.getValue(); }
513
uint32_t getOutputCharacteristics() const override;
514
StringRef getSectionName() const override { return ".bss"; }
515
516
private:
517
const COFFSymbolRef sym;
518
};
519
520
// A chunk for linker-created strings.
521
class StringChunk : public NonSectionChunk {
522
public:
523
explicit StringChunk(StringRef s) : str(s) {}
524
size_t getSize() const override { return str.size() + 1; }
525
void writeTo(uint8_t *buf) const override;
526
527
private:
528
StringRef str;
529
};
530
531
static const uint8_t importThunkX86[] = {
532
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0
533
};
534
535
static const uint8_t importThunkARM[] = {
536
0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0
537
0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0
538
0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip]
539
};
540
541
static const uint8_t importThunkARM64[] = {
542
0x10, 0x00, 0x00, 0x90, // adrp x16, #0
543
0x10, 0x02, 0x40, 0xf9, // ldr x16, [x16]
544
0x00, 0x02, 0x1f, 0xd6, // br x16
545
};
546
547
// Windows-specific.
548
// A chunk for DLL import jump table entry. In a final output, its
549
// contents will be a JMP instruction to some __imp_ symbol.
550
class ImportThunkChunk : public NonSectionCodeChunk {
551
public:
552
ImportThunkChunk(COFFLinkerContext &ctx, Defined *s)
553
: NonSectionCodeChunk(ImportThunkKind), impSymbol(s), ctx(ctx) {}
554
static bool classof(const Chunk *c) { return c->kind() == ImportThunkKind; }
555
556
protected:
557
Defined *impSymbol;
558
COFFLinkerContext &ctx;
559
};
560
561
class ImportThunkChunkX64 : public ImportThunkChunk {
562
public:
563
explicit ImportThunkChunkX64(COFFLinkerContext &ctx, Defined *s);
564
size_t getSize() const override { return sizeof(importThunkX86); }
565
void writeTo(uint8_t *buf) const override;
566
MachineTypes getMachine() const override { return AMD64; }
567
};
568
569
class ImportThunkChunkX86 : public ImportThunkChunk {
570
public:
571
explicit ImportThunkChunkX86(COFFLinkerContext &ctx, Defined *s)
572
: ImportThunkChunk(ctx, s) {}
573
size_t getSize() const override { return sizeof(importThunkX86); }
574
void getBaserels(std::vector<Baserel> *res) override;
575
void writeTo(uint8_t *buf) const override;
576
MachineTypes getMachine() const override { return I386; }
577
};
578
579
class ImportThunkChunkARM : public ImportThunkChunk {
580
public:
581
explicit ImportThunkChunkARM(COFFLinkerContext &ctx, Defined *s)
582
: ImportThunkChunk(ctx, s) {
583
setAlignment(2);
584
}
585
size_t getSize() const override { return sizeof(importThunkARM); }
586
void getBaserels(std::vector<Baserel> *res) override;
587
void writeTo(uint8_t *buf) const override;
588
MachineTypes getMachine() const override { return ARMNT; }
589
};
590
591
class ImportThunkChunkARM64 : public ImportThunkChunk {
592
public:
593
explicit ImportThunkChunkARM64(COFFLinkerContext &ctx, Defined *s)
594
: ImportThunkChunk(ctx, s) {
595
setAlignment(4);
596
}
597
size_t getSize() const override { return sizeof(importThunkARM64); }
598
void writeTo(uint8_t *buf) const override;
599
MachineTypes getMachine() const override { return ARM64; }
600
};
601
602
class RangeExtensionThunkARM : public NonSectionCodeChunk {
603
public:
604
explicit RangeExtensionThunkARM(COFFLinkerContext &ctx, Defined *t)
605
: target(t), ctx(ctx) {
606
setAlignment(2);
607
}
608
size_t getSize() const override;
609
void writeTo(uint8_t *buf) const override;
610
MachineTypes getMachine() const override { return ARMNT; }
611
612
Defined *target;
613
614
private:
615
COFFLinkerContext &ctx;
616
};
617
618
class RangeExtensionThunkARM64 : public NonSectionCodeChunk {
619
public:
620
explicit RangeExtensionThunkARM64(COFFLinkerContext &ctx, Defined *t)
621
: target(t), ctx(ctx) {
622
setAlignment(4);
623
}
624
size_t getSize() const override;
625
void writeTo(uint8_t *buf) const override;
626
MachineTypes getMachine() const override { return ARM64; }
627
628
Defined *target;
629
630
private:
631
COFFLinkerContext &ctx;
632
};
633
634
// Windows-specific.
635
// See comments for DefinedLocalImport class.
636
class LocalImportChunk : public NonSectionChunk {
637
public:
638
explicit LocalImportChunk(COFFLinkerContext &ctx, Defined *s);
639
size_t getSize() const override;
640
void getBaserels(std::vector<Baserel> *res) override;
641
void writeTo(uint8_t *buf) const override;
642
643
private:
644
Defined *sym;
645
COFFLinkerContext &ctx;
646
};
647
648
// Duplicate RVAs are not allowed in RVA tables, so unique symbols by chunk and
649
// offset into the chunk. Order does not matter as the RVA table will be sorted
650
// later.
651
struct ChunkAndOffset {
652
Chunk *inputChunk;
653
uint32_t offset;
654
655
struct DenseMapInfo {
656
static ChunkAndOffset getEmptyKey() {
657
return {llvm::DenseMapInfo<Chunk *>::getEmptyKey(), 0};
658
}
659
static ChunkAndOffset getTombstoneKey() {
660
return {llvm::DenseMapInfo<Chunk *>::getTombstoneKey(), 0};
661
}
662
static unsigned getHashValue(const ChunkAndOffset &co) {
663
return llvm::DenseMapInfo<std::pair<Chunk *, uint32_t>>::getHashValue(
664
{co.inputChunk, co.offset});
665
}
666
static bool isEqual(const ChunkAndOffset &lhs, const ChunkAndOffset &rhs) {
667
return lhs.inputChunk == rhs.inputChunk && lhs.offset == rhs.offset;
668
}
669
};
670
};
671
672
using SymbolRVASet = llvm::DenseSet<ChunkAndOffset>;
673
674
// Table which contains symbol RVAs. Used for /safeseh and /guard:cf.
675
class RVATableChunk : public NonSectionChunk {
676
public:
677
explicit RVATableChunk(SymbolRVASet s) : syms(std::move(s)) {}
678
size_t getSize() const override { return syms.size() * 4; }
679
void writeTo(uint8_t *buf) const override;
680
681
private:
682
SymbolRVASet syms;
683
};
684
685
// Table which contains symbol RVAs with flags. Used for /guard:ehcont.
686
class RVAFlagTableChunk : public NonSectionChunk {
687
public:
688
explicit RVAFlagTableChunk(SymbolRVASet s) : syms(std::move(s)) {}
689
size_t getSize() const override { return syms.size() * 5; }
690
void writeTo(uint8_t *buf) const override;
691
692
private:
693
SymbolRVASet syms;
694
};
695
696
// Windows-specific.
697
// This class represents a block in .reloc section.
698
// See the PE/COFF spec 5.6 for details.
699
class BaserelChunk : public NonSectionChunk {
700
public:
701
BaserelChunk(uint32_t page, Baserel *begin, Baserel *end);
702
size_t getSize() const override { return data.size(); }
703
void writeTo(uint8_t *buf) const override;
704
705
private:
706
std::vector<uint8_t> data;
707
};
708
709
class Baserel {
710
public:
711
Baserel(uint32_t v, uint8_t ty) : rva(v), type(ty) {}
712
explicit Baserel(uint32_t v, llvm::COFF::MachineTypes machine)
713
: Baserel(v, getDefaultType(machine)) {}
714
uint8_t getDefaultType(llvm::COFF::MachineTypes machine);
715
716
uint32_t rva;
717
uint8_t type;
718
};
719
720
// This is a placeholder Chunk, to allow attaching a DefinedSynthetic to a
721
// specific place in a section, without any data. This is used for the MinGW
722
// specific symbol __RUNTIME_PSEUDO_RELOC_LIST_END__, even though the concept
723
// of an empty chunk isn't MinGW specific.
724
class EmptyChunk : public NonSectionChunk {
725
public:
726
EmptyChunk() {}
727
size_t getSize() const override { return 0; }
728
void writeTo(uint8_t *buf) const override {}
729
};
730
731
class ECCodeMapEntry {
732
public:
733
ECCodeMapEntry(Chunk *first, Chunk *last, chpe_range_type type)
734
: first(first), last(last), type(type) {}
735
Chunk *first;
736
Chunk *last;
737
chpe_range_type type;
738
};
739
740
// This is a chunk containing CHPE code map on EC targets. It's a table
741
// of address ranges and their types.
742
class ECCodeMapChunk : public NonSectionChunk {
743
public:
744
ECCodeMapChunk(std::vector<ECCodeMapEntry> &map) : map(map) {}
745
size_t getSize() const override;
746
void writeTo(uint8_t *buf) const override;
747
748
private:
749
std::vector<ECCodeMapEntry> &map;
750
};
751
752
// MinGW specific, for the "automatic import of variables from DLLs" feature.
753
// This provides the table of runtime pseudo relocations, for variable
754
// references that turned out to need to be imported from a DLL even though
755
// the reference didn't use the dllimport attribute. The MinGW runtime will
756
// process this table after loading, before handling control over to user
757
// code.
758
class PseudoRelocTableChunk : public NonSectionChunk {
759
public:
760
PseudoRelocTableChunk(std::vector<RuntimePseudoReloc> &relocs)
761
: relocs(std::move(relocs)) {
762
setAlignment(4);
763
}
764
size_t getSize() const override;
765
void writeTo(uint8_t *buf) const override;
766
767
private:
768
std::vector<RuntimePseudoReloc> relocs;
769
};
770
771
// MinGW specific. A Chunk that contains one pointer-sized absolute value.
772
class AbsolutePointerChunk : public NonSectionChunk {
773
public:
774
AbsolutePointerChunk(COFFLinkerContext &ctx, uint64_t value)
775
: value(value), ctx(ctx) {
776
setAlignment(getSize());
777
}
778
size_t getSize() const override;
779
void writeTo(uint8_t *buf) const override;
780
781
private:
782
uint64_t value;
783
COFFLinkerContext &ctx;
784
};
785
786
// Return true if this file has the hotpatch flag set to true in the S_COMPILE3
787
// record in codeview debug info. Also returns true for some thunks synthesized
788
// by the linker.
789
inline bool Chunk::isHotPatchable() const {
790
if (auto *sc = dyn_cast<SectionChunk>(this))
791
return sc->file->hotPatchable;
792
else if (isa<ImportThunkChunk>(this))
793
return true;
794
return false;
795
}
796
797
inline Defined *Chunk::getEntryThunk() const {
798
if (auto *c = dyn_cast<const SectionChunkEC>(this))
799
return c->entryThunk;
800
return nullptr;
801
}
802
803
inline void Chunk::setEntryThunk(Defined *entryThunk) {
804
if (auto c = dyn_cast<SectionChunkEC>(this))
805
c->entryThunk = entryThunk;
806
}
807
808
void applyMOV32T(uint8_t *off, uint32_t v);
809
void applyBranch24T(uint8_t *off, int32_t v);
810
811
void applyArm64Addr(uint8_t *off, uint64_t s, uint64_t p, int shift);
812
void applyArm64Imm(uint8_t *off, uint64_t imm, uint32_t rangeLimit);
813
void applyArm64Branch26(uint8_t *off, int64_t v);
814
815
// Convenience class for initializing a coff_section with specific flags.
816
class FakeSection {
817
public:
818
FakeSection(int c) { section.Characteristics = c; }
819
820
coff_section section;
821
};
822
823
// Convenience class for initializing a SectionChunk with specific flags.
824
class FakeSectionChunk {
825
public:
826
FakeSectionChunk(const coff_section *section) : chunk(nullptr, section) {
827
// Comdats from LTO files can't be fully treated as regular comdats
828
// at this point; we don't know what size or contents they are going to
829
// have, so we can't do proper checking of such aspects of them.
830
chunk.selection = llvm::COFF::IMAGE_COMDAT_SELECT_ANY;
831
}
832
833
SectionChunk chunk;
834
};
835
836
} // namespace lld::coff
837
838
namespace llvm {
839
template <>
840
struct DenseMapInfo<lld::coff::ChunkAndOffset>
841
: lld::coff::ChunkAndOffset::DenseMapInfo {};
842
}
843
844
#endif
845
846