COFF: Move Windows-specific code from Chunk.{cpp,h} to DLL.{cpp,h}.

llvm-svn: 239239
This commit is contained in:
Rui Ueyama
2015-06-07 01:15:04 +00:00
parent ad66098c20
commit 4b22fa7437
6 changed files with 255 additions and 194 deletions

View File

@@ -4,6 +4,7 @@ add_public_tablegen_target(COFFOptionsTableGen)
add_llvm_library(lldCOFF
Chunks.cpp
DLL.cpp
Driver.cpp
DriverUtils.cpp
InputFiles.cpp

View File

@@ -26,9 +26,6 @@ using llvm::RoundUpToAlignment;
namespace lld {
namespace coff {
const size_t LookupChunk::Size = sizeof(uint64_t);
const size_t DirectoryChunk::Size = sizeof(ImportDirectoryTableEntry);
SectionChunk::SectionChunk(ObjectFile *F, const coff_section *H, uint32_t SI)
: File(F), Header(H), SectionIndex(SI) {
// Initialize SectionName.
@@ -170,109 +167,5 @@ void ImportThunkChunk::writeTo(uint8_t *Buf) {
write32le(Buf + FileOff + 2, Operand);
}
size_t HintNameChunk::getSize() const {
// Starts with 2 byte Hint field, followed by a null-terminated string,
// ends with 0 or 1 byte padding.
return RoundUpToAlignment(Name.size() + 3, 2);
}
void HintNameChunk::writeTo(uint8_t *Buf) {
write16le(Buf + FileOff, Hint);
memcpy(Buf + FileOff + 2, Name.data(), Name.size());
}
void LookupChunk::writeTo(uint8_t *Buf) {
write32le(Buf + FileOff, HintName->getRVA());
}
void OrdinalOnlyChunk::writeTo(uint8_t *Buf) {
// An import-by-ordinal slot has MSB 1 to indicate that
// this is import-by-ordinal (and not import-by-name).
write64le(Buf + FileOff, (uint64_t(1) << 63) | Ordinal);
}
void DirectoryChunk::writeTo(uint8_t *Buf) {
auto *E = (coff_import_directory_table_entry *)(Buf + FileOff);
E->ImportLookupTableRVA = LookupTab->getRVA();
E->NameRVA = DLLName->getRVA();
E->ImportAddressTableRVA = AddressTab->getRVA();
}
// Returns a list of .idata contents.
// See Microsoft PE/COFF spec 5.4 for details.
std::vector<Chunk *> IdataContents::getChunks() {
create();
std::vector<Chunk *> V;
// The loader assumes a specific order of data.
// Add each type in the correct order.
for (std::unique_ptr<Chunk> &C : Dirs)
V.push_back(C.get());
for (std::unique_ptr<Chunk> &C : Lookups)
V.push_back(C.get());
for (std::unique_ptr<Chunk> &C : Addresses)
V.push_back(C.get());
for (std::unique_ptr<Chunk> &C : Hints)
V.push_back(C.get());
for (auto &P : DLLNames) {
std::unique_ptr<Chunk> &C = P.second;
V.push_back(C.get());
}
return V;
}
void IdataContents::create() {
// Group DLL-imported symbols by DLL name because that's how
// symbols are layed out in the import descriptor table.
std::map<StringRef, std::vector<DefinedImportData *>> Map;
for (DefinedImportData *Sym : Imports)
Map[Sym->getDLLName()].push_back(Sym);
// Create .idata contents for each DLL.
for (auto &P : Map) {
StringRef Name = P.first;
std::vector<DefinedImportData *> &Syms = P.second;
// Sort symbols by name for each group.
std::sort(Syms.begin(), Syms.end(),
[](DefinedImportData *A, DefinedImportData *B) {
return A->getName() < B->getName();
});
// 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_unique<OrdinalOnlyChunk>(Ord));
Addresses.push_back(make_unique<OrdinalOnlyChunk>(Ord));
continue;
}
auto C = make_unique<HintNameChunk>(S->getExternalName(), Ord);
Lookups.push_back(make_unique<LookupChunk>(C.get()));
Addresses.push_back(make_unique<LookupChunk>(C.get()));
Hints.push_back(std::move(C));
}
// Terminate with null values.
Lookups.push_back(make_unique<NullChunk>(sizeof(uint64_t)));
Addresses.push_back(make_unique<NullChunk>(sizeof(uint64_t)));
for (int I = 0, E = Syms.size(); I < E; ++I)
Syms[I]->setLocation(Addresses[Base + I].get());
// Create the import table header.
if (!DLLNames.count(Name))
DLLNames[Name] = make_unique<StringChunk>(Name);
auto Dir = make_unique<DirectoryChunk>(DLLNames[Name].get());
Dir->LookupTab = Lookups[Base].get();
Dir->AddressTab = Addresses[Base].get();
Dirs.push_back(std::move(Dir));
}
// Add null terminator.
Dirs.push_back(make_unique<NullChunk>(DirectoryChunk::Size));
}
} // namespace coff
} // namespace lld

