Vendor import of lld trunk r303571:
https://llvm.org/svn/llvm-project/lld/trunk@303571
This commit is contained in:
parent
2dcc0c5ee6
commit
c53addf38e
@ -14,11 +14,9 @@ add_lld_library(lldCOFF
|
|||||||
Error.cpp
|
Error.cpp
|
||||||
ICF.cpp
|
ICF.cpp
|
||||||
InputFiles.cpp
|
InputFiles.cpp
|
||||||
Librarian.cpp
|
|
||||||
LTO.cpp
|
LTO.cpp
|
||||||
MapFile.cpp
|
MapFile.cpp
|
||||||
MarkLive.cpp
|
MarkLive.cpp
|
||||||
ModuleDef.cpp
|
|
||||||
PDB.cpp
|
PDB.cpp
|
||||||
Strings.cpp
|
Strings.cpp
|
||||||
SymbolTable.cpp
|
SymbolTable.cpp
|
||||||
|
@ -155,7 +155,6 @@ struct Configuration {
|
|||||||
uint32_t MajorOSVersion = 6;
|
uint32_t MajorOSVersion = 6;
|
||||||
uint32_t MinorOSVersion = 0;
|
uint32_t MinorOSVersion = 0;
|
||||||
bool DynamicBase = true;
|
bool DynamicBase = true;
|
||||||
bool AllowBind = true;
|
|
||||||
bool NxCompat = true;
|
bool NxCompat = true;
|
||||||
bool AllowIsolation = true;
|
bool AllowIsolation = true;
|
||||||
bool TerminalServerAware = true;
|
bool TerminalServerAware = true;
|
||||||
@ -164,7 +163,6 @@ struct Configuration {
|
|||||||
bool AppContainer = false;
|
bool AppContainer = false;
|
||||||
|
|
||||||
// This is for debugging.
|
// This is for debugging.
|
||||||
bool DebugPdb = false;
|
|
||||||
bool DumpPdb = false;
|
bool DumpPdb = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
160
COFF/DLL.cpp
160
COFF/DLL.cpp
@ -100,13 +100,17 @@ public:
|
|||||||
|
|
||||||
void writeTo(uint8_t *Buf) const override {
|
void writeTo(uint8_t *Buf) const override {
|
||||||
auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff);
|
auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff);
|
||||||
E->ImportLookupTableRVA = LookupTab->getRVA();
|
|
||||||
E->NameRVA = DLLName->getRVA();
|
E->NameRVA = DLLName->getRVA();
|
||||||
|
|
||||||
|
// The import descriptor table contains two pointers to
|
||||||
|
// the tables describing dllimported symbols. But the
|
||||||
|
// Windows loader actually uses only one. So we create
|
||||||
|
// only one table and set both fields to its address.
|
||||||
|
E->ImportLookupTableRVA = AddressTab->getRVA();
|
||||||
E->ImportAddressTableRVA = AddressTab->getRVA();
|
E->ImportAddressTableRVA = AddressTab->getRVA();
|
||||||
}
|
}
|
||||||
|
|
||||||
Chunk *DLLName;
|
Chunk *DLLName;
|
||||||
Chunk *LookupTab;
|
|
||||||
Chunk *AddressTab;
|
Chunk *AddressTab;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -136,9 +140,9 @@ binImports(const std::vector<DefinedImportData *> &Imports) {
|
|||||||
M[Sym->getDLLName().lower()].push_back(Sym);
|
M[Sym->getDLLName().lower()].push_back(Sym);
|
||||||
|
|
||||||
std::vector<std::vector<DefinedImportData *>> V;
|
std::vector<std::vector<DefinedImportData *>> V;
|
||||||
for (auto &P : M) {
|
for (auto &KV : M) {
|
||||||
// Sort symbols by name for each group.
|
// Sort symbols by name for each group.
|
||||||
std::vector<DefinedImportData *> &Syms = P.second;
|
std::vector<DefinedImportData *> &Syms = KV.second;
|
||||||
std::sort(Syms.begin(), Syms.end(),
|
std::sort(Syms.begin(), Syms.end(),
|
||||||
[](DefinedImportData *A, DefinedImportData *B) {
|
[](DefinedImportData *A, DefinedImportData *B) {
|
||||||
return A->getName() < B->getName();
|
return A->getName() < B->getName();
|
||||||
@ -383,21 +387,14 @@ uint64_t IdataContents::getIATSize() {
|
|||||||
// See Microsoft PE/COFF spec 5.4 for details.
|
// See Microsoft PE/COFF spec 5.4 for details.
|
||||||
std::vector<Chunk *> IdataContents::getChunks() {
|
std::vector<Chunk *> IdataContents::getChunks() {
|
||||||
create();
|
create();
|
||||||
std::vector<Chunk *> V;
|
|
||||||
// The loader assumes a specific order of data.
|
// The loader assumes a specific order of data.
|
||||||
// Add each type in the correct order.
|
// Add each type in the correct order.
|
||||||
for (std::unique_ptr<Chunk> &C : Dirs)
|
std::vector<Chunk *> V;
|
||||||
V.push_back(C.get());
|
V.insert(V.end(), Dirs.begin(), Dirs.end());
|
||||||
for (std::unique_ptr<Chunk> &C : Lookups)
|
V.insert(V.end(), Addresses.begin(), Addresses.end());
|
||||||
V.push_back(C.get());
|
V.insert(V.end(), Hints.begin(), Hints.end());
|
||||||
for (std::unique_ptr<Chunk> &C : Addresses)
|
V.insert(V.end(), DLLNames.begin(), DLLNames.end());
|
||||||
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;
|
return V;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,65 +403,50 @@ void IdataContents::create() {
|
|||||||
|
|
||||||
// Create .idata contents for each DLL.
|
// Create .idata contents for each DLL.
|
||||||
for (std::vector<DefinedImportData *> &Syms : V) {
|
for (std::vector<DefinedImportData *> &Syms : V) {
|
||||||
StringRef Name = Syms[0]->getDLLName();
|
|
||||||
|
|
||||||
// Create lookup and address tables. If they have external names,
|
// Create lookup and address tables. If they have external names,
|
||||||
// we need to create HintName chunks to store the names.
|
// we need to create HintName chunks to store the names.
|
||||||
// If they don't (if they are import-by-ordinals), we store only
|
// If they don't (if they are import-by-ordinals), we store only
|
||||||
// ordinal values to the table.
|
// ordinal values to the table.
|
||||||
size_t Base = Lookups.size();
|
size_t Base = Addresses.size();
|
||||||
for (DefinedImportData *S : Syms) {
|
for (DefinedImportData *S : Syms) {
|
||||||
uint16_t Ord = S->getOrdinal();
|
uint16_t Ord = S->getOrdinal();
|
||||||
if (S->getExternalName().empty()) {
|
if (S->getExternalName().empty()) {
|
||||||
Lookups.push_back(make_unique<OrdinalOnlyChunk>(Ord));
|
Addresses.push_back(make<OrdinalOnlyChunk>(Ord));
|
||||||
Addresses.push_back(make_unique<OrdinalOnlyChunk>(Ord));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto C = make_unique<HintNameChunk>(S->getExternalName(), Ord);
|
auto *C = make<HintNameChunk>(S->getExternalName(), Ord);
|
||||||
Lookups.push_back(make_unique<LookupChunk>(C.get()));
|
Addresses.push_back(make<LookupChunk>(C));
|
||||||
Addresses.push_back(make_unique<LookupChunk>(C.get()));
|
Hints.push_back(C);
|
||||||
Hints.push_back(std::move(C));
|
|
||||||
}
|
}
|
||||||
// Terminate with null values.
|
// Terminate with null values.
|
||||||
Lookups.push_back(make_unique<NullChunk>(ptrSize()));
|
Addresses.push_back(make<NullChunk>(ptrSize()));
|
||||||
Addresses.push_back(make_unique<NullChunk>(ptrSize()));
|
|
||||||
|
|
||||||
for (int I = 0, E = Syms.size(); I < E; ++I)
|
for (int I = 0, E = Syms.size(); I < E; ++I)
|
||||||
Syms[I]->setLocation(Addresses[Base + I].get());
|
Syms[I]->setLocation(Addresses[Base + I]);
|
||||||
|
|
||||||
// Create the import table header.
|
// Create the import table header.
|
||||||
if (!DLLNames.count(Name))
|
DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName()));
|
||||||
DLLNames[Name] = make_unique<StringChunk>(Name);
|
auto *Dir = make<ImportDirectoryChunk>(DLLNames.back());
|
||||||
auto Dir = make_unique<ImportDirectoryChunk>(DLLNames[Name].get());
|
Dir->AddressTab = Addresses[Base];
|
||||||
Dir->LookupTab = Lookups[Base].get();
|
Dirs.push_back(Dir);
|
||||||
Dir->AddressTab = Addresses[Base].get();
|
|
||||||
Dirs.push_back(std::move(Dir));
|
|
||||||
}
|
}
|
||||||
// Add null terminator.
|
// Add null terminator.
|
||||||
Dirs.push_back(make_unique<NullChunk>(sizeof(ImportDirectoryTableEntry)));
|
Dirs.push_back(make<NullChunk>(sizeof(ImportDirectoryTableEntry)));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Chunk *> DelayLoadContents::getChunks() {
|
std::vector<Chunk *> DelayLoadContents::getChunks() {
|
||||||
std::vector<Chunk *> V;
|
std::vector<Chunk *> V;
|
||||||
for (std::unique_ptr<Chunk> &C : Dirs)
|
V.insert(V.end(), Dirs.begin(), Dirs.end());
|
||||||
V.push_back(C.get());
|
V.insert(V.end(), Names.begin(), Names.end());
|
||||||
for (std::unique_ptr<Chunk> &C : Names)
|
V.insert(V.end(), HintNames.begin(), HintNames.end());
|
||||||
V.push_back(C.get());
|
V.insert(V.end(), DLLNames.begin(), DLLNames.end());
|
||||||
for (std::unique_ptr<Chunk> &C : HintNames)
|
|
||||||
V.push_back(C.get());
|
|
||||||
for (auto &P : DLLNames) {
|
|
||||||
std::unique_ptr<Chunk> &C = P.second;
|
|
||||||
V.push_back(C.get());
|
|
||||||
}
|
|
||||||
return V;
|
return V;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Chunk *> DelayLoadContents::getDataChunks() {
|
std::vector<Chunk *> DelayLoadContents::getDataChunks() {
|
||||||
std::vector<Chunk *> V;
|
std::vector<Chunk *> V;
|
||||||
for (std::unique_ptr<Chunk> &C : ModuleHandles)
|
V.insert(V.end(), ModuleHandles.begin(), ModuleHandles.end());
|
||||||
V.push_back(C.get());
|
V.insert(V.end(), Addresses.begin(), Addresses.end());
|
||||||
for (std::unique_ptr<Chunk> &C : Addresses)
|
|
||||||
V.push_back(C.get());
|
|
||||||
return V;
|
return V;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,55 +460,51 @@ void DelayLoadContents::create(Defined *H) {
|
|||||||
|
|
||||||
// Create .didat contents for each DLL.
|
// Create .didat contents for each DLL.
|
||||||
for (std::vector<DefinedImportData *> &Syms : V) {
|
for (std::vector<DefinedImportData *> &Syms : V) {
|
||||||
StringRef Name = Syms[0]->getDLLName();
|
|
||||||
|
|
||||||
// Create the delay import table header.
|
// Create the delay import table header.
|
||||||
if (!DLLNames.count(Name))
|
DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName()));
|
||||||
DLLNames[Name] = make_unique<StringChunk>(Name);
|
auto *Dir = make<DelayDirectoryChunk>(DLLNames.back());
|
||||||
auto Dir = make_unique<DelayDirectoryChunk>(DLLNames[Name].get());
|
|
||||||
|
|
||||||
size_t Base = Addresses.size();
|
size_t Base = Addresses.size();
|
||||||
for (DefinedImportData *S : Syms) {
|
for (DefinedImportData *S : Syms) {
|
||||||
Chunk *T = newThunkChunk(S, Dir.get());
|
Chunk *T = newThunkChunk(S, Dir);
|
||||||
auto A = make_unique<DelayAddressChunk>(T);
|
auto *A = make<DelayAddressChunk>(T);
|
||||||
Addresses.push_back(std::move(A));
|
Addresses.push_back(A);
|
||||||
Thunks.push_back(std::unique_ptr<Chunk>(T));
|
Thunks.push_back(T);
|
||||||
StringRef ExtName = S->getExternalName();
|
StringRef ExtName = S->getExternalName();
|
||||||
if (ExtName.empty()) {
|
if (ExtName.empty()) {
|
||||||
Names.push_back(make_unique<OrdinalOnlyChunk>(S->getOrdinal()));
|
Names.push_back(make<OrdinalOnlyChunk>(S->getOrdinal()));
|
||||||
} else {
|
} else {
|
||||||
auto C = make_unique<HintNameChunk>(ExtName, 0);
|
auto *C = make<HintNameChunk>(ExtName, 0);
|
||||||
Names.push_back(make_unique<LookupChunk>(C.get()));
|
Names.push_back(make<LookupChunk>(C));
|
||||||
HintNames.push_back(std::move(C));
|
HintNames.push_back(C);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Terminate with null values.
|
// Terminate with null values.
|
||||||
Addresses.push_back(make_unique<NullChunk>(8));
|
Addresses.push_back(make<NullChunk>(8));
|
||||||
Names.push_back(make_unique<NullChunk>(8));
|
Names.push_back(make<NullChunk>(8));
|
||||||
|
|
||||||
for (int I = 0, E = Syms.size(); I < E; ++I)
|
for (int I = 0, E = Syms.size(); I < E; ++I)
|
||||||
Syms[I]->setLocation(Addresses[Base + I].get());
|
Syms[I]->setLocation(Addresses[Base + I]);
|
||||||
auto *MH = new NullChunk(8);
|
auto *MH = make<NullChunk>(8);
|
||||||
MH->setAlign(8);
|
MH->setAlign(8);
|
||||||
ModuleHandles.push_back(std::unique_ptr<Chunk>(MH));
|
ModuleHandles.push_back(MH);
|
||||||
|
|
||||||
// Fill the delay import table header fields.
|
// Fill the delay import table header fields.
|
||||||
Dir->ModuleHandle = MH;
|
Dir->ModuleHandle = MH;
|
||||||
Dir->AddressTab = Addresses[Base].get();
|
Dir->AddressTab = Addresses[Base];
|
||||||
Dir->NameTab = Names[Base].get();
|
Dir->NameTab = Names[Base];
|
||||||
Dirs.push_back(std::move(Dir));
|
Dirs.push_back(Dir);
|
||||||
}
|
}
|
||||||
// Add null terminator.
|
// Add null terminator.
|
||||||
Dirs.push_back(
|
Dirs.push_back(make<NullChunk>(sizeof(delay_import_directory_table_entry)));
|
||||||
make_unique<NullChunk>(sizeof(delay_import_directory_table_entry)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) {
|
Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) {
|
||||||
switch (Config->Machine) {
|
switch (Config->Machine) {
|
||||||
case AMD64:
|
case AMD64:
|
||||||
return new ThunkChunkX64(S, Dir, Helper);
|
return make<ThunkChunkX64>(S, Dir, Helper);
|
||||||
case I386:
|
case I386:
|
||||||
return new ThunkChunkX86(S, Dir, Helper);
|
return make<ThunkChunkX86>(S, Dir, Helper);
|
||||||
default:
|
default:
|
||||||
llvm_unreachable("unsupported machine type");
|
llvm_unreachable("unsupported machine type");
|
||||||
}
|
}
|
||||||
@ -537,34 +515,32 @@ EdataContents::EdataContents() {
|
|||||||
for (Export &E : Config->Exports)
|
for (Export &E : Config->Exports)
|
||||||
MaxOrdinal = std::max(MaxOrdinal, E.Ordinal);
|
MaxOrdinal = std::max(MaxOrdinal, E.Ordinal);
|
||||||
|
|
||||||
auto *DLLName = new StringChunk(sys::path::filename(Config->OutputFile));
|
auto *DLLName = make<StringChunk>(sys::path::filename(Config->OutputFile));
|
||||||
auto *AddressTab = new AddressTableChunk(MaxOrdinal);
|
auto *AddressTab = make<AddressTableChunk>(MaxOrdinal);
|
||||||
std::vector<Chunk *> Names;
|
std::vector<Chunk *> Names;
|
||||||
for (Export &E : Config->Exports)
|
for (Export &E : Config->Exports)
|
||||||
if (!E.Noname)
|
if (!E.Noname)
|
||||||
Names.push_back(new StringChunk(E.ExportName));
|
Names.push_back(make<StringChunk>(E.ExportName));
|
||||||
|
|
||||||
std::vector<Chunk *> Forwards;
|
std::vector<Chunk *> Forwards;
|
||||||
for (Export &E : Config->Exports) {
|
for (Export &E : Config->Exports) {
|
||||||
if (E.ForwardTo.empty())
|
if (E.ForwardTo.empty())
|
||||||
continue;
|
continue;
|
||||||
E.ForwardChunk = new StringChunk(E.ForwardTo);
|
E.ForwardChunk = make<StringChunk>(E.ForwardTo);
|
||||||
Forwards.push_back(E.ForwardChunk);
|
Forwards.push_back(E.ForwardChunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *NameTab = new NamePointersChunk(Names);
|
auto *NameTab = make<NamePointersChunk>(Names);
|
||||||
auto *OrdinalTab = new ExportOrdinalChunk(Names.size());
|
auto *OrdinalTab = make<ExportOrdinalChunk>(Names.size());
|
||||||
auto *Dir = new ExportDirectoryChunk(MaxOrdinal, Names.size(), DLLName,
|
auto *Dir = make<ExportDirectoryChunk>(MaxOrdinal, Names.size(), DLLName,
|
||||||
AddressTab, NameTab, OrdinalTab);
|
AddressTab, NameTab, OrdinalTab);
|
||||||
Chunks.push_back(std::unique_ptr<Chunk>(Dir));
|
Chunks.push_back(Dir);
|
||||||
Chunks.push_back(std::unique_ptr<Chunk>(DLLName));
|
Chunks.push_back(DLLName);
|
||||||
Chunks.push_back(std::unique_ptr<Chunk>(AddressTab));
|
Chunks.push_back(AddressTab);
|
||||||
Chunks.push_back(std::unique_ptr<Chunk>(NameTab));
|
Chunks.push_back(NameTab);
|
||||||
Chunks.push_back(std::unique_ptr<Chunk>(OrdinalTab));
|
Chunks.push_back(OrdinalTab);
|
||||||
for (Chunk *C : Names)
|
Chunks.insert(Chunks.end(), Names.begin(), Names.end());
|
||||||
Chunks.push_back(std::unique_ptr<Chunk>(C));
|
Chunks.insert(Chunks.end(), Forwards.begin(), Forwards.end());
|
||||||
for (Chunk *C : Forwards)
|
|
||||||
Chunks.push_back(std::unique_ptr<Chunk>(C));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace coff
|
} // namespace coff
|
||||||
|
27
COFF/DLL.h
27
COFF/DLL.h
@ -35,11 +35,10 @@ private:
|
|||||||
void create();
|
void create();
|
||||||
|
|
||||||
std::vector<DefinedImportData *> Imports;
|
std::vector<DefinedImportData *> Imports;
|
||||||
std::vector<std::unique_ptr<Chunk>> Dirs;
|
std::vector<Chunk *> Dirs;
|
||||||
std::vector<std::unique_ptr<Chunk>> Lookups;
|
std::vector<Chunk *> Addresses;
|
||||||
std::vector<std::unique_ptr<Chunk>> Addresses;
|
std::vector<Chunk *> Hints;
|
||||||
std::vector<std::unique_ptr<Chunk>> Hints;
|
std::vector<Chunk *> DLLNames;
|
||||||
std::map<StringRef, std::unique_ptr<Chunk>> DLLNames;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Windows-specific.
|
// Windows-specific.
|
||||||
@ -51,7 +50,7 @@ public:
|
|||||||
void create(Defined *Helper);
|
void create(Defined *Helper);
|
||||||
std::vector<Chunk *> getChunks();
|
std::vector<Chunk *> getChunks();
|
||||||
std::vector<Chunk *> getDataChunks();
|
std::vector<Chunk *> getDataChunks();
|
||||||
std::vector<std::unique_ptr<Chunk>> &getCodeChunks() { return Thunks; }
|
ArrayRef<Chunk *> getCodeChunks() { return Thunks; }
|
||||||
|
|
||||||
uint64_t getDirRVA() { return Dirs[0]->getRVA(); }
|
uint64_t getDirRVA() { return Dirs[0]->getRVA(); }
|
||||||
uint64_t getDirSize();
|
uint64_t getDirSize();
|
||||||
@ -61,13 +60,13 @@ private:
|
|||||||
|
|
||||||
Defined *Helper;
|
Defined *Helper;
|
||||||
std::vector<DefinedImportData *> Imports;
|
std::vector<DefinedImportData *> Imports;
|
||||||
std::vector<std::unique_ptr<Chunk>> Dirs;
|
std::vector<Chunk *> Dirs;
|
||||||
std::vector<std::unique_ptr<Chunk>> ModuleHandles;
|
std::vector<Chunk *> ModuleHandles;
|
||||||
std::vector<std::unique_ptr<Chunk>> Addresses;
|
std::vector<Chunk *> Addresses;
|
||||||
std::vector<std::unique_ptr<Chunk>> Names;
|
std::vector<Chunk *> Names;
|
||||||
std::vector<std::unique_ptr<Chunk>> HintNames;
|
std::vector<Chunk *> HintNames;
|
||||||
std::vector<std::unique_ptr<Chunk>> Thunks;
|
std::vector<Chunk *> Thunks;
|
||||||
std::map<StringRef, std::unique_ptr<Chunk>> DLLNames;
|
std::vector<Chunk *> DLLNames;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Windows-specific.
|
// Windows-specific.
|
||||||
@ -75,7 +74,7 @@ private:
|
|||||||
class EdataContents {
|
class EdataContents {
|
||||||
public:
|
public:
|
||||||
EdataContents();
|
EdataContents();
|
||||||
std::vector<std::unique_ptr<Chunk>> Chunks;
|
std::vector<Chunk *> Chunks;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace coff
|
} // namespace coff
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#include "llvm/ADT/Optional.h"
|
#include "llvm/ADT/Optional.h"
|
||||||
#include "llvm/ADT/StringSwitch.h"
|
#include "llvm/ADT/StringSwitch.h"
|
||||||
#include "llvm/Object/ArchiveWriter.h"
|
#include "llvm/Object/ArchiveWriter.h"
|
||||||
|
#include "llvm/Object/COFFImportFile.h"
|
||||||
|
#include "llvm/Object/COFFModuleDefinition.h"
|
||||||
#include "llvm/Option/Arg.h"
|
#include "llvm/Option/Arg.h"
|
||||||
#include "llvm/Option/ArgList.h"
|
#include "llvm/Option/ArgList.h"
|
||||||
#include "llvm/Option/Option.h"
|
#include "llvm/Option/Option.h"
|
||||||
@ -35,6 +37,7 @@
|
|||||||
#include <future>
|
#include <future>
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
using namespace llvm::object;
|
||||||
using namespace llvm::COFF;
|
using namespace llvm::COFF;
|
||||||
using llvm::sys::Process;
|
using llvm::sys::Process;
|
||||||
using llvm::sys::fs::file_magic;
|
using llvm::sys::fs::file_magic;
|
||||||
@ -97,12 +100,11 @@ static std::future<MBErrPair> createFutureForFile(std::string Path) {
|
|||||||
|
|
||||||
MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> MB) {
|
MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> MB) {
|
||||||
MemoryBufferRef MBRef = *MB;
|
MemoryBufferRef MBRef = *MB;
|
||||||
OwningMBs.push_back(std::move(MB));
|
make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take ownership
|
||||||
|
|
||||||
if (Driver->Tar)
|
if (Driver->Tar)
|
||||||
Driver->Tar->append(relativeToRoot(MBRef.getBufferIdentifier()),
|
Driver->Tar->append(relativeToRoot(MBRef.getBufferIdentifier()),
|
||||||
MBRef.getBuffer());
|
MBRef.getBuffer());
|
||||||
|
|
||||||
return MBRef;
|
return MBRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,6 +422,84 @@ static std::string getMapFile(const opt::InputArgList &Args) {
|
|||||||
return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str();
|
return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string getImplibPath() {
|
||||||
|
if (!Config->Implib.empty())
|
||||||
|
return Config->Implib;
|
||||||
|
SmallString<128> Out = StringRef(Config->OutputFile);
|
||||||
|
sys::path::replace_extension(Out, ".lib");
|
||||||
|
return Out.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<COFFShortExport> createCOFFShortExportFromConfig() {
|
||||||
|
std::vector<COFFShortExport> Exports;
|
||||||
|
for (Export &E1 : Config->Exports) {
|
||||||
|
COFFShortExport E2;
|
||||||
|
E2.Name = E1.Name;
|
||||||
|
E2.ExtName = E1.ExtName;
|
||||||
|
E2.Ordinal = E1.Ordinal;
|
||||||
|
E2.Noname = E1.Noname;
|
||||||
|
E2.Data = E1.Data;
|
||||||
|
E2.Private = E1.Private;
|
||||||
|
E2.Constant = E1.Constant;
|
||||||
|
Exports.push_back(E2);
|
||||||
|
}
|
||||||
|
return Exports;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void createImportLibrary() {
|
||||||
|
std::vector<COFFShortExport> Exports = createCOFFShortExportFromConfig();
|
||||||
|
std::string DLLName = sys::path::filename(Config->OutputFile);
|
||||||
|
std::string Path = getImplibPath();
|
||||||
|
writeImportLibrary(DLLName, Path, Exports, Config->Machine);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parseModuleDefs(StringRef Path) {
|
||||||
|
std::unique_ptr<MemoryBuffer> MB = check(
|
||||||
|
MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path);
|
||||||
|
MemoryBufferRef MBRef = MB->getMemBufferRef();
|
||||||
|
|
||||||
|
Expected<COFFModuleDefinition> Def =
|
||||||
|
parseCOFFModuleDefinition(MBRef, Config->Machine);
|
||||||
|
if (!Def)
|
||||||
|
fatal(errorToErrorCode(Def.takeError()).message());
|
||||||
|
|
||||||
|
COFFModuleDefinition &M = *Def;
|
||||||
|
if (Config->OutputFile.empty())
|
||||||
|
Config->OutputFile = Saver.save(M.OutputFile);
|
||||||
|
|
||||||
|
if (M.ImageBase)
|
||||||
|
Config->ImageBase = M.ImageBase;
|
||||||
|
if (M.StackReserve)
|
||||||
|
Config->StackReserve = M.StackReserve;
|
||||||
|
if (M.StackCommit)
|
||||||
|
Config->StackCommit = M.StackCommit;
|
||||||
|
if (M.HeapReserve)
|
||||||
|
Config->HeapReserve = M.HeapReserve;
|
||||||
|
if (M.HeapCommit)
|
||||||
|
Config->HeapCommit = M.HeapCommit;
|
||||||
|
if (M.MajorImageVersion)
|
||||||
|
Config->MajorImageVersion = M.MajorImageVersion;
|
||||||
|
if (M.MinorImageVersion)
|
||||||
|
Config->MinorImageVersion = M.MinorImageVersion;
|
||||||
|
if (M.MajorOSVersion)
|
||||||
|
Config->MajorOSVersion = M.MajorOSVersion;
|
||||||
|
if (M.MinorOSVersion)
|
||||||
|
Config->MinorOSVersion = M.MinorOSVersion;
|
||||||
|
|
||||||
|
for (COFFShortExport E1 : M.Exports) {
|
||||||
|
Export E2;
|
||||||
|
E2.Name = Saver.save(E1.Name);
|
||||||
|
if (E1.isWeak())
|
||||||
|
E2.ExtName = Saver.save(E1.ExtName);
|
||||||
|
E2.Ordinal = E1.Ordinal;
|
||||||
|
E2.Noname = E1.Noname;
|
||||||
|
E2.Data = E1.Data;
|
||||||
|
E2.Private = E1.Private;
|
||||||
|
E2.Constant = E1.Constant;
|
||||||
|
Config->Exports.push_back(E2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<MemoryBufferRef> getArchiveMembers(Archive *File) {
|
std::vector<MemoryBufferRef> getArchiveMembers(Archive *File) {
|
||||||
std::vector<MemoryBufferRef> V;
|
std::vector<MemoryBufferRef> V;
|
||||||
Error Err = Error::success();
|
Error Err = Error::success();
|
||||||
@ -821,8 +901,6 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
|
|||||||
Config->ManifestInput.push_back(Arg->getValue());
|
Config->ManifestInput.push_back(Arg->getValue());
|
||||||
|
|
||||||
// Handle miscellaneous boolean flags.
|
// Handle miscellaneous boolean flags.
|
||||||
if (Args.hasArg(OPT_allowbind_no))
|
|
||||||
Config->AllowBind = false;
|
|
||||||
if (Args.hasArg(OPT_allowisolation_no))
|
if (Args.hasArg(OPT_allowisolation_no))
|
||||||
Config->AllowIsolation = false;
|
Config->AllowIsolation = false;
|
||||||
if (Args.hasArg(OPT_dynamicbase_no))
|
if (Args.hasArg(OPT_dynamicbase_no))
|
||||||
@ -834,7 +912,6 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
|
|||||||
if (Args.hasArg(OPT_nosymtab))
|
if (Args.hasArg(OPT_nosymtab))
|
||||||
Config->WriteSymtab = false;
|
Config->WriteSymtab = false;
|
||||||
Config->DumpPdb = Args.hasArg(OPT_dumppdb);
|
Config->DumpPdb = Args.hasArg(OPT_dumppdb);
|
||||||
Config->DebugPdb = Args.hasArg(OPT_debugpdb);
|
|
||||||
|
|
||||||
Config->MapFile = getMapFile(Args);
|
Config->MapFile = getMapFile(Args);
|
||||||
|
|
||||||
@ -916,9 +993,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
|
|||||||
// Handle /def
|
// Handle /def
|
||||||
if (auto *Arg = Args.getLastArg(OPT_deffile)) {
|
if (auto *Arg = Args.getLastArg(OPT_deffile)) {
|
||||||
// parseModuleDefs mutates Config object.
|
// parseModuleDefs mutates Config object.
|
||||||
parseModuleDefs(
|
parseModuleDefs(Arg->getValue());
|
||||||
takeBuffer(check(MemoryBuffer::getFile(Arg->getValue()),
|
|
||||||
Twine("could not open ") + Arg->getValue())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle /delayload
|
// Handle /delayload
|
||||||
@ -1038,7 +1113,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
|
|||||||
// need to create a .lib file.
|
// need to create a .lib file.
|
||||||
if (!Config->Exports.empty() || Config->DLL) {
|
if (!Config->Exports.empty() || Config->DLL) {
|
||||||
fixupExports();
|
fixupExports();
|
||||||
writeImportLibrary();
|
createImportLibrary();
|
||||||
assignExportOrdinals();
|
assignExportOrdinals();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,18 +119,11 @@ private:
|
|||||||
void enqueueTask(std::function<void()> Task);
|
void enqueueTask(std::function<void()> Task);
|
||||||
bool run();
|
bool run();
|
||||||
|
|
||||||
// Driver is the owner of all opened files.
|
|
||||||
// InputFiles have MemoryBufferRefs to them.
|
|
||||||
std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
|
|
||||||
|
|
||||||
std::list<std::function<void()>> TaskQueue;
|
std::list<std::function<void()>> TaskQueue;
|
||||||
std::vector<StringRef> FilePaths;
|
std::vector<StringRef> FilePaths;
|
||||||
std::vector<MemoryBufferRef> Resources;
|
std::vector<MemoryBufferRef> Resources;
|
||||||
};
|
};
|
||||||
|
|
||||||
void parseModuleDefs(MemoryBufferRef MB);
|
|
||||||
void writeImportLibrary();
|
|
||||||
|
|
||||||
// Functions below this line are defined in DriverUtils.cpp.
|
// Functions below this line are defined in DriverUtils.cpp.
|
||||||
|
|
||||||
void printHelp(const char *Argv0);
|
void printHelp(const char *Argv0);
|
||||||
|
@ -43,7 +43,7 @@ namespace {
|
|||||||
|
|
||||||
class Executor {
|
class Executor {
|
||||||
public:
|
public:
|
||||||
explicit Executor(StringRef S) : Saver(Alloc), Prog(Saver.save(S)) {}
|
explicit Executor(StringRef S) : Prog(Saver.save(S)) {}
|
||||||
void add(StringRef S) { Args.push_back(Saver.save(S)); }
|
void add(StringRef S) { Args.push_back(Saver.save(S)); }
|
||||||
void add(std::string &S) { Args.push_back(Saver.save(S)); }
|
void add(std::string &S) { Args.push_back(Saver.save(S)); }
|
||||||
void add(Twine S) { Args.push_back(Saver.save(S)); }
|
void add(Twine S) { Args.push_back(Saver.save(S)); }
|
||||||
@ -67,8 +67,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BumpPtrAllocator Alloc;
|
|
||||||
StringSaver Saver;
|
|
||||||
StringRef Prog;
|
StringRef Prog;
|
||||||
std::vector<StringRef> Args;
|
std::vector<StringRef> Args;
|
||||||
};
|
};
|
||||||
|
@ -137,13 +137,13 @@ void ObjectFile::initializeChunks() {
|
|||||||
// CodeView sections are stored to a different vector because they are
|
// CodeView sections are stored to a different vector because they are
|
||||||
// not linked in the regular manner.
|
// not linked in the regular manner.
|
||||||
if (Name == ".debug" || Name.startswith(".debug$")) {
|
if (Name == ".debug" || Name.startswith(".debug$")) {
|
||||||
DebugChunks.push_back(new (Alloc) SectionChunk(this, Sec));
|
DebugChunks.push_back(make<SectionChunk>(this, Sec));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
|
if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
|
||||||
continue;
|
continue;
|
||||||
auto *C = new (Alloc) SectionChunk(this, Sec);
|
auto *C = make<SectionChunk>(this, Sec);
|
||||||
Chunks.push_back(C);
|
Chunks.push_back(C);
|
||||||
SparseChunks[I] = C;
|
SparseChunks[I] = C;
|
||||||
}
|
}
|
||||||
@ -200,7 +200,7 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
|
|||||||
bool IsFirst) {
|
bool IsFirst) {
|
||||||
StringRef Name;
|
StringRef Name;
|
||||||
if (Sym.isCommon()) {
|
if (Sym.isCommon()) {
|
||||||
auto *C = new (Alloc) CommonChunk(Sym);
|
auto *C = make<CommonChunk>(Sym);
|
||||||
Chunks.push_back(C);
|
Chunks.push_back(C);
|
||||||
COFFObj->getSymbolName(Sym, Name);
|
COFFObj->getSymbolName(Sym, Name);
|
||||||
Symbol *S =
|
Symbol *S =
|
||||||
@ -221,7 +221,7 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
|
|||||||
if (Sym.isExternal())
|
if (Sym.isExternal())
|
||||||
return Symtab->addAbsolute(Name, Sym)->body();
|
return Symtab->addAbsolute(Name, Sym)->body();
|
||||||
else
|
else
|
||||||
return new (Alloc) DefinedAbsolute(Name, Sym);
|
return make<DefinedAbsolute>(Name, Sym);
|
||||||
}
|
}
|
||||||
int32_t SectionNumber = Sym.getSectionNumber();
|
int32_t SectionNumber = Sym.getSectionNumber();
|
||||||
if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG)
|
if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG)
|
||||||
@ -258,8 +258,8 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
|
|||||||
Symtab->addRegular(this, Name, SC->isCOMDAT(), Sym.getGeneric(), SC);
|
Symtab->addRegular(this, Name, SC->isCOMDAT(), Sym.getGeneric(), SC);
|
||||||
B = cast<DefinedRegular>(S->body());
|
B = cast<DefinedRegular>(S->body());
|
||||||
} else
|
} else
|
||||||
B = new (Alloc) DefinedRegular(this, /*Name*/ "", SC->isCOMDAT(),
|
B = make<DefinedRegular>(this, /*Name*/ "", SC->isCOMDAT(),
|
||||||
/*IsExternal*/ false, Sym.getGeneric(), SC);
|
/*IsExternal*/ false, Sym.getGeneric(), SC);
|
||||||
if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP)
|
if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP)
|
||||||
SC->setSymbol(B);
|
SC->setSymbol(B);
|
||||||
|
|
||||||
@ -301,8 +301,8 @@ void ImportFile::parse() {
|
|||||||
fatal("broken import library");
|
fatal("broken import library");
|
||||||
|
|
||||||
// Read names and create an __imp_ symbol.
|
// Read names and create an __imp_ symbol.
|
||||||
StringRef Name = StringAlloc.save(StringRef(Buf + sizeof(*Hdr)));
|
StringRef Name = Saver.save(StringRef(Buf + sizeof(*Hdr)));
|
||||||
StringRef ImpName = StringAlloc.save("__imp_" + Name);
|
StringRef ImpName = Saver.save("__imp_" + Name);
|
||||||
const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1;
|
const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1;
|
||||||
DLLName = StringRef(NameStart);
|
DLLName = StringRef(NameStart);
|
||||||
StringRef ExtName;
|
StringRef ExtName;
|
||||||
|
@ -130,7 +130,6 @@ private:
|
|||||||
SymbolBody *createUndefined(COFFSymbolRef Sym);
|
SymbolBody *createUndefined(COFFSymbolRef Sym);
|
||||||
|
|
||||||
std::unique_ptr<COFFObjectFile> COFFObj;
|
std::unique_ptr<COFFObjectFile> COFFObj;
|
||||||
llvm::BumpPtrAllocator Alloc;
|
|
||||||
const coff_section *SXData = nullptr;
|
const coff_section *SXData = nullptr;
|
||||||
|
|
||||||
// List of all chunks defined by this file. This includes both section
|
// List of all chunks defined by this file. This includes both section
|
||||||
@ -162,8 +161,7 @@ private:
|
|||||||
// for details about the format.
|
// for details about the format.
|
||||||
class ImportFile : public InputFile {
|
class ImportFile : public InputFile {
|
||||||
public:
|
public:
|
||||||
explicit ImportFile(MemoryBufferRef M)
|
explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M) {}
|
||||||
: InputFile(ImportKind, M), StringAlloc(StringAllocAux) {}
|
|
||||||
static bool classof(const InputFile *F) { return F->kind() == ImportKind; }
|
static bool classof(const InputFile *F) { return F->kind() == ImportKind; }
|
||||||
|
|
||||||
DefinedImportData *ImpSym = nullptr;
|
DefinedImportData *ImpSym = nullptr;
|
||||||
@ -174,9 +172,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
void parse() override;
|
void parse() override;
|
||||||
|
|
||||||
llvm::BumpPtrAllocator StringAllocAux;
|
|
||||||
llvm::StringSaver StringAlloc;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StringRef ExternalName;
|
StringRef ExternalName;
|
||||||
const coff_import_header *Hdr;
|
const coff_import_header *Hdr;
|
||||||
|
@ -1,511 +0,0 @@
|
|||||||
//===- Librarian.cpp ------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// The LLVM Linker
|
|
||||||
//
|
|
||||||
// This file is distributed under the University of Illinois Open Source
|
|
||||||
// License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// This file contains functions for the Librarian. The librarian creates and
|
|
||||||
// manages libraries of the Common Object File Format (COFF) object files. It
|
|
||||||
// primarily is used for creating static libraries and import libraries.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
#include "Driver.h"
|
|
||||||
#include "Error.h"
|
|
||||||
#include "Symbols.h"
|
|
||||||
#include "llvm/Object/Archive.h"
|
|
||||||
#include "llvm/Object/ArchiveWriter.h"
|
|
||||||
#include "llvm/Object/COFF.h"
|
|
||||||
#include "llvm/Support/Path.h"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
using namespace lld::coff;
|
|
||||||
using namespace llvm::COFF;
|
|
||||||
using namespace llvm::object;
|
|
||||||
using namespace llvm;
|
|
||||||
|
|
||||||
static bool is32bit() {
|
|
||||||
switch (Config->Machine) {
|
|
||||||
default:
|
|
||||||
llvm_unreachable("unsupported machine");
|
|
||||||
case IMAGE_FILE_MACHINE_AMD64:
|
|
||||||
return false;
|
|
||||||
case IMAGE_FILE_MACHINE_ARMNT:
|
|
||||||
case IMAGE_FILE_MACHINE_I386:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t getImgRelRelocation() {
|
|
||||||
switch (Config->Machine) {
|
|
||||||
default:
|
|
||||||
llvm_unreachable("unsupported machine");
|
|
||||||
case IMAGE_FILE_MACHINE_AMD64:
|
|
||||||
return IMAGE_REL_AMD64_ADDR32NB;
|
|
||||||
case IMAGE_FILE_MACHINE_ARMNT:
|
|
||||||
return IMAGE_REL_ARM_ADDR32NB;
|
|
||||||
case IMAGE_FILE_MACHINE_I386:
|
|
||||||
return IMAGE_REL_I386_DIR32NB;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {
|
|
||||||
size_t S = B.size();
|
|
||||||
B.resize(S + sizeof(T));
|
|
||||||
memcpy(&B[S], &Data, sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void writeStringTable(std::vector<uint8_t> &B,
|
|
||||||
ArrayRef<const std::string> Strings) {
|
|
||||||
// The COFF string table consists of a 4-byte value which is the size of the
|
|
||||||
// table, including the length field itself. This value is followed by the
|
|
||||||
// string content itself, which is an array of null-terminated C-style
|
|
||||||
// strings. The termination is important as they are referenced to by offset
|
|
||||||
// by the symbol entity in the file format.
|
|
||||||
|
|
||||||
std::vector<uint8_t>::size_type Pos = B.size();
|
|
||||||
std::vector<uint8_t>::size_type Offset = B.size();
|
|
||||||
|
|
||||||
// Skip over the length field, we will fill it in later as we will have
|
|
||||||
// computed the length while emitting the string content itself.
|
|
||||||
Pos += sizeof(uint32_t);
|
|
||||||
|
|
||||||
for (const auto &S : Strings) {
|
|
||||||
B.resize(Pos + S.length() + 1);
|
|
||||||
strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str());
|
|
||||||
Pos += S.length() + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Backfill the length of the table now that it has been computed.
|
|
||||||
support::ulittle32_t Length(B.size() - Offset);
|
|
||||||
memcpy(&B[Offset], &Length, sizeof(Length));
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string getImplibPath() {
|
|
||||||
if (!Config->Implib.empty())
|
|
||||||
return Config->Implib;
|
|
||||||
SmallString<128> Out = StringRef(Config->OutputFile);
|
|
||||||
sys::path::replace_extension(Out, ".lib");
|
|
||||||
return Out.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
static ImportNameType getNameType(StringRef Sym, StringRef ExtName) {
|
|
||||||
if (Sym != ExtName)
|
|
||||||
return IMPORT_NAME_UNDECORATE;
|
|
||||||
if (Config->Machine == I386 && Sym.startswith("_"))
|
|
||||||
return IMPORT_NAME_NOPREFIX;
|
|
||||||
return IMPORT_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string replace(StringRef S, StringRef From, StringRef To) {
|
|
||||||
size_t Pos = S.find(From);
|
|
||||||
|
|
||||||
// From and To may be mangled, but substrings in S may not.
|
|
||||||
if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) {
|
|
||||||
From = From.substr(1);
|
|
||||||
To = To.substr(1);
|
|
||||||
Pos = S.find(From);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Pos == StringRef::npos) {
|
|
||||||
error(S + ": replacing '" + From + "' with '" + To + "' failed");
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::string NullImportDescriptorSymbolName =
|
|
||||||
"__NULL_IMPORT_DESCRIPTOR";
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
// This class constructs various small object files necessary to support linking
|
|
||||||
// symbols imported from a DLL. The contents are pretty strictly defined and
|
|
||||||
// nearly entirely static. The details of the structures files are defined in
|
|
||||||
// WINNT.h and the PE/COFF specification.
|
|
||||||
class ObjectFactory {
|
|
||||||
using u16 = support::ulittle16_t;
|
|
||||||
using u32 = support::ulittle32_t;
|
|
||||||
|
|
||||||
BumpPtrAllocator Alloc;
|
|
||||||
StringRef DLLName;
|
|
||||||
StringRef Library;
|
|
||||||
std::string ImportDescriptorSymbolName;
|
|
||||||
std::string NullThunkSymbolName;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ObjectFactory(StringRef S)
|
|
||||||
: DLLName(S), Library(S.drop_back(4)),
|
|
||||||
ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()),
|
|
||||||
NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {}
|
|
||||||
|
|
||||||
// Creates an Import Descriptor. This is a small object file which contains a
|
|
||||||
// reference to the terminators and contains the library name (entry) for the
|
|
||||||
// import name table. It will force the linker to construct the necessary
|
|
||||||
// structure to import symbols from the DLL.
|
|
||||||
NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);
|
|
||||||
|
|
||||||
// Creates a NULL import descriptor. This is a small object file whcih
|
|
||||||
// contains a NULL import descriptor. It is used to terminate the imports
|
|
||||||
// from a specific DLL.
|
|
||||||
NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);
|
|
||||||
|
|
||||||
// Create a NULL Thunk Entry. This is a small object file which contains a
|
|
||||||
// NULL Import Address Table entry and a NULL Import Lookup Table Entry. It
|
|
||||||
// is used to terminate the IAT and ILT.
|
|
||||||
NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);
|
|
||||||
|
|
||||||
// Create a short import file which is described in PE/COFF spec 7. Import
|
|
||||||
// Library Format.
|
|
||||||
NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
|
|
||||||
ImportType Type, ImportNameType NameType);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
NewArchiveMember
|
|
||||||
ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
|
|
||||||
static const uint32_t NumberOfSections = 2;
|
|
||||||
static const uint32_t NumberOfSymbols = 7;
|
|
||||||
static const uint32_t NumberOfRelocations = 3;
|
|
||||||
|
|
||||||
// COFF Header
|
|
||||||
coff_file_header Header{
|
|
||||||
u16(Config->Machine), u16(NumberOfSections), u32(0),
|
|
||||||
u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
|
|
||||||
// .idata$2
|
|
||||||
sizeof(coff_import_directory_table_entry) +
|
|
||||||
NumberOfRelocations * sizeof(coff_relocation) +
|
|
||||||
// .idata$4
|
|
||||||
(DLLName.size() + 1)),
|
|
||||||
u32(NumberOfSymbols), u16(0),
|
|
||||||
u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0),
|
|
||||||
};
|
|
||||||
append(Buffer, Header);
|
|
||||||
|
|
||||||
// Section Header Table
|
|
||||||
static const coff_section SectionTable[NumberOfSections] = {
|
|
||||||
{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
|
|
||||||
u32(0),
|
|
||||||
u32(0),
|
|
||||||
u32(sizeof(coff_import_directory_table_entry)),
|
|
||||||
u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
|
|
||||||
u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
|
|
||||||
sizeof(coff_import_directory_table_entry)),
|
|
||||||
u32(0),
|
|
||||||
u16(NumberOfRelocations),
|
|
||||||
u16(0),
|
|
||||||
u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
|
|
||||||
IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
|
|
||||||
{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
|
|
||||||
u32(0),
|
|
||||||
u32(0),
|
|
||||||
u32(DLLName.size() + 1),
|
|
||||||
u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
|
|
||||||
sizeof(coff_import_directory_table_entry) +
|
|
||||||
NumberOfRelocations * sizeof(coff_relocation)),
|
|
||||||
u32(0),
|
|
||||||
u32(0),
|
|
||||||
u16(0),
|
|
||||||
u16(0),
|
|
||||||
u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
|
|
||||||
IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
|
|
||||||
};
|
|
||||||
append(Buffer, SectionTable);
|
|
||||||
|
|
||||||
// .idata$2
|
|
||||||
static const coff_import_directory_table_entry ImportDescriptor{
|
|
||||||
u32(0), u32(0), u32(0), u32(0), u32(0),
|
|
||||||
};
|
|
||||||
append(Buffer, ImportDescriptor);
|
|
||||||
|
|
||||||
static const coff_relocation RelocationTable[NumberOfRelocations] = {
|
|
||||||
{u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
|
|
||||||
u16(getImgRelRelocation())},
|
|
||||||
{u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
|
|
||||||
u32(3), u16(getImgRelRelocation())},
|
|
||||||
{u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
|
|
||||||
u32(4), u16(getImgRelRelocation())},
|
|
||||||
};
|
|
||||||
append(Buffer, RelocationTable);
|
|
||||||
|
|
||||||
// .idata$6
|
|
||||||
auto S = Buffer.size();
|
|
||||||
Buffer.resize(S + DLLName.size() + 1);
|
|
||||||
memcpy(&Buffer[S], DLLName.data(), DLLName.size());
|
|
||||||
Buffer[S + DLLName.size()] = '\0';
|
|
||||||
|
|
||||||
// Symbol Table
|
|
||||||
coff_symbol16 SymbolTable[NumberOfSymbols] = {
|
|
||||||
{{{0, 0, 0, 0, 0, 0, 0, 0}},
|
|
||||||
u32(0),
|
|
||||||
u16(1),
|
|
||||||
u16(0),
|
|
||||||
IMAGE_SYM_CLASS_EXTERNAL,
|
|
||||||
0},
|
|
||||||
{{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
|
|
||||||
u32(0),
|
|
||||||
u16(1),
|
|
||||||
u16(0),
|
|
||||||
IMAGE_SYM_CLASS_SECTION,
|
|
||||||
0},
|
|
||||||
{{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
|
|
||||||
u32(0),
|
|
||||||
u16(2),
|
|
||||||
u16(0),
|
|
||||||
IMAGE_SYM_CLASS_STATIC,
|
|
||||||
0},
|
|
||||||
{{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
|
|
||||||
u32(0),
|
|
||||||
u16(0),
|
|
||||||
u16(0),
|
|
||||||
IMAGE_SYM_CLASS_SECTION,
|
|
||||||
0},
|
|
||||||
{{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
|
|
||||||
u32(0),
|
|
||||||
u16(0),
|
|
||||||
u16(0),
|
|
||||||
IMAGE_SYM_CLASS_SECTION,
|
|
||||||
0},
|
|
||||||
{{{0, 0, 0, 0, 0, 0, 0, 0}},
|
|
||||||
u32(0),
|
|
||||||
u16(0),
|
|
||||||
u16(0),
|
|
||||||
IMAGE_SYM_CLASS_EXTERNAL,
|
|
||||||
0},
|
|
||||||
{{{0, 0, 0, 0, 0, 0, 0, 0}},
|
|
||||||
u32(0),
|
|
||||||
u16(0),
|
|
||||||
u16(0),
|
|
||||||
IMAGE_SYM_CLASS_EXTERNAL,
|
|
||||||
0},
|
|
||||||
};
|
|
||||||
reinterpret_cast<StringTableOffset &>(SymbolTable[0].Name).Offset =
|
|
||||||
sizeof(uint32_t);
|
|
||||||
reinterpret_cast<StringTableOffset &>(SymbolTable[5].Name).Offset =
|
|
||||||
sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
|
|
||||||
reinterpret_cast<StringTableOffset &>(SymbolTable[6].Name).Offset =
|
|
||||||
sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
|
|
||||||
NullImportDescriptorSymbolName.length() + 1;
|
|
||||||
append(Buffer, SymbolTable);
|
|
||||||
|
|
||||||
// String Table
|
|
||||||
writeStringTable(Buffer,
|
|
||||||
{ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
|
|
||||||
NullThunkSymbolName});
|
|
||||||
|
|
||||||
StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
|
|
||||||
return {MemoryBufferRef(F, DLLName)};
|
|
||||||
}
|
|
||||||
|
|
||||||
NewArchiveMember
|
|
||||||
ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
|
|
||||||
static const uint32_t NumberOfSections = 1;
|
|
||||||
static const uint32_t NumberOfSymbols = 1;
|
|
||||||
|
|
||||||
// COFF Header
|
|
||||||
coff_file_header Header{
|
|
||||||
u16(Config->Machine), u16(NumberOfSections), u32(0),
|
|
||||||
u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
|
|
||||||
// .idata$3
|
|
||||||
sizeof(coff_import_directory_table_entry)),
|
|
||||||
u32(NumberOfSymbols), u16(0),
|
|
||||||
u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0),
|
|
||||||
};
|
|
||||||
append(Buffer, Header);
|
|
||||||
|
|
||||||
// Section Header Table
|
|
||||||
static const coff_section SectionTable[NumberOfSections] = {
|
|
||||||
{{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
|
|
||||||
u32(0),
|
|
||||||
u32(0),
|
|
||||||
u32(sizeof(coff_import_directory_table_entry)),
|
|
||||||
u32(sizeof(coff_file_header) +
|
|
||||||
(NumberOfSections * sizeof(coff_section))),
|
|
||||||
u32(0),
|
|
||||||
u32(0),
|
|
||||||
u16(0),
|
|
||||||
u16(0),
|
|
||||||
u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
|
|
||||||
IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
|
|
||||||
};
|
|
||||||
append(Buffer, SectionTable);
|
|
||||||
|
|
||||||
// .idata$3
|
|
||||||
static const coff_import_directory_table_entry ImportDescriptor{
|
|
||||||
u32(0), u32(0), u32(0), u32(0), u32(0),
|
|
||||||
};
|
|
||||||
append(Buffer, ImportDescriptor);
|
|
||||||
|
|
||||||
// Symbol Table
|
|
||||||
coff_symbol16 SymbolTable[NumberOfSymbols] = {
|
|
||||||
{{{0, 0, 0, 0, 0, 0, 0, 0}},
|
|
||||||
u32(0),
|
|
||||||
u16(1),
|
|
||||||
u16(0),
|
|
||||||
IMAGE_SYM_CLASS_EXTERNAL,
|
|
||||||
0},
|
|
||||||
};
|
|
||||||
reinterpret_cast<StringTableOffset &>(SymbolTable[0].Name).Offset =
|
|
||||||
sizeof(uint32_t);
|
|
||||||
append(Buffer, SymbolTable);
|
|
||||||
|
|
||||||
// String Table
|
|
||||||
writeStringTable(Buffer, {NullImportDescriptorSymbolName});
|
|
||||||
|
|
||||||
StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
|
|
||||||
return {MemoryBufferRef(F, DLLName)};
|
|
||||||
}
|
|
||||||
|
|
||||||
NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
|
|
||||||
static const uint32_t NumberOfSections = 2;
|
|
||||||
static const uint32_t NumberOfSymbols = 1;
|
|
||||||
uint32_t VASize = is32bit() ? 4 : 8;
|
|
||||||
|
|
||||||
// COFF Header
|
|
||||||
coff_file_header Header{
|
|
||||||
u16(Config->Machine), u16(NumberOfSections), u32(0),
|
|
||||||
u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
|
|
||||||
// .idata$5
|
|
||||||
VASize +
|
|
||||||
// .idata$4
|
|
||||||
VASize),
|
|
||||||
u32(NumberOfSymbols), u16(0),
|
|
||||||
u16(is32bit() ? IMAGE_FILE_32BIT_MACHINE : 0),
|
|
||||||
};
|
|
||||||
append(Buffer, Header);
|
|
||||||
|
|
||||||
// Section Header Table
|
|
||||||
static const coff_section SectionTable[NumberOfSections] = {
|
|
||||||
{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
|
|
||||||
u32(0),
|
|
||||||
u32(0),
|
|
||||||
u32(VASize),
|
|
||||||
u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
|
|
||||||
u32(0),
|
|
||||||
u32(0),
|
|
||||||
u16(0),
|
|
||||||
u16(0),
|
|
||||||
u32((is32bit() ? IMAGE_SCN_ALIGN_4BYTES : IMAGE_SCN_ALIGN_8BYTES) |
|
|
||||||
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
|
|
||||||
IMAGE_SCN_MEM_WRITE)},
|
|
||||||
{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
|
|
||||||
u32(0),
|
|
||||||
u32(0),
|
|
||||||
u32(VASize),
|
|
||||||
u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
|
|
||||||
VASize),
|
|
||||||
u32(0),
|
|
||||||
u32(0),
|
|
||||||
u16(0),
|
|
||||||
u16(0),
|
|
||||||
u32((is32bit() ? IMAGE_SCN_ALIGN_4BYTES : IMAGE_SCN_ALIGN_8BYTES) |
|
|
||||||
IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
|
|
||||||
IMAGE_SCN_MEM_WRITE)},
|
|
||||||
};
|
|
||||||
append(Buffer, SectionTable);
|
|
||||||
|
|
||||||
// .idata$5, ILT
|
|
||||||
append(Buffer, u32(0));
|
|
||||||
if (!is32bit())
|
|
||||||
append(Buffer, u32(0));
|
|
||||||
|
|
||||||
// .idata$4, IAT
|
|
||||||
append(Buffer, u32(0));
|
|
||||||
if (!is32bit())
|
|
||||||
append(Buffer, u32(0));
|
|
||||||
|
|
||||||
// Symbol Table
|
|
||||||
coff_symbol16 SymbolTable[NumberOfSymbols] = {
|
|
||||||
{{{0, 0, 0, 0, 0, 0, 0, 0}},
|
|
||||||
u32(0),
|
|
||||||
u16(1),
|
|
||||||
u16(0),
|
|
||||||
IMAGE_SYM_CLASS_EXTERNAL,
|
|
||||||
0},
|
|
||||||
};
|
|
||||||
reinterpret_cast<StringTableOffset &>(SymbolTable[0].Name).Offset =
|
|
||||||
sizeof(uint32_t);
|
|
||||||
append(Buffer, SymbolTable);
|
|
||||||
|
|
||||||
// String Table
|
|
||||||
writeStringTable(Buffer, {NullThunkSymbolName});
|
|
||||||
|
|
||||||
StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
|
|
||||||
return {MemoryBufferRef{F, DLLName}};
|
|
||||||
}
|
|
||||||
|
|
||||||
NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
|
|
||||||
uint16_t Ordinal,
|
|
||||||
ImportType ImportType,
|
|
||||||
ImportNameType NameType) {
|
|
||||||
size_t ImpSize = DLLName.size() + Sym.size() + 2; // +2 for NULs
|
|
||||||
size_t Size = sizeof(coff_import_header) + ImpSize;
|
|
||||||
char *Buf = Alloc.Allocate<char>(Size);
|
|
||||||
memset(Buf, 0, Size);
|
|
||||||
char *P = Buf;
|
|
||||||
|
|
||||||
// Write short import library.
|
|
||||||
auto *Imp = reinterpret_cast<coff_import_header *>(P);
|
|
||||||
P += sizeof(*Imp);
|
|
||||||
Imp->Sig2 = 0xFFFF;
|
|
||||||
Imp->Machine = Config->Machine;
|
|
||||||
Imp->SizeOfData = ImpSize;
|
|
||||||
if (Ordinal > 0)
|
|
||||||
Imp->OrdinalHint = Ordinal;
|
|
||||||
Imp->TypeInfo = (NameType << 2) | ImportType;
|
|
||||||
|
|
||||||
// Write symbol name and DLL name.
|
|
||||||
memcpy(P, Sym.data(), Sym.size());
|
|
||||||
P += Sym.size() + 1;
|
|
||||||
memcpy(P, DLLName.data(), DLLName.size());
|
|
||||||
|
|
||||||
return {MemoryBufferRef(StringRef(Buf, Size), DLLName)};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates an import library for a DLL. In this function, we first
|
|
||||||
// create an empty import library using lib.exe and then adds short
|
|
||||||
// import files to that file.
|
|
||||||
void lld::coff::writeImportLibrary() {
|
|
||||||
std::vector<NewArchiveMember> Members;
|
|
||||||
|
|
||||||
std::string Path = getImplibPath();
|
|
||||||
std::string DLLName = sys::path::filename(Config->OutputFile);
|
|
||||||
ObjectFactory OF(DLLName);
|
|
||||||
|
|
||||||
std::vector<uint8_t> ImportDescriptor;
|
|
||||||
Members.push_back(OF.createImportDescriptor(ImportDescriptor));
|
|
||||||
|
|
||||||
std::vector<uint8_t> NullImportDescriptor;
|
|
||||||
Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
|
|
||||||
|
|
||||||
std::vector<uint8_t> NullThunk;
|
|
||||||
Members.push_back(OF.createNullThunk(NullThunk));
|
|
||||||
|
|
||||||
for (Export &E : Config->Exports) {
|
|
||||||
if (E.Private)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ImportType ImportType = IMPORT_CODE;
|
|
||||||
if (E.Data)
|
|
||||||
ImportType = IMPORT_DATA;
|
|
||||||
if (E.Constant)
|
|
||||||
ImportType = IMPORT_CONST;
|
|
||||||
|
|
||||||
ImportNameType NameType = getNameType(E.SymbolName, E.Name);
|
|
||||||
std::string Name = E.ExtName.empty()
|
|
||||||
? std::string(E.SymbolName)
|
|
||||||
: replace(E.SymbolName, E.Name, E.ExtName);
|
|
||||||
Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType,
|
|
||||||
NameType));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<StringRef, std::error_code> Result =
|
|
||||||
writeArchive(Path, Members, /*WriteSymtab*/ true, object::Archive::K_GNU,
|
|
||||||
/*Deterministic*/ true, /*Thin*/ false);
|
|
||||||
if (auto EC = Result.second)
|
|
||||||
fatal(EC, "failed to write " + Path);
|
|
||||||
}
|
|
@ -1,304 +0,0 @@
|
|||||||
//===- COFF/ModuleDef.cpp -------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// The LLVM Linker
|
|
||||||
//
|
|
||||||
// This file is distributed under the University of Illinois Open Source
|
|
||||||
// License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// Windows-specific.
|
|
||||||
// A parser for the module-definition file (.def file).
|
|
||||||
// Parsed results are directly written to Config global variable.
|
|
||||||
//
|
|
||||||
// The format of module-definition files are described in this document:
|
|
||||||
// https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "Config.h"
|
|
||||||
#include "Error.h"
|
|
||||||
#include "Memory.h"
|
|
||||||
#include "llvm/ADT/StringRef.h"
|
|
||||||
#include "llvm/ADT/StringSwitch.h"
|
|
||||||
#include "llvm/Support/StringSaver.h"
|
|
||||||
#include "llvm/Support/raw_ostream.h"
|
|
||||||
#include <system_error>
|
|
||||||
|
|
||||||
using namespace llvm;
|
|
||||||
|
|
||||||
namespace lld {
|
|
||||||
namespace coff {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
enum Kind {
|
|
||||||
Unknown,
|
|
||||||
Eof,
|
|
||||||
Identifier,
|
|
||||||
Comma,
|
|
||||||
Equal,
|
|
||||||
KwBase,
|
|
||||||
KwConstant,
|
|
||||||
KwData,
|
|
||||||
KwExports,
|
|
||||||
KwHeapsize,
|
|
||||||
KwLibrary,
|
|
||||||
KwName,
|
|
||||||
KwNoname,
|
|
||||||
KwPrivate,
|
|
||||||
KwStacksize,
|
|
||||||
KwVersion,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Token {
|
|
||||||
explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
|
|
||||||
Kind K;
|
|
||||||
StringRef Value;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool isDecorated(StringRef Sym) {
|
|
||||||
return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?");
|
|
||||||
}
|
|
||||||
|
|
||||||
class Lexer {
|
|
||||||
public:
|
|
||||||
explicit Lexer(StringRef S) : Buf(S) {}
|
|
||||||
|
|
||||||
Token lex() {
|
|
||||||
Buf = Buf.trim();
|
|
||||||
if (Buf.empty())
|
|
||||||
return Token(Eof);
|
|
||||||
|
|
||||||
switch (Buf[0]) {
|
|
||||||
case '\0':
|
|
||||||
return Token(Eof);
|
|
||||||
case ';': {
|
|
||||||
size_t End = Buf.find('\n');
|
|
||||||
Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
|
|
||||||
return lex();
|
|
||||||
}
|
|
||||||
case '=':
|
|
||||||
Buf = Buf.drop_front();
|
|
||||||
return Token(Equal, "=");
|
|
||||||
case ',':
|
|
||||||
Buf = Buf.drop_front();
|
|
||||||
return Token(Comma, ",");
|
|
||||||
case '"': {
|
|
||||||
StringRef S;
|
|
||||||
std::tie(S, Buf) = Buf.substr(1).split('"');
|
|
||||||
return Token(Identifier, S);
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
size_t End = Buf.find_first_of("=,\r\n \t\v");
|
|
||||||
StringRef Word = Buf.substr(0, End);
|
|
||||||
Kind K = llvm::StringSwitch<Kind>(Word)
|
|
||||||
.Case("BASE", KwBase)
|
|
||||||
.Case("CONSTANT", KwConstant)
|
|
||||||
.Case("DATA", KwData)
|
|
||||||
.Case("EXPORTS", KwExports)
|
|
||||||
.Case("HEAPSIZE", KwHeapsize)
|
|
||||||
.Case("LIBRARY", KwLibrary)
|
|
||||||
.Case("NAME", KwName)
|
|
||||||
.Case("NONAME", KwNoname)
|
|
||||||
.Case("PRIVATE", KwPrivate)
|
|
||||||
.Case("STACKSIZE", KwStacksize)
|
|
||||||
.Case("VERSION", KwVersion)
|
|
||||||
.Default(Identifier);
|
|
||||||
Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
|
|
||||||
return Token(K, Word);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
StringRef Buf;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Parser {
|
|
||||||
public:
|
|
||||||
explicit Parser(StringRef S) : Lex(S) {}
|
|
||||||
|
|
||||||
void parse() {
|
|
||||||
do {
|
|
||||||
parseOne();
|
|
||||||
} while (Tok.K != Eof);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void read() {
|
|
||||||
if (Stack.empty()) {
|
|
||||||
Tok = Lex.lex();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Tok = Stack.back();
|
|
||||||
Stack.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
void readAsInt(uint64_t *I) {
|
|
||||||
read();
|
|
||||||
if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
|
|
||||||
fatal("integer expected");
|
|
||||||
}
|
|
||||||
|
|
||||||
void expect(Kind Expected, StringRef Msg) {
|
|
||||||
read();
|
|
||||||
if (Tok.K != Expected)
|
|
||||||
fatal(Msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void unget() { Stack.push_back(Tok); }
|
|
||||||
|
|
||||||
void parseOne() {
|
|
||||||
read();
|
|
||||||
switch (Tok.K) {
|
|
||||||
case Eof:
|
|
||||||
return;
|
|
||||||
case KwExports:
|
|
||||||
for (;;) {
|
|
||||||
read();
|
|
||||||
if (Tok.K != Identifier) {
|
|
||||||
unget();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
parseExport();
|
|
||||||
}
|
|
||||||
case KwHeapsize:
|
|
||||||
parseNumbers(&Config->HeapReserve, &Config->HeapCommit);
|
|
||||||
return;
|
|
||||||
case KwStacksize:
|
|
||||||
parseNumbers(&Config->StackReserve, &Config->StackCommit);
|
|
||||||
return;
|
|
||||||
case KwLibrary:
|
|
||||||
case KwName: {
|
|
||||||
bool IsDll = Tok.K == KwLibrary; // Check before parseName.
|
|
||||||
std::string Name;
|
|
||||||
parseName(&Name, &Config->ImageBase);
|
|
||||||
|
|
||||||
// Append the appropriate file extension if not already present.
|
|
||||||
StringRef Ext = IsDll ? ".dll" : ".exe";
|
|
||||||
if (!StringRef(Name).endswith_lower(Ext))
|
|
||||||
Name += Ext;
|
|
||||||
|
|
||||||
// Set the output file, but don't override /out if it was already passed.
|
|
||||||
if (Config->OutputFile.empty())
|
|
||||||
Config->OutputFile = Name;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case KwVersion:
|
|
||||||
parseVersion(&Config->MajorImageVersion, &Config->MinorImageVersion);
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
fatal("unknown directive: " + Tok.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void parseExport() {
|
|
||||||
Export E;
|
|
||||||
E.Name = Tok.Value;
|
|
||||||
read();
|
|
||||||
if (Tok.K == Equal) {
|
|
||||||
read();
|
|
||||||
if (Tok.K != Identifier)
|
|
||||||
fatal("identifier expected, but got " + Tok.Value);
|
|
||||||
E.ExtName = E.Name;
|
|
||||||
E.Name = Tok.Value;
|
|
||||||
} else {
|
|
||||||
unget();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config->Machine == I386) {
|
|
||||||
if (!isDecorated(E.Name))
|
|
||||||
E.Name = Saver.save("_" + E.Name);
|
|
||||||
if (!E.ExtName.empty() && !isDecorated(E.ExtName))
|
|
||||||
E.ExtName = Saver.save("_" + E.ExtName);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
read();
|
|
||||||
if (Tok.K == Identifier && Tok.Value[0] == '@') {
|
|
||||||
Tok.Value.drop_front().getAsInteger(10, E.Ordinal);
|
|
||||||
read();
|
|
||||||
if (Tok.K == KwNoname) {
|
|
||||||
E.Noname = true;
|
|
||||||
} else {
|
|
||||||
unget();
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (Tok.K == KwData) {
|
|
||||||
E.Data = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (Tok.K == KwConstant) {
|
|
||||||
warn("CONSTANT keyword is obsolete; use DATA");
|
|
||||||
E.Constant = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (Tok.K == KwPrivate) {
|
|
||||||
E.Private = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
unget();
|
|
||||||
Config->Exports.push_back(E);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HEAPSIZE/STACKSIZE reserve[,commit]
|
|
||||||
void parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
|
|
||||||
readAsInt(Reserve);
|
|
||||||
read();
|
|
||||||
if (Tok.K != Comma) {
|
|
||||||
unget();
|
|
||||||
Commit = nullptr;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
readAsInt(Commit);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NAME outputPath [BASE=address]
|
|
||||||
void parseName(std::string *Out, uint64_t *Baseaddr) {
|
|
||||||
read();
|
|
||||||
if (Tok.K == Identifier) {
|
|
||||||
*Out = Tok.Value;
|
|
||||||
} else {
|
|
||||||
*Out = "";
|
|
||||||
unget();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
read();
|
|
||||||
if (Tok.K == KwBase) {
|
|
||||||
expect(Equal, "'=' expected");
|
|
||||||
readAsInt(Baseaddr);
|
|
||||||
} else {
|
|
||||||
unget();
|
|
||||||
*Baseaddr = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// VERSION major[.minor]
|
|
||||||
void parseVersion(uint32_t *Major, uint32_t *Minor) {
|
|
||||||
read();
|
|
||||||
if (Tok.K != Identifier)
|
|
||||||
fatal("identifier expected, but got " + Tok.Value);
|
|
||||||
StringRef V1, V2;
|
|
||||||
std::tie(V1, V2) = Tok.Value.split('.');
|
|
||||||
if (V1.getAsInteger(10, *Major))
|
|
||||||
fatal("integer expected, but got " + Tok.Value);
|
|
||||||
if (V2.empty())
|
|
||||||
*Minor = 0;
|
|
||||||
else if (V2.getAsInteger(10, *Minor))
|
|
||||||
fatal("integer expected, but got " + Tok.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Lexer Lex;
|
|
||||||
Token Tok;
|
|
||||||
std::vector<Token> Stack;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
void parseModuleDefs(MemoryBufferRef MB) { Parser(MB.getBuffer()).parse(); }
|
|
||||||
|
|
||||||
} // namespace coff
|
|
||||||
} // namespace lld
|
|
@ -102,7 +102,6 @@ def nosymtab : F<"nosymtab">;
|
|||||||
def msvclto : F<"msvclto">;
|
def msvclto : F<"msvclto">;
|
||||||
|
|
||||||
// Flags for debugging
|
// Flags for debugging
|
||||||
def debugpdb : F<"debugpdb">;
|
|
||||||
def dumppdb : Joined<["/", "-"], "dumppdb">;
|
def dumppdb : Joined<["/", "-"], "dumppdb">;
|
||||||
def lldmap : F<"lldmap">;
|
def lldmap : F<"lldmap">;
|
||||||
def lldmap_file : Joined<["/", "-"], "lldmap:">;
|
def lldmap_file : Joined<["/", "-"], "lldmap:">;
|
||||||
|
15
COFF/PDB.cpp
15
COFF/PDB.cpp
@ -14,7 +14,8 @@
|
|||||||
#include "SymbolTable.h"
|
#include "SymbolTable.h"
|
||||||
#include "Symbols.h"
|
#include "Symbols.h"
|
||||||
#include "llvm/DebugInfo/CodeView/CVDebugRecord.h"
|
#include "llvm/DebugInfo/CodeView/CVDebugRecord.h"
|
||||||
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
|
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
||||||
|
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
|
||||||
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
|
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
|
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
|
||||||
@ -107,6 +108,7 @@ static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder,
|
|||||||
BinaryByteStream Stream(Data, support::little);
|
BinaryByteStream Stream(Data, support::little);
|
||||||
codeview::CVTypeArray Types;
|
codeview::CVTypeArray Types;
|
||||||
BinaryStreamReader Reader(Stream);
|
BinaryStreamReader Reader(Stream);
|
||||||
|
SmallVector<TypeIndex, 128> SourceToDest;
|
||||||
// Follow type servers. If the same type server is encountered more than
|
// Follow type servers. If the same type server is encountered more than
|
||||||
// once for this instance of `PDBTypeServerHandler` (for example if many
|
// once for this instance of `PDBTypeServerHandler` (for example if many
|
||||||
// object files reference the same TypeServer), the types from the
|
// object files reference the same TypeServer), the types from the
|
||||||
@ -115,8 +117,8 @@ static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder,
|
|||||||
Handler.addSearchPath(llvm::sys::path::parent_path(File->getName()));
|
Handler.addSearchPath(llvm::sys::path::parent_path(File->getName()));
|
||||||
if (auto EC = Reader.readArray(Types, Reader.getLength()))
|
if (auto EC = Reader.readArray(Types, Reader.getLength()))
|
||||||
fatal(EC, "Reader::readArray failed");
|
fatal(EC, "Reader::readArray failed");
|
||||||
if (auto Err =
|
if (auto Err = codeview::mergeTypeStreams(IDTable, TypeTable, SourceToDest,
|
||||||
codeview::mergeTypeStreams(IDTable, TypeTable, &Handler, Types))
|
&Handler, Types))
|
||||||
fatal(Err, "codeview::mergeTypeStreams failed");
|
fatal(Err, "codeview::mergeTypeStreams failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,12 +135,11 @@ static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) {
|
|||||||
if (Data.empty())
|
if (Data.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TypeDatabase TDB(0);
|
LazyRandomTypeCollection Types(Data, 100);
|
||||||
TypeDumpVisitor TDV(TDB, &W, false);
|
TypeDumpVisitor TDV(Types, &W, false);
|
||||||
// Use a default implementation that does not follow type servers and instead
|
// Use a default implementation that does not follow type servers and instead
|
||||||
// just dumps the contents of the TypeServer2 record.
|
// just dumps the contents of the TypeServer2 record.
|
||||||
CVTypeDumper TypeDumper(TDB);
|
if (auto EC = codeview::visitTypeStream(Types, TDV))
|
||||||
if (auto EC = TypeDumper.dump(Data, TDV))
|
|
||||||
fatal(EC, "CVTypeDumper::dump failed");
|
fatal(EC, "CVTypeDumper::dump failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
#include "llvm/ADT/CachedHashString.h"
|
#include "llvm/ADT/CachedHashString.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/DenseMapInfo.h"
|
#include "llvm/ADT/DenseMapInfo.h"
|
||||||
#include "llvm/Support/Allocator.h"
|
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
@ -48,8 +48,7 @@ namespace {
|
|||||||
|
|
||||||
class DebugDirectoryChunk : public Chunk {
|
class DebugDirectoryChunk : public Chunk {
|
||||||
public:
|
public:
|
||||||
DebugDirectoryChunk(const std::vector<std::unique_ptr<Chunk>> &R)
|
DebugDirectoryChunk(const std::vector<Chunk *> &R) : Records(R) {}
|
||||||
: Records(R) {}
|
|
||||||
|
|
||||||
size_t getSize() const override {
|
size_t getSize() const override {
|
||||||
return Records.size() * sizeof(debug_directory);
|
return Records.size() * sizeof(debug_directory);
|
||||||
@ -58,7 +57,7 @@ public:
|
|||||||
void writeTo(uint8_t *B) const override {
|
void writeTo(uint8_t *B) const override {
|
||||||
auto *D = reinterpret_cast<debug_directory *>(B + OutputSectionOff);
|
auto *D = reinterpret_cast<debug_directory *>(B + OutputSectionOff);
|
||||||
|
|
||||||
for (const std::unique_ptr<Chunk> &Record : Records) {
|
for (const Chunk *Record : Records) {
|
||||||
D->Characteristics = 0;
|
D->Characteristics = 0;
|
||||||
D->TimeDateStamp = 0;
|
D->TimeDateStamp = 0;
|
||||||
D->MajorVersion = 0;
|
D->MajorVersion = 0;
|
||||||
@ -74,7 +73,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::vector<std::unique_ptr<Chunk>> &Records;
|
const std::vector<Chunk *> &Records;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CVDebugRecordChunk : public Chunk {
|
class CVDebugRecordChunk : public Chunk {
|
||||||
@ -142,10 +141,10 @@ private:
|
|||||||
IdataContents Idata;
|
IdataContents Idata;
|
||||||
DelayLoadContents DelayIdata;
|
DelayLoadContents DelayIdata;
|
||||||
EdataContents Edata;
|
EdataContents Edata;
|
||||||
std::unique_ptr<SEHTableChunk> SEHTable;
|
SEHTableChunk *SEHTable = nullptr;
|
||||||
|
|
||||||
std::unique_ptr<Chunk> DebugDirectory;
|
Chunk *DebugDirectory = nullptr;
|
||||||
std::vector<std::unique_ptr<Chunk>> DebugRecords;
|
std::vector<Chunk *> DebugRecords;
|
||||||
CVDebugRecordChunk *BuildId = nullptr;
|
CVDebugRecordChunk *BuildId = nullptr;
|
||||||
ArrayRef<uint8_t> SectionTable;
|
ArrayRef<uint8_t> SectionTable;
|
||||||
|
|
||||||
@ -153,8 +152,6 @@ private:
|
|||||||
uint32_t PointerToSymbolTable = 0;
|
uint32_t PointerToSymbolTable = 0;
|
||||||
uint64_t SizeOfImage;
|
uint64_t SizeOfImage;
|
||||||
uint64_t SizeOfHeaders;
|
uint64_t SizeOfHeaders;
|
||||||
|
|
||||||
std::vector<std::unique_ptr<Chunk>> Chunks;
|
|
||||||
};
|
};
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
@ -258,7 +255,7 @@ void Writer::run() {
|
|||||||
sortExceptionTable();
|
sortExceptionTable();
|
||||||
writeBuildId();
|
writeBuildId();
|
||||||
|
|
||||||
if (!Config->PDBPath.empty()) {
|
if (!Config->PDBPath.empty() && Config->Debug) {
|
||||||
const llvm::codeview::DebugInfo *DI = nullptr;
|
const llvm::codeview::DebugInfo *DI = nullptr;
|
||||||
if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV))
|
if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV))
|
||||||
DI = BuildId->DI;
|
DI = BuildId->DI;
|
||||||
@ -324,19 +321,19 @@ void Writer::createMiscChunks() {
|
|||||||
|
|
||||||
// Create Debug Information Chunks
|
// Create Debug Information Chunks
|
||||||
if (Config->Debug) {
|
if (Config->Debug) {
|
||||||
DebugDirectory = llvm::make_unique<DebugDirectoryChunk>(DebugRecords);
|
DebugDirectory = make<DebugDirectoryChunk>(DebugRecords);
|
||||||
|
|
||||||
// TODO(compnerd) create a coffgrp entry if DebugType::CV is not enabled
|
// TODO(compnerd) create a coffgrp entry if DebugType::CV is not enabled
|
||||||
if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV)) {
|
if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV)) {
|
||||||
auto Chunk = llvm::make_unique<CVDebugRecordChunk>();
|
auto *Chunk = make<CVDebugRecordChunk>();
|
||||||
|
|
||||||
BuildId = Chunk.get();
|
BuildId = Chunk;
|
||||||
DebugRecords.push_back(std::move(Chunk));
|
DebugRecords.push_back(Chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
RData->addChunk(DebugDirectory.get());
|
RData->addChunk(DebugDirectory);
|
||||||
for (const std::unique_ptr<Chunk> &C : DebugRecords)
|
for (Chunk *C : DebugRecords)
|
||||||
RData->addChunk(C.get());
|
RData->addChunk(C);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create SEH table. x86-only.
|
// Create SEH table. x86-only.
|
||||||
@ -352,8 +349,8 @@ void Writer::createMiscChunks() {
|
|||||||
Handlers.insert(cast<Defined>(B));
|
Handlers.insert(cast<Defined>(B));
|
||||||
}
|
}
|
||||||
|
|
||||||
SEHTable.reset(new SEHTableChunk(Handlers));
|
SEHTable = make<SEHTableChunk>(Handlers);
|
||||||
RData->addChunk(SEHTable.get());
|
RData->addChunk(SEHTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create .idata section for the DLL-imported symbol table.
|
// Create .idata section for the DLL-imported symbol table.
|
||||||
@ -398,8 +395,8 @@ void Writer::createImportTables() {
|
|||||||
for (Chunk *C : DelayIdata.getDataChunks())
|
for (Chunk *C : DelayIdata.getDataChunks())
|
||||||
Sec->addChunk(C);
|
Sec->addChunk(C);
|
||||||
Sec = createSection(".text");
|
Sec = createSection(".text");
|
||||||
for (std::unique_ptr<Chunk> &C : DelayIdata.getCodeChunks())
|
for (Chunk *C : DelayIdata.getCodeChunks())
|
||||||
Sec->addChunk(C.get());
|
Sec->addChunk(C);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,8 +404,8 @@ void Writer::createExportTable() {
|
|||||||
if (Config->Exports.empty())
|
if (Config->Exports.empty())
|
||||||
return;
|
return;
|
||||||
OutputSection *Sec = createSection(".edata");
|
OutputSection *Sec = createSection(".edata");
|
||||||
for (std::unique_ptr<Chunk> &C : Edata.Chunks)
|
for (Chunk *C : Edata.Chunks)
|
||||||
Sec->addChunk(C.get());
|
Sec->addChunk(C);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Windows loader doesn't seem to like empty sections,
|
// The Windows loader doesn't seem to like empty sections,
|
||||||
@ -602,14 +599,19 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
|
|||||||
PE->SizeOfStackCommit = Config->StackCommit;
|
PE->SizeOfStackCommit = Config->StackCommit;
|
||||||
PE->SizeOfHeapReserve = Config->HeapReserve;
|
PE->SizeOfHeapReserve = Config->HeapReserve;
|
||||||
PE->SizeOfHeapCommit = Config->HeapCommit;
|
PE->SizeOfHeapCommit = Config->HeapCommit;
|
||||||
|
|
||||||
|
// Import Descriptor Tables and Import Address Tables are merged
|
||||||
|
// in our output. That's not compatible with the Binding feature
|
||||||
|
// that is sort of prelinking. Setting this flag to make it clear
|
||||||
|
// that our outputs are not for the Binding.
|
||||||
|
PE->DLLCharacteristics = IMAGE_DLL_CHARACTERISTICS_NO_BIND;
|
||||||
|
|
||||||
if (Config->AppContainer)
|
if (Config->AppContainer)
|
||||||
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER;
|
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER;
|
||||||
if (Config->DynamicBase)
|
if (Config->DynamicBase)
|
||||||
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE;
|
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE;
|
||||||
if (Config->HighEntropyVA)
|
if (Config->HighEntropyVA)
|
||||||
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA;
|
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA;
|
||||||
if (!Config->AllowBind)
|
|
||||||
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND;
|
|
||||||
if (Config->NxCompat)
|
if (Config->NxCompat)
|
||||||
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;
|
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;
|
||||||
if (!Config->AllowIsolation)
|
if (!Config->AllowIsolation)
|
||||||
|
@ -390,14 +390,28 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
// ARM SBREL relocations are of the form S + A - B where B is the static base
|
||||||
static typename ELFT::uint
|
// The ARM ABI defines base to be "addressing origin of the output segment
|
||||||
getRelocTargetVA(uint32_t Type, int64_t A, typename ELFT::uint P,
|
// defining the symbol S". We defined the "addressing origin"/static base to be
|
||||||
const SymbolBody &Body, RelExpr Expr) {
|
// the base of the PT_LOAD segment containing the Body.
|
||||||
|
// The procedure call standard only defines a Read Write Position Independent
|
||||||
|
// RWPI variant so in practice we should expect the static base to be the base
|
||||||
|
// of the RW segment.
|
||||||
|
static uint64_t getARMStaticBase(const SymbolBody &Body) {
|
||||||
|
OutputSection *OS = Body.getOutputSection();
|
||||||
|
if (!OS || !OS->FirstInPtLoad)
|
||||||
|
fatal("SBREL relocation to " + Body.getName() + " without static base\n");
|
||||||
|
return OS->FirstInPtLoad->Addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P,
|
||||||
|
const SymbolBody &Body, RelExpr Expr) {
|
||||||
switch (Expr) {
|
switch (Expr) {
|
||||||
case R_ABS:
|
case R_ABS:
|
||||||
case R_RELAX_GOT_PC_NOPIC:
|
case R_RELAX_GOT_PC_NOPIC:
|
||||||
return Body.getVA(A);
|
return Body.getVA(A);
|
||||||
|
case R_ARM_SBREL:
|
||||||
|
return Body.getVA(A) - getARMStaticBase(Body);
|
||||||
case R_GOT:
|
case R_GOT:
|
||||||
case R_RELAX_TLS_GD_TO_IE_ABS:
|
case R_RELAX_TLS_GD_TO_IE_ABS:
|
||||||
return Body.getGotVA() + A;
|
return Body.getGotVA() + A;
|
||||||
@ -518,7 +532,7 @@ getRelocTargetVA(uint32_t Type, int64_t A, typename ELFT::uint P,
|
|||||||
case R_NEG_TLS:
|
case R_NEG_TLS:
|
||||||
return Out::TlsPhdr->p_memsz - Body.getVA(A);
|
return Out::TlsPhdr->p_memsz - Body.getVA(A);
|
||||||
case R_SIZE:
|
case R_SIZE:
|
||||||
return Body.getSize<ELFT>() + A;
|
return A; // Body.getSize was already folded into the addend.
|
||||||
case R_TLSDESC:
|
case R_TLSDESC:
|
||||||
return InX::Got->getGlobalDynAddr(Body) + A;
|
return InX::Got->getGlobalDynAddr(Body) + A;
|
||||||
case R_TLSDESC_PAGE:
|
case R_TLSDESC_PAGE:
|
||||||
@ -566,7 +580,7 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
|
|||||||
uint64_t SymVA = 0;
|
uint64_t SymVA = 0;
|
||||||
if (!Sym.isTls() || Out::TlsPhdr)
|
if (!Sym.isTls() || Out::TlsPhdr)
|
||||||
SymVA = SignExtend64<sizeof(typename ELFT::uint) * 8>(
|
SymVA = SignExtend64<sizeof(typename ELFT::uint) * 8>(
|
||||||
getRelocTargetVA<ELFT>(Type, Addend, AddrLoc, Sym, R_ABS));
|
getRelocTargetVA(Type, Addend, AddrLoc, Sym, R_ABS));
|
||||||
Target->relocateOne(BufLoc, Type, SymVA);
|
Target->relocateOne(BufLoc, Type, SymVA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -577,19 +591,28 @@ template <class ELFT> elf::ObjectFile<ELFT> *InputSectionBase::getFile() const {
|
|||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) {
|
void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) {
|
||||||
|
if (Flags & SHF_ALLOC)
|
||||||
|
relocateAlloc(Buf, BufEnd);
|
||||||
|
else
|
||||||
|
relocateNonAlloc<ELFT>(Buf, BufEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ELFT>
|
||||||
|
void InputSectionBase::relocateNonAlloc(uint8_t *Buf, uint8_t *BufEnd) {
|
||||||
// scanReloc function in Writer.cpp constructs Relocations
|
// scanReloc function in Writer.cpp constructs Relocations
|
||||||
// vector only for SHF_ALLOC'ed sections. For other sections,
|
// vector only for SHF_ALLOC'ed sections. For other sections,
|
||||||
// we handle relocations directly here.
|
// we handle relocations directly here.
|
||||||
auto *IS = dyn_cast<InputSection>(this);
|
auto *IS = cast<InputSection>(this);
|
||||||
if (IS && !(IS->Flags & SHF_ALLOC)) {
|
assert(!(IS->Flags & SHF_ALLOC));
|
||||||
if (IS->AreRelocsRela)
|
if (IS->AreRelocsRela)
|
||||||
IS->relocateNonAlloc<ELFT>(Buf, IS->template relas<ELFT>());
|
IS->relocateNonAlloc<ELFT>(Buf, IS->template relas<ELFT>());
|
||||||
else
|
else
|
||||||
IS->relocateNonAlloc<ELFT>(Buf, IS->template rels<ELFT>());
|
IS->relocateNonAlloc<ELFT>(Buf, IS->template rels<ELFT>());
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned Bits = sizeof(typename ELFT::uint) * 8;
|
void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
|
||||||
|
assert(Flags & SHF_ALLOC);
|
||||||
|
const unsigned Bits = Config->Wordsize * 8;
|
||||||
for (const Relocation &Rel : Relocations) {
|
for (const Relocation &Rel : Relocations) {
|
||||||
uint64_t Offset = getOffset(Rel.Offset);
|
uint64_t Offset = getOffset(Rel.Offset);
|
||||||
uint8_t *BufLoc = Buf + Offset;
|
uint8_t *BufLoc = Buf + Offset;
|
||||||
@ -597,8 +620,8 @@ void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) {
|
|||||||
|
|
||||||
uint64_t AddrLoc = getOutputSection()->Addr + Offset;
|
uint64_t AddrLoc = getOutputSection()->Addr + Offset;
|
||||||
RelExpr Expr = Rel.Expr;
|
RelExpr Expr = Rel.Expr;
|
||||||
uint64_t TargetVA = SignExtend64<Bits>(
|
uint64_t TargetVA = SignExtend64(
|
||||||
getRelocTargetVA<ELFT>(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr));
|
getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits);
|
||||||
|
|
||||||
switch (Expr) {
|
switch (Expr) {
|
||||||
case R_RELAX_GOT_PC:
|
case R_RELAX_GOT_PC:
|
||||||
|
@ -167,6 +167,8 @@ public:
|
|||||||
template <class ELFT> std::string getObjMsg(uint64_t Offset);
|
template <class ELFT> std::string getObjMsg(uint64_t Offset);
|
||||||
|
|
||||||
template <class ELFT> void relocate(uint8_t *Buf, uint8_t *BufEnd);
|
template <class ELFT> void relocate(uint8_t *Buf, uint8_t *BufEnd);
|
||||||
|
void relocateAlloc(uint8_t *Buf, uint8_t *BufEnd);
|
||||||
|
template <class ELFT> void relocateNonAlloc(uint8_t *Buf, uint8_t *BufEnd);
|
||||||
|
|
||||||
std::vector<Relocation> Relocations;
|
std::vector<Relocation> Relocations;
|
||||||
|
|
||||||
|
@ -440,9 +440,6 @@ void LinkerScript::fabricateDefaultCommands() {
|
|||||||
// For each OutputSection that needs a VA fabricate an OutputSectionCommand
|
// For each OutputSection that needs a VA fabricate an OutputSectionCommand
|
||||||
// with an InputSectionDescription describing the InputSections
|
// with an InputSectionDescription describing the InputSections
|
||||||
for (OutputSection *Sec : *OutputSections) {
|
for (OutputSection *Sec : *OutputSections) {
|
||||||
if (!(Sec->Flags & SHF_ALLOC))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto *OSCmd = make<OutputSectionCommand>(Sec->Name);
|
auto *OSCmd = make<OutputSectionCommand>(Sec->Name);
|
||||||
OSCmd->Sec = Sec;
|
OSCmd->Sec = Sec;
|
||||||
SecToCommand[Sec] = OSCmd;
|
SecToCommand[Sec] = OSCmd;
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
#include "MapFile.h"
|
#include "MapFile.h"
|
||||||
#include "InputFiles.h"
|
#include "InputFiles.h"
|
||||||
|
#include "LinkerScript.h"
|
||||||
|
#include "OutputSections.h"
|
||||||
#include "Strings.h"
|
#include "Strings.h"
|
||||||
#include "SymbolTable.h"
|
#include "SymbolTable.h"
|
||||||
#include "Threads.h"
|
#include "Threads.h"
|
||||||
@ -98,7 +100,7 @@ getSymbolStrings(ArrayRef<DefinedRegular *> Syms) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
void elf::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
|
void elf::writeMapFile(llvm::ArrayRef<BaseCommand *> Script) {
|
||||||
if (Config->MapFile.empty())
|
if (Config->MapFile.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -121,7 +123,11 @@ void elf::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
|
|||||||
<< " Align Out In Symbol\n";
|
<< " Align Out In Symbol\n";
|
||||||
|
|
||||||
// Print out file contents.
|
// Print out file contents.
|
||||||
for (OutputSection *OSec : OutputSections) {
|
for (BaseCommand *Base : Script) {
|
||||||
|
auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
|
||||||
|
if (!Cmd)
|
||||||
|
continue;
|
||||||
|
OutputSection *OSec = Cmd->Sec;
|
||||||
writeHeader<ELFT>(OS, OSec->Addr, OSec->Size, OSec->Alignment);
|
writeHeader<ELFT>(OS, OSec->Addr, OSec->Size, OSec->Alignment);
|
||||||
OS << OSec->Name << '\n';
|
OS << OSec->Name << '\n';
|
||||||
|
|
||||||
@ -136,7 +142,7 @@ void elf::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template void elf::writeMapFile<ELF32LE>(ArrayRef<OutputSection *>);
|
template void elf::writeMapFile<ELF32LE>(ArrayRef<BaseCommand *>);
|
||||||
template void elf::writeMapFile<ELF32BE>(ArrayRef<OutputSection *>);
|
template void elf::writeMapFile<ELF32BE>(ArrayRef<BaseCommand *>);
|
||||||
template void elf::writeMapFile<ELF64LE>(ArrayRef<OutputSection *>);
|
template void elf::writeMapFile<ELF64LE>(ArrayRef<BaseCommand *>);
|
||||||
template void elf::writeMapFile<ELF64BE>(ArrayRef<OutputSection *>);
|
template void elf::writeMapFile<ELF64BE>(ArrayRef<BaseCommand *>);
|
||||||
|
@ -10,12 +10,12 @@
|
|||||||
#ifndef LLD_ELF_MAPFILE_H
|
#ifndef LLD_ELF_MAPFILE_H
|
||||||
#define LLD_ELF_MAPFILE_H
|
#define LLD_ELF_MAPFILE_H
|
||||||
|
|
||||||
#include "OutputSections.h"
|
#include <llvm/ADT/ArrayRef.h>
|
||||||
|
|
||||||
namespace lld {
|
namespace lld {
|
||||||
namespace elf {
|
namespace elf {
|
||||||
template <class ELFT>
|
struct BaseCommand;
|
||||||
void writeMapFile(llvm::ArrayRef<OutputSection *> OutputSections);
|
template <class ELFT> void writeMapFile(llvm::ArrayRef<BaseCommand *> Script);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -935,6 +935,10 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
|
|||||||
bool IsConstant =
|
bool IsConstant =
|
||||||
isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, Sec, Rel.r_offset);
|
isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, Sec, Rel.r_offset);
|
||||||
|
|
||||||
|
// The size is not going to change, so we fold it in here.
|
||||||
|
if (Expr == R_SIZE)
|
||||||
|
Addend += Body.getSize<ELFT>();
|
||||||
|
|
||||||
// If the output being produced is position independent, the final value
|
// If the output being produced is position independent, the final value
|
||||||
// is still not known. In that case we still need some help from the
|
// is still not known. In that case we still need some help from the
|
||||||
// dynamic linker. We can however do better than just copying the incoming
|
// dynamic linker. We can however do better than just copying the incoming
|
||||||
|
@ -27,6 +27,7 @@ class OutputSection;
|
|||||||
// doesn't have to know about architecture-specific details.
|
// doesn't have to know about architecture-specific details.
|
||||||
enum RelExpr {
|
enum RelExpr {
|
||||||
R_ABS,
|
R_ABS,
|
||||||
|
R_ARM_SBREL,
|
||||||
R_GOT,
|
R_GOT,
|
||||||
R_GOTONLY_PC,
|
R_GOTONLY_PC,
|
||||||
R_GOTONLY_PC_FROM_END,
|
R_GOTONLY_PC_FROM_END,
|
||||||
|
@ -600,7 +600,7 @@ template <class ELFT> void EhFrameSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (EhInputSection *S : Sections)
|
for (EhInputSection *S : Sections)
|
||||||
S->template relocate<ELFT>(Buf, nullptr);
|
S->relocateAlloc(Buf, nullptr);
|
||||||
|
|
||||||
// Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table
|
// Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table
|
||||||
// to get a FDE from an address to which FDE is applied. So here
|
// to get a FDE from an address to which FDE is applied. So here
|
||||||
@ -617,16 +617,16 @@ template <class ELFT> void EhFrameSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GotBaseSection::GotBaseSection()
|
GotSection::GotSection()
|
||||||
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
|
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
|
||||||
Target->GotEntrySize, ".got") {}
|
Target->GotEntrySize, ".got") {}
|
||||||
|
|
||||||
void GotBaseSection::addEntry(SymbolBody &Sym) {
|
void GotSection::addEntry(SymbolBody &Sym) {
|
||||||
Sym.GotIndex = NumEntries;
|
Sym.GotIndex = NumEntries;
|
||||||
++NumEntries;
|
++NumEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GotBaseSection::addDynTlsEntry(SymbolBody &Sym) {
|
bool GotSection::addDynTlsEntry(SymbolBody &Sym) {
|
||||||
if (Sym.GlobalDynIndex != -1U)
|
if (Sym.GlobalDynIndex != -1U)
|
||||||
return false;
|
return false;
|
||||||
Sym.GlobalDynIndex = NumEntries;
|
Sym.GlobalDynIndex = NumEntries;
|
||||||
@ -637,7 +637,7 @@ bool GotBaseSection::addDynTlsEntry(SymbolBody &Sym) {
|
|||||||
|
|
||||||
// Reserves TLS entries for a TLS module ID and a TLS block offset.
|
// Reserves TLS entries for a TLS module ID and a TLS block offset.
|
||||||
// In total it takes two GOT slots.
|
// In total it takes two GOT slots.
|
||||||
bool GotBaseSection::addTlsIndex() {
|
bool GotSection::addTlsIndex() {
|
||||||
if (TlsIndexOff != uint32_t(-1))
|
if (TlsIndexOff != uint32_t(-1))
|
||||||
return false;
|
return false;
|
||||||
TlsIndexOff = NumEntries * Config->Wordsize;
|
TlsIndexOff = NumEntries * Config->Wordsize;
|
||||||
@ -645,27 +645,23 @@ bool GotBaseSection::addTlsIndex() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t GotBaseSection::getGlobalDynAddr(const SymbolBody &B) const {
|
uint64_t GotSection::getGlobalDynAddr(const SymbolBody &B) const {
|
||||||
return this->getVA() + B.GlobalDynIndex * Config->Wordsize;
|
return this->getVA() + B.GlobalDynIndex * Config->Wordsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t GotBaseSection::getGlobalDynOffset(const SymbolBody &B) const {
|
uint64_t GotSection::getGlobalDynOffset(const SymbolBody &B) const {
|
||||||
return B.GlobalDynIndex * Config->Wordsize;
|
return B.GlobalDynIndex * Config->Wordsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GotBaseSection::finalizeContents() {
|
void GotSection::finalizeContents() { Size = NumEntries * Config->Wordsize; }
|
||||||
Size = NumEntries * Config->Wordsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GotBaseSection::empty() const {
|
bool GotSection::empty() const {
|
||||||
// If we have a relocation that is relative to GOT (such as GOTOFFREL),
|
// If we have a relocation that is relative to GOT (such as GOTOFFREL),
|
||||||
// we need to emit a GOT even if it's empty.
|
// we need to emit a GOT even if it's empty.
|
||||||
return NumEntries == 0 && !HasGotOffRel;
|
return NumEntries == 0 && !HasGotOffRel;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
|
void GotSection::writeTo(uint8_t *Buf) { relocateAlloc(Buf, Buf + Size); }
|
||||||
this->template relocate<ELFT>(Buf, Buf + Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
MipsGotSection::MipsGotSection()
|
MipsGotSection::MipsGotSection()
|
||||||
: SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16,
|
: SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16,
|
||||||
@ -2242,7 +2238,7 @@ StringTableSection *InX::DynStrTab;
|
|||||||
SymbolTableBaseSection *InX::DynSymTab;
|
SymbolTableBaseSection *InX::DynSymTab;
|
||||||
InputSection *InX::Interp;
|
InputSection *InX::Interp;
|
||||||
GdbIndexSection *InX::GdbIndex;
|
GdbIndexSection *InX::GdbIndex;
|
||||||
GotBaseSection *InX::Got;
|
GotSection *InX::Got;
|
||||||
GotPltSection *InX::GotPlt;
|
GotPltSection *InX::GotPlt;
|
||||||
GnuHashTableSection *InX::GnuHashTab;
|
GnuHashTableSection *InX::GnuHashTab;
|
||||||
IgotPltSection *InX::IgotPlt;
|
IgotPltSection *InX::IgotPlt;
|
||||||
@ -2284,11 +2280,6 @@ template class elf::MipsReginfoSection<ELF32BE>;
|
|||||||
template class elf::MipsReginfoSection<ELF64LE>;
|
template class elf::MipsReginfoSection<ELF64LE>;
|
||||||
template class elf::MipsReginfoSection<ELF64BE>;
|
template class elf::MipsReginfoSection<ELF64BE>;
|
||||||
|
|
||||||
template class elf::GotSection<ELF32LE>;
|
|
||||||
template class elf::GotSection<ELF32BE>;
|
|
||||||
template class elf::GotSection<ELF64LE>;
|
|
||||||
template class elf::GotSection<ELF64BE>;
|
|
||||||
|
|
||||||
template class elf::DynamicSection<ELF32LE>;
|
template class elf::DynamicSection<ELF32LE>;
|
||||||
template class elf::DynamicSection<ELF32BE>;
|
template class elf::DynamicSection<ELF32BE>;
|
||||||
template class elf::DynamicSection<ELF64LE>;
|
template class elf::DynamicSection<ELF64LE>;
|
||||||
|
@ -104,12 +104,13 @@ private:
|
|||||||
llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
|
llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GotBaseSection : public SyntheticSection {
|
class GotSection : public SyntheticSection {
|
||||||
public:
|
public:
|
||||||
GotBaseSection();
|
GotSection();
|
||||||
size_t getSize() const override { return Size; }
|
size_t getSize() const override { return Size; }
|
||||||
void finalizeContents() override;
|
void finalizeContents() override;
|
||||||
bool empty() const override;
|
bool empty() const override;
|
||||||
|
void writeTo(uint8_t *Buf) override;
|
||||||
|
|
||||||
void addEntry(SymbolBody &Sym);
|
void addEntry(SymbolBody &Sym);
|
||||||
bool addDynTlsEntry(SymbolBody &Sym);
|
bool addDynTlsEntry(SymbolBody &Sym);
|
||||||
@ -130,11 +131,6 @@ protected:
|
|||||||
uint64_t Size = 0;
|
uint64_t Size = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class ELFT> class GotSection final : public GotBaseSection {
|
|
||||||
public:
|
|
||||||
void writeTo(uint8_t *Buf) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// .note.gnu.build-id section.
|
// .note.gnu.build-id section.
|
||||||
class BuildIdSection : public SyntheticSection {
|
class BuildIdSection : public SyntheticSection {
|
||||||
// First 16 bytes are a header.
|
// First 16 bytes are a header.
|
||||||
@ -764,7 +760,7 @@ struct InX {
|
|||||||
static GnuHashTableSection *GnuHashTab;
|
static GnuHashTableSection *GnuHashTab;
|
||||||
static InputSection *Interp;
|
static InputSection *Interp;
|
||||||
static GdbIndexSection *GdbIndex;
|
static GdbIndexSection *GdbIndex;
|
||||||
static GotBaseSection *Got;
|
static GotSection *Got;
|
||||||
static GotPltSection *GotPlt;
|
static GotPltSection *GotPlt;
|
||||||
static IgotPltSection *IgotPlt;
|
static IgotPltSection *IgotPlt;
|
||||||
static MipsGotSection *MipsGot;
|
static MipsGotSection *MipsGot;
|
||||||
|
@ -1693,6 +1693,8 @@ RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
|
|||||||
case R_ARM_TLS_IE32:
|
case R_ARM_TLS_IE32:
|
||||||
// GOT(S) + A - P
|
// GOT(S) + A - P
|
||||||
return R_GOT_PC;
|
return R_GOT_PC;
|
||||||
|
case R_ARM_SBREL32:
|
||||||
|
return R_ARM_SBREL;
|
||||||
case R_ARM_TARGET1:
|
case R_ARM_TARGET1:
|
||||||
return Config->Target1Rel ? R_PC : R_ABS;
|
return Config->Target1Rel ? R_PC : R_ABS;
|
||||||
case R_ARM_TARGET2:
|
case R_ARM_TARGET2:
|
||||||
@ -1832,6 +1834,7 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
|
|||||||
case R_ARM_GOT_PREL:
|
case R_ARM_GOT_PREL:
|
||||||
case R_ARM_REL32:
|
case R_ARM_REL32:
|
||||||
case R_ARM_RELATIVE:
|
case R_ARM_RELATIVE:
|
||||||
|
case R_ARM_SBREL32:
|
||||||
case R_ARM_TARGET1:
|
case R_ARM_TARGET1:
|
||||||
case R_ARM_TARGET2:
|
case R_ARM_TARGET2:
|
||||||
case R_ARM_TLS_GD32:
|
case R_ARM_TLS_GD32:
|
||||||
|
@ -288,8 +288,13 @@ template <class ELFT> void Writer<ELFT>::run() {
|
|||||||
if (ErrorCount)
|
if (ErrorCount)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Clear the OutputSections to make sure it is not used anymore. Any
|
||||||
|
// code from this point on should be using the linker script
|
||||||
|
// commands.
|
||||||
|
OutputSections.clear();
|
||||||
|
|
||||||
// Handle -Map option.
|
// Handle -Map option.
|
||||||
writeMapFile<ELFT>(OutputSections);
|
writeMapFile<ELFT>(Script->Opt.Commands);
|
||||||
if (ErrorCount)
|
if (ErrorCount)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -403,7 +408,7 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
|
|||||||
InX::MipsGot = make<MipsGotSection>();
|
InX::MipsGot = make<MipsGotSection>();
|
||||||
Add(InX::MipsGot);
|
Add(InX::MipsGot);
|
||||||
} else {
|
} else {
|
||||||
InX::Got = make<GotSection<ELFT>>();
|
InX::Got = make<GotSection>();
|
||||||
Add(InX::Got);
|
Add(InX::Got);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,22 +631,22 @@ bool elf::isRelroSection(const OutputSection *Sec) {
|
|||||||
// * It is easy to check if a give branch was taken.
|
// * It is easy to check if a give branch was taken.
|
||||||
// * It is easy two see how similar two ranks are (see getRankProximity).
|
// * It is easy two see how similar two ranks are (see getRankProximity).
|
||||||
enum RankFlags {
|
enum RankFlags {
|
||||||
RF_NOT_ADDR_SET = 1 << 16,
|
RF_NOT_ADDR_SET = 1 << 15,
|
||||||
RF_NOT_INTERP = 1 << 15,
|
RF_NOT_INTERP = 1 << 14,
|
||||||
RF_NOT_ALLOC = 1 << 14,
|
RF_NOT_ALLOC = 1 << 13,
|
||||||
RF_WRITE = 1 << 13,
|
RF_WRITE = 1 << 12,
|
||||||
RF_EXEC = 1 << 12,
|
RF_EXEC = 1 << 11,
|
||||||
RF_NON_TLS_BSS = 1 << 11,
|
RF_NON_TLS_BSS = 1 << 10,
|
||||||
RF_NON_TLS_BSS_RO = 1 << 10,
|
RF_NON_TLS_BSS_RO = 1 << 9,
|
||||||
RF_NOT_TLS = 1 << 9,
|
RF_NOT_TLS = 1 << 8,
|
||||||
RF_BSS = 1 << 8,
|
RF_BSS = 1 << 7,
|
||||||
RF_PPC_NOT_TOCBSS = 1 << 7,
|
RF_PPC_NOT_TOCBSS = 1 << 6,
|
||||||
RF_PPC_OPD = 1 << 6,
|
RF_PPC_OPD = 1 << 5,
|
||||||
RF_PPC_TOCL = 1 << 5,
|
RF_PPC_TOCL = 1 << 4,
|
||||||
RF_PPC_TOC = 1 << 4,
|
RF_PPC_TOC = 1 << 3,
|
||||||
RF_PPC_BRANCH_LT = 1 << 3,
|
RF_PPC_BRANCH_LT = 1 << 2,
|
||||||
RF_MIPS_GPREL = 1 << 2,
|
RF_MIPS_GPREL = 1 << 1,
|
||||||
RF_MIPS_NOT_GOT = 1 << 1
|
RF_MIPS_NOT_GOT = 1 << 0
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned getSectionRank(const OutputSection *Sec) {
|
static unsigned getSectionRank(const OutputSection *Sec) {
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
# CHECK: Import {
|
# CHECK: Import {
|
||||||
# CHECK: Name: library.dll
|
# CHECK: Name: library.dll
|
||||||
# CHECK: ImportLookupTableRVA: 0x2028
|
# CHECK: ImportLookupTableRVA: 0x2028
|
||||||
# CHECK: ImportAddressTableRVA: 0x2030
|
# CHECK: ImportAddressTableRVA: 0x2028
|
||||||
# CHECK: Symbol: function (0)
|
# CHECK: Symbol: function (0)
|
||||||
# CHECK: }
|
# CHECK: }
|
||||||
|
|
||||||
|
@ -41,9 +41,10 @@ HEADER-NEXT: MinorSubsystemVersion: 0
|
|||||||
HEADER-NEXT: SizeOfImage: 16896
|
HEADER-NEXT: SizeOfImage: 16896
|
||||||
HEADER-NEXT: SizeOfHeaders: 512
|
HEADER-NEXT: SizeOfHeaders: 512
|
||||||
HEADER-NEXT: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3)
|
HEADER-NEXT: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3)
|
||||||
HEADER-NEXT: Characteristics [ (0x9140)
|
HEADER-NEXT: Characteristics [ (0x9940)
|
||||||
HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_APPCONTAINER (0x1000)
|
HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_APPCONTAINER (0x1000)
|
||||||
HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE (0x40)
|
HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE (0x40)
|
||||||
|
HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_NO_BIND (0x800)
|
||||||
HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT (0x100)
|
HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT (0x100)
|
||||||
HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000)
|
HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000)
|
||||||
HEADER-NEXT: ]
|
HEADER-NEXT: ]
|
||||||
@ -77,7 +78,7 @@ HEADER-NEXT: LoadConfigTableRVA: 0x0
|
|||||||
HEADER-NEXT: LoadConfigTableSize: 0x0
|
HEADER-NEXT: LoadConfigTableSize: 0x0
|
||||||
HEADER-NEXT: BoundImportRVA: 0x0
|
HEADER-NEXT: BoundImportRVA: 0x0
|
||||||
HEADER-NEXT: BoundImportSize: 0x0
|
HEADER-NEXT: BoundImportSize: 0x0
|
||||||
HEADER-NEXT: IATRVA: 0x3034
|
HEADER-NEXT: IATRVA: 0x3028
|
||||||
HEADER-NEXT: IATSize: 0xC
|
HEADER-NEXT: IATSize: 0xC
|
||||||
HEADER-NEXT: DelayImportDescriptorRVA: 0x0
|
HEADER-NEXT: DelayImportDescriptorRVA: 0x0
|
||||||
HEADER-NEXT: DelayImportDescriptorSize: 0x0
|
HEADER-NEXT: DelayImportDescriptorSize: 0x0
|
||||||
@ -113,7 +114,7 @@ IMPORTS: AddressSize: 32bit
|
|||||||
IMPORTS: Import {
|
IMPORTS: Import {
|
||||||
IMPORTS: Name: std32.dll
|
IMPORTS: Name: std32.dll
|
||||||
IMPORTS: ImportLookupTableRVA: 0x3028
|
IMPORTS: ImportLookupTableRVA: 0x3028
|
||||||
IMPORTS: ImportAddressTableRVA: 0x3034
|
IMPORTS: ImportAddressTableRVA: 0x3028
|
||||||
IMPORTS: Symbol: ExitProcess (0)
|
IMPORTS: Symbol: ExitProcess (0)
|
||||||
IMPORTS: Symbol: MessageBoxA (1)
|
IMPORTS: Symbol: MessageBoxA (1)
|
||||||
IMPORTS: }
|
IMPORTS: }
|
||||||
|
@ -21,14 +21,14 @@ TEXT-NEXT: callq 60
|
|||||||
TEXT-NEXT: movl $0, %ecx
|
TEXT-NEXT: movl $0, %ecx
|
||||||
TEXT-NEXT: callq 18
|
TEXT-NEXT: callq 18
|
||||||
TEXT-NEXT: callq 29
|
TEXT-NEXT: callq 29
|
||||||
TEXT: jmpq *4098(%rip)
|
TEXT: jmpq *4066(%rip)
|
||||||
TEXT: jmpq *4090(%rip)
|
TEXT: jmpq *4058(%rip)
|
||||||
TEXT: jmpq *4082(%rip)
|
TEXT: jmpq *4050(%rip)
|
||||||
|
|
||||||
IMPORT: Import {
|
IMPORT: Import {
|
||||||
IMPORT-NEXT: Name: std64.dll
|
IMPORT-NEXT: Name: std64.dll
|
||||||
IMPORT-NEXT: ImportLookupTableRVA: 0x3028
|
IMPORT-NEXT: ImportLookupTableRVA: 0x3028
|
||||||
IMPORT-NEXT: ImportAddressTableRVA: 0x3048
|
IMPORT-NEXT: ImportAddressTableRVA: 0x3028
|
||||||
IMPORT-NEXT: Symbol: ExitProcess (0)
|
IMPORT-NEXT: Symbol: ExitProcess (0)
|
||||||
IMPORT-NEXT: Symbol: (50)
|
IMPORT-NEXT: Symbol: (50)
|
||||||
IMPORT-NEXT: Symbol: MessageBoxA (1)
|
IMPORT-NEXT: Symbol: MessageBoxA (1)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
|
# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
|
||||||
# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
|
# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
|
||||||
# RUN: lld-link /debug /debugtype:invalid /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \
|
# RUN: lld-link /debug /debugtype:invalid /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \
|
||||||
# RUN: /debugpdb %t1.obj %t2.obj
|
# RUN: %t1.obj %t2.obj
|
||||||
|
|
||||||
|
@ -2,13 +2,7 @@
|
|||||||
|
|
||||||
# RUN: lld-link /out:%t.exe /entry:main %t.obj
|
# RUN: lld-link /out:%t.exe /entry:main %t.obj
|
||||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BIND %s
|
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BIND %s
|
||||||
# RUN: lld-link /allowbind /out:%t.exe /entry:main %t.obj
|
BIND: IMAGE_DLL_CHARACTERISTICS_NO_BIND
|
||||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BIND %s
|
|
||||||
BIND-NOT: IMAGE_DLL_CHARACTERISTICS_NO_BIND
|
|
||||||
|
|
||||||
# RUN: lld-link /allowbind:no /out:%t.exe /entry:main %t.obj
|
|
||||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOBIND %s
|
|
||||||
NOBIND: IMAGE_DLL_CHARACTERISTICS_NO_BIND
|
|
||||||
|
|
||||||
# RUN: lld-link /out:%t.exe /entry:main %t.obj
|
# RUN: lld-link /out:%t.exe /entry:main %t.obj
|
||||||
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ISO %s
|
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ISO %s
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
|
# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
|
||||||
# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
|
# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
|
||||||
# RUN: lld-link /debug /debugtype:pdata /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \
|
# RUN: lld-link /debug /debugtype:pdata /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \
|
||||||
# RUN: /debugpdb %t1.obj %t2.obj
|
# RUN: %t1.obj %t2.obj
|
||||||
|
|
||||||
# RUN: llvm-pdbdump pdb2yaml -pdb-stream %t.pdb | FileCheck %s
|
# RUN: llvm-pdbdump pdb2yaml -pdb-stream %t.pdb | FileCheck %s
|
||||||
|
|
||||||
|
20
test/COFF/pdb-options.test
Normal file
20
test/COFF/pdb-options.test
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
|
||||||
|
# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
|
||||||
|
|
||||||
|
; If /DEBUG is not specified, /pdb is ignored.
|
||||||
|
# RUN: lld-link /pdb:%t.pdb /entry:main /nodefaultlib %t1.obj %t2.obj
|
||||||
|
# RUN: not ls %t.pdb
|
||||||
|
|
||||||
|
; If /DEBUG and /pdb are specified, it uses the specified name.
|
||||||
|
# RUN: lld-link /DEBUG /pdb:%t.pdb /entry:main /nodefaultlib %t1.obj %t2.obj
|
||||||
|
# RUN: ls %t.pdb
|
||||||
|
# RUN: rm %t.pdb
|
||||||
|
|
||||||
|
; If /DEBUG is specified but not /pdb, it uses a default name in the current
|
||||||
|
; directory. This is a bit hacky since but we need to be IN our test specific
|
||||||
|
; temporary directory when we run this command or we can't test this
|
||||||
|
# RUN: cd %T
|
||||||
|
# RUN: lld-link /DEBUG /entry:main /nodefaultlib %t1.obj %t2.obj
|
||||||
|
# RUN: ls %t1.pdb
|
||||||
|
# RUN: rm %t*
|
||||||
|
# RUN: cd %T/..
|
@ -1,7 +1,7 @@
|
|||||||
# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
|
# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
|
||||||
# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
|
# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
|
||||||
# RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \
|
# RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \
|
||||||
# RUN: /debugpdb %t1.obj %t2.obj
|
# RUN: %t1.obj %t2.obj
|
||||||
|
|
||||||
# RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory -pdb-stream \
|
# RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory -pdb-stream \
|
||||||
# RUN: -dbi-stream -ipi-stream -tpi-stream %t.pdb | FileCheck %s
|
# RUN: -dbi-stream -ipi-stream -tpi-stream %t.pdb | FileCheck %s
|
||||||
|
39
test/ELF/arm-sbrel32.s
Normal file
39
test/ELF/arm-sbrel32.s
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
|
||||||
|
// RUN: ld.lld %t -o %t2 2>&1
|
||||||
|
// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
|
||||||
|
// REQUIRES: arm
|
||||||
|
|
||||||
|
// Test the R_ARM_SBREL32 relocation which calculates the offset of the Symbol
|
||||||
|
// from the static base. We define the static base to be the address of the
|
||||||
|
// segment containing the symbol
|
||||||
|
.text
|
||||||
|
.syntax unified
|
||||||
|
|
||||||
|
.globl _start
|
||||||
|
.p2align 2
|
||||||
|
.type _start,%function
|
||||||
|
_start:
|
||||||
|
.fnstart
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.long foo(sbrel)
|
||||||
|
.long foo2(sbrel)
|
||||||
|
.long foo3(sbrel)
|
||||||
|
.long foo4(sbrel)
|
||||||
|
// RW segment starts here
|
||||||
|
.data
|
||||||
|
.p2align 4
|
||||||
|
foo: .word 10
|
||||||
|
foo2: .word 20
|
||||||
|
|
||||||
|
.bss
|
||||||
|
foo3: .space 4
|
||||||
|
foo4: .space 4
|
||||||
|
|
||||||
|
// CHECK: Disassembly of section .text:
|
||||||
|
// CHECK-NEXT: _start:
|
||||||
|
// CHECK-NEXT: 11000: 1e ff 2f e1 bx lr
|
||||||
|
// CHECK: 11004: 00 00 00 00 .word 0x00000000
|
||||||
|
// CHECK-NEXT: 11008: 04 00 00 00 .word 0x00000004
|
||||||
|
// CHECK-NEXT: 1100c: 08 00 00 00 .word 0x00000008
|
||||||
|
// CHECK-NEXT: 11010: 0c 00 00 00 .word 0x0000000c
|
Loading…
x
Reference in New Issue
Block a user