mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-03 19:32:35 +00:00
a431dd7ae7
Shaves another pointer off of SectionChunk, reducing the size from 96 to 88 bytes, down from 144 before I started working on this. Combined with D62356, this reduced peak memory usage when linking chrome_child.dll from 713MB to 675MB, or 5%. Create NonSectionChunk to provide virtual dispatch to the rest of the chunk types. Reviewers: ruiu, aganea Differential Revision: https://reviews.llvm.org/D62362 llvm-svn: 361667
643 lines
21 KiB
C++
643 lines
21 KiB
C++
//===- DLL.cpp ------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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
|
|
|
|
// A chunk for the import descriptor table.
|
|
class HintNameChunk : public NonSectionChunk {
|
|
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 {
|
|
memset(Buf, 0, getSize());
|
|
write16le(Buf, Hint);
|
|
memcpy(Buf + 2, Name.data(), Name.size());
|
|
}
|
|
|
|
private:
|
|
StringRef Name;
|
|
uint16_t Hint;
|
|
};
|
|
|
|
// A chunk for the import descriptor table.
|
|
class LookupChunk : public NonSectionChunk {
|
|
public:
|
|
explicit LookupChunk(Chunk *C) : HintName(C) {
|
|
setAlignment(Config->Wordsize);
|
|
}
|
|
size_t getSize() const override { return Config->Wordsize; }
|
|
|
|
void writeTo(uint8_t *Buf) const override {
|
|
if (Config->is64())
|
|
write64le(Buf, HintName->getRVA());
|
|
else
|
|
write32le(Buf, 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 NonSectionChunk {
|
|
public:
|
|
explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {
|
|
setAlignment(Config->Wordsize);
|
|
}
|
|
size_t getSize() const override { return Config->Wordsize; }
|
|
|
|
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, (1ULL << 63) | Ordinal);
|
|
} else {
|
|
write32le(Buf, (1ULL << 31) | Ordinal);
|
|
}
|
|
}
|
|
|
|
uint16_t Ordinal;
|
|
};
|
|
|
|
// A chunk for the import descriptor table.
|
|
class ImportDirectoryChunk : public NonSectionChunk {
|
|
public:
|
|
explicit ImportDirectoryChunk(Chunk *N) : DLLName(N) {}
|
|
size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); }
|
|
|
|
void writeTo(uint8_t *Buf) const override {
|
|
memset(Buf, 0, getSize());
|
|
|
|
auto *E = (coff_import_directory_table_entry *)(Buf);
|
|
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 NonSectionChunk {
|
|
public:
|
|
explicit NullChunk(size_t N) : Size(N) { HasData = false; }
|
|
size_t getSize() const override { return Size; }
|
|
|
|
void writeTo(uint8_t *Buf) const override {
|
|
memset(Buf, 0, 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 NonSectionChunk {
|
|
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 {
|
|
memset(Buf, 0, getSize());
|
|
|
|
auto *E = (delay_import_directory_table_entry *)(Buf);
|
|
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
|
|
};
|
|
|
|
static const uint8_t ThunkARM64[] = {
|
|
0x11, 0x00, 0x00, 0x90, // adrp x17, #0 __imp_<FUNCNAME>
|
|
0x31, 0x02, 0x00, 0x91, // add x17, x17, #0 :lo12:__imp_<FUNCNAME>
|
|
0xfd, 0x7b, 0xb3, 0xa9, // stp x29, x30, [sp, #-208]!
|
|
0xfd, 0x03, 0x00, 0x91, // mov x29, sp
|
|
0xe0, 0x07, 0x01, 0xa9, // stp x0, x1, [sp, #16]
|
|
0xe2, 0x0f, 0x02, 0xa9, // stp x2, x3, [sp, #32]
|
|
0xe4, 0x17, 0x03, 0xa9, // stp x4, x5, [sp, #48]
|
|
0xe6, 0x1f, 0x04, 0xa9, // stp x6, x7, [sp, #64]
|
|
0xe0, 0x87, 0x02, 0xad, // stp q0, q1, [sp, #80]
|
|
0xe2, 0x8f, 0x03, 0xad, // stp q2, q3, [sp, #112]
|
|
0xe4, 0x97, 0x04, 0xad, // stp q4, q5, [sp, #144]
|
|
0xe6, 0x9f, 0x05, 0xad, // stp q6, q7, [sp, #176]
|
|
0xe1, 0x03, 0x11, 0xaa, // mov x1, x17
|
|
0x00, 0x00, 0x00, 0x90, // adrp x0, #0 DELAY_IMPORT_DESCRIPTOR
|
|
0x00, 0x00, 0x00, 0x91, // add x0, x0, #0 :lo12:DELAY_IMPORT_DESCRIPTOR
|
|
0x00, 0x00, 0x00, 0x94, // bl #0 __delayLoadHelper2
|
|
0xf0, 0x03, 0x00, 0xaa, // mov x16, x0
|
|
0xe6, 0x9f, 0x45, 0xad, // ldp q6, q7, [sp, #176]
|
|
0xe4, 0x97, 0x44, 0xad, // ldp q4, q5, [sp, #144]
|
|
0xe2, 0x8f, 0x43, 0xad, // ldp q2, q3, [sp, #112]
|
|
0xe0, 0x87, 0x42, 0xad, // ldp q0, q1, [sp, #80]
|
|
0xe6, 0x1f, 0x44, 0xa9, // ldp x6, x7, [sp, #64]
|
|
0xe4, 0x17, 0x43, 0xa9, // ldp x4, x5, [sp, #48]
|
|
0xe2, 0x0f, 0x42, 0xa9, // ldp x2, x3, [sp, #32]
|
|
0xe0, 0x07, 0x41, 0xa9, // ldp x0, x1, [sp, #16]
|
|
0xfd, 0x7b, 0xcd, 0xa8, // ldp x29, x30, [sp], #208
|
|
0x00, 0x02, 0x1f, 0xd6, // br x16
|
|
};
|
|
|
|
// A chunk for the delay import thunk.
|
|
class ThunkChunkX64 : public NonSectionChunk {
|
|
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, ThunkX64, sizeof(ThunkX64));
|
|
write32le(Buf + 36, Imp->getRVA() - RVA - 40);
|
|
write32le(Buf + 43, Desc->getRVA() - RVA - 47);
|
|
write32le(Buf + 48, Helper->getRVA() - RVA - 52);
|
|
}
|
|
|
|
Defined *Imp = nullptr;
|
|
Chunk *Desc = nullptr;
|
|
Defined *Helper = nullptr;
|
|
};
|
|
|
|
class ThunkChunkX86 : public NonSectionChunk {
|
|
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, ThunkX86, sizeof(ThunkX86));
|
|
write32le(Buf + 3, Imp->getRVA() + Config->ImageBase);
|
|
write32le(Buf + 8, Desc->getRVA() + Config->ImageBase);
|
|
write32le(Buf + 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 NonSectionChunk {
|
|
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, ThunkARM, sizeof(ThunkARM));
|
|
applyMOV32T(Buf + 0, Imp->getRVA() + Config->ImageBase);
|
|
applyMOV32T(Buf + 22, Desc->getRVA() + Config->ImageBase);
|
|
applyBranch24T(Buf + 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;
|
|
};
|
|
|
|
class ThunkChunkARM64 : public NonSectionChunk {
|
|
public:
|
|
ThunkChunkARM64(Defined *I, Chunk *D, Defined *H)
|
|
: Imp(I), Desc(D), Helper(H) {}
|
|
|
|
size_t getSize() const override { return sizeof(ThunkARM64); }
|
|
|
|
void writeTo(uint8_t *Buf) const override {
|
|
memcpy(Buf, ThunkARM64, sizeof(ThunkARM64));
|
|
applyArm64Addr(Buf + 0, Imp->getRVA(), RVA + 0, 12);
|
|
applyArm64Imm(Buf + 4, Imp->getRVA() & 0xfff, 0);
|
|
applyArm64Addr(Buf + 52, Desc->getRVA(), RVA + 52, 12);
|
|
applyArm64Imm(Buf + 56, Desc->getRVA() & 0xfff, 0);
|
|
applyArm64Branch26(Buf + 60, Helper->getRVA() - RVA - 60);
|
|
}
|
|
|
|
Defined *Imp = nullptr;
|
|
Chunk *Desc = nullptr;
|
|
Defined *Helper = nullptr;
|
|
};
|
|
|
|
// A chunk for the import descriptor table.
|
|
class DelayAddressChunk : public NonSectionChunk {
|
|
public:
|
|
explicit DelayAddressChunk(Chunk *C) : Thunk(C) {
|
|
setAlignment(Config->Wordsize);
|
|
}
|
|
size_t getSize() const override { return Config->Wordsize; }
|
|
|
|
void writeTo(uint8_t *Buf) const override {
|
|
if (Config->is64()) {
|
|
write64le(Buf, 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, (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 NonSectionChunk {
|
|
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 {
|
|
memset(Buf, 0, getSize());
|
|
|
|
auto *E = (export_directory_table_entry *)(Buf);
|
|
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 NonSectionChunk {
|
|
public:
|
|
explicit AddressTableChunk(size_t MaxOrdinal) : Size(MaxOrdinal + 1) {}
|
|
size_t getSize() const override { return Size * 4; }
|
|
|
|
void writeTo(uint8_t *Buf) const override {
|
|
memset(Buf, 0, getSize());
|
|
|
|
for (const Export &E : Config->Exports) {
|
|
uint8_t *P = Buf + 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 NonSectionChunk {
|
|
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 {
|
|
for (Chunk *C : Chunks) {
|
|
write32le(Buf, C->getRVA());
|
|
Buf += 4;
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::vector<Chunk *> Chunks;
|
|
};
|
|
|
|
class ExportOrdinalChunk : public NonSectionChunk {
|
|
public:
|
|
explicit ExportOrdinalChunk(size_t I) : Size(I) {}
|
|
size_t getSize() const override { return Size * 2; }
|
|
|
|
void writeTo(uint8_t *Buf) const override {
|
|
for (Export &E : Config->Exports) {
|
|
if (E.Noname)
|
|
continue;
|
|
write16le(Buf, E.Ordinal);
|
|
Buf += 2;
|
|
}
|
|
}
|
|
|
|
private:
|
|
size_t Size;
|
|
};
|
|
|
|
} // anonymous namespace
|
|
|
|
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>(Config->Wordsize));
|
|
Addresses.push_back(make<NullChunk>(Config->Wordsize));
|
|
|
|
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->setAlignment(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);
|
|
case ARM64:
|
|
return make<ThunkChunkARM64>(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
|