mirror of
https://github.com/intel/llvm.git
synced 2026-01-24 08:30:34 +08:00
COFF: Move Windows-specific code from Chunk.{cpp,h} to DLL.{cpp,h}.
llvm-svn: 239239
This commit is contained in:
@@ -4,6 +4,7 @@ add_public_tablegen_target(COFFOptionsTableGen)
|
||||
|
||||
add_llvm_library(lldCOFF
|
||||
Chunks.cpp
|
||||
DLL.cpp
|
||||
Driver.cpp
|
||||
DriverUtils.cpp
|
||||
InputFiles.cpp
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
205
lld/COFF/DLL.cpp
Normal 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
47
lld/COFF/DLL.h
Normal 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
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user