View File

@@ -166,16 +166,11 @@ private:
StringRef Str;
};
// All chunks below are for the DLL import descriptor table and
// Windows-specific. You may need to read the Microsoft PE/COFF spec
// to understand details about the data structures.
// If you are not particularly interested, you can skip them and
// still be able to understand the rest of the linker.
static const uint8_t ImportThunkData[] = {
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0
};
// Windows-specific.
// A chunk for DLL import jump table entry. In a final output, it's
// contents will be a JMP instruction to some __imp_ symbol.
class ImportThunkChunk : public Chunk {
@@ -188,87 +183,6 @@ private:
Defined *ImpSymbol;
};
// 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;
void writeTo(uint8_t *Buf) override;
private:
StringRef Name;
uint16_t Hint;
};
// A chunk for the import descriptor table.
class LookupChunk : public Chunk {
public:
explicit LookupChunk(Chunk *C) : HintName(C) {}
size_t getSize() const override { return Size; }
void writeTo(uint8_t *Buf) override;
static const size_t Size;
Chunk *HintName;
};
// A chunk for the import descriptor table.
// This chunk represent import-by-ordinal symbols.
// See the Microsoft PE/COFF spec 7.1. Import Header for details.
class OrdinalOnlyChunk : public Chunk {
public:
explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {}
size_t getSize() const override { return sizeof(uint64_t); }
void writeTo(uint8_t *Buf) override;
uint16_t Ordinal;
};
// A chunk for the import descriptor table.
class DirectoryChunk : public Chunk {
public:
explicit DirectoryChunk(Chunk *N) : DLLName(N) {}
size_t getSize() const override { return Size; }
void writeTo(uint8_t *Buf) override;
static const size_t Size;
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;
};
// IdataContents creates all chunks for the .idata section.
// You are supposed to call add() to add symbols and then
// call getChunks() to get a list of chunks.
class IdataContents {
public:
void add(DefinedImportData *Sym) { Imports.push_back(Sym); }
std::vector<Chunk *> getChunks();
uint64_t getDirRVA() { return Dirs[0]->getRVA(); }
uint64_t getDirSize() { return Dirs.size() * DirectoryChunk::Size; }
uint64_t getIATRVA() { return Addresses[0]->getRVA(); }
uint64_t getIATSize() { return Addresses.size() * LookupChunk::Size; }
private:
void create();
std::vector<DefinedImportData *> Imports;
std::vector<std::unique_ptr<Chunk>> Dirs;
std::vector<std::unique_ptr<Chunk>> Lookups;
std::vector<std::unique_ptr<Chunk>> Addresses;
std::vector<std::unique_ptr<Chunk>> Hints;
std::map<StringRef, std::unique_ptr<Chunk>> DLLNames;
};
} // namespace coff
} // namespace lld

205
lld/COFF/DLL.cpp Normal file
View File

