aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-05-22 19:44:12 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-05-22 19:44:12 +0000
commitc53addf38e24e4dafe992aafb3ae928bfa8fdb0a (patch)
tree5a8f08e745d2dbfdd66c9e4838a8b7eeb7f0453f
parent2dcc0c5ee66570f02392d1fbf29f573fa47258f8 (diff)
downloadsrc-c53addf38e24e4dafe992aafb3ae928bfa8fdb0a.tar.gz
src-c53addf38e24e4dafe992aafb3ae928bfa8fdb0a.zip
Vendor import of lld trunk r303571:vendor/lld/lld-trunk-r303571
Notes
Notes: svn path=/vendor/lld/dist/; revision=318671 svn path=/vendor/lld/lld-trunk-r303571/; revision=318672; tag=vendor/lld/lld-trunk-r303571
-rw-r--r--COFF/CMakeLists.txt2
-rw-r--r--COFF/Config.h2
-rw-r--r--COFF/DLL.cpp160
-rw-r--r--COFF/DLL.h27
-rw-r--r--COFF/Driver.cpp93
-rw-r--r--COFF/Driver.h7
-rw-r--r--COFF/DriverUtils.cpp4
-rw-r--r--COFF/InputFiles.cpp16
-rw-r--r--COFF/InputFiles.h7
-rw-r--r--COFF/Librarian.cpp511
-rw-r--r--COFF/ModuleDef.cpp304
-rw-r--r--COFF/Options.td1
-rw-r--r--COFF/PDB.cpp15
-rw-r--r--COFF/SymbolTable.h1
-rw-r--r--COFF/Writer.cpp52
-rw-r--r--ELF/InputSection.cpp57
-rw-r--r--ELF/InputSection.h2
-rw-r--r--ELF/LinkerScript.cpp3
-rw-r--r--ELF/MapFile.cpp18
-rw-r--r--ELF/MapFile.h6
-rw-r--r--ELF/Relocations.cpp4
-rw-r--r--ELF/Relocations.h1
-rw-r--r--ELF/SyntheticSections.cpp31
-rw-r--r--ELF/SyntheticSections.h12
-rw-r--r--ELF/Target.cpp3
-rw-r--r--ELF/Writer.cpp41
-rw-r--r--test/COFF/armnt-imports.test2
-rw-r--r--test/COFF/hello32.test7
-rw-r--r--test/COFF/imports.test8
-rw-r--r--test/COFF/invalid-debug-type.test2
-rw-r--r--test/COFF/options.test8
-rw-r--r--test/COFF/pdb-none.test2
-rw-r--r--test/COFF/pdb-options.test20
-rw-r--r--test/COFF/pdb.test2
-rw-r--r--test/ELF/arm-sbrel32.s39
35 files changed, 385 insertions, 1085 deletions
diff --git a/COFF/CMakeLists.txt b/COFF/CMakeLists.txt
index 8f24e36c0eca..14f553e540d9 100644
--- a/COFF/CMakeLists.txt
+++ b/COFF/CMakeLists.txt
@@ -14,11 +14,9 @@ add_lld_library(lldCOFF
Error.cpp
ICF.cpp
InputFiles.cpp
- Librarian.cpp
LTO.cpp
MapFile.cpp
MarkLive.cpp
- ModuleDef.cpp
PDB.cpp
Strings.cpp
SymbolTable.cpp
diff --git a/COFF/Config.h b/COFF/Config.h
index fafd3bcde2e3..d859b1fbb7d9 100644
--- a/COFF/Config.h
+++ b/COFF/Config.h
@@ -155,7 +155,6 @@ struct Configuration {
uint32_t MajorOSVersion = 6;
uint32_t MinorOSVersion = 0;
bool DynamicBase = true;
- bool AllowBind = true;
bool NxCompat = true;
bool AllowIsolation = true;
bool TerminalServerAware = true;
@@ -164,7 +163,6 @@ struct Configuration {
bool AppContainer = false;
// This is for debugging.
- bool DebugPdb = false;
bool DumpPdb = false;
};
diff --git a/COFF/DLL.cpp b/COFF/DLL.cpp
index f93dc5cde44c..3ac14e4ea2b0 100644
--- a/COFF/DLL.cpp
+++ b/COFF/DLL.cpp
@@ -100,13 +100,17 @@ public:
void writeTo(uint8_t *Buf) const override {
auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff);
- E->ImportLookupTableRVA = LookupTab->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();
}
Chunk *DLLName;
- Chunk *LookupTab;
Chunk *AddressTab;
};
@@ -136,9 +140,9 @@ binImports(const std::vector<DefinedImportData *> &Imports) {
M[Sym->getDLLName().lower()].push_back(Sym);
std::vector<std::vector<DefinedImportData *>> V;
- for (auto &P : M) {
+ for (auto &KV : M) {
// 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(),
[](DefinedImportData *A, DefinedImportData *B) {
return A->getName() < B->getName();
@@ -383,21 +387,14 @@ uint64_t IdataContents::getIATSize() {
// See Microsoft PE/COFF spec 5.4 for details.
std::vector<Chunk *> IdataContents::getChunks() {
create();
- std::vector<Chunk *> V;
+
// The loader assumes a specific order of data.
// Add each type in the correct order.
- for (std::unique_ptr<Chunk> &C : Dirs)
- V.push_back(C.get());
- for (std::unique_ptr<Chunk> &C : Lookups)
- V.push_back(C.get());
- for (std::unique_ptr<Chunk> &C : Addresses)
- V.push_back(C.get());
- for (std::unique_ptr<Chunk> &C : Hints)
- V.push_back(C.get());
- for (auto &P : DLLNames) {
- std::unique_ptr<Chunk> &C = P.second;
- V.push_back(C.get());
- }
+ std::vector<Chunk *> V;
+ V.insert(V.end(), Dirs.begin(), Dirs.end());
+ V.insert(V.end(), Addresses.begin(), Addresses.end());
+ V.insert(V.end(), Hints.begin(), Hints.end());
+ V.insert(V.end(), DLLNames.begin(), DLLNames.end());
return V;
}
@@ -406,65 +403,50 @@ void IdataContents::create() {
// Create .idata contents for each DLL.
for (std::vector<DefinedImportData *> &Syms : V) {
- StringRef Name = Syms[0]->getDLLName();
-
// Create lookup and address tables. If they have external names,
// we need to create HintName chunks to store the names.
// If they don't (if they are import-by-ordinals), we store only
// ordinal values to the table.
- size_t Base = Lookups.size();
+ size_t Base = Addresses.size();
for (DefinedImportData *S : Syms) {
uint16_t Ord = S->getOrdinal();
if (S->getExternalName().empty()) {
- Lookups.push_back(make_unique<OrdinalOnlyChunk>(Ord));
- Addresses.push_back(make_unique<OrdinalOnlyChunk>(Ord));
+ Addresses.push_back(make<OrdinalOnlyChunk>(Ord));
continue;
}
- auto C = make_unique<HintNameChunk>(S->getExternalName(), Ord);
- Lookups.push_back(make_unique<LookupChunk>(C.get()));
- Addresses.push_back(make_unique<LookupChunk>(C.get()));
- Hints.push_back(std::move(C));
+ auto *C = make<HintNameChunk>(S->getExternalName(), Ord);
+ Addresses.push_back(make<LookupChunk>(C));
+ Hints.push_back(C);
}
// Terminate with null values.
- Lookups.push_back(make_unique<NullChunk>(ptrSize()));
- Addresses.push_back(make_unique<NullChunk>(ptrSize()));
+ Addresses.push_back(make<NullChunk>(ptrSize()));
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.
- if (!DLLNames.count(Name))
- DLLNames[Name] = make_unique<StringChunk>(Name);
- auto Dir = make_unique<ImportDirectoryChunk>(DLLNames[Name].get());
- Dir->LookupTab = Lookups[Base].get();
- Dir->AddressTab = Addresses[Base].get();
- Dirs.push_back(std::move(Dir));
+ DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName()));
+ auto *Dir = make<ImportDirectoryChunk>(DLLNames.back());
+ Dir->AddressTab = Addresses[Base];
+ Dirs.push_back(Dir);
}
// 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 *> V;
- for (std::unique_ptr<Chunk> &C : Dirs)
- V.push_back(C.get());
- for (std::unique_ptr<Chunk> &C : Names)
- V.push_back(C.get());
- 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());
- }
+ V.insert(V.end(), Dirs.begin(), Dirs.end());
+ V.insert(V.end(), Names.begin(), Names.end());
+ V.insert(V.end(), HintNames.begin(), HintNames.end());
+ V.insert(V.end(), DLLNames.begin(), DLLNames.end());
return V;
}
std::vector<Chunk *> DelayLoadContents::getDataChunks() {
std::vector<Chunk *> V;
- for (std::unique_ptr<Chunk> &C : ModuleHandles)
- V.push_back(C.get());
- for (std::unique_ptr<Chunk> &C : Addresses)
- V.push_back(C.get());
+ V.insert(V.end(), ModuleHandles.begin(), ModuleHandles.end());
+ V.insert(V.end(), Addresses.begin(), Addresses.end());
return V;
}
@@ -478,55 +460,51 @@ void DelayLoadContents::create(Defined *H) {
// Create .didat contents for each DLL.
for (std::vector<DefinedImportData *> &Syms : V) {
- StringRef Name = Syms[0]->getDLLName();
-
// Create the delay import table header.
- if (!DLLNames.count(Name))
- DLLNames[Name] = make_unique<StringChunk>(Name);
- auto Dir = make_unique<DelayDirectoryChunk>(DLLNames[Name].get());
+ DLLNames.push_back(make<StringChunk>(Syms[0]->getDLLName()));
+ auto *Dir = make<DelayDirectoryChunk>(DLLNames.back());
size_t Base = Addresses.size();
for (DefinedImportData *S : Syms) {
- Chunk *T = newThunkChunk(S, Dir.get());
- auto A = make_unique<DelayAddressChunk>(T);
- Addresses.push_back(std::move(A));
- Thunks.push_back(std::unique_ptr<Chunk>(T));
+ Chunk *T = newThunkChunk(S, Dir);
+ auto *A = make<DelayAddressChunk>(T);
+ Addresses.push_back(A);
+ Thunks.push_back(T);
StringRef ExtName = S->getExternalName();
if (ExtName.empty()) {
- Names.push_back(make_unique<OrdinalOnlyChunk>(S->getOrdinal()));
+ Names.push_back(make<OrdinalOnlyChunk>(S->getOrdinal()));
} else {
- auto C = make_unique<HintNameChunk>(ExtName, 0);
- Names.push_back(make_unique<LookupChunk>(C.get()));
- HintNames.push_back(std::move(C));
+ auto *C = make<HintNameChunk>(ExtName, 0);
+ Names.push_back(make<LookupChunk>(C));
+ HintNames.push_back(C);
}
}
// Terminate with null values.
- Addresses.push_back(make_unique<NullChunk>(8));
- Names.push_back(make_unique<NullChunk>(8));
+ Addresses.push_back(make<NullChunk>(8));
+ Names.push_back(make<NullChunk>(8));
for (int I = 0, E = Syms.size(); I < E; ++I)
- Syms[I]->setLocation(Addresses[Base + I].get());
- auto *MH = new NullChunk(8);
+ Syms[I]->setLocation(Addresses[Base + I]);
+ auto *MH = make<NullChunk>(8);
MH->setAlign(8);
- ModuleHandles.push_back(std::unique_ptr<Chunk>(MH));
+ ModuleHandles.push_back(MH);
// Fill the delay import table header fields.
Dir->ModuleHandle = MH;
- Dir->AddressTab = Addresses[Base].get();
- Dir->NameTab = Names[Base].get();
- Dirs.push_back(std::move(Dir));
+ Dir->AddressTab = Addresses[Base];
+ Dir->NameTab = Names[Base];
+ Dirs.push_back(Dir);
}
// Add null terminator.
- Dirs.push_back(
- make_unique<NullChunk>(sizeof(delay_import_directory_table_entry)));
+ Dirs.push_back(make<NullChunk>(sizeof(delay_import_directory_table_entry)));
}
Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) {
switch (Config->Machine) {
case AMD64:
- return new ThunkChunkX64(S, Dir, Helper);
+ return make<ThunkChunkX64>(S, Dir, Helper);
case I386:
- return new ThunkChunkX86(S, Dir, Helper);
+ return make<ThunkChunkX86>(S, Dir, Helper);
default:
llvm_unreachable("unsupported machine type");
}
@@ -537,34 +515,32 @@ EdataContents::EdataContents() {
for (Export &E : Config->Exports)
MaxOrdinal = std::max(MaxOrdinal, E.Ordinal);
- auto *DLLName = new StringChunk(sys::path::filename(Config->OutputFile));
- auto *AddressTab = new AddressTableChunk(MaxOrdinal);
+ auto *DLLName = make<StringChunk>(sys::path::filename(Config->OutputFile));
+ auto *AddressTab = make<AddressTableChunk>(MaxOrdinal);
std::vector<Chunk *> Names;
for (Export &E : Config->Exports)
if (!E.Noname)
- Names.push_back(new StringChunk(E.ExportName));
+ Names.push_back(make<StringChunk>(E.ExportName));
std::vector<Chunk *> Forwards;
for (Export &E : Config->Exports) {
if (E.ForwardTo.empty())
continue;
- E.ForwardChunk = new StringChunk(E.ForwardTo);
+ E.ForwardChunk = make<StringChunk>(E.ForwardTo);
Forwards.push_back(E.ForwardChunk);
}
- auto *NameTab = new NamePointersChunk(Names);
- auto *OrdinalTab = new ExportOrdinalChunk(Names.size());
- auto *Dir = new ExportDirectoryChunk(MaxOrdinal, Names.size(), DLLName,
- AddressTab, NameTab, OrdinalTab);
- Chunks.push_back(std::unique_ptr<Chunk>(Dir));
- Chunks.push_back(std::unique_ptr<Chunk>(DLLName));
- Chunks.push_back(std::unique_ptr<Chunk>(AddressTab));
- Chunks.push_back(std::unique_ptr<Chunk>(NameTab));
- Chunks.push_back(std::unique_ptr<Chunk>(OrdinalTab));
- for (Chunk *C : Names)
- Chunks.push_back(std::unique_ptr<Chunk>(C));
- for (Chunk *C : Forwards)
- Chunks.push_back(std::unique_ptr<Chunk>(C));
+ auto *NameTab = make<NamePointersChunk>(Names);
+ auto *OrdinalTab = make<ExportOrdinalChunk>(Names.size());
+ auto *Dir = make<ExportDirectoryChunk>(MaxOrdinal, Names.size(), DLLName,
+ AddressTab, NameTab, OrdinalTab);
+ Chunks.push_back(Dir);
+ Chunks.push_back(DLLName);
+ Chunks.push_back(AddressTab);
+ Chunks.push_back(NameTab);
+ Chunks.push_back(OrdinalTab);
+ Chunks.insert(Chunks.end(), Names.begin(), Names.end());
+ Chunks.insert(Chunks.end(), Forwards.begin(), Forwards.end());
}
} // namespace coff
diff --git a/COFF/DLL.h b/COFF/DLL.h
index 83a12df185c2..939771b3290c 100644
--- a/COFF/DLL.h
+++ b/COFF/DLL.h
@@ -35,11 +35,10 @@ private:
void create();
std::vector<DefinedImportData *> Imports;
- std::vector<std::unique_ptr<Chunk>> Dirs;
- std::vector<std::unique_ptr<Chunk>> Lookups;
- std::vector<std::unique_ptr<Chunk>> Addresses;
- std::vector<std::unique_ptr<Chunk>> Hints;
- std::map<StringRef, std::unique_ptr<Chunk>> DLLNames;
+ std::vector<Chunk *> Dirs;
+ std::vector<Chunk *> Addresses;
+ std::vector<Chunk *> Hints;
+ std::vector<Chunk *> DLLNames;
};
// Windows-specific.
@@ -51,7 +50,7 @@ public:
void create(Defined *Helper);
std::vector<Chunk *> getChunks();
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 getDirSize();
@@ -61,13 +60,13 @@ private:
Defined *Helper;
std::vector<DefinedImportData *> Imports;
- std::vector<std::unique_ptr<Chunk>> Dirs;
- std::vector<std::unique_ptr<Chunk>> ModuleHandles;
- std::vector<std::unique_ptr<Chunk>> Addresses;
- std::vector<std::unique_ptr<Chunk>> Names;
- std::vector<std::unique_ptr<Chunk>> HintNames;
- std::vector<std::unique_ptr<Chunk>> Thunks;
- std::map<StringRef, std::unique_ptr<Chunk>> DLLNames;
+ std::vector<Chunk *> Dirs;
+ std::vector<Chunk *> ModuleHandles;
+ std::vector<Chunk *> Addresses;
+ std::vector<Chunk *> Names;
+ std::vector<Chunk *> HintNames;
+ std::vector<Chunk *> Thunks;
+ std::vector<Chunk *> DLLNames;
};
// Windows-specific.
@@ -75,7 +74,7 @@ private:
class EdataContents {
public:
EdataContents();
- std::vector<std::unique_ptr<Chunk>> Chunks;
+ std::vector<Chunk *> Chunks;
};
} // namespace coff
diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp
index 4c0ea44b875e..d871f942737d 100644
--- a/COFF/Driver.cpp
+++ b/COFF/Driver.cpp
@@ -19,6 +19,8 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Object/ArchiveWriter.h"
+#include "llvm/Object/COFFImportFile.h"
+#include "llvm/Object/COFFModuleDefinition.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
@@ -35,6 +37,7 @@
#include <future>
using namespace llvm;
+using namespace llvm::object;
using namespace llvm::COFF;
using llvm::sys::Process;
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 MBRef = *MB;
- OwningMBs.push_back(std::move(MB));
+ make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take ownership
if (Driver->Tar)
Driver->Tar->append(relativeToRoot(MBRef.getBufferIdentifier()),
MBRef.getBuffer());
-
return MBRef;
}
@@ -420,6 +422,84 @@ static std::string getMapFile(const opt::InputArgList &Args) {
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> V;
Error Err = Error::success();
@@ -821,8 +901,6 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
Config->ManifestInput.push_back(Arg->getValue());
// Handle miscellaneous boolean flags.
- if (Args.hasArg(OPT_allowbind_no))
- Config->AllowBind = false;
if (Args.hasArg(OPT_allowisolation_no))
Config->AllowIsolation = false;
if (Args.hasArg(OPT_dynamicbase_no))
@@ -834,7 +912,6 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (Args.hasArg(OPT_nosymtab))
Config->WriteSymtab = false;
Config->DumpPdb = Args.hasArg(OPT_dumppdb);
- Config->DebugPdb = Args.hasArg(OPT_debugpdb);
Config->MapFile = getMapFile(Args);
@@ -916,9 +993,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /def
if (auto *Arg = Args.getLastArg(OPT_deffile)) {
// parseModuleDefs mutates Config object.
- parseModuleDefs(
- takeBuffer(check(MemoryBuffer::getFile(Arg->getValue()),
- Twine("could not open ") + Arg->getValue())));
+ parseModuleDefs(Arg->getValue());
}
// Handle /delayload
@@ -1038,7 +1113,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// need to create a .lib file.
if (!Config->Exports.empty() || Config->DLL) {
fixupExports();
- writeImportLibrary();
+ createImportLibrary();
assignExportOrdinals();
}
diff --git a/COFF/Driver.h b/COFF/Driver.h
index ad725625e030..3eb950cca25c 100644
--- a/COFF/Driver.h
+++ b/COFF/Driver.h
@@ -119,18 +119,11 @@ private:
void enqueueTask(std::function<void()> Task);
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::vector<StringRef> FilePaths;
std::vector<MemoryBufferRef> Resources;
};
-void parseModuleDefs(MemoryBufferRef MB);
-void writeImportLibrary();
-
// Functions below this line are defined in DriverUtils.cpp.
void printHelp(const char *Argv0);
diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp
index 252590c7d870..ee4bd0f6b22c 100644
--- a/COFF/DriverUtils.cpp
+++ b/COFF/DriverUtils.cpp
@@ -43,7 +43,7 @@ namespace {
class Executor {
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(std::string &S) { Args.push_back(Saver.save(S)); }
void add(Twine S) { Args.push_back(Saver.save(S)); }
@@ -67,8 +67,6 @@ public:
}
private:
- BumpPtrAllocator Alloc;
- StringSaver Saver;
StringRef Prog;
std::vector<StringRef> Args;
};
diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp
index df3b6a032cf8..6e6465cd5d62 100644
--- a/COFF/InputFiles.cpp
+++ b/COFF/InputFiles.cpp
@@ -137,13 +137,13 @@ void ObjectFile::initializeChunks() {
// CodeView sections are stored to a different vector because they are
// not linked in the regular manner.
if (Name == ".debug" || Name.startswith(".debug$")) {
- DebugChunks.push_back(new (Alloc) SectionChunk(this, Sec));
+ DebugChunks.push_back(make<SectionChunk>(this, Sec));
continue;
}
if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
continue;
- auto *C = new (Alloc) SectionChunk(this, Sec);
+ auto *C = make<SectionChunk>(this, Sec);
Chunks.push_back(C);
SparseChunks[I] = C;
}
@@ -200,7 +200,7 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
bool IsFirst) {
StringRef Name;
if (Sym.isCommon()) {
- auto *C = new (Alloc) CommonChunk(Sym);
+ auto *C = make<CommonChunk>(Sym);
Chunks.push_back(C);
COFFObj->getSymbolName(Sym, Name);
Symbol *S =
@@ -221,7 +221,7 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
if (Sym.isExternal())
return Symtab->addAbsolute(Name, Sym)->body();
else
- return new (Alloc) DefinedAbsolute(Name, Sym);
+ return make<DefinedAbsolute>(Name, Sym);
}
int32_t SectionNumber = Sym.getSectionNumber();
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);
B = cast<DefinedRegular>(S->body());
} else
- B = new (Alloc) DefinedRegular(this, /*Name*/ "", SC->isCOMDAT(),
- /*IsExternal*/ false, Sym.getGeneric(), SC);
+ B = make<DefinedRegular>(this, /*Name*/ "", SC->isCOMDAT(),
+ /*IsExternal*/ false, Sym.getGeneric(), SC);
if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP)
SC->setSymbol(B);
@@ -301,8 +301,8 @@ void ImportFile::parse() {
fatal("broken import library");
// Read names and create an __imp_ symbol.
- StringRef Name = StringAlloc.save(StringRef(Buf + sizeof(*Hdr)));
- StringRef ImpName = StringAlloc.save("__imp_" + Name);
+ StringRef Name = Saver.save(StringRef(Buf + sizeof(*Hdr)));
+ StringRef ImpName = Saver.save("__imp_" + Name);
const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1;
DLLName = StringRef(NameStart);
StringRef ExtName;
diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h
index a2fd3f59ad70..9e32b3b9f9d6 100644
--- a/COFF/InputFiles.h
+++ b/COFF/InputFiles.h
@@ -130,7 +130,6 @@ private:
SymbolBody *createUndefined(COFFSymbolRef Sym);
std::unique_ptr<COFFObjectFile> COFFObj;
- llvm::BumpPtrAllocator Alloc;
const coff_section *SXData = nullptr;
// List of all chunks defined by this file. This includes both section
@@ -162,8 +161,7 @@ private:
// for details about the format.
class ImportFile : public InputFile {
public:
- explicit ImportFile(MemoryBufferRef M)
- : InputFile(ImportKind, M), StringAlloc(StringAllocAux) {}
+ explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M) {}
static bool classof(const InputFile *F) { return F->kind() == ImportKind; }
DefinedImportData *ImpSym = nullptr;
@@ -174,9 +172,6 @@ public:
private:
void parse() override;
- llvm::BumpPtrAllocator StringAllocAux;
- llvm::StringSaver StringAlloc;
-
public:
StringRef ExternalName;
const coff_import_header *Hdr;
diff --git a/COFF/Librarian.cpp b/COFF/Librarian.cpp
deleted file mode 100644
index 91316ee6b0c9..000000000000
--- a/COFF/Librarian.cpp
+++ /dev/null
@@ -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);
-}
diff --git a/COFF/ModuleDef.cpp b/COFF/ModuleDef.cpp
deleted file mode 100644
index 740ce867a7c4..000000000000
--- a/COFF/ModuleDef.cpp
+++ /dev/null
@@ -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
diff --git a/COFF/Options.td b/COFF/Options.td
index 7b5573b31cd3..14a1aa04afd6 100644
--- a/COFF/Options.td
+++ b/COFF/Options.td
@@ -102,7 +102,6 @@ def nosymtab : F<"nosymtab">;
def msvclto : F<"msvclto">;
// Flags for debugging
-def debugpdb : F<"debugpdb">;
def dumppdb : Joined<["/", "-"], "dumppdb">;
def lldmap : F<"lldmap">;
def lldmap_file : Joined<["/", "-"], "lldmap:">;
diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp
index 61b0c64de3a8..0266148cc6c9 100644
--- a/COFF/PDB.cpp
+++ b/COFF/PDB.cpp
@@ -14,7 +14,8 @@
#include "SymbolTable.h"
#include "Symbols.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/TypeDatabase.h"
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
@@ -107,6 +108,7 @@ static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder,
BinaryByteStream Stream(Data, support::little);
codeview::CVTypeArray Types;
BinaryStreamReader Reader(Stream);
+ SmallVector<TypeIndex, 128> SourceToDest;
// Follow type servers. If the same type server is encountered more than
// once for this instance of `PDBTypeServerHandler` (for example if many
// 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()));
if (auto EC = Reader.readArray(Types, Reader.getLength()))
fatal(EC, "Reader::readArray failed");
- if (auto Err =
- codeview::mergeTypeStreams(IDTable, TypeTable, &Handler, Types))
+ if (auto Err = codeview::mergeTypeStreams(IDTable, TypeTable, SourceToDest,
+ &Handler, Types))
fatal(Err, "codeview::mergeTypeStreams failed");
}
@@ -133,12 +135,11 @@ static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) {
if (Data.empty())
return;
- TypeDatabase TDB(0);
- TypeDumpVisitor TDV(TDB, &W, false);
+ LazyRandomTypeCollection Types(Data, 100);
+ TypeDumpVisitor TDV(Types, &W, false);
// Use a default implementation that does not follow type servers and instead
// just dumps the contents of the TypeServer2 record.
- CVTypeDumper TypeDumper(TDB);
- if (auto EC = TypeDumper.dump(Data, TDV))
+ if (auto EC = codeview::visitTypeStream(Types, TDV))
fatal(EC, "CVTypeDumper::dump failed");
}
diff --git a/COFF/SymbolTable.h b/COFF/SymbolTable.h
index bf8d6618d964..0aa8a4593b5c 100644
--- a/COFF/SymbolTable.h
+++ b/COFF/SymbolTable.h
@@ -15,7 +15,6 @@
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseMapInfo.h"
-#include "llvm/Support/Allocator.h"
#include "llvm/Support/raw_ostream.h"
namespace llvm {
diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp
index 5c9c8375dadc..cf3ad7ef045c 100644
--- a/COFF/Writer.cpp
+++ b/COFF/Writer.cpp
@@ -48,8 +48,7 @@ namespace {
class DebugDirectoryChunk : public Chunk {
public:
- DebugDirectoryChunk(const std::vector<std::unique_ptr<Chunk>> &R)
- : Records(R) {}
+ DebugDirectoryChunk(const std::vector<Chunk *> &R) : Records(R) {}
size_t getSize() const override {
return Records.size() * sizeof(debug_directory);
@@ -58,7 +57,7 @@ public:
void writeTo(uint8_t *B) const override {
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->TimeDateStamp = 0;
D->MajorVersion = 0;
@@ -74,7 +73,7 @@ public:
}
private:
- const std::vector<std::unique_ptr<Chunk>> &Records;
+ const std::vector<Chunk *> &Records;
};
class CVDebugRecordChunk : public Chunk {
@@ -142,10 +141,10 @@ private:
IdataContents Idata;
DelayLoadContents DelayIdata;
EdataContents Edata;
- std::unique_ptr<SEHTableChunk> SEHTable;
+ SEHTableChunk *SEHTable = nullptr;
- std::unique_ptr<Chunk> DebugDirectory;
- std::vector<std::unique_ptr<Chunk>> DebugRecords;
+ Chunk *DebugDirectory = nullptr;
+ std::vector<Chunk *> DebugRecords;
CVDebugRecordChunk *BuildId = nullptr;
ArrayRef<uint8_t> SectionTable;
@@ -153,8 +152,6 @@ private:
uint32_t PointerToSymbolTable = 0;
uint64_t SizeOfImage;
uint64_t SizeOfHeaders;
-
- std::vector<std::unique_ptr<Chunk>> Chunks;
};
} // anonymous namespace
@@ -258,7 +255,7 @@ void Writer::run() {
sortExceptionTable();
writeBuildId();
- if (!Config->PDBPath.empty()) {
+ if (!Config->PDBPath.empty() && Config->Debug) {
const llvm::codeview::DebugInfo *DI = nullptr;
if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV))
DI = BuildId->DI;
@@ -324,19 +321,19 @@ void Writer::createMiscChunks() {
// Create Debug Information Chunks
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
if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV)) {
- auto Chunk = llvm::make_unique<CVDebugRecordChunk>();
+ auto *Chunk = make<CVDebugRecordChunk>();
- BuildId = Chunk.get();
- DebugRecords.push_back(std::move(Chunk));
+ BuildId = Chunk;
+ DebugRecords.push_back(Chunk);
}
- RData->addChunk(DebugDirectory.get());
- for (const std::unique_ptr<Chunk> &C : DebugRecords)
- RData->addChunk(C.get());
+ RData->addChunk(DebugDirectory);
+ for (Chunk *C : DebugRecords)
+ RData->addChunk(C);
}
// Create SEH table. x86-only.
@@ -352,8 +349,8 @@ void Writer::createMiscChunks() {
Handlers.insert(cast<Defined>(B));
}
- SEHTable.reset(new SEHTableChunk(Handlers));
- RData->addChunk(SEHTable.get());
+ SEHTable = make<SEHTableChunk>(Handlers);
+ RData->addChunk(SEHTable);
}
// Create .idata section for the DLL-imported symbol table.
@@ -398,8 +395,8 @@ void Writer::createImportTables() {
for (Chunk *C : DelayIdata.getDataChunks())
Sec->addChunk(C);
Sec = createSection(".text");
- for (std::unique_ptr<Chunk> &C : DelayIdata.getCodeChunks())
- Sec->addChunk(C.get());
+ for (Chunk *C : DelayIdata.getCodeChunks())
+ Sec->addChunk(C);
}
}
@@ -407,8 +404,8 @@ void Writer::createExportTable() {
if (Config->Exports.empty())
return;
OutputSection *Sec = createSection(".edata");
- for (std::unique_ptr<Chunk> &C : Edata.Chunks)
- Sec->addChunk(C.get());
+ for (Chunk *C : Edata.Chunks)
+ Sec->addChunk(C);
}
// 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->SizeOfHeapReserve = Config->HeapReserve;
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)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER;
if (Config->DynamicBase)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE;
if (Config->HighEntropyVA)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA;
- if (!Config->AllowBind)
- PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND;
if (Config->NxCompat)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT;
if (!Config->AllowIsolation)
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index 87896ec96b29..e8cfd21c4c49 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -390,14 +390,28 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A,
}
}
-template <class ELFT>
-static typename ELFT::uint
-getRelocTargetVA(uint32_t Type, int64_t A, typename ELFT::uint P,
- const SymbolBody &Body, RelExpr Expr) {
+// ARM SBREL relocations are of the form S + A - B where B is the static base
+// The ARM ABI defines base to be "addressing origin of the output segment
+// defining the symbol S". We defined the "addressing origin"/static base to be
+// 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) {
case R_ABS:
case R_RELAX_GOT_PC_NOPIC:
return Body.getVA(A);
+ case R_ARM_SBREL:
+ return Body.getVA(A) - getARMStaticBase(Body);
case R_GOT:
case R_RELAX_TLS_GD_TO_IE_ABS:
return Body.getGotVA() + A;
@@ -518,7 +532,7 @@ getRelocTargetVA(uint32_t Type, int64_t A, typename ELFT::uint P,
case R_NEG_TLS:
return Out::TlsPhdr->p_memsz - Body.getVA(A);
case R_SIZE:
- return Body.getSize<ELFT>() + A;
+ return A; // Body.getSize was already folded into the addend.
case R_TLSDESC:
return InX::Got->getGlobalDynAddr(Body) + A;
case R_TLSDESC_PAGE:
@@ -566,7 +580,7 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
uint64_t SymVA = 0;
if (!Sym.isTls() || Out::TlsPhdr)
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);
}
}
@@ -577,19 +591,28 @@ template <class ELFT> elf::ObjectFile<ELFT> *InputSectionBase::getFile() const {
template <class ELFT>
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
// vector only for SHF_ALLOC'ed sections. For other sections,
// we handle relocations directly here.
- auto *IS = dyn_cast<InputSection>(this);
- if (IS && !(IS->Flags & SHF_ALLOC)) {
- if (IS->AreRelocsRela)
- IS->relocateNonAlloc<ELFT>(Buf, IS->template relas<ELFT>());
- else
- IS->relocateNonAlloc<ELFT>(Buf, IS->template rels<ELFT>());
- return;
- }
+ auto *IS = cast<InputSection>(this);
+ assert(!(IS->Flags & SHF_ALLOC));
+ if (IS->AreRelocsRela)
+ IS->relocateNonAlloc<ELFT>(Buf, IS->template relas<ELFT>());
+ else
+ IS->relocateNonAlloc<ELFT>(Buf, IS->template rels<ELFT>());
+}
- 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) {
uint64_t Offset = getOffset(Rel.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;
RelExpr Expr = Rel.Expr;
- uint64_t TargetVA = SignExtend64<Bits>(
- getRelocTargetVA<ELFT>(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr));
+ uint64_t TargetVA = SignExtend64(
+ getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits);
switch (Expr) {
case R_RELAX_GOT_PC:
diff --git a/ELF/InputSection.h b/ELF/InputSection.h
index 57458588b690..303c398b58cd 100644
--- a/ELF/InputSection.h
+++ b/ELF/InputSection.h
@@ -167,6 +167,8 @@ public:
template <class ELFT> std::string getObjMsg(uint64_t Offset);
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;
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index 161909abf00d..c303f0524ad4 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -440,9 +440,6 @@ void LinkerScript::fabricateDefaultCommands() {
// For each OutputSection that needs a VA fabricate an OutputSectionCommand
// with an InputSectionDescription describing the InputSections
for (OutputSection *Sec : *OutputSections) {
- if (!(Sec->Flags & SHF_ALLOC))
- continue;
-
auto *OSCmd = make<OutputSectionCommand>(Sec->Name);
OSCmd->Sec = Sec;
SecToCommand[Sec] = OSCmd;
diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp
index 23c63e845c9a..7b82eceba02a 100644
--- a/ELF/MapFile.cpp
+++ b/ELF/MapFile.cpp
@@ -21,6 +21,8 @@
#include "MapFile.h"
#include "InputFiles.h"
+#include "LinkerScript.h"
+#include "OutputSections.h"
#include "Strings.h"
#include "SymbolTable.h"
#include "Threads.h"
@@ -98,7 +100,7 @@ getSymbolStrings(ArrayRef<DefinedRegular *> Syms) {
}
template <class ELFT>
-void elf::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
+void elf::writeMapFile(llvm::ArrayRef<BaseCommand *> Script) {
if (Config->MapFile.empty())
return;
@@ -121,7 +123,11 @@ void elf::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
<< " Align Out In Symbol\n";
// 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);
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<ELF32BE>(ArrayRef<OutputSection *>);
-template void elf::writeMapFile<ELF64LE>(ArrayRef<OutputSection *>);
-template void elf::writeMapFile<ELF64BE>(ArrayRef<OutputSection *>);
+template void elf::writeMapFile<ELF32LE>(ArrayRef<BaseCommand *>);
+template void elf::writeMapFile<ELF32BE>(ArrayRef<BaseCommand *>);
+template void elf::writeMapFile<ELF64LE>(ArrayRef<BaseCommand *>);
+template void elf::writeMapFile<ELF64BE>(ArrayRef<BaseCommand *>);
diff --git a/ELF/MapFile.h b/ELF/MapFile.h
index 24d636890e53..f50ef00061ff 100644
--- a/ELF/MapFile.h
+++ b/ELF/MapFile.h
@@ -10,12 +10,12 @@
#ifndef LLD_ELF_MAPFILE_H
#define LLD_ELF_MAPFILE_H
-#include "OutputSections.h"
+#include <llvm/ADT/ArrayRef.h>
namespace lld {
namespace elf {
-template <class ELFT>
-void writeMapFile(llvm::ArrayRef<OutputSection *> OutputSections);
+struct BaseCommand;
+template <class ELFT> void writeMapFile(llvm::ArrayRef<BaseCommand *> Script);
}
}
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
index c505a14f3c64..5564ea246eeb 100644
--- a/ELF/Relocations.cpp
+++ b/ELF/Relocations.cpp
@@ -935,6 +935,10 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
bool IsConstant =
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
// 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
diff --git a/ELF/Relocations.h b/ELF/Relocations.h
index f3512e0a89fc..206f0d9423c9 100644
--- a/ELF/Relocations.h
+++ b/ELF/Relocations.h
@@ -27,6 +27,7 @@ class OutputSection;
// doesn't have to know about architecture-specific details.
enum RelExpr {
R_ABS,
+ R_ARM_SBREL,
R_GOT,
R_GOTONLY_PC,
R_GOTONLY_PC_FROM_END,
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp
index 5a2c2c37efd8..599f1441a47f 100644
--- a/ELF/SyntheticSections.cpp
+++ b/ELF/SyntheticSections.cpp
@@ -600,7 +600,7 @@ template <class ELFT> void EhFrameSection<ELFT>::writeTo(uint8_t *Buf) {
}
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
// 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,
Target->GotEntrySize, ".got") {}
-void GotBaseSection::addEntry(SymbolBody &Sym) {
+void GotSection::addEntry(SymbolBody &Sym) {
Sym.GotIndex = NumEntries;
++NumEntries;
}
-bool GotBaseSection::addDynTlsEntry(SymbolBody &Sym) {
+bool GotSection::addDynTlsEntry(SymbolBody &Sym) {
if (Sym.GlobalDynIndex != -1U)
return false;
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.
// In total it takes two GOT slots.
-bool GotBaseSection::addTlsIndex() {
+bool GotSection::addTlsIndex() {
if (TlsIndexOff != uint32_t(-1))
return false;
TlsIndexOff = NumEntries * Config->Wordsize;
@@ -645,27 +645,23 @@ bool GotBaseSection::addTlsIndex() {
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;
}
-uint64_t GotBaseSection::getGlobalDynOffset(const SymbolBody &B) const {
+uint64_t GotSection::getGlobalDynOffset(const SymbolBody &B) const {
return B.GlobalDynIndex * Config->Wordsize;
}
-void GotBaseSection::finalizeContents() {
- Size = NumEntries * Config->Wordsize;
-}
+void GotSection::finalizeContents() { 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),
// we need to emit a GOT even if it's empty.
return NumEntries == 0 && !HasGotOffRel;
}
-template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
- this->template relocate<ELFT>(Buf, Buf + Size);
-}
+void GotSection::writeTo(uint8_t *Buf) { relocateAlloc(Buf, Buf + Size); }
MipsGotSection::MipsGotSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16,
@@ -2242,7 +2238,7 @@ StringTableSection *InX::DynStrTab;
SymbolTableBaseSection *InX::DynSymTab;
InputSection *InX::Interp;
GdbIndexSection *InX::GdbIndex;
-GotBaseSection *InX::Got;
+GotSection *InX::Got;
GotPltSection *InX::GotPlt;
GnuHashTableSection *InX::GnuHashTab;
IgotPltSection *InX::IgotPlt;
@@ -2284,11 +2280,6 @@ template class elf::MipsReginfoSection<ELF32BE>;
template class elf::MipsReginfoSection<ELF64LE>;
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<ELF32BE>;
template class elf::DynamicSection<ELF64LE>;
diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h
index 0477c601a7df..c5ffb88c1366 100644
--- a/ELF/SyntheticSections.h
+++ b/ELF/SyntheticSections.h
@@ -104,12 +104,13 @@ private:
llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
};
-class GotBaseSection : public SyntheticSection {
+class GotSection : public SyntheticSection {
public:
- GotBaseSection();
+ GotSection();
size_t getSize() const override { return Size; }
void finalizeContents() override;
bool empty() const override;
+ void writeTo(uint8_t *Buf) override;
void addEntry(SymbolBody &Sym);
bool addDynTlsEntry(SymbolBody &Sym);
@@ -130,11 +131,6 @@ protected:
uint64_t Size = 0;
};
-template <class ELFT> class GotSection final : public GotBaseSection {
-public:
- void writeTo(uint8_t *Buf) override;
-};
-
// .note.gnu.build-id section.
class BuildIdSection : public SyntheticSection {
// First 16 bytes are a header.
@@ -764,7 +760,7 @@ struct InX {
static GnuHashTableSection *GnuHashTab;
static InputSection *Interp;
static GdbIndexSection *GdbIndex;
- static GotBaseSection *Got;
+ static GotSection *Got;
static GotPltSection *GotPlt;
static IgotPltSection *IgotPlt;
static MipsGotSection *MipsGot;
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
index 781d7fe3bc3f..cf7d912ad829 100644
--- a/ELF/Target.cpp
+++ b/ELF/Target.cpp
@@ -1693,6 +1693,8 @@ RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
case R_ARM_TLS_IE32:
// GOT(S) + A - P
return R_GOT_PC;
+ case R_ARM_SBREL32:
+ return R_ARM_SBREL;
case R_ARM_TARGET1:
return Config->Target1Rel ? R_PC : R_ABS;
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_REL32:
case R_ARM_RELATIVE:
+ case R_ARM_SBREL32:
case R_ARM_TARGET1:
case R_ARM_TARGET2:
case R_ARM_TLS_GD32:
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index 4be6fe53c18b..7a21d2b9f13d 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -288,8 +288,13 @@ template <class ELFT> void Writer<ELFT>::run() {
if (ErrorCount)
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.
- writeMapFile<ELFT>(OutputSections);
+ writeMapFile<ELFT>(Script->Opt.Commands);
if (ErrorCount)
return;
@@ -403,7 +408,7 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
InX::MipsGot = make<MipsGotSection>();
Add(InX::MipsGot);
} else {
- InX::Got = make<GotSection<ELFT>>();
+ InX::Got = make<GotSection>();
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 two see how similar two ranks are (see getRankProximity).
enum RankFlags {
- RF_NOT_ADDR_SET = 1 << 16,
- RF_NOT_INTERP = 1 << 15,
- RF_NOT_ALLOC = 1 << 14,
- RF_WRITE = 1 << 13,
- RF_EXEC = 1 << 12,
- RF_NON_TLS_BSS = 1 << 11,
- RF_NON_TLS_BSS_RO = 1 << 10,
- RF_NOT_TLS = 1 << 9,
- RF_BSS = 1 << 8,
- RF_PPC_NOT_TOCBSS = 1 << 7,
- RF_PPC_OPD = 1 << 6,
- RF_PPC_TOCL = 1 << 5,
- RF_PPC_TOC = 1 << 4,
- RF_PPC_BRANCH_LT = 1 << 3,
- RF_MIPS_GPREL = 1 << 2,
- RF_MIPS_NOT_GOT = 1 << 1
+ RF_NOT_ADDR_SET = 1 << 15,
+ RF_NOT_INTERP = 1 << 14,
+ RF_NOT_ALLOC = 1 << 13,
+ RF_WRITE = 1 << 12,
+ RF_EXEC = 1 << 11,
+ RF_NON_TLS_BSS = 1 << 10,
+ RF_NON_TLS_BSS_RO = 1 << 9,
+ RF_NOT_TLS = 1 << 8,
+ RF_BSS = 1 << 7,
+ RF_PPC_NOT_TOCBSS = 1 << 6,
+ RF_PPC_OPD = 1 << 5,
+ RF_PPC_TOCL = 1 << 4,
+ RF_PPC_TOC = 1 << 3,
+ RF_PPC_BRANCH_LT = 1 << 2,
+ RF_MIPS_GPREL = 1 << 1,
+ RF_MIPS_NOT_GOT = 1 << 0
};
static unsigned getSectionRank(const OutputSection *Sec) {
diff --git a/test/COFF/armnt-imports.test b/test/COFF/armnt-imports.test
index 519886eb0c06..f0aaebd3f293 100644
--- a/test/COFF/armnt-imports.test
+++ b/test/COFF/armnt-imports.test
@@ -6,7 +6,7 @@
# CHECK: Import {
# CHECK: Name: library.dll
# CHECK: ImportLookupTableRVA: 0x2028
-# CHECK: ImportAddressTableRVA: 0x2030
+# CHECK: ImportAddressTableRVA: 0x2028
# CHECK: Symbol: function (0)
# CHECK: }
diff --git a/test/COFF/hello32.test b/test/COFF/hello32.test
index b7bc887d46eb..b7c5f28c3534 100644
--- a/test/COFF/hello32.test
+++ b/test/COFF/hello32.test
@@ -41,9 +41,10 @@ HEADER-NEXT: MinorSubsystemVersion: 0
HEADER-NEXT: SizeOfImage: 16896
HEADER-NEXT: SizeOfHeaders: 512
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_DYNAMIC_BASE (0x40)
+HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_NO_BIND (0x800)
HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT (0x100)
HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000)
HEADER-NEXT: ]
@@ -77,7 +78,7 @@ HEADER-NEXT: LoadConfigTableRVA: 0x0
HEADER-NEXT: LoadConfigTableSize: 0x0
HEADER-NEXT: BoundImportRVA: 0x0
HEADER-NEXT: BoundImportSize: 0x0
-HEADER-NEXT: IATRVA: 0x3034
+HEADER-NEXT: IATRVA: 0x3028
HEADER-NEXT: IATSize: 0xC
HEADER-NEXT: DelayImportDescriptorRVA: 0x0
HEADER-NEXT: DelayImportDescriptorSize: 0x0
@@ -113,7 +114,7 @@ IMPORTS: AddressSize: 32bit
IMPORTS: Import {
IMPORTS: Name: std32.dll
IMPORTS: ImportLookupTableRVA: 0x3028
-IMPORTS: ImportAddressTableRVA: 0x3034
+IMPORTS: ImportAddressTableRVA: 0x3028
IMPORTS: Symbol: ExitProcess (0)
IMPORTS: Symbol: MessageBoxA (1)
IMPORTS: }
diff --git a/test/COFF/imports.test b/test/COFF/imports.test
index 584c24eb1b76..4df6d492ff28 100644
--- a/test/COFF/imports.test
+++ b/test/COFF/imports.test
@@ -21,14 +21,14 @@ TEXT-NEXT: callq 60
TEXT-NEXT: movl $0, %ecx
TEXT-NEXT: callq 18
TEXT-NEXT: callq 29
-TEXT: jmpq *4098(%rip)
-TEXT: jmpq *4090(%rip)
-TEXT: jmpq *4082(%rip)
+TEXT: jmpq *4066(%rip)
+TEXT: jmpq *4058(%rip)
+TEXT: jmpq *4050(%rip)
IMPORT: Import {
IMPORT-NEXT: Name: std64.dll
IMPORT-NEXT: ImportLookupTableRVA: 0x3028
-IMPORT-NEXT: ImportAddressTableRVA: 0x3048
+IMPORT-NEXT: ImportAddressTableRVA: 0x3028
IMPORT-NEXT: Symbol: ExitProcess (0)
IMPORT-NEXT: Symbol: (50)
IMPORT-NEXT: Symbol: MessageBoxA (1)
diff --git a/test/COFF/invalid-debug-type.test b/test/COFF/invalid-debug-type.test
index e48b3fdd2e06..10264180314d 100644
--- a/test/COFF/invalid-debug-type.test
+++ b/test/COFF/invalid-debug-type.test
@@ -1,5 +1,5 @@
# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.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: /debugpdb %t1.obj %t2.obj
+# RUN: %t1.obj %t2.obj
diff --git a/test/COFF/options.test b/test/COFF/options.test
index 39f944beddbc..a23da1971d15 100644
--- a/test/COFF/options.test
+++ b/test/COFF/options.test
@@ -2,13 +2,7 @@
# RUN: lld-link /out:%t.exe /entry:main %t.obj
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=BIND %s
-# RUN: lld-link /allowbind /out:%t.exe /entry:main %t.obj
-# 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
+BIND: IMAGE_DLL_CHARACTERISTICS_NO_BIND
# RUN: lld-link /out:%t.exe /entry:main %t.obj
# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=ISO %s
diff --git a/test/COFF/pdb-none.test b/test/COFF/pdb-none.test
index 480ff2a4ace3..7e428693aec4 100644
--- a/test/COFF/pdb-none.test
+++ b/test/COFF/pdb-none.test
@@ -1,7 +1,7 @@
# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.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: /debugpdb %t1.obj %t2.obj
+# RUN: %t1.obj %t2.obj
# RUN: llvm-pdbdump pdb2yaml -pdb-stream %t.pdb | FileCheck %s
diff --git a/test/COFF/pdb-options.test b/test/COFF/pdb-options.test
new file mode 100644
index 000000000000..1cc4b3abda7c
--- /dev/null
+++ b/test/COFF/pdb-options.test
@@ -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/..
diff --git a/test/COFF/pdb.test b/test/COFF/pdb.test
index aa14d290c737..f1fa4ec7c2b6 100644
--- a/test/COFF/pdb.test
+++ b/test/COFF/pdb.test
@@ -1,7 +1,7 @@
# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
# 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: -dbi-stream -ipi-stream -tpi-stream %t.pdb | FileCheck %s
diff --git a/test/ELF/arm-sbrel32.s b/test/ELF/arm-sbrel32.s
new file mode 100644
index 000000000000..7f12717195a9
--- /dev/null
+++ b/test/ELF/arm-sbrel32.s
@@ -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