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 // Verify that chunk relocations are within their ranges. 189 virtual bool verifyRanges() { return true; }; 190 191 // If needed, extend the chunk to ensure all relocations are within the 192 // allowed ranges. Return the additional space required for the extension. 193 virtual uint32_t extendRanges() { return 0; }; 194 195 static bool classof(const Chunk *c) { return c->kind() >= OtherKind; } 196 197 protected: 198 NonSectionChunk(Kind k = OtherKind) : Chunk(k) {} 199 }; 200 201 class NonSectionCodeChunk : public NonSectionChunk { 202 public: 203 virtual uint32_t getOutputCharacteristics() const override { 204 return llvm::COFF::IMAGE_SCN_MEM_READ | llvm::COFF::IMAGE_SCN_MEM_EXECUTE; 205 } 206 207 protected: 208 NonSectionCodeChunk(Kind k = OtherKind) : NonSectionChunk(k) {} 209 }; 210 211 // MinGW specific; information about one individual location in the image 212 // that needs to be fixed up at runtime after loading. This represents 213 // one individual element in the PseudoRelocTableChunk table. 214 class RuntimePseudoReloc { 215 public: 216 RuntimePseudoReloc(Defined *sym, SectionChunk *target, uint32_t targetOffset, 217 int flags) 218 : sym(sym), target(target), targetOffset(targetOffset), flags(flags) {} 219 220 Defined *sym; 221 SectionChunk *target; 222 uint32_t targetOffset; 223 // The Flags field contains the size of the relocation, in bits. No other 224 // flags are currently defined. 225 int flags; 226 }; 227 228 // A chunk corresponding a section of an input file. 229 class SectionChunk : public Chunk { 230 // Identical COMDAT Folding feature accesses section internal data. 231 friend class ICF; 232 233 public: 234 class symbol_iterator : public llvm::iterator_adaptor_base< 235 symbol_iterator, const coff_relocation *, 236 std::random_access_iterator_tag, Symbol *> { 237 friend SectionChunk; 238 239 ObjFile *file; 240 241 symbol_iterator(ObjFile *file, const coff_relocation *i) 242 : symbol_iterator::iterator_adaptor_base(i), file(file) {} 243 244 public: 245 symbol_iterator() = default; 246 247 Symbol *operator*() const { return file->getSymbol(I->SymbolTableIndex); } 248 }; 249 250 SectionChunk(ObjFile *file, const coff_section *header, Kind k = SectionKind); 251 static bool classof(const Chunk *c) { return c->kind() <= SectionECKind; } 252 size_t getSize() const { return header->SizeOfRawData; } 253 ArrayRef<uint8_t> getContents() const; 254 void writeTo(uint8_t *buf) const; 255 256 MachineTypes getMachine() const { return file->getMachineType(); } 257 258 // Defend against unsorted relocations. This may be overly conservative. 259 void sortRelocations(); 260 261 // Write and relocate a portion of the section. This is intended to be called 262 // in a loop. Relocations must be sorted first. 263 void writeAndRelocateSubsection(ArrayRef<uint8_t> sec, 264 ArrayRef<uint8_t> subsec, 265 uint32_t &nextRelocIndex, uint8_t *buf) const; 266 267 uint32_t getOutputCharacteristics() const { 268 return header->Characteristics & (permMask | typeMask); 269 } 270 StringRef getSectionName() const { 271 return StringRef(sectionNameData, sectionNameSize); 272 } 273 void getBaserels(std::vector<Baserel> *res); 274 bool isCOMDAT() const; 275 void applyRelocation(uint8_t *off, const coff_relocation &rel) const; 276 void applyRelX64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s, 277 uint64_t p, uint64_t imageBase) const; 278 void applyRelX86(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s, 279 uint64_t p, uint64_t imageBase) const; 280 void applyRelARM(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s, 281 uint64_t p, uint64_t imageBase) const; 282 void applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s, 283 uint64_t p, uint64_t imageBase) const; 284 285 void getRuntimePseudoRelocs(std::vector<RuntimePseudoReloc> &res); 286 287 // Called if the garbage collector decides to not include this chunk 288 // in a final output. It's supposed to print out a log message to stdout. 289 void printDiscardedMessage() const; 290 291 // Adds COMDAT associative sections to this COMDAT section. A chunk 292 // and its children are treated as a group by the garbage collector. 293 void addAssociative(SectionChunk *child); 294 295 StringRef getDebugName() const; 296 297 // True if this is a codeview debug info chunk. These will not be laid out in 298 // the image. Instead they will end up in the PDB, if one is requested. 299 bool isCodeView() const { 300 return getSectionName() == ".debug" || getSectionName().starts_with(".debug$"); 301 } 302 303 // True if this is a DWARF debug info or exception handling chunk. 304 bool isDWARF() const { 305 return getSectionName().starts_with(".debug_") || getSectionName() == ".eh_frame"; 306 } 307 308 // Allow iteration over the bodies of this chunk's relocated symbols. 309 llvm::iterator_range<symbol_iterator> symbols() const { 310 return llvm::make_range(symbol_iterator(file, relocsData), 311 symbol_iterator(file, relocsData + relocsSize)); 312 } 313 314 ArrayRef<coff_relocation> getRelocs() const { 315 return llvm::ArrayRef(relocsData, relocsSize); 316 } 317 318 // Reloc setter used by ARM range extension thunk insertion. 319 void setRelocs(ArrayRef<coff_relocation> newRelocs) { 320 relocsData = newRelocs.data(); 321 relocsSize = newRelocs.size(); 322 assert(relocsSize == newRelocs.size() && "reloc size truncation"); 323 } 324 325 // Single linked list iterator for associated comdat children. 326 class AssociatedIterator 327 : public llvm::iterator_facade_base< 328 AssociatedIterator, std::forward_iterator_tag, SectionChunk> { 329 public: 330 AssociatedIterator() = default; 331 AssociatedIterator(SectionChunk *head) : cur(head) {} 332 bool operator==(const AssociatedIterator &r) const { return cur == r.cur; } 333 // FIXME: Wrong const-ness, but it makes filter ranges work. 334 SectionChunk &operator*() const { return *cur; } 335 SectionChunk &operator*() { return *cur; } 336 AssociatedIterator &operator++() { 337 cur = cur->assocChildren; 338 return *this; 339 } 340 341 private: 342 SectionChunk *cur = nullptr; 343 }; 344 345 // Allow iteration over the associated child chunks for this section. 346 llvm::iterator_range<AssociatedIterator> children() const { 347 // Associated sections do not have children. The assocChildren field is 348 // part of the parent's list of children. 349 bool isAssoc = selection == llvm::COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE; 350 return llvm::make_range( 351 AssociatedIterator(isAssoc ? nullptr : assocChildren), 352 AssociatedIterator(nullptr)); 353 } 354 355 // The section ID this chunk belongs to in its Obj. 356 uint32_t getSectionNumber() const; 357 358 ArrayRef<uint8_t> consumeDebugMagic(); 359 360 static ArrayRef<uint8_t> consumeDebugMagic(ArrayRef<uint8_t> data, 361 StringRef sectionName); 362 363 static SectionChunk *findByName(ArrayRef<SectionChunk *> sections, 364 StringRef name); 365 366 // The file that this chunk was created from. 367 ObjFile *file; 368 369 // Pointer to the COFF section header in the input file. 370 const coff_section *header; 371 372 // The COMDAT leader symbol if this is a COMDAT chunk. 373 DefinedRegular *sym = nullptr; 374 375 // The CRC of the contents as described in the COFF spec 4.5.5. 376 // Auxiliary Format 5: Section Definitions. Used for ICF. 377 uint32_t checksum = 0; 378 379 // Used by the garbage collector. 380 bool live; 381 382 // Whether this section needs to be kept distinct from other sections during 383 // ICF. This is set by the driver using address-significance tables. 384 bool keepUnique = false; 385 386 // The COMDAT selection if this is a COMDAT chunk. 387 llvm::COFF::COMDATType selection = (llvm::COFF::COMDATType)0; 388 389 // A pointer pointing to a replacement for this chunk. 390 // Initially it points to "this" object. If this chunk is merged 391 // with other chunk by ICF, it points to another chunk, 392 // and this chunk is considered as dead. 393 SectionChunk *repl; 394 395 private: 396 SectionChunk *assocChildren = nullptr; 397 398 // Used for ICF (Identical COMDAT Folding) 399 void replace(SectionChunk *other); 400 uint32_t eqClass[2] = {0, 0}; 401 402 // Relocations for this section. Size is stored below. 403 const coff_relocation *relocsData; 404 405 // Section name string. Size is stored below. 406 const char *sectionNameData; 407 408 uint32_t relocsSize = 0; 409 uint32_t sectionNameSize = 0; 410 }; 411 412 // A section chunk corresponding a section of an EC input file. 413 class SectionChunkEC final : public SectionChunk { 414 public: 415 static bool classof(const Chunk *c) { return c->kind() == SectionECKind; } 416 417 SectionChunkEC(ObjFile *file, const coff_section *header) 418 : SectionChunk(file, header, SectionECKind) {} 419 Defined *entryThunk = nullptr; 420 }; 421 422 // Inline methods to implement faux-virtual dispatch for SectionChunk. 423 424 inline size_t Chunk::getSize() const { 425 if (isa<SectionChunk>(this)) 426 return static_cast<const SectionChunk *>(this)->getSize(); 427 return static_cast<const NonSectionChunk *>(this)->getSize(); 428 } 429 430 inline uint32_t Chunk::getOutputCharacteristics() const { 431 if (isa<SectionChunk>(this)) 432 return static_cast<const SectionChunk *>(this)->getOutputCharacteristics(); 433 return static_cast<const NonSectionChunk *>(this)->getOutputCharacteristics(); 434 } 435 436 inline void Chunk::writeTo(uint8_t *buf) const { 437 if (isa<SectionChunk>(this)) 438 static_cast<const SectionChunk *>(this)->writeTo(buf); 439 else 440 static_cast<const NonSectionChunk *>(this)->writeTo(buf); 441 } 442 443 inline StringRef Chunk::getSectionName() const { 444 if (isa<SectionChunk>(this)) 445 return static_cast<const SectionChunk *>(this)->getSectionName(); 446 return static_cast<const NonSectionChunk *>(this)->getSectionName(); 447 } 448 449 inline void Chunk::getBaserels(std::vector<Baserel> *res) { 450 if (isa<SectionChunk>(this)) 451 static_cast<SectionChunk *>(this)->getBaserels(res); 452 else 453 static_cast<NonSectionChunk *>(this)->getBaserels(res); 454 } 455 456 inline StringRef Chunk::getDebugName() const { 457 if (isa<SectionChunk>(this)) 458 return static_cast<const SectionChunk *>(this)->getDebugName(); 459 return static_cast<const NonSectionChunk *>(this)->getDebugName(); 460 } 461 462 inline MachineTypes Chunk::getMachine() const { 463 if (isa<SectionChunk>(this)) 464 return static_cast<const SectionChunk *>(this)->getMachine(); 465 return static_cast<const NonSectionChunk *>(this)->getMachine(); 466 } 467 468 inline llvm::Triple::ArchType Chunk::getArch() const { 469 return llvm::getMachineArchType(getMachine()); 470 } 471 472 inline std::optional<chpe_range_type> Chunk::getArm64ECRangeType() const { 473 // Data sections don't need codemap entries. 474 if (!(getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE)) 475 return std::nullopt; 476 477 switch (getMachine()) { 478 case AMD64: 479 return chpe_range_type::Amd64; 480 case ARM64EC: 481 return chpe_range_type::Arm64EC; 482 default: 483 return chpe_range_type::Arm64; 484 } 485 } 486 487 // This class is used to implement an lld-specific feature (not implemented in 488 // MSVC) that minimizes the output size by finding string literals sharing tail 489 // parts and merging them. 490 // 491 // If string tail merging is enabled and a section is identified as containing a 492 // string literal, it is added to a MergeChunk with an appropriate alignment. 493 // The MergeChunk then tail merges the strings using the StringTableBuilder 494 // class and assigns RVAs and section offsets to each of the member chunks based 495 // on the offsets assigned by the StringTableBuilder. 496 class MergeChunk : public NonSectionChunk { 497 public: 498 MergeChunk(uint32_t alignment); 499 static void addSection(COFFLinkerContext &ctx, SectionChunk *c); 500 void finalizeContents(); 501 void assignSubsectionRVAs(); 502 503 uint32_t getOutputCharacteristics() const override; 504 StringRef getSectionName() const override { return ".rdata"; } 505 size_t getSize() const override; 506 void writeTo(uint8_t *buf) const override; 507 508 std::vector<SectionChunk *> sections; 509 510 private: 511 llvm::StringTableBuilder builder; 512 bool finalized = false; 513 }; 514 515 // A chunk for common symbols. Common chunks don't have actual data. 516 class CommonChunk : public NonSectionChunk { 517 public: 518 CommonChunk(const COFFSymbolRef sym); 519 size_t getSize() const override { return sym.getValue(); } 520 uint32_t getOutputCharacteristics() const override; 521 StringRef getSectionName() const override { return ".bss"; } 522 523 private: 524 const COFFSymbolRef sym; 525 }; 526 527 // A chunk for linker-created strings. 528 class StringChunk : public NonSectionChunk { 529 public: 530 explicit StringChunk(StringRef s) : str(s) {} 531 size_t getSize() const override { return str.size() + 1; } 532 void writeTo(uint8_t *buf) const override; 533 534 private: 535 StringRef str; 536 }; 537 538 static const uint8_t importThunkX86[] = { 539 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0 540 }; 541 542 static const uint8_t importThunkARM[] = { 543 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 544 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 545 0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip] 546 }; 547 548 static const uint8_t importThunkARM64[] = { 549 0x10, 0x00, 0x00, 0x90, // adrp x16, #0 550 0x10, 0x02, 0x40, 0xf9, // ldr x16, [x16] 551 0x00, 0x02, 0x1f, 0xd6, // br x16 552 }; 553 554 static const uint8_t importThunkARM64EC[] = { 555 0x0b, 0x00, 0x00, 0x90, // adrp x11, 0x0 556 0x6b, 0x01, 0x40, 0xf9, // ldr x11, [x11] 557 0x0a, 0x00, 0x00, 0x90, // adrp x10, 0x0 558 0x4a, 0x01, 0x00, 0x91, // add x10, x10, #0x0 559 0x00, 0x00, 0x00, 0x14 // b 0x0 560 }; 561 562 // Windows-specific. 563 // A chunk for DLL import jump table entry. In a final output, its 564 // contents will be a JMP instruction to some __imp_ symbol. 565 class ImportThunkChunk : public NonSectionCodeChunk { 566 public: 567 ImportThunkChunk(COFFLinkerContext &ctx, Defined *s); 568 static bool classof(const Chunk *c) { return c->kind() == ImportThunkKind; } 569 570 // We track the usage of the thunk symbol separately from the import file 571 // to avoid generating unnecessary thunks. 572 bool live; 573 574 protected: 575 Defined *impSymbol; 576 COFFLinkerContext &ctx; 577 }; 578 579 class ImportThunkChunkX64 : public ImportThunkChunk { 580 public: 581 explicit ImportThunkChunkX64(COFFLinkerContext &ctx, Defined *s); 582 size_t getSize() const override { return sizeof(importThunkX86); } 583 void writeTo(uint8_t *buf) const override; 584 MachineTypes getMachine() const override { return AMD64; } 585 }; 586 587 class ImportThunkChunkX86 : public ImportThunkChunk { 588 public: 589 explicit ImportThunkChunkX86(COFFLinkerContext &ctx, Defined *s) 590 : ImportThunkChunk(ctx, s) {} 591 size_t getSize() const override { return sizeof(importThunkX86); } 592 void getBaserels(std::vector<Baserel> *res) override; 593 void writeTo(uint8_t *buf) const override; 594 MachineTypes getMachine() const override { return I386; } 595 }; 596 597 class ImportThunkChunkARM : public ImportThunkChunk { 598 public: 599 explicit ImportThunkChunkARM(COFFLinkerContext &ctx, Defined *s) 600 : ImportThunkChunk(ctx, s) { 601 setAlignment(2); 602 } 603 size_t getSize() const override { return sizeof(importThunkARM); } 604 void getBaserels(std::vector<Baserel> *res) override; 605 void writeTo(uint8_t *buf) const override; 606 MachineTypes getMachine() const override { return ARMNT; } 607 }; 608 609 class ImportThunkChunkARM64 : public ImportThunkChunk { 610 public: 611 explicit ImportThunkChunkARM64(COFFLinkerContext &ctx, Defined *s, 612 MachineTypes machine) 613 : ImportThunkChunk(ctx, s), machine(machine) { 614 setAlignment(4); 615 } 616 size_t getSize() const override { return sizeof(importThunkARM64); } 617 void writeTo(uint8_t *buf) const override; 618 MachineTypes getMachine() const override { return machine; } 619 620 private: 621 MachineTypes machine; 622 }; 623 624 // ARM64EC __impchk_* thunk implementation. 625 // Performs an indirect call to an imported function pointer 626 // using the __icall_helper_arm64ec helper function. 627 class ImportThunkChunkARM64EC : public ImportThunkChunk { 628 public: 629 explicit ImportThunkChunkARM64EC(ImportFile *file); 630 size_t getSize() const override; 631 MachineTypes getMachine() const override { return ARM64EC; } 632 void writeTo(uint8_t *buf) const override; 633 bool verifyRanges() override; 634 uint32_t extendRanges() override; 635 636 Defined *exitThunk; 637 Defined *sym = nullptr; 638 bool extended = false; 639 640 private: 641 ImportFile *file; 642 }; 643 644 class RangeExtensionThunkARM : public NonSectionCodeChunk { 645 public: 646 explicit RangeExtensionThunkARM(COFFLinkerContext &ctx, Defined *t) 647 : target(t), ctx(ctx) { 648 setAlignment(2); 649 } 650 size_t getSize() const override; 651 void writeTo(uint8_t *buf) const override; 652 MachineTypes getMachine() const override { return ARMNT; } 653 654 Defined *target; 655 656 private: 657 COFFLinkerContext &ctx; 658 }; 659 660 // A ragnge extension thunk used for both ARM64EC and ARM64 machine types. 661 class RangeExtensionThunkARM64 : public NonSectionCodeChunk { 662 public: 663 explicit RangeExtensionThunkARM64(MachineTypes machine, Defined *t) 664 : target(t), machine(machine) { 665 setAlignment(4); 666 assert(llvm::COFF::isAnyArm64(machine)); 667 } 668 size_t getSize() const override; 669 void writeTo(uint8_t *buf) const override; 670 MachineTypes getMachine() const override { return machine; } 671 672 Defined *target; 673 674 private: 675 MachineTypes machine; 676 }; 677 678 // Windows-specific. 679 // See comments for DefinedLocalImport class. 680 class LocalImportChunk : public NonSectionChunk { 681 public: 682 explicit LocalImportChunk(COFFLinkerContext &ctx, Defined *s); 683 size_t getSize() const override; 684 void getBaserels(std::vector<Baserel> *res) override; 685 void writeTo(uint8_t *buf) const override; 686 687 private: 688 Defined *sym; 689 COFFLinkerContext &ctx; 690 }; 691 692 // Duplicate RVAs are not allowed in RVA tables, so unique symbols by chunk and 693 // offset into the chunk. Order does not matter as the RVA table will be sorted 694 // later. 695 struct ChunkAndOffset { 696 Chunk *inputChunk; 697 uint32_t offset; 698 699 struct DenseMapInfo { 700 static ChunkAndOffset getEmptyKey() { 701 return {llvm::DenseMapInfo<Chunk *>::getEmptyKey(), 0}; 702 } 703 static ChunkAndOffset getTombstoneKey() { 704 return {llvm::DenseMapInfo<Chunk *>::getTombstoneKey(), 0}; 705 } 706 static unsigned getHashValue(const ChunkAndOffset &co) { 707 return llvm::DenseMapInfo<std::pair<Chunk *, uint32_t>>::getHashValue( 708 {co.inputChunk, co.offset}); 709 } 710 static bool isEqual(const ChunkAndOffset &lhs, const ChunkAndOffset &rhs) { 711 return lhs.inputChunk == rhs.inputChunk && lhs.offset == rhs.offset; 712 } 713 }; 714 }; 715 716 using SymbolRVASet = llvm::DenseSet<ChunkAndOffset>; 717 718 // Table which contains symbol RVAs. Used for /safeseh and /guard:cf. 719 class RVATableChunk : public NonSectionChunk { 720 public: 721 explicit RVATableChunk(SymbolRVASet s) : syms(std::move(s)) {} 722 size_t getSize() const override { return syms.size() * 4; } 723 void writeTo(uint8_t *buf) const override; 724 725 private: 726 SymbolRVASet syms; 727 }; 728 729 // Table which contains symbol RVAs with flags. Used for /guard:ehcont. 730 class RVAFlagTableChunk : public NonSectionChunk { 731 public: 732 explicit RVAFlagTableChunk(SymbolRVASet s) : syms(std::move(s)) {} 733 size_t getSize() const override { return syms.size() * 5; } 734 void writeTo(uint8_t *buf) const override; 735 736 private: 737 SymbolRVASet syms; 738 }; 739 740 // Windows-specific. 741 // This class represents a block in .reloc section. 742 // See the PE/COFF spec 5.6 for details. 743 class BaserelChunk : public NonSectionChunk { 744 public: 745 BaserelChunk(uint32_t page, Baserel *begin, Baserel *end); 746 size_t getSize() const override { return data.size(); } 747 void writeTo(uint8_t *buf) const override; 748 749 private: 750 std::vector<uint8_t> data; 751 }; 752 753 class Baserel { 754 public: 755 Baserel(uint32_t v, uint8_t ty) : rva(v), type(ty) {} 756 explicit Baserel(uint32_t v, llvm::COFF::MachineTypes machine) 757 : Baserel(v, getDefaultType(machine)) {} 758 static uint8_t getDefaultType(llvm::COFF::MachineTypes machine); 759 760 uint32_t rva; 761 uint8_t type; 762 }; 763 764 // This is a placeholder Chunk, to allow attaching a DefinedSynthetic to a 765 // specific place in a section, without any data. This is used for the MinGW 766 // specific symbol __RUNTIME_PSEUDO_RELOC_LIST_END__, even though the concept 767 // of an empty chunk isn't MinGW specific. 768 class EmptyChunk : public NonSectionChunk { 769 public: 770 EmptyChunk() {} 771 size_t getSize() const override { return 0; } 772 void writeTo(uint8_t *buf) const override {} 773 }; 774 775 class ECCodeMapEntry { 776 public: 777 ECCodeMapEntry(Chunk *first, Chunk *last, chpe_range_type type) 778 : first(first), last(last), type(type) {} 779 Chunk *first; 780 Chunk *last; 781 chpe_range_type type; 782 }; 783 784 // This is a chunk containing CHPE code map on EC targets. It's a table 785 // of address ranges and their types. 786 class ECCodeMapChunk : public NonSectionChunk { 787 public: 788 ECCodeMapChunk(std::vector<ECCodeMapEntry> &map) : map(map) {} 789 size_t getSize() const override; 790 void writeTo(uint8_t *buf) const override; 791 792 private: 793 std::vector<ECCodeMapEntry> ↦ 794 }; 795 796 class CHPECodeRangesChunk : public NonSectionChunk { 797 public: 798 CHPECodeRangesChunk(std::vector<std::pair<Chunk *, Defined *>> &exportThunks) 799 : exportThunks(exportThunks) {} 800 size_t getSize() const override; 801 void writeTo(uint8_t *buf) const override; 802 803 private: 804 std::vector<std::pair<Chunk *, Defined *>> &exportThunks; 805 }; 806 807 class CHPERedirectionChunk : public NonSectionChunk { 808 public: 809 CHPERedirectionChunk(std::vector<std::pair<Chunk *, Defined *>> &exportThunks) 810 : exportThunks(exportThunks) {} 811 size_t getSize() const override; 812 void writeTo(uint8_t *buf) const override; 813 814 private: 815 std::vector<std::pair<Chunk *, Defined *>> &exportThunks; 816 }; 817 818 static const uint8_t ECExportThunkCode[] = { 819 0x48, 0x8b, 0xc4, // movq %rsp, %rax 820 0x48, 0x89, 0x58, 0x20, // movq %rbx, 0x20(%rax) 821 0x55, // pushq %rbp 822 0x5d, // popq %rbp 823 0xe9, 0, 0, 0, 0, // jmp *0x0 824 0xcc, // int3 825 0xcc // int3 826 }; 827 828 class ECExportThunkChunk : public NonSectionCodeChunk { 829 public: 830 explicit ECExportThunkChunk(Defined *targetSym) : target(targetSym) {} 831 size_t getSize() const override { return sizeof(ECExportThunkCode); }; 832 void writeTo(uint8_t *buf) const override; 833 MachineTypes getMachine() const override { return AMD64; } 834 835 Defined *target; 836 }; 837 838 // ARM64X relocation value, potentially relative to a symbol. 839 class Arm64XRelocVal { 840 public: 841 Arm64XRelocVal(uint64_t value = 0) : value(value) {} 842 Arm64XRelocVal(Defined *sym, int32_t offset = 0) : sym(sym), value(offset) {} 843 Arm64XRelocVal(Chunk *chunk, int32_t offset = 0) 844 : chunk(chunk), value(offset) {} 845 uint64_t get() const; 846 847 private: 848 Defined *sym = nullptr; 849 Chunk *chunk = nullptr; 850 uint64_t value; 851 }; 852 853 // ARM64X entry for dynamic relocations. 854 class Arm64XDynamicRelocEntry { 855 public: 856 Arm64XDynamicRelocEntry(llvm::COFF::Arm64XFixupType type, uint8_t size, 857 Arm64XRelocVal offset, Arm64XRelocVal value) 858 : offset(offset), value(value), type(type), size(size) {} 859 860 size_t getSize() const; 861 void writeTo(uint8_t *buf) const; 862 863 Arm64XRelocVal offset; 864 Arm64XRelocVal value; 865 866 private: 867 llvm::COFF::Arm64XFixupType type; 868 uint8_t size; 869 }; 870 871 // Dynamic relocation chunk containing ARM64X relocations for the hybrid image. 872 class DynamicRelocsChunk : public NonSectionChunk { 873 public: 874 DynamicRelocsChunk() {} 875 size_t getSize() const override { return size; } 876 void writeTo(uint8_t *buf) const override; 877 void finalize(); 878 879 void add(llvm::COFF::Arm64XFixupType type, uint8_t size, 880 Arm64XRelocVal offset, Arm64XRelocVal value = Arm64XRelocVal()) { 881 arm64xRelocs.emplace_back(type, size, offset, value); 882 } 883 884 void set(uint32_t rva, Arm64XRelocVal value); 885 886 private: 887 std::vector<Arm64XDynamicRelocEntry> arm64xRelocs; 888 size_t size; 889 }; 890 891 // MinGW specific, for the "automatic import of variables from DLLs" feature. 892 // This provides the table of runtime pseudo relocations, for variable 893 // references that turned out to need to be imported from a DLL even though 894 // the reference didn't use the dllimport attribute. The MinGW runtime will 895 // process this table after loading, before handling control over to user 896 // code. 897 class PseudoRelocTableChunk : public NonSectionChunk { 898 public: 899 PseudoRelocTableChunk(std::vector<RuntimePseudoReloc> &relocs) 900 : relocs(std::move(relocs)) { 901 setAlignment(4); 902 } 903 size_t getSize() const override; 904 void writeTo(uint8_t *buf) const override; 905 906 private: 907 std::vector<RuntimePseudoReloc> relocs; 908 }; 909 910 // MinGW specific. A Chunk that contains one pointer-sized absolute value. 911 class AbsolutePointerChunk : public NonSectionChunk { 912 public: 913 AbsolutePointerChunk(COFFLinkerContext &ctx, uint64_t value) 914 : value(value), ctx(ctx) { 915 setAlignment(getSize()); 916 } 917 size_t getSize() const override; 918 void writeTo(uint8_t *buf) const override; 919 920 private: 921 uint64_t value; 922 COFFLinkerContext &ctx; 923 }; 924 925 // Return true if this file has the hotpatch flag set to true in the S_COMPILE3 926 // record in codeview debug info. Also returns true for some thunks synthesized 927 // by the linker. 928 inline bool Chunk::isHotPatchable() const { 929 if (auto *sc = dyn_cast<SectionChunk>(this)) 930 return sc->file->hotPatchable; 931 else if (isa<ImportThunkChunk>(this)) 932 return true; 933 return false; 934 } 935 936 inline Defined *Chunk::getEntryThunk() const { 937 if (auto *c = dyn_cast<const SectionChunkEC>(this)) 938 return c->entryThunk; 939 return nullptr; 940 } 941 942 inline void Chunk::setEntryThunk(Defined *entryThunk) { 943 if (auto c = dyn_cast<SectionChunkEC>(this)) 944 c->entryThunk = entryThunk; 945 } 946 947 void applyMOV32T(uint8_t *off, uint32_t v); 948 void applyBranch24T(uint8_t *off, int32_t v); 949 950 void applyArm64Addr(uint8_t *off, uint64_t s, uint64_t p, int shift); 951 void applyArm64Imm(uint8_t *off, uint64_t imm, uint32_t rangeLimit); 952 void applyArm64Branch26(uint8_t *off, int64_t v); 953 954 // Convenience class for initializing a coff_section with specific flags. 955 class FakeSection { 956 public: 957 FakeSection(int c) { section.Characteristics = c; } 958 959 coff_section section; 960 }; 961 962 // Convenience class for initializing a SectionChunk with specific flags. 963 class FakeSectionChunk { 964 public: 965 FakeSectionChunk(const coff_section *section) : chunk(nullptr, section) { 966 // Comdats from LTO files can't be fully treated as regular comdats 967 // at this point; we don't know what size or contents they are going to 968 // have, so we can't do proper checking of such aspects of them. 969 chunk.selection = llvm::COFF::IMAGE_COMDAT_SELECT_ANY; 970 } 971 972 SectionChunk chunk; 973 }; 974 975 } // namespace lld::coff 976 977 namespace llvm { 978 template <> 979 struct DenseMapInfo<lld::coff::ChunkAndOffset> 980 : lld::coff::ChunkAndOffset::DenseMapInfo {}; 981 } 982 983 #endif 984