@@ -0,0 +1,205 @@
//===- 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
// descriptor table. 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 "Chunks.h"
#include "DLL.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Endian.h"
using namespace llvm;
using namespace llvm::object;
using namespace llvm::support::endian;
using namespace llvm::COFF;
using llvm::RoundUpToAlignment;
const size_t LookupChunkSize = sizeof(uint64_t);
const size_t DirectoryChunkSize = sizeof(ImportDirectoryTableEntry);
namespace lld {
namespace coff {
// 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 RoundUpToAlignment(Name.size() + 3, 2);
}
void writeTo(uint8_t *Buf) override {
write16le(Buf + FileOff, Hint);
memcpy(Buf + FileOff + 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) {}
size_t getSize() const override { return LookupChunkSize; }
void writeTo(uint8_t *Buf) override {
write32le(Buf + FileOff, 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) {}
size_t getSize() const override { return sizeof(uint64_t); }
void writeTo(uint8_t *Buf) override {
// An import-by-ordinal slot has MSB 1 to indicate that
// this is import-by-ordinal (and not import-by-name).
write64le(Buf + FileOff, (uint64_t(1) << 63) | Ordinal);
}
uint16_t Ordinal;
};
// A chunk for the import descriptor table.
class DirectoryChunk : public Chunk {
public:
explicit DirectoryChunk(Chunk *N) : DLLName(N) {}
size_t getSize() const override { return DirectoryChunkSize; }
void writeTo(uint8_t *Buf) override {
auto *E = (coff_import_directory_table_entry *)(Buf + FileOff);
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;
};
uint64_t IdataContents::getDirSize() {
return Dirs.size() * DirectoryChunkSize;
}
uint64_t IdataContents::getIATSize() {
return Addresses.size() * LookupChunkSize;
}
// Returns a list of .idata contents.
// See Microsoft PE/COFF spec 5.4 for details.
std::vector<Chunk *> IdataContents::getChunks() {
create();
std::vector<Chunk *> V;
// The loader assumes a specific order of data.
// Add each type in the correct order.
for (std::unique_ptr<Chunk> &C : Dirs)
V.push_back(C.get());
for (std::unique_ptr<Chunk> &C : Lookups)
V.push_back(C.get());
for (std::unique_ptr<Chunk> &C : Addresses)
V.push_back(C.get());
for (std::unique_ptr<Chunk> &C : Hints)
V.push_back(C.get());
for (auto &P : DLLNames) {
std::unique_ptr<Chunk> &C = P.second;
V.push_back(C.get());
}
return V;
}
void IdataContents::create() {
// Group DLL-imported symbols by DLL name because that's how
// symbols are layed out in the import descriptor table.
std::map<StringRef, std::vector<DefinedImportData *>> Map;
for (DefinedImportData *Sym : Imports)
Map[Sym->getDLLName()].push_back(Sym);
// Create .idata contents for each DLL.
for (auto &P : Map) {
StringRef Name = P.first;
std::vector<DefinedImportData *> &Syms = P.second;
// Sort symbols by name for each group.
std::sort(Syms.begin(), Syms.end(),
[](DefinedImportData *A, DefinedImportData *B) {
return A->getName() < B->getName();
});
// 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_unique<OrdinalOnlyChunk>(Ord));
Addresses.push_back(make_unique<OrdinalOnlyChunk>(Ord));
continue;
}
auto C = make_unique<HintNameChunk>(S->getExternalName(), Ord);
Lookups.push_back(make_unique<LookupChunk>(C.get()));
Addresses.push_back(make_unique<LookupChunk>(C.get()));
Hints.push_back(std::move(C));
}
// Terminate with null values.
Lookups.push_back(make_unique<NullChunk>(sizeof(uint64_t)));
Addresses.push_back(make_unique<NullChunk>(sizeof(uint64_t)));
for (int I = 0, E = Syms.size(); I < E; ++I)
Syms[I]->setLocation(Addresses[Base + I].get());
// Create the import table header.
if (!DLLNames.count(Name))
DLLNames[Name] = make_unique<StringChunk>(Name);
auto Dir = make_unique<DirectoryChunk>(DLLNames[Name].get());
Dir->LookupTab = Lookups[Base].get();
Dir->AddressTab = Addresses[Base].get();
Dirs.push_back(std::move(Dir));
}
// Add null terminator.
Dirs.push_back(make_unique<NullChunk>(DirectoryChunkSize));
}
} // namespace coff
} // namespace lld

47
lld/COFF/DLL.h Normal file
View File

@@ -0,0 +1,47 @@
//===- DLL.h -------------------------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_COFF_DLL_H
#define LLD_COFF_DLL_H
#include "Chunks.h"
#include "Symbols.h"
namespace lld {
namespace coff {
// Windows-specific.
// IdataContents creates all chunks for the .idata section.
// You are supposed to call add() to add symbols and then
// call getChunks() to get a list of chunks.
class IdataContents {
public:
void add(DefinedImportData *Sym) { Imports.push_back(Sym); }
std::vector<Chunk *> getChunks();
uint64_t getDirRVA() { return Dirs[0]->getRVA(); }
uint64_t getDirSize();
uint64_t getIATRVA() { return Addresses[0]->getRVA(); }
uint64_t getIATSize();
private:
void create();
std::vector<DefinedImportData *> Imports;
std::vector<std::unique_ptr<Chunk>> Dirs;
std::vector<std::unique_ptr<Chunk>> Lookups;
std::vector<std::unique_ptr<Chunk>> Addresses;
std::vector<std::unique_ptr<Chunk>> Hints;
std::map<StringRef, std::unique_ptr<Chunk>> DLLNames;
};
} // namespace coff
} // namespace lld
#endif

View File

@@ -10,6 +10,7 @@
#ifndef LLD_COFF_WRITER_H
#define LLD_COFF_WRITER_H
#include "DLL.h"
#include "InputFiles.h"
#include "SymbolTable.h"
#include "llvm/Support/FileOutputBuffer.h"