Path: blob/main/contrib/llvm-project/lld/COFF/Chunks.h
34870 views
//===- Chunks.h -------------------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef LLD_COFF_CHUNKS_H9#define LLD_COFF_CHUNKS_H1011#include "Config.h"12#include "InputFiles.h"13#include "lld/Common/LLVM.h"14#include "llvm/ADT/ArrayRef.h"15#include "llvm/ADT/PointerIntPair.h"16#include "llvm/ADT/iterator.h"17#include "llvm/ADT/iterator_range.h"18#include "llvm/MC/StringTableBuilder.h"19#include "llvm/Object/COFF.h"20#include "llvm/Object/WindowsMachineFlag.h"21#include <utility>22#include <vector>2324namespace lld::coff {2526using llvm::COFF::ImportDirectoryTableEntry;27using llvm::object::chpe_range_type;28using llvm::object::coff_relocation;29using llvm::object::coff_section;30using llvm::object::COFFSymbolRef;31using llvm::object::SectionRef;3233class Baserel;34class Defined;35class DefinedImportData;36class DefinedRegular;37class ObjFile;38class OutputSection;39class RuntimePseudoReloc;40class Symbol;4142// Mask for permissions (discardable, writable, readable, executable, etc).43const uint32_t permMask = 0xFE000000;4445// Mask for section types (code, data, bss).46const uint32_t typeMask = 0x000000E0;4748// The log base 2 of the largest section alignment, which is log2(8192), or 13.49enum : unsigned { Log2MaxSectionAlignment = 13 };5051// A Chunk represents a chunk of data that will occupy space in the52// output (if the resolver chose that). It may or may not be backed by53// a section of an input file. It could be linker-created data, or54// doesn't even have actual data (if common or bss).55class Chunk {56public:57enum Kind : uint8_t {58SectionKind,59SectionECKind,60OtherKind,61ImportThunkKind62};63Kind kind() const { return chunkKind; }6465// Returns the size of this chunk (even if this is a common or BSS.)66size_t getSize() const;6768// Returns chunk alignment in power of two form. Value values are powers of69// two from 1 to 8192.70uint32_t getAlignment() const { return 1U << p2Align; }7172// Update the chunk section alignment measured in bytes. Internally alignment73// is stored in log2.74void setAlignment(uint32_t align) {75// Treat zero byte alignment as 1 byte alignment.76align = align ? align : 1;77assert(llvm::isPowerOf2_32(align) && "alignment is not a power of 2");78p2Align = llvm::Log2_32(align);79assert(p2Align <= Log2MaxSectionAlignment &&80"impossible requested alignment");81}8283// Write this chunk to a mmap'ed file, assuming Buf is pointing to84// beginning of the file. Because this function may use RVA values85// of other chunks for relocations, you need to set them properly86// before calling this function.87void writeTo(uint8_t *buf) const;8889// The writer sets and uses the addresses. In practice, PE images cannot be90// larger than 2GB. Chunks are always laid as part of the image, so Chunk RVAs91// can be stored with 32 bits.92uint32_t getRVA() const { return rva; }93void setRVA(uint64_t v) {94// This may truncate. The writer checks for overflow later.95rva = (uint32_t)v;96}9798// Returns readable/writable/executable bits.99uint32_t getOutputCharacteristics() const;100101// Returns the section name if this is a section chunk.102// It is illegal to call this function on non-section chunks.103StringRef getSectionName() const;104105// An output section has pointers to chunks in the section, and each106// chunk has a back pointer to an output section.107void setOutputSectionIdx(uint16_t o) { osidx = o; }108uint16_t getOutputSectionIdx() const { return osidx; }109110// Windows-specific.111// Collect all locations that contain absolute addresses for base relocations.112void getBaserels(std::vector<Baserel> *res);113114// Returns a human-readable name of this chunk. Chunks are unnamed chunks of115// bytes, so this is used only for logging or debugging.116StringRef getDebugName() const;117118// Return true if this file has the hotpatch flag set to true in the119// S_COMPILE3 record in codeview debug info. Also returns true for some thunks120// synthesized by the linker.121bool isHotPatchable() const;122123MachineTypes getMachine() const;124llvm::Triple::ArchType getArch() const;125std::optional<chpe_range_type> getArm64ECRangeType() const;126127// ARM64EC entry thunk associated with the chunk.128Defined *getEntryThunk() const;129void setEntryThunk(Defined *entryThunk);130131protected:132Chunk(Kind k = OtherKind) : chunkKind(k), hasData(true), p2Align(0) {}133134const Kind chunkKind;135136public:137// Returns true if this has non-zero data. BSS chunks return138// false. If false is returned, the space occupied by this chunk139// will be filled with zeros. Corresponds to the140// IMAGE_SCN_CNT_UNINITIALIZED_DATA section characteristic bit.141uint8_t hasData : 1;142143public:144// The alignment of this chunk, stored in log2 form. The writer uses the145// value.146uint8_t p2Align : 7;147148// The output section index for this chunk. The first valid section number is149// one.150uint16_t osidx = 0;151152// The RVA of this chunk in the output. The writer sets a value.153uint32_t rva = 0;154};155156class NonSectionChunk : public Chunk {157public:158virtual ~NonSectionChunk() = default;159160// Returns the size of this chunk (even if this is a common or BSS.)161virtual size_t getSize() const = 0;162163virtual uint32_t getOutputCharacteristics() const { return 0; }164165// Write this chunk to a mmap'ed file, assuming Buf is pointing to166// beginning of the file. Because this function may use RVA values167// of other chunks for relocations, you need to set them properly168// before calling this function.169virtual void writeTo(uint8_t *buf) const {}170171// Returns the section name if this is a section chunk.172// It is illegal to call this function on non-section chunks.173virtual StringRef getSectionName() const {174llvm_unreachable("unimplemented getSectionName");175}176177// Windows-specific.178// Collect all locations that contain absolute addresses for base relocations.179virtual void getBaserels(std::vector<Baserel> *res) {}180181virtual MachineTypes getMachine() const { return IMAGE_FILE_MACHINE_UNKNOWN; }182183// Returns a human-readable name of this chunk. Chunks are unnamed chunks of184// bytes, so this is used only for logging or debugging.185virtual StringRef getDebugName() const { return ""; }186187static bool classof(const Chunk *c) { return c->kind() >= OtherKind; }188189protected:190NonSectionChunk(Kind k = OtherKind) : Chunk(k) {}191};192193class NonSectionCodeChunk : public NonSectionChunk {194public:195virtual uint32_t getOutputCharacteristics() const override {196return llvm::COFF::IMAGE_SCN_MEM_READ | llvm::COFF::IMAGE_SCN_MEM_EXECUTE;197}198199protected:200NonSectionCodeChunk(Kind k = OtherKind) : NonSectionChunk(k) {}201};202203// MinGW specific; information about one individual location in the image204// that needs to be fixed up at runtime after loading. This represents205// one individual element in the PseudoRelocTableChunk table.206class RuntimePseudoReloc {207public:208RuntimePseudoReloc(Defined *sym, SectionChunk *target, uint32_t targetOffset,209int flags)210: sym(sym), target(target), targetOffset(targetOffset), flags(flags) {}211212Defined *sym;213SectionChunk *target;214uint32_t targetOffset;215// The Flags field contains the size of the relocation, in bits. No other216// flags are currently defined.217int flags;218};219220// A chunk corresponding a section of an input file.221class SectionChunk : public Chunk {222// Identical COMDAT Folding feature accesses section internal data.223friend class ICF;224225public:226class symbol_iterator : public llvm::iterator_adaptor_base<227symbol_iterator, const coff_relocation *,228std::random_access_iterator_tag, Symbol *> {229friend SectionChunk;230231ObjFile *file;232233symbol_iterator(ObjFile *file, const coff_relocation *i)234: symbol_iterator::iterator_adaptor_base(i), file(file) {}235236public:237symbol_iterator() = default;238239Symbol *operator*() const { return file->getSymbol(I->SymbolTableIndex); }240};241242SectionChunk(ObjFile *file, const coff_section *header, Kind k = SectionKind);243static bool classof(const Chunk *c) { return c->kind() <= SectionECKind; }244size_t getSize() const { return header->SizeOfRawData; }245ArrayRef<uint8_t> getContents() const;246void writeTo(uint8_t *buf) const;247248MachineTypes getMachine() const { return file->getMachineType(); }249250// Defend against unsorted relocations. This may be overly conservative.251void sortRelocations();252253// Write and relocate a portion of the section. This is intended to be called254// in a loop. Relocations must be sorted first.255void writeAndRelocateSubsection(ArrayRef<uint8_t> sec,256ArrayRef<uint8_t> subsec,257uint32_t &nextRelocIndex, uint8_t *buf) const;258259uint32_t getOutputCharacteristics() const {260return header->Characteristics & (permMask | typeMask);261}262StringRef getSectionName() const {263return StringRef(sectionNameData, sectionNameSize);264}265void getBaserels(std::vector<Baserel> *res);266bool isCOMDAT() const;267void applyRelocation(uint8_t *off, const coff_relocation &rel) const;268void applyRelX64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,269uint64_t p, uint64_t imageBase) const;270void applyRelX86(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,271uint64_t p, uint64_t imageBase) const;272void applyRelARM(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,273uint64_t p, uint64_t imageBase) const;274void applyRelARM64(uint8_t *off, uint16_t type, OutputSection *os, uint64_t s,275uint64_t p, uint64_t imageBase) const;276277void getRuntimePseudoRelocs(std::vector<RuntimePseudoReloc> &res);278279// Called if the garbage collector decides to not include this chunk280// in a final output. It's supposed to print out a log message to stdout.281void printDiscardedMessage() const;282283// Adds COMDAT associative sections to this COMDAT section. A chunk284// and its children are treated as a group by the garbage collector.285void addAssociative(SectionChunk *child);286287StringRef getDebugName() const;288289// True if this is a codeview debug info chunk. These will not be laid out in290// the image. Instead they will end up in the PDB, if one is requested.291bool isCodeView() const {292return getSectionName() == ".debug" || getSectionName().starts_with(".debug$");293}294295// True if this is a DWARF debug info or exception handling chunk.296bool isDWARF() const {297return getSectionName().starts_with(".debug_") || getSectionName() == ".eh_frame";298}299300// Allow iteration over the bodies of this chunk's relocated symbols.301llvm::iterator_range<symbol_iterator> symbols() const {302return llvm::make_range(symbol_iterator(file, relocsData),303symbol_iterator(file, relocsData + relocsSize));304}305306ArrayRef<coff_relocation> getRelocs() const {307return llvm::ArrayRef(relocsData, relocsSize);308}309310// Reloc setter used by ARM range extension thunk insertion.311void setRelocs(ArrayRef<coff_relocation> newRelocs) {312relocsData = newRelocs.data();313relocsSize = newRelocs.size();314assert(relocsSize == newRelocs.size() && "reloc size truncation");315}316317// Single linked list iterator for associated comdat children.318class AssociatedIterator319: public llvm::iterator_facade_base<320AssociatedIterator, std::forward_iterator_tag, SectionChunk> {321public:322AssociatedIterator() = default;323AssociatedIterator(SectionChunk *head) : cur(head) {}324bool operator==(const AssociatedIterator &r) const { return cur == r.cur; }325// FIXME: Wrong const-ness, but it makes filter ranges work.326SectionChunk &operator*() const { return *cur; }327SectionChunk &operator*() { return *cur; }328AssociatedIterator &operator++() {329cur = cur->assocChildren;330return *this;331}332333private:334SectionChunk *cur = nullptr;335};336337// Allow iteration over the associated child chunks for this section.338llvm::iterator_range<AssociatedIterator> children() const {339// Associated sections do not have children. The assocChildren field is340// part of the parent's list of children.341bool isAssoc = selection == llvm::COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE;342return llvm::make_range(343AssociatedIterator(isAssoc ? nullptr : assocChildren),344AssociatedIterator(nullptr));345}346347// The section ID this chunk belongs to in its Obj.348uint32_t getSectionNumber() const;349350ArrayRef<uint8_t> consumeDebugMagic();351352static ArrayRef<uint8_t> consumeDebugMagic(ArrayRef<uint8_t> data,353StringRef sectionName);354355static SectionChunk *findByName(ArrayRef<SectionChunk *> sections,356StringRef name);357358// The file that this chunk was created from.359ObjFile *file;360361// Pointer to the COFF section header in the input file.362const coff_section *header;363364// The COMDAT leader symbol if this is a COMDAT chunk.365DefinedRegular *sym = nullptr;366367// The CRC of the contents as described in the COFF spec 4.5.5.368// Auxiliary Format 5: Section Definitions. Used for ICF.369uint32_t checksum = 0;370371// Used by the garbage collector.372bool live;373374// Whether this section needs to be kept distinct from other sections during375// ICF. This is set by the driver using address-significance tables.376bool keepUnique = false;377378// The COMDAT selection if this is a COMDAT chunk.379llvm::COFF::COMDATType selection = (llvm::COFF::COMDATType)0;380381// A pointer pointing to a replacement for this chunk.382// Initially it points to "this" object. If this chunk is merged383// with other chunk by ICF, it points to another chunk,384// and this chunk is considered as dead.385SectionChunk *repl;386387private:388SectionChunk *assocChildren = nullptr;389390// Used for ICF (Identical COMDAT Folding)391void replace(SectionChunk *other);392uint32_t eqClass[2] = {0, 0};393394// Relocations for this section. Size is stored below.395const coff_relocation *relocsData;396397// Section name string. Size is stored below.398const char *sectionNameData;399400uint32_t relocsSize = 0;401uint32_t sectionNameSize = 0;402};403404// A section chunk corresponding a section of an EC input file.405class SectionChunkEC final : public SectionChunk {406public:407static bool classof(const Chunk *c) { return c->kind() == SectionECKind; }408409SectionChunkEC(ObjFile *file, const coff_section *header)410: SectionChunk(file, header, SectionECKind) {}411Defined *entryThunk = nullptr;412};413414// Inline methods to implement faux-virtual dispatch for SectionChunk.415416inline size_t Chunk::getSize() const {417if (isa<SectionChunk>(this))418return static_cast<const SectionChunk *>(this)->getSize();419return static_cast<const NonSectionChunk *>(this)->getSize();420}421422inline uint32_t Chunk::getOutputCharacteristics() const {423if (isa<SectionChunk>(this))424return static_cast<const SectionChunk *>(this)->getOutputCharacteristics();425return static_cast<const NonSectionChunk *>(this)->getOutputCharacteristics();426}427428inline void Chunk::writeTo(uint8_t *buf) const {429if (isa<SectionChunk>(this))430static_cast<const SectionChunk *>(this)->writeTo(buf);431else432static_cast<const NonSectionChunk *>(this)->writeTo(buf);433}434435inline StringRef Chunk::getSectionName() const {436if (isa<SectionChunk>(this))437return static_cast<const SectionChunk *>(this)->getSectionName();438return static_cast<const NonSectionChunk *>(this)->getSectionName();439}440441inline void Chunk::getBaserels(std::vector<Baserel> *res) {442if (isa<SectionChunk>(this))443static_cast<SectionChunk *>(this)->getBaserels(res);444else445static_cast<NonSectionChunk *>(this)->getBaserels(res);446}447448inline StringRef Chunk::getDebugName() const {449if (isa<SectionChunk>(this))450return static_cast<const SectionChunk *>(this)->getDebugName();451return static_cast<const NonSectionChunk *>(this)->getDebugName();452}453454inline MachineTypes Chunk::getMachine() const {455if (isa<SectionChunk>(this))456return static_cast<const SectionChunk *>(this)->getMachine();457return static_cast<const NonSectionChunk *>(this)->getMachine();458}459460inline llvm::Triple::ArchType Chunk::getArch() const {461return llvm::getMachineArchType(getMachine());462}463464inline std::optional<chpe_range_type> Chunk::getArm64ECRangeType() const {465// Data sections don't need codemap entries.466if (!(getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE))467return std::nullopt;468469switch (getMachine()) {470case AMD64:471return chpe_range_type::Amd64;472case ARM64EC:473return chpe_range_type::Arm64EC;474default:475return chpe_range_type::Arm64;476}477}478479// This class is used to implement an lld-specific feature (not implemented in480// MSVC) that minimizes the output size by finding string literals sharing tail481// parts and merging them.482//483// If string tail merging is enabled and a section is identified as containing a484// string literal, it is added to a MergeChunk with an appropriate alignment.485// The MergeChunk then tail merges the strings using the StringTableBuilder486// class and assigns RVAs and section offsets to each of the member chunks based487// on the offsets assigned by the StringTableBuilder.488class MergeChunk : public NonSectionChunk {489public:490MergeChunk(uint32_t alignment);491static void addSection(COFFLinkerContext &ctx, SectionChunk *c);492void finalizeContents();493void assignSubsectionRVAs();494495uint32_t getOutputCharacteristics() const override;496StringRef getSectionName() const override { return ".rdata"; }497size_t getSize() const override;498void writeTo(uint8_t *buf) const override;499500std::vector<SectionChunk *> sections;501502private:503llvm::StringTableBuilder builder;504bool finalized = false;505};506507// A chunk for common symbols. Common chunks don't have actual data.508class CommonChunk : public NonSectionChunk {509public:510CommonChunk(const COFFSymbolRef sym);511size_t getSize() const override { return sym.getValue(); }512uint32_t getOutputCharacteristics() const override;513StringRef getSectionName() const override { return ".bss"; }514515private:516const COFFSymbolRef sym;517};518519// A chunk for linker-created strings.520class StringChunk : public NonSectionChunk {521public:522explicit StringChunk(StringRef s) : str(s) {}523size_t getSize() const override { return str.size() + 1; }524void writeTo(uint8_t *buf) const override;525526private:527StringRef str;528};529530static const uint8_t importThunkX86[] = {5310xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0532};533534static const uint8_t importThunkARM[] = {5350x40, 0xf2, 0x00, 0x0c, // mov.w ip, #05360xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #05370xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip]538};539540static const uint8_t importThunkARM64[] = {5410x10, 0x00, 0x00, 0x90, // adrp x16, #05420x10, 0x02, 0x40, 0xf9, // ldr x16, [x16]5430x00, 0x02, 0x1f, 0xd6, // br x16544};545546// Windows-specific.547// A chunk for DLL import jump table entry. In a final output, its548// contents will be a JMP instruction to some __imp_ symbol.549class ImportThunkChunk : public NonSectionCodeChunk {550public:551ImportThunkChunk(COFFLinkerContext &ctx, Defined *s)552: NonSectionCodeChunk(ImportThunkKind), impSymbol(s), ctx(ctx) {}553static bool classof(const Chunk *c) { return c->kind() == ImportThunkKind; }554555protected:556Defined *impSymbol;557COFFLinkerContext &ctx;558};559560class ImportThunkChunkX64 : public ImportThunkChunk {561public:562explicit ImportThunkChunkX64(COFFLinkerContext &ctx, Defined *s);563size_t getSize() const override { return sizeof(importThunkX86); }564void writeTo(uint8_t *buf) const override;565MachineTypes getMachine() const override { return AMD64; }566};567568class ImportThunkChunkX86 : public ImportThunkChunk {569public:570explicit ImportThunkChunkX86(COFFLinkerContext &ctx, Defined *s)571: ImportThunkChunk(ctx, s) {}572size_t getSize() const override { return sizeof(importThunkX86); }573void getBaserels(std::vector<Baserel> *res) override;574void writeTo(uint8_t *buf) const override;575MachineTypes getMachine() const override { return I386; }576};577578class ImportThunkChunkARM : public ImportThunkChunk {579public:580explicit ImportThunkChunkARM(COFFLinkerContext &ctx, Defined *s)581: ImportThunkChunk(ctx, s) {582setAlignment(2);583}584size_t getSize() const override { return sizeof(importThunkARM); }585void getBaserels(std::vector<Baserel> *res) override;586void writeTo(uint8_t *buf) const override;587MachineTypes getMachine() const override { return ARMNT; }588};589590class ImportThunkChunkARM64 : public ImportThunkChunk {591public:592explicit ImportThunkChunkARM64(COFFLinkerContext &ctx, Defined *s)593: ImportThunkChunk(ctx, s) {594setAlignment(4);595}596size_t getSize() const override { return sizeof(importThunkARM64); }597void writeTo(uint8_t *buf) const override;598MachineTypes getMachine() const override { return ARM64; }599};600601class RangeExtensionThunkARM : public NonSectionCodeChunk {602public:603explicit RangeExtensionThunkARM(COFFLinkerContext &ctx, Defined *t)604: target(t), ctx(ctx) {605setAlignment(2);606}607size_t getSize() const override;608void writeTo(uint8_t *buf) const override;609MachineTypes getMachine() const override { return ARMNT; }610611Defined *target;612613private:614COFFLinkerContext &ctx;615};616617class RangeExtensionThunkARM64 : public NonSectionCodeChunk {618public:619explicit RangeExtensionThunkARM64(COFFLinkerContext &ctx, Defined *t)620: target(t), ctx(ctx) {621setAlignment(4);622}623size_t getSize() const override;624void writeTo(uint8_t *buf) const override;625MachineTypes getMachine() const override { return ARM64; }626627Defined *target;628629private:630COFFLinkerContext &ctx;631};632633// Windows-specific.634// See comments for DefinedLocalImport class.635class LocalImportChunk : public NonSectionChunk {636public:637explicit LocalImportChunk(COFFLinkerContext &ctx, Defined *s);638size_t getSize() const override;639void getBaserels(std::vector<Baserel> *res) override;640void writeTo(uint8_t *buf) const override;641642private:643Defined *sym;644COFFLinkerContext &ctx;645};646647// Duplicate RVAs are not allowed in RVA tables, so unique symbols by chunk and648// offset into the chunk. Order does not matter as the RVA table will be sorted649// later.650struct ChunkAndOffset {651Chunk *inputChunk;652uint32_t offset;653654struct DenseMapInfo {655static ChunkAndOffset getEmptyKey() {656return {llvm::DenseMapInfo<Chunk *>::getEmptyKey(), 0};657}658static ChunkAndOffset getTombstoneKey() {659return {llvm::DenseMapInfo<Chunk *>::getTombstoneKey(), 0};660}661static unsigned getHashValue(const ChunkAndOffset &co) {662return llvm::DenseMapInfo<std::pair<Chunk *, uint32_t>>::getHashValue(663{co.inputChunk, co.offset});664}665static bool isEqual(const ChunkAndOffset &lhs, const ChunkAndOffset &rhs) {666return lhs.inputChunk == rhs.inputChunk && lhs.offset == rhs.offset;667}668};669};670671using SymbolRVASet = llvm::DenseSet<ChunkAndOffset>;672673// Table which contains symbol RVAs. Used for /safeseh and /guard:cf.674class RVATableChunk : public NonSectionChunk {675public:676explicit RVATableChunk(SymbolRVASet s) : syms(std::move(s)) {}677size_t getSize() const override { return syms.size() * 4; }678void writeTo(uint8_t *buf) const override;679680private:681SymbolRVASet syms;682};683684// Table which contains symbol RVAs with flags. Used for /guard:ehcont.685class RVAFlagTableChunk : public NonSectionChunk {686public:687explicit RVAFlagTableChunk(SymbolRVASet s) : syms(std::move(s)) {}688size_t getSize() const override { return syms.size() * 5; }689void writeTo(uint8_t *buf) const override;690691private:692SymbolRVASet syms;693};694695// Windows-specific.696// This class represents a block in .reloc section.697// See the PE/COFF spec 5.6 for details.698class BaserelChunk : public NonSectionChunk {699public:700BaserelChunk(uint32_t page, Baserel *begin, Baserel *end);701size_t getSize() const override { return data.size(); }702void writeTo(uint8_t *buf) const override;703704private:705std::vector<uint8_t> data;706};707708class Baserel {709public:710Baserel(uint32_t v, uint8_t ty) : rva(v), type(ty) {}711explicit Baserel(uint32_t v, llvm::COFF::MachineTypes machine)712: Baserel(v, getDefaultType(machine)) {}713uint8_t getDefaultType(llvm::COFF::MachineTypes machine);714715uint32_t rva;716uint8_t type;717};718719// This is a placeholder Chunk, to allow attaching a DefinedSynthetic to a720// specific place in a section, without any data. This is used for the MinGW721// specific symbol __RUNTIME_PSEUDO_RELOC_LIST_END__, even though the concept722// of an empty chunk isn't MinGW specific.723class EmptyChunk : public NonSectionChunk {724public:725EmptyChunk() {}726size_t getSize() const override { return 0; }727void writeTo(uint8_t *buf) const override {}728};729730class ECCodeMapEntry {731public:732ECCodeMapEntry(Chunk *first, Chunk *last, chpe_range_type type)733: first(first), last(last), type(type) {}734Chunk *first;735Chunk *last;736chpe_range_type type;737};738739// This is a chunk containing CHPE code map on EC targets. It's a table740// of address ranges and their types.741class ECCodeMapChunk : public NonSectionChunk {742public:743ECCodeMapChunk(std::vector<ECCodeMapEntry> &map) : map(map) {}744size_t getSize() const override;745void writeTo(uint8_t *buf) const override;746747private:748std::vector<ECCodeMapEntry> ↦749};750751// MinGW specific, for the "automatic import of variables from DLLs" feature.752// This provides the table of runtime pseudo relocations, for variable753// references that turned out to need to be imported from a DLL even though754// the reference didn't use the dllimport attribute. The MinGW runtime will755// process this table after loading, before handling control over to user756// code.757class PseudoRelocTableChunk : public NonSectionChunk {758public:759PseudoRelocTableChunk(std::vector<RuntimePseudoReloc> &relocs)760: relocs(std::move(relocs)) {761setAlignment(4);762}763size_t getSize() const override;764void writeTo(uint8_t *buf) const override;765766private:767std::vector<RuntimePseudoReloc> relocs;768};769770// MinGW specific. A Chunk that contains one pointer-sized absolute value.771class AbsolutePointerChunk : public NonSectionChunk {772public:773AbsolutePointerChunk(COFFLinkerContext &ctx, uint64_t value)774: value(value), ctx(ctx) {775setAlignment(getSize());776}777size_t getSize() const override;778void writeTo(uint8_t *buf) const override;779780private:781uint64_t value;782COFFLinkerContext &ctx;783};784785// Return true if this file has the hotpatch flag set to true in the S_COMPILE3786// record in codeview debug info. Also returns true for some thunks synthesized787// by the linker.788inline bool Chunk::isHotPatchable() const {789if (auto *sc = dyn_cast<SectionChunk>(this))790return sc->file->hotPatchable;791else if (isa<ImportThunkChunk>(this))792return true;793return false;794}795796inline Defined *Chunk::getEntryThunk() const {797if (auto *c = dyn_cast<const SectionChunkEC>(this))798return c->entryThunk;799return nullptr;800}801802inline void Chunk::setEntryThunk(Defined *entryThunk) {803if (auto c = dyn_cast<SectionChunkEC>(this))804c->entryThunk = entryThunk;805}806807void applyMOV32T(uint8_t *off, uint32_t v);808void applyBranch24T(uint8_t *off, int32_t v);809810void applyArm64Addr(uint8_t *off, uint64_t s, uint64_t p, int shift);811void applyArm64Imm(uint8_t *off, uint64_t imm, uint32_t rangeLimit);812void applyArm64Branch26(uint8_t *off, int64_t v);813814// Convenience class for initializing a coff_section with specific flags.815class FakeSection {816public:817FakeSection(int c) { section.Characteristics = c; }818819coff_section section;820};821822// Convenience class for initializing a SectionChunk with specific flags.823class FakeSectionChunk {824public:825FakeSectionChunk(const coff_section *section) : chunk(nullptr, section) {826// Comdats from LTO files can't be fully treated as regular comdats827// at this point; we don't know what size or contents they are going to828// have, so we can't do proper checking of such aspects of them.829chunk.selection = llvm::COFF::IMAGE_COMDAT_SELECT_ANY;830}831832SectionChunk chunk;833};834835} // namespace lld::coff836837namespace llvm {838template <>839struct DenseMapInfo<lld::coff::ChunkAndOffset>840: lld::coff::ChunkAndOffset::DenseMapInfo {};841}842843#endif844845846