|  | //===- DLL.cpp ------------------------------------------------------------===// | 
|  | // | 
|  | //                             The LLVM Linker | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file defines various types of chunks for the DLL import or export | 
|  | // descriptor tables. They are inherently Windows-specific. | 
|  | // You need to read Microsoft PE/COFF spec to understand details | 
|  | // about the data structures. | 
|  | // | 
|  | // If you are not particularly interested in linking against Windows | 
|  | // DLL, you can skip this file, and you should still be able to | 
|  | // understand the rest of the linker. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "DLL.h" | 
|  | #include "Chunks.h" | 
|  | #include "llvm/Object/COFF.h" | 
|  | #include "llvm/Support/Endian.h" | 
|  | #include "llvm/Support/Path.h" | 
|  |  | 
|  | using namespace llvm; | 
|  | using namespace llvm::object; | 
|  | using namespace llvm::support::endian; | 
|  | using namespace llvm::COFF; | 
|  |  | 
|  | namespace lld { | 
|  | namespace coff { | 
|  | namespace { | 
|  |  | 
|  | // Import table | 
|  |  | 
|  | static int ptrSize() { return Config->is64() ? 8 : 4; } | 
|  |  | 
|  | // A chunk for the import descriptor table. | 
|  | class HintNameChunk : public Chunk { | 
|  | public: | 
|  | HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {} | 
|  |  | 
|  | size_t getSize() const override { | 
|  | // Starts with 2 byte Hint field, followed by a null-terminated string, | 
|  | // ends with 0 or 1 byte padding. | 
|  | return alignTo(Name.size() + 3, 2); | 
|  | } | 
|  |  | 
|  | void writeTo(uint8_t *Buf) const override { | 
|  | write16le(Buf + OutputSectionOff, Hint); | 
|  | memcpy(Buf + OutputSectionOff + 2, Name.data(), Name.size()); | 
|  | } | 
|  |  | 
|  | private: | 
|  | StringRef Name; | 
|  | uint16_t Hint; | 
|  | }; | 
|  |  | 
|  | // A chunk for the import descriptor table. | 
|  | class LookupChunk : public Chunk { | 
|  | public: | 
|  | explicit LookupChunk(Chunk *C) : HintName(C) { Alignment = ptrSize(); } | 
|  | size_t getSize() const override { return ptrSize(); } | 
|  |  | 
|  | void writeTo(uint8_t *Buf) const override { | 
|  | write32le(Buf + OutputSectionOff, HintName->getRVA()); | 
|  | } | 
|  |  | 
|  | Chunk *HintName; | 
|  | }; | 
|  |  | 
|  | // A chunk for the import descriptor table. | 
|  | // This chunk represent import-by-ordinal symbols. | 
|  | // See Microsoft PE/COFF spec 7.1. Import Header for details. | 
|  | class OrdinalOnlyChunk : public Chunk { | 
|  | public: | 
|  | explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) { Alignment = ptrSize(); } | 
|  | size_t getSize() const override { return ptrSize(); } | 
|  |  | 
|  | void writeTo(uint8_t *Buf) const override { | 
|  | // An import-by-ordinal slot has MSB 1 to indicate that | 
|  | // this is import-by-ordinal (and not import-by-name). | 
|  | if (Config->is64()) { | 
|  | write64le(Buf + OutputSectionOff, (1ULL << 63) | Ordinal); | 
|  | } else { | 
|  | write32le(Buf + OutputSectionOff, (1ULL << 31) | Ordinal); | 
|  | } | 
|  | } | 
|  |  | 
|  | uint16_t Ordinal; | 
|  | }; | 
|  |  | 
|  | // A chunk for the import descriptor table. | 
|  | class ImportDirectoryChunk : public Chunk { | 
|  | public: | 
|  | explicit ImportDirectoryChunk(Chunk *N) : DLLName(N) {} | 
|  | size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); } | 
|  |  | 
|  | void writeTo(uint8_t *Buf) const override { | 
|  | auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff); | 
|  | E->ImportLookupTableRVA = LookupTab->getRVA(); | 
|  | E->NameRVA = DLLName->getRVA(); | 
|  | E->ImportAddressTableRVA = AddressTab->getRVA(); | 
|  | } | 
|  |  | 
|  | Chunk *DLLName; | 
|  | Chunk *LookupTab; | 
|  | Chunk *AddressTab; | 
|  | }; | 
|  |  | 
|  | // A chunk representing null terminator in the import table. | 
|  | // Contents of this chunk is always null bytes. | 
|  | class NullChunk : public Chunk { | 
|  | public: | 
|  | explicit NullChunk(size_t N) : Size(N) {} | 
|  | bool hasData() const override { return false; } | 
|  | size_t getSize() const override { return Size; } | 
|  |  | 
|  | private: | 
|  | size_t Size; | 
|  | }; | 
|  |  | 
|  | static std::vector<std::vector<DefinedImportData *>> | 
|  | binImports(const std::vector<DefinedImportData *> &Imports) { | 
|  | // Group DLL-imported symbols by DLL name because that's how | 
|  | // symbols are layed out in the import descriptor table. | 
|  | auto Less = [](const std::string &A, const std::string &B) { | 
|  | return Config->DLLOrder[A] < Config->DLLOrder[B]; | 
|  | }; | 
|  | std::map<std::string, std::vector<DefinedImportData *>, | 
|  | bool(*)(const std::string &, const std::string &)> M(Less); | 
|  | for (DefinedImportData *Sym : Imports) | 
|  | M[Sym->getDLLName().lower()].push_back(Sym); | 
|  |  | 
|  | std::vector<std::vector<DefinedImportData *>> V; | 
|  | for (auto &KV : M) { | 
|  | // Sort symbols by name for each group. | 
|  | std::vector<DefinedImportData *> &Syms = KV.second; | 
|  | std::sort(Syms.begin(), Syms.end(), | 
|  | [](DefinedImportData *A, DefinedImportData *B) { | 
|  | return A->getName() < B->getName(); | 
|  | }); | 
|  | V.push_back(std::move(Syms)); | 
|  | } | 
|  | return V; | 
|  | } | 
|  |  | 
|  | // Export table | 
|  | // See Microsoft PE/COFF spec 4.3 for details. | 
|  |  | 
|  | // A chunk for the delay import descriptor table etnry. | 
|  | class DelayDirectoryChunk : public Chunk { | 
|  | public: | 
|  | explicit DelayDirectoryChunk(Chunk *N) : DLLName(N) {} | 
|  |  | 
|  | size_t getSize() const override { | 
|  | return sizeof(delay_import_directory_table_entry); | 
|  | } | 
|  |  | 
|  | void writeTo(uint8_t *Buf) const override { | 
|  | auto *E = (delay_import_directory_table_entry *)(Buf + OutputSectionOff); | 
|  | E->Attributes = 1; | 
|  | E->Name = DLLName->getRVA(); | 
|  | E->ModuleHandle = ModuleHandle->getRVA(); | 
|  | E->DelayImportAddressTable = AddressTab->getRVA(); | 
|  | E->DelayImportNameTable = NameTab->getRVA(); | 
|  | } | 
|  |  | 
|  | Chunk *DLLName; | 
|  | Chunk *ModuleHandle; | 
|  | Chunk *AddressTab; | 
|  | Chunk *NameTab; | 
|  | }; | 
|  |  | 
|  | // Initial contents for delay-loaded functions. | 
|  | // This code calls __delayLoadHelper2 function to resolve a symbol | 
|  | // and then overwrites its jump table slot with the result | 
|  | // for subsequent function calls. | 
|  | static const uint8_t ThunkX64[] = { | 
|  | 0x51,                               // push    rcx | 
|  | 0x52,                               // push    rdx | 
|  | 0x41, 0x50,                         // push    r8 | 
|  | 0x41, 0x51,                         // push    r9 | 
|  | 0x48, 0x83, 0xEC, 0x48,             // sub     rsp, 48h | 
|  | 0x66, 0x0F, 0x7F, 0x04, 0x24,       // movdqa  xmmword ptr [rsp], xmm0 | 
|  | 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa  xmmword ptr [rsp+10h], xmm1 | 
|  | 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa  xmmword ptr [rsp+20h], xmm2 | 
|  | 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa  xmmword ptr [rsp+30h], xmm3 | 
|  | 0x48, 0x8D, 0x15, 0, 0, 0, 0,       // lea     rdx, [__imp_<FUNCNAME>] | 
|  | 0x48, 0x8D, 0x0D, 0, 0, 0, 0,       // lea     rcx, [___DELAY_IMPORT_...] | 
|  | 0xE8, 0, 0, 0, 0,                   // call    __delayLoadHelper2 | 
|  | 0x66, 0x0F, 0x6F, 0x04, 0x24,       // movdqa  xmm0, xmmword ptr [rsp] | 
|  | 0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa  xmm1, xmmword ptr [rsp+10h] | 
|  | 0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa  xmm2, xmmword ptr [rsp+20h] | 
|  | 0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa  xmm3, xmmword ptr [rsp+30h] | 
|  | 0x48, 0x83, 0xC4, 0x48,             // add     rsp, 48h | 
|  | 0x41, 0x59,                         // pop     r9 | 
|  | 0x41, 0x58,                         // pop     r8 | 
|  | 0x5A,                               // pop     rdx | 
|  | 0x59,                               // pop     rcx | 
|  | 0xFF, 0xE0,                         // jmp     rax | 
|  | }; | 
|  |  | 
|  | static const uint8_t ThunkX86[] = { | 
|  | 0x51,              // push  ecx | 
|  | 0x52,              // push  edx | 
|  | 0x68, 0, 0, 0, 0,  // push  offset ___imp__<FUNCNAME> | 
|  | 0x68, 0, 0, 0, 0,  // push  offset ___DELAY_IMPORT_DESCRIPTOR_<DLLNAME>_dll | 
|  | 0xE8, 0, 0, 0, 0,  // call  ___delayLoadHelper2@8 | 
|  | 0x5A,              // pop   edx | 
|  | 0x59,              // pop   ecx | 
|  | 0xFF, 0xE0,        // jmp   eax | 
|  | }; | 
|  |  | 
|  | static const uint8_t ThunkARM[] = { | 
|  | 0x40, 0xf2, 0x00, 0x0c, // mov.w   ip, #0 __imp_<FUNCNAME> | 
|  | 0xc0, 0xf2, 0x00, 0x0c, // mov.t   ip, #0 __imp_<FUNCNAME> | 
|  | 0x2d, 0xe9, 0x0f, 0x48, // push.w  {r0, r1, r2, r3, r11, lr} | 
|  | 0x0d, 0xf2, 0x10, 0x0b, // addw    r11, sp, #16 | 
|  | 0x2d, 0xed, 0x10, 0x0b, // vpush   {d0, d1, d2, d3, d4, d5, d6, d7} | 
|  | 0x61, 0x46,             // mov     r1, ip | 
|  | 0x40, 0xf2, 0x00, 0x00, // mov.w   r0, #0 DELAY_IMPORT_DESCRIPTOR | 
|  | 0xc0, 0xf2, 0x00, 0x00, // mov.t   r0, #0 DELAY_IMPORT_DESCRIPTOR | 
|  | 0x00, 0xf0, 0x00, 0xd0, // bl      #0 __delayLoadHelper2 | 
|  | 0x84, 0x46,             // mov     ip, r0 | 
|  | 0xbd, 0xec, 0x10, 0x0b, // vpop    {d0, d1, d2, d3, d4, d5, d6, d7} | 
|  | 0xbd, 0xe8, 0x0f, 0x48, // pop.w   {r0, r1, r2, r3, r11, lr} | 
|  | 0x60, 0x47,             // bx      ip | 
|  | }; | 
|  |  | 
|  | // A chunk for the delay import thunk. | 
|  | class ThunkChunkX64 : public Chunk { | 
|  | public: | 
|  | ThunkChunkX64(Defined *I, Chunk *D, Defined *H) | 
|  | : Imp(I), Desc(D), Helper(H) {} | 
|  |  | 
|  | size_t getSize() const override { return sizeof(ThunkX64); } | 
|  |  | 
|  | void writeTo(uint8_t *Buf) const override { | 
|  | memcpy(Buf + OutputSectionOff, ThunkX64, sizeof(ThunkX64)); | 
|  | write32le(Buf + OutputSectionOff + 36, Imp->getRVA() - RVA - 40); | 
|  | write32le(Buf + OutputSectionOff + 43, Desc->getRVA() - RVA - 47); | 
|  | write32le(Buf + OutputSectionOff + 48, Helper->getRVA() - RVA - 52); | 
|  | } | 
|  |  | 
|  | Defined *Imp = nullptr; | 
|  | Chunk *Desc = nullptr; | 
|  | Defined *Helper = nullptr; | 
|  | }; | 
|  |  | 
|  | class ThunkChunkX86 : public Chunk { | 
|  | public: | 
|  | ThunkChunkX86(Defined *I, Chunk *D, Defined *H) | 
|  | : Imp(I), Desc(D), Helper(H) {} | 
|  |  | 
|  | size_t getSize() const override { return sizeof(ThunkX86); } | 
|  |  | 
|  | void writeTo(uint8_t *Buf) const override { | 
|  | memcpy(Buf + OutputSectionOff, ThunkX86, sizeof(ThunkX86)); | 
|  | write32le(Buf + OutputSectionOff + 3, Imp->getRVA() + Config->ImageBase); | 
|  | write32le(Buf + OutputSectionOff + 8, Desc->getRVA() + Config->ImageBase); | 
|  | write32le(Buf + OutputSectionOff + 13, Helper->getRVA() - RVA - 17); | 
|  | } | 
|  |  | 
|  | void getBaserels(std::vector<Baserel> *Res) override { | 
|  | Res->emplace_back(RVA + 3); | 
|  | Res->emplace_back(RVA + 8); | 
|  | } | 
|  |  | 
|  | Defined *Imp = nullptr; | 
|  | Chunk *Desc = nullptr; | 
|  | Defined *Helper = nullptr; | 
|  | }; | 
|  |  | 
|  | class ThunkChunkARM : public Chunk { | 
|  | public: | 
|  | ThunkChunkARM(Defined *I, Chunk *D, Defined *H) | 
|  | : Imp(I), Desc(D), Helper(H) {} | 
|  |  | 
|  | size_t getSize() const override { return sizeof(ThunkARM); } | 
|  |  | 
|  | void writeTo(uint8_t *Buf) const override { | 
|  | memcpy(Buf + OutputSectionOff, ThunkARM, sizeof(ThunkARM)); | 
|  | applyMOV32T(Buf + OutputSectionOff + 0, Imp->getRVA() + Config->ImageBase); | 
|  | applyMOV32T(Buf + OutputSectionOff + 22, Desc->getRVA() + Config->ImageBase); | 
|  | applyBranch24T(Buf + OutputSectionOff + 30, Helper->getRVA() - RVA - 34); | 
|  | } | 
|  |  | 
|  | void getBaserels(std::vector<Baserel> *Res) override { | 
|  | Res->emplace_back(RVA + 0, IMAGE_REL_BASED_ARM_MOV32T); | 
|  | Res->emplace_back(RVA + 22, IMAGE_REL_BASED_ARM_MOV32T); | 
|  | } | 
|  |  | 
|  | Defined *Imp = nullptr; | 
|  | Chunk *Desc = nullptr; | 
|  | Defined *Helper = nullptr; | 
|  | }; | 
|  |  | 
|  | // A chunk for the import descriptor table. | 
|  | class DelayAddressChunk : public Chunk { | 
|  | public: | 
|  | explicit DelayAddressChunk(Chunk *C) : Thunk(C) { Alignment = ptrSize(); } | 
|  | size_t getSize() const override { return ptrSize(); } | 
|  |  | 
|  | void writeTo(uint8_t *Buf) const override { | 
|  | if (Config->is64()) { | 
|  | write64le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase); | 
|  | } else { | 
|  | uint32_t Bit = 0; | 
|  | // Pointer to thumb code must have the LSB set, so adjust it. | 
|  | if (Config->Machine == ARMNT) | 
|  | Bit = 1; | 
|  | write32le(Buf + OutputSectionOff, (Thunk->getRVA() + Config->ImageBase) | Bit); | 
|  | } | 
|  | } | 
|  |  | 
|  | void getBaserels(std::vector<Baserel> *Res) override { | 
|  | Res->emplace_back(RVA); | 
|  | } | 
|  |  | 
|  | Chunk *Thunk; | 
|  | }; | 
|  |  | 
|  | // Export table | 
|  | // Read Microsoft PE/COFF spec 5.3 for details. | 
|  |  | 
|  | // A chunk for the export descriptor table. | 
|  | class ExportDirectoryChunk : public Chunk { | 
|  | public: | 
|  | ExportDirectoryChunk(int I, int J, Chunk *D, Chunk *A, Chunk *N, Chunk *O) | 
|  | : MaxOrdinal(I), NameTabSize(J), DLLName(D), AddressTab(A), NameTab(N), | 
|  | OrdinalTab(O) {} | 
|  |  | 
|  | size_t getSize() const override { | 
|  | return sizeof(export_directory_table_entry); | 
|  | } | 
|  |  | 
|  | void writeTo(uint8_t *Buf) const override { | 
|  | auto *E = (export_directory_table_entry *)(Buf + OutputSectionOff); | 
|  | E->NameRVA = DLLName->getRVA(); | 
|  | E->OrdinalBase = 0; | 
|  | E->AddressTableEntries = MaxOrdinal + 1; | 
|  | E->NumberOfNamePointers = NameTabSize; | 
|  | E->ExportAddressTableRVA = AddressTab->getRVA(); | 
|  | E->NamePointerRVA = NameTab->getRVA(); | 
|  | E->OrdinalTableRVA = OrdinalTab->getRVA(); | 
|  | } | 
|  |  | 
|  | uint16_t MaxOrdinal; | 
|  | uint16_t NameTabSize; | 
|  | Chunk *DLLName; | 
|  | Chunk *AddressTab; | 
|  | Chunk *NameTab; | 
|  | Chunk *OrdinalTab; | 
|  | }; | 
|  |  | 
|  | class AddressTableChunk : public Chunk { | 
|  | public: | 
|  | explicit AddressTableChunk(size_t MaxOrdinal) : Size(MaxOrdinal + 1) {} | 
|  | size_t getSize() const override { return Size * 4; } | 
|  |  | 
|  | void writeTo(uint8_t *Buf) const override { | 
|  | for (const Export &E : Config->Exports) { | 
|  | uint8_t *P = Buf + OutputSectionOff + E.Ordinal * 4; | 
|  | uint32_t Bit = 0; | 
|  | // Pointer to thumb code must have the LSB set, so adjust it. | 
|  | if (Config->Machine == ARMNT && !E.Data) | 
|  | Bit = 1; | 
|  | if (E.ForwardChunk) { | 
|  | write32le(P, E.ForwardChunk->getRVA() | Bit); | 
|  | } else { | 
|  | write32le(P, cast<Defined>(E.Sym)->getRVA() | Bit); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | size_t Size; | 
|  | }; | 
|  |  | 
|  | class NamePointersChunk : public Chunk { | 
|  | public: | 
|  | explicit NamePointersChunk(std::vector<Chunk *> &V) : Chunks(V) {} | 
|  | size_t getSize() const override { return Chunks.size() * 4; } | 
|  |  | 
|  | void writeTo(uint8_t *Buf) const override { | 
|  | uint8_t *P = Buf + OutputSectionOff; | 
|  | for (Chunk *C : Chunks) { | 
|  | write32le(P, C->getRVA()); | 
|  | P += 4; | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | std::vector<Chunk *> Chunks; | 
|  | }; | 
|  |  | 
|  | class ExportOrdinalChunk : public Chunk { | 
|  | public: | 
|  | explicit ExportOrdinalChunk(size_t I) : Size(I) {} | 
|  | size_t getSize() const override { return Size * 2; } | 
|  |  | 
|  | void writeTo(uint8_t *Buf) const override { | 
|  | uint8_t *P = Buf + OutputSectionOff; | 
|  | for (Export &E : Config->Exports) { | 
|  | if (E.Noname) | 
|  | continue; | 
|  | write16le(P, E.Ordinal); | 
|  | P += 2; | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | size_t Size; | 
|  | }; | 
|  |  | 
|  | } // anonymous namespace | 
|  |  | 
|  | uint64_t IdataContents::getDirSize() { | 
|  | return Dirs.size() * sizeof(ImportDirectoryTableEntry); | 
|  | } | 
|  |  | 
|  | uint64_t IdataContents::getIATSize() { | 
|  | return Addresses.size() * ptrSize(); | 
|  | } | 
|  |  | 
|  | // Returns a list of .idata contents. | 
|  | // See Microsoft PE/COFF spec 5.4 for details. | 
|  | std::vector<Chunk *> IdataContents::getChunks() { | 
|  | create(); | 
|  |  | 
|  | // The loader assumes a specific order of data. | 
|  | // Add each type in the correct order. | 
|  | std::vector<Chunk *> V; | 
|  | V.insert(V.end(), Dirs.begin(), Dirs.end()); | 
|  | V.insert(V.end(), Lookups.begin(), Lookups.end()); | 
|  | V.insert(V.end(), Addresses.begin(), Addresses.end()); | 
|  | V.insert(V.end(), Hints.begin(), Hints.end()); | 
|  | V.insert(V.end(), DLLNames.begin(), DLLNames.end()); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | void IdataContents::create() { | 
|  | std::vector<std::vector<DefinedImportData *>> V = binImports(Imports); | 
|  |  | 
|  | // Create .idata contents for each DLL. | 
|  | for (std::vector<DefinedImportData *> &Syms : V) { | 
|  | // Create lookup and address tables. If they have external names, | 
|  | // we need to create HintName chunks to store the names. | 
|  | // If they don't (if they are import-by-ordinals), we store only | 
|  | // ordinal values to the table. | 
|  | size_t Base = Lookups.size(); | 
|  | for (DefinedImportData *S : Syms) { | 
|  | uint16_t Ord = S->getOrdinal(); | 
|  | if (S->getExternalName().empty()) { | 
|  | Lookups.push_back(make<OrdinalOnlyChunk>(Ord)); | 
|  | Addresses.push_back(make<OrdinalOnlyChunk>(Ord)); | 
|  | continue; | 
|  | } | 
|  | auto *C = make<HintNameChunk>(S->getExternalName(), Ord); | 
|  | Lookups.push_back(make<LookupChunk>(C)); | 
|  | Addresses.push_back(make<LookupChunk>(C)); | 
|  | Hints.push_back(C); | 
|  | } | 
|  | // Terminate with null values. | 
|  | Lookups.push_back(make<NullChunk>(ptrSize())); | 
|  | Addresses.push_back(make<NullChunk>(ptrSize())); | 
|  |  | 
|  | for (int I = 0, E = Syms.size(); I < E; ++I) | 
|  | Syms[I]->setLocation(Addresses[Base + I]); | 
|  |  | 
|  | // Create the import table header. | 
|  | DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName())); | 
|  | auto *Dir = make<ImportDirectoryChunk>(DLLNames.back()); | 
|  | Dir->LookupTab = Lookups[Base]; | 
|  | Dir->AddressTab = Addresses[Base]; | 
|  | Dirs.push_back(Dir); | 
|  | } | 
|  | // Add null terminator. | 
|  | Dirs.push_back(make<NullChunk>(sizeof(ImportDirectoryTableEntry))); | 
|  | } | 
|  |  | 
|  | std::vector<Chunk *> DelayLoadContents::getChunks() { | 
|  | std::vector<Chunk *> V; | 
|  | V.insert(V.end(), Dirs.begin(), Dirs.end()); | 
|  | V.insert(V.end(), Names.begin(), Names.end()); | 
|  | V.insert(V.end(), HintNames.begin(), HintNames.end()); | 
|  | V.insert(V.end(), DLLNames.begin(), DLLNames.end()); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | std::vector<Chunk *> DelayLoadContents::getDataChunks() { | 
|  | std::vector<Chunk *> V; | 
|  | V.insert(V.end(), ModuleHandles.begin(), ModuleHandles.end()); | 
|  | V.insert(V.end(), Addresses.begin(), Addresses.end()); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | uint64_t DelayLoadContents::getDirSize() { | 
|  | return Dirs.size() * sizeof(delay_import_directory_table_entry); | 
|  | } | 
|  |  | 
|  | void DelayLoadContents::create(Defined *H) { | 
|  | Helper = H; | 
|  | std::vector<std::vector<DefinedImportData *>> V = binImports(Imports); | 
|  |  | 
|  | // Create .didat contents for each DLL. | 
|  | for (std::vector<DefinedImportData *> &Syms : V) { | 
|  | // Create the delay import table header. | 
|  | DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName())); | 
|  | auto *Dir = make<DelayDirectoryChunk>(DLLNames.back()); | 
|  |  | 
|  | size_t Base = Addresses.size(); | 
|  | for (DefinedImportData *S : Syms) { | 
|  | Chunk *T = newThunkChunk(S, Dir); | 
|  | auto *A = make<DelayAddressChunk>(T); | 
|  | Addresses.push_back(A); | 
|  | Thunks.push_back(T); | 
|  | StringRef ExtName = S->getExternalName(); | 
|  | if (ExtName.empty()) { | 
|  | Names.push_back(make<OrdinalOnlyChunk>(S->getOrdinal())); | 
|  | } else { | 
|  | auto *C = make<HintNameChunk>(ExtName, 0); | 
|  | Names.push_back(make<LookupChunk>(C)); | 
|  | HintNames.push_back(C); | 
|  | } | 
|  | } | 
|  | // Terminate with null values. | 
|  | Addresses.push_back(make<NullChunk>(8)); | 
|  | Names.push_back(make<NullChunk>(8)); | 
|  |  | 
|  | for (int I = 0, E = Syms.size(); I < E; ++I) | 
|  | Syms[I]->setLocation(Addresses[Base + I]); | 
|  | auto *MH = make<NullChunk>(8); | 
|  | MH->Alignment = 8; | 
|  | ModuleHandles.push_back(MH); | 
|  |  | 
|  | // Fill the delay import table header fields. | 
|  | Dir->ModuleHandle = MH; | 
|  | Dir->AddressTab = Addresses[Base]; | 
|  | Dir->NameTab = Names[Base]; | 
|  | Dirs.push_back(Dir); | 
|  | } | 
|  | // Add null terminator. | 
|  | Dirs.push_back(make<NullChunk>(sizeof(delay_import_directory_table_entry))); | 
|  | } | 
|  |  | 
|  | Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) { | 
|  | switch (Config->Machine) { | 
|  | case AMD64: | 
|  | return make<ThunkChunkX64>(S, Dir, Helper); | 
|  | case I386: | 
|  | return make<ThunkChunkX86>(S, Dir, Helper); | 
|  | case ARMNT: | 
|  | return make<ThunkChunkARM>(S, Dir, Helper); | 
|  | default: | 
|  | llvm_unreachable("unsupported machine type"); | 
|  | } | 
|  | } | 
|  |  | 
|  | EdataContents::EdataContents() { | 
|  | uint16_t MaxOrdinal = 0; | 
|  | for (Export &E : Config->Exports) | 
|  | MaxOrdinal = std::max(MaxOrdinal, E.Ordinal); | 
|  |  | 
|  | auto *DLLName = make<StringChunk>(sys::path::filename(Config->OutputFile)); | 
|  | auto *AddressTab = make<AddressTableChunk>(MaxOrdinal); | 
|  | std::vector<Chunk *> Names; | 
|  | for (Export &E : Config->Exports) | 
|  | if (!E.Noname) | 
|  | Names.push_back(make<StringChunk>(E.ExportName)); | 
|  |  | 
|  | std::vector<Chunk *> Forwards; | 
|  | for (Export &E : Config->Exports) { | 
|  | if (E.ForwardTo.empty()) | 
|  | continue; | 
|  | E.ForwardChunk = make<StringChunk>(E.ForwardTo); | 
|  | Forwards.push_back(E.ForwardChunk); | 
|  | } | 
|  |  | 
|  | auto *NameTab = make<NamePointersChunk>(Names); | 
|  | auto *OrdinalTab = make<ExportOrdinalChunk>(Names.size()); | 
|  | auto *Dir = make<ExportDirectoryChunk>(MaxOrdinal, Names.size(), DLLName, | 
|  | AddressTab, NameTab, OrdinalTab); | 
|  | Chunks.push_back(Dir); | 
|  | Chunks.push_back(DLLName); | 
|  | Chunks.push_back(AddressTab); | 
|  | Chunks.push_back(NameTab); | 
|  | Chunks.push_back(OrdinalTab); | 
|  | Chunks.insert(Chunks.end(), Names.begin(), Names.end()); | 
|  | Chunks.insert(Chunks.end(), Forwards.begin(), Forwards.end()); | 
|  | } | 
|  |  | 
|  | } // namespace coff | 
|  | } // namespace lld |