aboutsummaryrefslogtreecommitdiffstats
path: root/COFF
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-07-23 20:48:50 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-07-23 20:48:50 +0000
commit1c98619801a5705c688e683be3ef9d70169a0686 (patch)
tree8422105cd1a94c368315f2db16b9ac746cf7c000 /COFF
parentf4f3ce4613680903220815690ad79fc7ba0a2e26 (diff)
downloadsrc-1c98619801a5705c688e683be3ef9d70169a0686.tar.gz
src-1c98619801a5705c688e683be3ef9d70169a0686.zip
Vendor import of lld release_39 branch r276489:vendor/lld/lld-release_39-r276489
Notes
Notes: svn path=/vendor/lld/dist/; revision=303239 svn path=/vendor/lld/lld-release_39-r276489/; revision=303240; tag=vendor/lld/lld-release_39-r276489
Diffstat (limited to 'COFF')
-rw-r--r--COFF/CMakeLists.txt3
-rw-r--r--COFF/Chunks.cpp13
-rw-r--r--COFF/Chunks.h10
-rw-r--r--COFF/Config.h4
-rw-r--r--COFF/DLL.cpp2
-rw-r--r--COFF/Driver.cpp55
-rw-r--r--COFF/Driver.h5
-rw-r--r--COFF/DriverUtils.cpp332
-rw-r--r--COFF/Error.cpp13
-rw-r--r--COFF/Error.h18
-rw-r--r--COFF/ICF.cpp6
-rw-r--r--COFF/InputFiles.cpp119
-rw-r--r--COFF/InputFiles.h9
-rw-r--r--COFF/Librarian.cpp489
-rw-r--r--COFF/ModuleDef.cpp14
-rw-r--r--COFF/Options.td2
-rw-r--r--COFF/PDB.cpp3
-rw-r--r--COFF/README.md266
-rw-r--r--COFF/SymbolTable.cpp33
-rw-r--r--COFF/SymbolTable.h2
-rw-r--r--COFF/Symbols.cpp28
-rw-r--r--COFF/Symbols.h4
-rw-r--r--COFF/Writer.cpp72
23 files changed, 844 insertions, 658 deletions
diff --git a/COFF/CMakeLists.txt b/COFF/CMakeLists.txt
index 3f31ba9ba1fb..3319f392efe1 100644
--- a/COFF/CMakeLists.txt
+++ b/COFF/CMakeLists.txt
@@ -10,6 +10,7 @@ add_lld_library(lldCOFF
Error.cpp
ICF.cpp
InputFiles.cpp
+ Librarian.cpp
MarkLive.cpp
ModuleDef.cpp
PDB.cpp
@@ -28,6 +29,8 @@ add_lld_library(lldCOFF
Target
Option
Support
+
+ LINK_LIBS ${PTHREAD_LIB}
)
add_dependencies(lldCOFF COFFOptionsTableGen)
diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp
index f9f768d69866..1c1b18176aa2 100644
--- a/COFF/Chunks.cpp
+++ b/COFF/Chunks.cpp
@@ -34,10 +34,7 @@ SectionChunk::SectionChunk(ObjectFile *F, const coff_section *H)
// Initialize SectionName.
File->getCOFFObj()->getSectionName(Header, SectionName);
- // Bit [20:24] contains section alignment. Both 0 and 1 mean alignment 1.
- unsigned Shift = (Header->Characteristics >> 20) & 0xF;
- if (Shift > 0)
- Align = uint32_t(1) << (Shift - 1);
+ Align = Header->getAlignment();
// Only COMDAT sections are subject of dead-stripping.
Live = !isCOMDAT();
@@ -64,7 +61,7 @@ void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym,
case IMAGE_REL_AMD64_SECTION: add16(Off, Sym->getSectionIndex()); break;
case IMAGE_REL_AMD64_SECREL: add32(Off, Sym->getSecrel()); break;
default:
- error("Unsupported relocation type");
+ fatal("unsupported relocation type");
}
}
@@ -79,7 +76,7 @@ void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym,
case IMAGE_REL_I386_SECTION: add16(Off, Sym->getSectionIndex()); break;
case IMAGE_REL_I386_SECREL: add32(Off, Sym->getSecrel()); break;
default:
- error("Unsupported relocation type");
+ fatal("unsupported relocation type");
}
}
@@ -123,7 +120,7 @@ void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym,
case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, S - P - 4); break;
case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, S - P - 4); break;
default:
- error("Unsupported relocation type");
+ fatal("unsupported relocation type");
}
}
@@ -310,7 +307,7 @@ void SEHTableChunk::writeTo(uint8_t *Buf) const {
BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) {
// Block header consists of 4 byte page RVA and 4 byte block size.
// Each entry is 2 byte. Last entry may be padding.
- Data.resize(align((End - Begin) * 2 + 8, 4));
+ Data.resize(alignTo((End - Begin) * 2 + 8, 4));
uint8_t *P = Data.data();
write32le(P, Page);
write32le(P + 4, Data.size());
diff --git a/COFF/Chunks.h b/COFF/Chunks.h
index 274135516eb9..cd0e2e69ef5d 100644
--- a/COFF/Chunks.h
+++ b/COFF/Chunks.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/iterator_range.h"
#include "llvm/Object/COFF.h"
#include <atomic>
+#include <utility>
#include <vector>
namespace lld {
@@ -138,6 +139,7 @@ public:
SectionChunk(ObjectFile *File, const coff_section *Header);
static bool classof(const Chunk *C) { return C->kind() == SectionKind; }
size_t getSize() const override { return Header->SizeOfRawData; }
+ ArrayRef<uint8_t> getContents() const;
void writeTo(uint8_t *Buf) const override;
bool hasData() const override;
uint32_t getPermissions() const override;
@@ -186,8 +188,6 @@ public:
uint32_t Checksum = 0;
private:
- ArrayRef<uint8_t> getContents() const;
-
// A file this chunk was created from.
ObjectFile *File;
@@ -295,7 +295,7 @@ private:
// functions. x86-only.
class SEHTableChunk : public Chunk {
public:
- explicit SEHTableChunk(std::set<Defined *> S) : Syms(S) {}
+ explicit SEHTableChunk(std::set<Defined *> S) : Syms(std::move(S)) {}
size_t getSize() const override { return Syms.size() * 4; }
void writeTo(uint8_t *Buf) const override;
@@ -326,10 +326,6 @@ public:
uint8_t Type;
};
-inline uint64_t align(uint64_t Value, uint64_t Align) {
- return llvm::RoundUpToAlignment(Value, Align);
-}
-
} // namespace coff
} // namespace lld
diff --git a/COFF/Config.h b/COFF/Config.h
index 9cfccadba5fa..a5472e937fa1 100644
--- a/COFF/Config.h
+++ b/COFF/Config.h
@@ -106,11 +106,15 @@ struct Configuration {
// Used for /merge:from=to (e.g. /merge:.rdata=.text)
std::map<StringRef, StringRef> Merge;
+ // Used for /section=.name,{DEKPRSW} to set section attributes.
+ std::map<StringRef, uint32_t> Section;
+
// Options for manifest files.
ManifestKind Manifest = SideBySide;
int ManifestID = 1;
StringRef ManifestDependency;
bool ManifestUAC = true;
+ std::vector<std::string> ManifestInput;
StringRef ManifestLevel = "'asInvoker'";
StringRef ManifestUIAccess = "'false'";
StringRef ManifestFile;
diff --git a/COFF/DLL.cpp b/COFF/DLL.cpp
index 8f3383d75c7b..9ac370c11d59 100644
--- a/COFF/DLL.cpp
+++ b/COFF/DLL.cpp
@@ -45,7 +45,7 @@ public:
size_t getSize() const override {
// Starts with 2 byte Hint field, followed by a null-terminated string,
// ends with 0 or 1 byte padding.
- return align(Name.size() + 3, 2);
+ return alignTo(Name.size() + 3, 2);
}
void writeTo(uint8_t *Buf) const override {
diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp
index 4cacf0ff552a..bb6a60e4fc4c 100644
--- a/COFF/Driver.cpp
+++ b/COFF/Driver.cpp
@@ -14,6 +14,7 @@
#include "SymbolTable.h"
#include "Symbols.h"
#include "Writer.h"
+#include "lld/Driver/Driver.h"
#include "llvm/ADT/Optional.h"
#include "llvm/LibDriver/LibDriver.h"
#include "llvm/Option/Arg.h"
@@ -40,27 +41,28 @@ namespace coff {
Configuration *Config;
LinkerDriver *Driver;
-void link(llvm::ArrayRef<const char *> Args) {
+bool link(llvm::ArrayRef<const char *> Args) {
Configuration C;
LinkerDriver D;
Config = &C;
Driver = &D;
- return Driver->link(Args);
+ Driver->link(Args);
+ return true;
}
-// Drop directory components and replace extension with ".exe".
+// Drop directory components and replace extension with ".exe" or ".dll".
static std::string getOutputPath(StringRef Path) {
auto P = Path.find_last_of("\\/");
StringRef S = (P == StringRef::npos) ? Path : Path.substr(P + 1);
- return (S.substr(0, S.rfind('.')) + ".exe").str();
+ const char* E = Config->DLL ? ".dll" : ".exe";
+ return (S.substr(0, S.rfind('.')) + E).str();
}
// Opens a file. Path has to be resolved already.
// Newly created memory buffers are owned by this driver.
MemoryBufferRef LinkerDriver::openFile(StringRef Path) {
- auto MBOrErr = MemoryBuffer::getFile(Path);
- error(MBOrErr, Twine("Could not open ") + Path);
- std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
+ std::unique_ptr<MemoryBuffer> MB =
+ check(MemoryBuffer::getFile(Path), "could not open " + Path);
MemoryBufferRef MBRef = MB->getMemBufferRef();
OwningMBs.push_back(std::move(MB)); // take ownership
return MBRef;
@@ -116,12 +118,16 @@ void LinkerDriver::parseDirectives(StringRef S) {
case OPT_nodefaultlib:
Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()));
break;
+ case OPT_section:
+ parseSection(Arg->getValue());
+ break;
case OPT_editandcontinue:
+ case OPT_fastfail:
case OPT_guardsym:
case OPT_throwingnew:
break;
default:
- error(Twine(Arg->getSpelling()) + " is not allowed in .drectve");
+ fatal(Arg->getSpelling() + " is not allowed in .drectve");
}
}
}
@@ -246,7 +252,7 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
// We call our own implementation of lib.exe that understands bitcode files.
if (ArgsArr.size() > 1 && StringRef(ArgsArr[1]).equals_lower("/lib")) {
if (llvm::libDriverMain(ArgsArr.slice(1)) != 0)
- error("lib failed");
+ fatal("lib failed");
return;
}
@@ -268,7 +274,7 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
}
if (Args.filtered_begin(OPT_INPUT) == Args.filtered_end())
- error("no input files.");
+ fatal("no input files");
// Construct search path list.
SearchPaths.push_back("");
@@ -295,7 +301,7 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
// Handle /noentry
if (Args.hasArg(OPT_noentry)) {
if (!Args.hasArg(OPT_dll))
- error("/noentry must be specified with /dll");
+ fatal("/noentry must be specified with /dll");
Config->NoEntry = true;
}
@@ -308,7 +314,7 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
// Handle /fixed
if (Args.hasArg(OPT_fixed)) {
if (Args.hasArg(OPT_dynamicbase))
- error("/fixed must not be specified with /dynamicbase");
+ fatal("/fixed must not be specified with /dynamicbase");
Config->Relocatable = false;
Config->DynamicBase = false;
}
@@ -382,17 +388,17 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
StringRef OptLevel = StringRef(S).substr(7);
if (OptLevel.getAsInteger(10, Config->LTOOptLevel) ||
Config->LTOOptLevel > 3)
- error("/opt:lldlto: invalid optimization level: " + OptLevel);
+ fatal("/opt:lldlto: invalid optimization level: " + OptLevel);
continue;
}
if (StringRef(S).startswith("lldltojobs=")) {
StringRef Jobs = StringRef(S).substr(11);
if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0)
- error("/opt:lldltojobs: invalid job count: " + Jobs);
+ fatal("/opt:lldltojobs: invalid job count: " + Jobs);
continue;
}
if (S != "ref" && S != "lbr" && S != "nolbr")
- error(Twine("/opt: unknown option: ") + S);
+ fatal("/opt: unknown option: " + S);
}
}
@@ -404,6 +410,10 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
for (auto *Arg : Args.filtered(OPT_merge))
parseMerge(Arg->getValue());
+ // Handle /section
+ for (auto *Arg : Args.filtered(OPT_section))
+ parseSection(Arg->getValue());
+
// Handle /manifest
if (auto *Arg = Args.getLastArg(OPT_manifest_colon))
parseManifest(Arg->getValue());
@@ -420,6 +430,10 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
if (auto *Arg = Args.getLastArg(OPT_manifestfile))
Config->ManifestFile = Arg->getValue();
+ // Handle /manifestinput
+ for (auto *Arg : Args.filtered(OPT_manifestinput))
+ Config->ManifestInput.push_back(Arg->getValue());
+
// Handle miscellaneous boolean flags.
if (Args.hasArg(OPT_allowbind_no))
Config->AllowBind = false;
@@ -485,7 +499,7 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
continue;
}
if (Config->Machine != MT)
- error(Twine(File->getShortName()) + ": machine type " + machineToStr(MT) +
+ fatal(File->getShortName() + ": machine type " + machineToStr(MT) +
" conflicts with " + machineToStr(Config->Machine));
}
if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
@@ -520,7 +534,7 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
// infer that from user-defined entry name.
StringRef S = findDefaultEntry();
if (S.empty())
- error("entry point must be defined");
+ fatal("entry point must be defined");
Config->Entry = addUndefined(S);
if (Config->Verbose)
llvm::outs() << "Entry name inferred: " << S << "\n";
@@ -627,14 +641,14 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
Config->Subsystem = inferSubsystem();
if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
- error("subsystem must be defined");
+ fatal("subsystem must be defined");
}
// Handle /safeseh.
if (Args.hasArg(OPT_safeseh))
for (ObjectFile *File : Symtab.ObjectFiles)
if (!File->SEHCompat)
- error("/safeseh: " + File->getName() + " is not compatible with SEH");
+ fatal("/safeseh: " + File->getName() + " is not compatible with SEH");
// Windows specific -- when we are creating a .dll file, we also
// need to create a .lib file.
@@ -668,7 +682,8 @@ void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
if (auto *Arg = Args.getLastArg(OPT_lldmap)) {
std::error_code EC;
llvm::raw_fd_ostream Out(Arg->getValue(), EC, OpenFlags::F_Text);
- error(EC, "Could not create the symbol map");
+ if (EC)
+ fatal(EC, "could not create the symbol map");
Symtab.printMap(Out);
}
// Call exit to avoid calling destructors.
diff --git a/COFF/Driver.h b/COFF/Driver.h
index e50da20cbb04..23969ee802fb 100644
--- a/COFF/Driver.h
+++ b/COFF/Driver.h
@@ -34,9 +34,6 @@ using llvm::COFF::WindowsSubsystem;
using llvm::Optional;
class InputFile;
-// Entry point of the COFF linker.
-void link(llvm::ArrayRef<const char *> Args);
-
// Implemented in MarkLive.cpp.
void markLive(const std::vector<Chunk *> &Chunks);
@@ -136,6 +133,7 @@ void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
void parseAlternateName(StringRef);
void parseMerge(StringRef);
+void parseSection(StringRef);
// Parses a string in the form of "EMBED[,=<integer>]|NO".
void parseManifest(StringRef Arg);
@@ -163,7 +161,6 @@ void checkFailIfMismatch(StringRef Arg);
std::unique_ptr<MemoryBuffer>
convertResToCOFF(const std::vector<MemoryBufferRef> &MBs);
-void touchFile(StringRef Path);
void createPDB(StringRef Path);
// Create enum with OPT_xxx values for each option in Options.td
diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp
index 014fee7fefd7..5d7dc2bc65af 100644
--- a/COFF/DriverUtils.cpp
+++ b/COFF/DriverUtils.cpp
@@ -19,15 +19,12 @@
#include "Symbols.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Object/Archive.h"
-#include "llvm/Object/ArchiveWriter.h"
#include "llvm/Object/COFF.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileUtilities.h"
-#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
@@ -53,7 +50,8 @@ public:
void run() {
ErrorOr<std::string> ExeOrErr = llvm::sys::findProgramByName(Prog);
- error(ExeOrErr, Twine("unable to find ") + Prog + " in PATH: ");
+ if (auto EC = ExeOrErr.getError())
+ fatal(EC, "unable to find " + Prog + " in PATH: ");
const char *Exe = Saver.save(*ExeOrErr);
Args.insert(Args.begin(), Exe);
Args.push_back(nullptr);
@@ -61,7 +59,7 @@ public:
for (const char *S : Args)
if (S)
llvm::errs() << S << " ";
- error("failed");
+ fatal("ExecuteAndWait failed");
}
}
@@ -85,7 +83,7 @@ MachineTypes getMachineType(StringRef S) {
.Default(IMAGE_FILE_MACHINE_UNKNOWN);
if (MT != IMAGE_FILE_MACHINE_UNKNOWN)
return MT;
- error(Twine("unknown /machine argument: ") + S);
+ fatal("unknown /machine argument: " + S);
}
StringRef machineToStr(MachineTypes MT) {
@@ -106,9 +104,9 @@ void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size) {
StringRef S1, S2;
std::tie(S1, S2) = Arg.split(',');
if (S1.getAsInteger(0, *Addr))
- error(Twine("invalid number: ") + S1);
+ fatal("invalid number: " + S1);
if (Size && !S2.empty() && S2.getAsInteger(0, *Size))
- error(Twine("invalid number: ") + S2);
+ fatal("invalid number: " + S2);
}
// Parses a string in the form of "<integer>[.<integer>]".
@@ -117,10 +115,10 @@ void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) {
StringRef S1, S2;
std::tie(S1, S2) = Arg.split('.');
if (S1.getAsInteger(0, *Major))
- error(Twine("invalid number: ") + S1);
+ fatal("invalid number: " + S1);
*Minor = 0;
if (!S2.empty() && S2.getAsInteger(0, *Minor))
- error(Twine("invalid number: ") + S2);
+ fatal("invalid number: " + S2);
}
// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
@@ -140,7 +138,7 @@ void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
.Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI)
.Default(IMAGE_SUBSYSTEM_UNKNOWN);
if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN)
- error(Twine("unknown subsystem: ") + SysStr);
+ fatal("unknown subsystem: " + SysStr);
if (!Ver.empty())
parseVersion(Ver, Major, Minor);
}
@@ -151,10 +149,10 @@ void parseAlternateName(StringRef S) {
StringRef From, To;
std::tie(From, To) = S.split('=');
if (From.empty() || To.empty())
- error(Twine("/alternatename: invalid argument: ") + S);
+ fatal("/alternatename: invalid argument: " + S);
auto It = Config->AlternateNames.find(From);
if (It != Config->AlternateNames.end() && It->second != To)
- error(Twine("/alternatename: conflicts: ") + S);
+ fatal("/alternatename: conflicts: " + S);
Config->AlternateNames.insert(It, std::make_pair(From, To));
}
@@ -164,7 +162,7 @@ void parseMerge(StringRef S) {
StringRef From, To;
std::tie(From, To) = S.split('=');
if (From.empty() || To.empty())
- error(Twine("/merge: invalid argument: ") + S);
+ fatal("/merge: invalid argument: " + S);
auto Pair = Config->Merge.insert(std::make_pair(From, To));
bool Inserted = Pair.second;
if (!Inserted) {
@@ -175,6 +173,47 @@ void parseMerge(StringRef S) {
}
}
+static uint32_t parseSectionAttributes(StringRef S) {
+ uint32_t Ret = 0;
+ for (char C : S.lower()) {
+ switch (C) {
+ case 'd':
+ Ret |= IMAGE_SCN_MEM_DISCARDABLE;
+ break;
+ case 'e':
+ Ret |= IMAGE_SCN_MEM_EXECUTE;
+ break;
+ case 'k':
+ Ret |= IMAGE_SCN_MEM_NOT_CACHED;
+ break;
+ case 'p':
+ Ret |= IMAGE_SCN_MEM_NOT_PAGED;
+ break;
+ case 'r':
+ Ret |= IMAGE_SCN_MEM_READ;
+ break;
+ case 's':
+ Ret |= IMAGE_SCN_MEM_SHARED;
+ break;
+ case 'w':
+ Ret |= IMAGE_SCN_MEM_WRITE;
+ break;
+ default:
+ fatal("/section: invalid argument: " + S);
+ }
+ }
+ return Ret;
+}
+
+// Parses /section option argument.
+void parseSection(StringRef S) {
+ StringRef Name, Attrs;
+ std::tie(Name, Attrs) = S.split(',');
+ if (Name.empty() || Attrs.empty())
+ fatal("/section: invalid argument: " + S);
+ Config->Section[Name] = parseSectionAttributes(Attrs);
+}
+
// Parses a string in the form of "EMBED[,=<integer>]|NO".
// Results are directly written to Config.
void parseManifest(StringRef Arg) {
@@ -183,16 +222,16 @@ void parseManifest(StringRef Arg) {
return;
}
if (!Arg.startswith_lower("embed"))
- error(Twine("Invalid option ") + Arg);
+ fatal("invalid option " + Arg);
Config->Manifest = Configuration::Embed;
Arg = Arg.substr(strlen("embed"));
if (Arg.empty())
return;
if (!Arg.startswith_lower(",id="))
- error(Twine("Invalid option ") + Arg);
+ fatal("invalid option " + Arg);
Arg = Arg.substr(strlen(",id="));
if (Arg.getAsInteger(0, Config->ManifestID))
- error(Twine("Invalid option ") + Arg);
+ fatal("invalid option " + Arg);
}
// Parses a string in the form of "level=<string>|uiAccess=<string>|NO".
@@ -216,7 +255,7 @@ void parseManifestUAC(StringRef Arg) {
std::tie(Config->ManifestUIAccess, Arg) = Arg.split(" ");
continue;
}
- error(Twine("Invalid option ") + Arg);
+ fatal("invalid option " + Arg);
}
}
@@ -240,10 +279,19 @@ static void quoteAndPrint(raw_ostream &Out, StringRef S) {
}
}
-// Create a manifest file contents.
-static std::string createManifestXml() {
- std::string S;
- llvm::raw_string_ostream OS(S);
+// Create the default manifest file as a temporary file.
+static std::string createDefaultXml() {
+ // Create a temporary file.
+ SmallString<128> Path;
+ if (auto EC = sys::fs::createTemporaryFile("tmp", "manifest", Path))
+ fatal(EC, "cannot create a temporary file");
+
+ // Open the temporary file for writing.
+ std::error_code EC;
+ llvm::raw_fd_ostream OS(Path, EC, sys::fs::F_Text);
+ if (EC)
+ fatal(EC, "failed to open " + Path);
+
// Emit the XML. Note that we do *not* verify that the XML attributes are
// syntactically correct. This is intentional for link.exe compatibility.
OS << "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
@@ -267,21 +315,57 @@ static std::string createManifestXml() {
}
}
OS << "</assembly>\n";
- OS.flush();
- return S;
+ OS.close();
+ return StringRef(Path);
+}
+
+static std::string readFile(StringRef Path) {
+ std::unique_ptr<MemoryBuffer> MB =
+ check(MemoryBuffer::getFile(Path), "could not open " + Path);
+ std::unique_ptr<MemoryBuffer> Buf(std::move(MB));
+ return Buf->getBuffer();
+}
+
+static std::string createManifestXml() {
+ // Create the default manifest file.
+ std::string Path1 = createDefaultXml();
+ if (Config->ManifestInput.empty())
+ return readFile(Path1);
+
+ // If manifest files are supplied by the user using /MANIFESTINPUT
+ // option, we need to merge them with the default manifest.
+ SmallString<128> Path2;
+ if (auto EC = sys::fs::createTemporaryFile("tmp", "manifest", Path2))
+ fatal(EC, "cannot create a temporary file");
+ FileRemover Remover1(Path1);
+ FileRemover Remover2(Path2);
+
+ Executor E("mt.exe");
+ E.add("/manifest");
+ E.add(Path1);
+ for (StringRef Filename : Config->ManifestInput) {
+ E.add("/manifest");
+ E.add(Filename);
+ }
+ E.add("/nologo");
+ E.add("/out:" + StringRef(Path2));
+ E.run();
+ return readFile(Path2);
}
// Create a resource file containing a manifest XML.
std::unique_ptr<MemoryBuffer> createManifestRes() {
// Create a temporary file for the resource script file.
SmallString<128> RCPath;
- std::error_code EC = sys::fs::createTemporaryFile("tmp", "rc", RCPath);
- error(EC, "cannot create a temporary file");
+ if (auto EC = sys::fs::createTemporaryFile("tmp", "rc", RCPath))
+ fatal(EC, "cannot create a temporary file");
FileRemover RCRemover(RCPath);
// Open the temporary file for writing.
+ std::error_code EC;
llvm::raw_fd_ostream Out(RCPath, EC, sys::fs::F_Text);
- error(EC, Twine("failed to open ") + RCPath);
+ if (EC)
+ fatal(EC, "failed to open " + RCPath);
// Write resource script to the RC file.
Out << "#define LANG_ENGLISH 9\n"
@@ -296,8 +380,8 @@ std::unique_ptr<MemoryBuffer> createManifestRes() {
// Create output resource file.
SmallString<128> ResPath;
- EC = sys::fs::createTemporaryFile("tmp", "res", ResPath);
- error(EC, "cannot create a temporary file");
+ if (auto EC = sys::fs::createTemporaryFile("tmp", "res", ResPath))
+ fatal(EC, "cannot create a temporary file");
Executor E("rc.exe");
E.add("/fo");
@@ -305,18 +389,17 @@ std::unique_ptr<MemoryBuffer> createManifestRes() {
E.add("/nologo");
E.add(RCPath.str());
E.run();
- ErrorOr<std::unique_ptr<MemoryBuffer>> Ret = MemoryBuffer::getFile(ResPath);
- error(Ret, Twine("Could not open ") + ResPath);
- return std::move(*Ret);
+ return check(MemoryBuffer::getFile(ResPath), "could not open " + ResPath);
}
void createSideBySideManifest() {
std::string Path = Config->ManifestFile;
if (Path == "")
- Path = (Twine(Config->OutputFile) + ".manifest").str();
+ Path = Config->OutputFile + ".manifest";
std::error_code EC;
llvm::raw_fd_ostream Out(Path, EC, llvm::sys::fs::F_Text);
- error(EC, "failed to create manifest");
+ if (EC)
+ fatal(EC, "failed to create manifest");
Out << createManifestXml();
}
@@ -380,7 +463,7 @@ Export parseExport(StringRef Arg) {
return E;
err:
- error(Twine("invalid /export: ") + Arg);
+ fatal("invalid /export: " + Arg);
}
static StringRef undecorate(StringRef Sym) {
@@ -398,7 +481,7 @@ void fixupExports() {
if (E.Ordinal == 0)
continue;
if (!Ords.insert(E.Ordinal).second)
- error("duplicate export ordinal: " + E.Name);
+ fatal("duplicate export ordinal: " + E.Name);
}
for (Export &E : Config->Exports) {
@@ -459,11 +542,11 @@ void checkFailIfMismatch(StringRef Arg) {
StringRef K, V;
std::tie(K, V) = Arg.split('=');
if (K.empty() || V.empty())
- error(Twine("/failifmismatch: invalid argument: ") + Arg);
+ fatal("/failifmismatch: invalid argument: " + Arg);
StringRef Existing = Config->MustMatch[K];
if (!Existing.empty() && V != Existing)
- error(Twine("/failifmismatch: mismatch detected: ") + Existing + " and " +
- V + " for key " + K);
+ fatal("/failifmismatch: mismatch detected: " + Existing + " and " + V +
+ " for key " + K);
Config->MustMatch[K] = V;
}
@@ -473,8 +556,8 @@ std::unique_ptr<MemoryBuffer>
convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) {
// Create an output file path.
SmallString<128> Path;
- if (llvm::sys::fs::createTemporaryFile("resource", "obj", Path))
- error("Could not create temporary file");
+ if (auto EC = llvm::sys::fs::createTemporaryFile("resource", "obj", Path))
+ fatal(EC, "could not create temporary file");
// Execute cvtres.exe.
Executor E("cvtres.exe");
@@ -485,170 +568,7 @@ convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) {
for (MemoryBufferRef MB : MBs)
E.add(MB.getBufferIdentifier());
E.run();
- ErrorOr<std::unique_ptr<MemoryBuffer>> Ret = MemoryBuffer::getFile(Path);
- error(Ret, Twine("Could not open ") + Path);
- return std::move(*Ret);
-}
-
-static std::string writeToTempFile(StringRef Contents) {
- SmallString<128> Path;
- int FD;
- if (llvm::sys::fs::createTemporaryFile("tmp", "def", FD, Path)) {
- llvm::errs() << "failed to create a temporary file\n";
- return "";
- }
- llvm::raw_fd_ostream OS(FD, /*shouldClose*/ true);
- OS << Contents;
- return Path.str();
-}
-
-void touchFile(StringRef Path) {
- int FD;
- std::error_code EC = sys::fs::openFileForWrite(Path, FD, sys::fs::F_Append);
- error(EC, "failed to create a file");
- sys::Process::SafelyCloseFileDescriptor(FD);
-}
-
-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 std::unique_ptr<MemoryBuffer> createEmptyImportLibrary() {
- std::string S = (Twine("LIBRARY \"") +
- llvm::sys::path::filename(Config->OutputFile) + "\"\n")
- .str();
- std::string Path1 = writeToTempFile(S);
- std::string Path2 = getImplibPath();
- llvm::FileRemover Remover1(Path1);
- llvm::FileRemover Remover2(Path2);
-
- Executor E("lib.exe");
- E.add("/nologo");
- E.add("/machine:" + machineToStr(Config->Machine));
- E.add(Twine("/def:") + Path1);
- E.add(Twine("/out:") + Path2);
- E.run();
-
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
- MemoryBuffer::getFile(Path2, -1, false);
- error(BufOrErr, Twine("Failed to open ") + Path2);
- return MemoryBuffer::getMemBufferCopy((*BufOrErr)->getBuffer());
-}
-
-static std::vector<NewArchiveIterator>
-readMembers(const object::Archive &Archive) {
- std::vector<NewArchiveIterator> V;
- for (const auto &ChildOrErr : Archive.children()) {
- error(ChildOrErr, "Archive::Child::getName failed");
- const object::Archive::Child C(*ChildOrErr);
- ErrorOr<StringRef> NameOrErr = C.getName();
- error(NameOrErr, "Archive::Child::getName failed");
- V.emplace_back(C, *NameOrErr);
- }
- return V;
-}
-
-// This class creates short import files which is described in
-// PE/COFF spec 7. Import Library Format.
-class ShortImportCreator {
-public:
- ShortImportCreator(object::Archive *A, StringRef S) : Parent(A), DLLName(S) {}
-
- NewArchiveIterator create(StringRef Sym, uint16_t Ordinal,
- ImportNameType NameType, bool isData) {
- size_t ImpSize = DLLName.size() + Sym.size() + 2; // +2 for NULs
- size_t Size = sizeof(object::ArchiveMemberHeader) +
- sizeof(coff_import_header) + ImpSize;
- char *Buf = Alloc.Allocate<char>(Size);
- memset(Buf, 0, Size);
- char *P = Buf;
-
- // Write archive member header
- auto *Hdr = reinterpret_cast<object::ArchiveMemberHeader *>(P);
- P += sizeof(*Hdr);
- sprintf(Hdr->Name, "%-12s", "dummy");
- sprintf(Hdr->LastModified, "%-12d", 0);
- sprintf(Hdr->UID, "%-6d", 0);
- sprintf(Hdr->GID, "%-6d", 0);
- sprintf(Hdr->AccessMode, "%-8d", 0644);
- sprintf(Hdr->Size, "%-10d", int(sizeof(coff_import_header) + ImpSize));
-
- // 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 = (isData ? IMPORT_DATA : IMPORT_CODE);
- Imp->TypeInfo |= NameType << 2;
-
- // Write symbol name and DLL name.
- memcpy(P, Sym.data(), Sym.size());
- P += Sym.size() + 1;
- memcpy(P, DLLName.data(), DLLName.size());
-
- std::error_code EC;
- object::Archive::Child C(Parent, Buf, &EC);
- assert(!EC && "We created an invalid buffer");
- return NewArchiveIterator(C, DLLName);
- }
-
-private:
- BumpPtrAllocator Alloc;
- object::Archive *Parent;
- StringRef DLLName;
-};
-
-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);
- assert(Pos != StringRef::npos);
- return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
-}
-
-// 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 writeImportLibrary() {
- std::unique_ptr<MemoryBuffer> Buf = createEmptyImportLibrary();
- std::error_code EC;
- object::Archive Archive(Buf->getMemBufferRef(), EC);
- error(EC, "Error reading an empty import file");
- std::vector<NewArchiveIterator> Members = readMembers(Archive);
-
- std::string DLLName = llvm::sys::path::filename(Config->OutputFile);
- ShortImportCreator ShortImport(&Archive, DLLName);
- for (Export &E : Config->Exports) {
- if (E.Private)
- continue;
- if (E.ExtName.empty()) {
- Members.push_back(ShortImport.create(
- E.SymbolName, E.Ordinal, getNameType(E.SymbolName, E.Name), E.Data));
- } else {
- Members.push_back(ShortImport.create(
- replace(E.SymbolName, E.Name, E.ExtName), E.Ordinal,
- getNameType(E.SymbolName, E.Name), E.Data));
- }
- }
-
- std::string Path = getImplibPath();
- std::pair<StringRef, std::error_code> Result =
- writeArchive(Path, Members, /*WriteSymtab*/ true, object::Archive::K_GNU,
- /*Deterministic*/ true, /*Thin*/ false);
- error(Result.second, Twine("Failed to write ") + Path);
+ return check(MemoryBuffer::getFile(Path), "could not open " + Path);
}
// Create OptTable
@@ -695,7 +615,7 @@ llvm::opt::InputArgList ArgParser::parse(ArrayRef<const char *> ArgsArr) {
}
if (MissingCount)
- error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) +
+ fatal("missing arg value for \"" + Twine(Args.getArgString(MissingIndex)) +
"\", expected " + Twine(MissingCount) +
(MissingCount == 1 ? " argument." : " arguments."));
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
diff --git a/COFF/Error.cpp b/COFF/Error.cpp
index 255d9bbad9d8..602a8544ce2b 100644
--- a/COFF/Error.cpp
+++ b/COFF/Error.cpp
@@ -10,20 +10,23 @@
#include "Error.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/raw_ostream.h"
namespace lld {
namespace coff {
-void error(const Twine &Msg) {
+void fatal(const Twine &Msg) {
llvm::errs() << Msg << "\n";
exit(1);
}
-void error(std::error_code EC, const Twine &Prefix) {
- if (!EC)
- return;
- error(Prefix + ": " + EC.message());
+void fatal(std::error_code EC, const Twine &Msg) {
+ fatal(Msg + ": " + EC.message());
+}
+
+void fatal(llvm::Error &Err, const Twine &Msg) {
+ fatal(errorToErrorCode(std::move(Err)), Msg);
}
} // namespace coff
diff --git a/COFF/Error.h b/COFF/Error.h
index cb0a185f0917..c9f64c662580 100644
--- a/COFF/Error.h
+++ b/COFF/Error.h
@@ -11,15 +11,25 @@
#define LLD_COFF_ERROR_H
#include "lld/Core/LLVM.h"
+#include "llvm/Support/Error.h"
namespace lld {
namespace coff {
-LLVM_ATTRIBUTE_NORETURN void error(const Twine &Msg);
-void error(std::error_code EC, const Twine &Prefix);
+LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
+LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix);
+LLVM_ATTRIBUTE_NORETURN void fatal(llvm::Error &Err, const Twine &Prefix);
-template <typename T> void error(const ErrorOr<T> &V, const Twine &Prefix) {
- error(V.getError(), Prefix);
+template <class T> T check(ErrorOr<T> &&V, const Twine &Prefix) {
+ if (auto EC = V.getError())
+ fatal(EC, Prefix);
+ return std::move(*V);
+}
+
+template <class T> T check(Expected<T> E, const Twine &Prefix) {
+ if (llvm::Error Err = E.takeError())
+ fatal(Err, Prefix);
+ return std::move(*E);
}
} // namespace coff
diff --git a/COFF/ICF.cpp b/COFF/ICF.cpp
index f99b41624a84..a2c5a90334d0 100644
--- a/COFF/ICF.cpp
+++ b/COFF/ICF.cpp
@@ -70,7 +70,7 @@ private:
static bool equalsConstant(const SectionChunk *A, const SectionChunk *B);
static bool equalsVariable(const SectionChunk *A, const SectionChunk *B);
bool forEachGroup(std::vector<SectionChunk *> &Chunks, Comparator Eq);
- bool partition(ChunkIterator Begin, ChunkIterator End, Comparator Eq);
+ bool segregate(ChunkIterator Begin, ChunkIterator End, Comparator Eq);
std::atomic<uint64_t> NextID = { 1 };
};
@@ -148,7 +148,7 @@ bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) {
return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq);
}
-bool ICF::partition(ChunkIterator Begin, ChunkIterator End, Comparator Eq) {
+bool ICF::segregate(ChunkIterator Begin, ChunkIterator End, Comparator Eq) {
bool R = false;
for (auto It = Begin;;) {
SectionChunk *Head = *It;
@@ -171,7 +171,7 @@ bool ICF::forEachGroup(std::vector<SectionChunk *> &Chunks, Comparator Eq) {
auto Bound = std::find_if(It + 1, End, [&](SectionChunk *SC) {
return SC->GroupID != Head->GroupID;
});
- if (partition(It, Bound, Eq))
+ if (segregate(It, Bound, Eq))
R = true;
It = Bound;
}
diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp
index 23af1e89c34d..ff26826371fa 100644
--- a/COFF/InputFiles.cpp
+++ b/COFF/InputFiles.cpp
@@ -8,30 +8,41 @@
//===----------------------------------------------------------------------===//
#include "Chunks.h"
+#include "Config.h"
#include "Error.h"
#include "InputFiles.h"
#include "Symbols.h"
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/IR/LLVMContext.h"
-#include "llvm/LTO/LTOModule.h"
+#include "llvm/LTO/legacy/LTOModule.h"
+#include "llvm/Object/Binary.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/COFF.h"
-#include "llvm/Support/Debug.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/Endian.h"
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Target/TargetOptions.h"
+#include "llvm-c/lto.h"
+#include <cstring>
+#include <system_error>
+#include <utility>
using namespace llvm::COFF;
using namespace llvm::object;
using namespace llvm::support::endian;
+
using llvm::Triple;
using llvm::support::ulittle32_t;
-using llvm::sys::fs::file_magic;
-using llvm::sys::fs::identify_magic;
namespace lld {
namespace coff {
int InputFile::NextIndex = 0;
+llvm::LLVMContext BitcodeFile::Context;
// Returns the last element of a path, which is supposed to be a filename.
static StringRef getBasename(StringRef Path) {
@@ -52,9 +63,7 @@ std::string InputFile::getShortName() {
void ArchiveFile::parse() {
// Parse a MemoryBufferRef as an archive file.
- auto ArchiveOrErr = Archive::create(MB);
- error(ArchiveOrErr, "Failed to parse static library");
- File = std::move(*ArchiveOrErr);
+ File = check(Archive::create(MB), "failed to parse static library");
// Allocate a buffer for Lazy objects.
size_t NumSyms = File->getNumberOfSymbols();
@@ -67,40 +76,38 @@ void ArchiveFile::parse() {
// Seen is a map from member files to boolean values. Initially
// all members are mapped to false, which indicates all these files
// are not read yet.
- for (auto &ChildOrErr : File->children()) {
- error(ChildOrErr, "Failed to parse static library");
- const Archive::Child &Child = *ChildOrErr;
+ Error Err;
+ for (auto &Child : File->children(Err))
Seen[Child.getChildOffset()].clear();
- }
+ if (Err)
+ fatal(Err, "failed to parse static library");
}
// Returns a buffer pointing to a member file containing a given symbol.
// This function is thread-safe.
MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) {
- auto COrErr = Sym->getMember();
- error(COrErr, Twine("Could not get the member for symbol ") + Sym->getName());
- const Archive::Child &C = *COrErr;
+ const Archive::Child &C =
+ check(Sym->getMember(),
+ "could not get the member for symbol " + Sym->getName());
// Return an empty buffer if we have already returned the same buffer.
if (Seen[C.getChildOffset()].test_and_set())
return MemoryBufferRef();
- ErrorOr<MemoryBufferRef> Ret = C.getMemoryBufferRef();
- error(Ret, Twine("Could not get the buffer for the member defining symbol ") +
- Sym->getName());
- return *Ret;
+ return check(C.getMemoryBufferRef(),
+ "could not get the buffer for the member defining symbol " +
+ Sym->getName());
}
void ObjectFile::parse() {
// Parse a memory buffer as a COFF file.
- auto BinOrErr = createBinary(MB);
- error(BinOrErr, "Failed to parse object file");
- std::unique_ptr<Binary> Bin = std::move(*BinOrErr);
+ std::unique_ptr<Binary> Bin =
+ check(createBinary(MB), "failed to parse object file");
if (auto *Obj = dyn_cast<COFFObjectFile>(Bin.get())) {
Bin.release();
COFFObj.reset(Obj);
} else {
- error(Twine(getName()) + " is not a COFF file.");
+ fatal(getName() + " is not a COFF file");
}
// Read section and symbol tables.
@@ -116,10 +123,10 @@ void ObjectFile::initializeChunks() {
for (uint32_t I = 1; I < NumSections + 1; ++I) {
const coff_section *Sec;
StringRef Name;
- std::error_code EC = COFFObj->getSection(I, Sec);
- error(EC, Twine("getSection failed: #") + Twine(I));
- EC = COFFObj->getSectionName(Sec, Name);
- error(EC, Twine("getSectionName failed: #") + Twine(I));
+ if (auto EC = COFFObj->getSection(I, Sec))
+ fatal(EC, "getSection failed: #" + Twine(I));
+ if (auto EC = COFFObj->getSectionName(Sec, Name))
+ fatal(EC, "getSectionName failed: #" + Twine(I));
if (Name == ".sxdata") {
SXData = Sec;
continue;
@@ -149,14 +156,12 @@ void ObjectFile::initializeSymbols() {
uint32_t NumSymbols = COFFObj->getNumberOfSymbols();
SymbolBodies.reserve(NumSymbols);
SparseSymbolBodies.resize(NumSymbols);
- llvm::SmallVector<Undefined *, 8> WeakAliases;
+ llvm::SmallVector<std::pair<Undefined *, uint32_t>, 8> WeakAliases;
int32_t LastSectionNumber = 0;
for (uint32_t I = 0; I < NumSymbols; ++I) {
// Get a COFFSymbolRef object.
- auto SymOrErr = COFFObj->getSymbol(I);
- error(SymOrErr, Twine("broken object file: ") + getName());
-
- COFFSymbolRef Sym = *SymOrErr;
+ COFFSymbolRef Sym =
+ check(COFFObj->getSymbol(I), "broken object file: " + getName());
const void *AuxP = nullptr;
if (Sym.getNumberOfAuxSymbols())
@@ -167,8 +172,10 @@ void ObjectFile::initializeSymbols() {
if (Sym.isUndefined()) {
Body = createUndefined(Sym);
} else if (Sym.isWeakExternal()) {
- Body = createWeakExternal(Sym, AuxP);
- WeakAliases.push_back((Undefined *)Body);
+ Body = createUndefined(Sym);
+ uint32_t TagIndex =
+ static_cast<const coff_aux_weak_external *>(AuxP)->TagIndex;
+ WeakAliases.emplace_back((Undefined *)Body, TagIndex);
} else {
Body = createDefined(Sym, AuxP, IsFirst);
}
@@ -179,8 +186,8 @@ void ObjectFile::initializeSymbols() {
I += Sym.getNumberOfAuxSymbols();
LastSectionNumber = Sym.getSectionNumber();
}
- for (Undefined *U : WeakAliases)
- U->WeakAlias = SparseSymbolBodies[(uintptr_t)U->WeakAlias];
+ for (auto WeakAlias : WeakAliases)
+ WeakAlias.first->WeakAlias = SparseSymbolBodies[WeakAlias.second];
}
Undefined *ObjectFile::createUndefined(COFFSymbolRef Sym) {
@@ -189,15 +196,6 @@ Undefined *ObjectFile::createUndefined(COFFSymbolRef Sym) {
return new (Alloc) Undefined(Name);
}
-Undefined *ObjectFile::createWeakExternal(COFFSymbolRef Sym, const void *AuxP) {
- StringRef Name;
- COFFObj->getSymbolName(Sym, Name);
- auto *U = new (Alloc) Undefined(Name);
- auto *Aux = (const coff_aux_weak_external *)AuxP;
- U->WeakAlias = (Undefined *)(uintptr_t)Aux->TagIndex;
- return U;
-}
-
Defined *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
bool IsFirst) {
StringRef Name;
@@ -219,11 +217,21 @@ Defined *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
}
return new (Alloc) DefinedAbsolute(Name, Sym);
}
- if (Sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_DEBUG)
+ int32_t SectionNumber = Sym.getSectionNumber();
+ if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG)
return nullptr;
+ // Reserved sections numbers don't have contents.
+ if (llvm::COFF::isReservedSectionNumber(SectionNumber))
+ fatal("broken object file: " + getName());
+
+ // This symbol references a section which is not present in the section
+ // header.
+ if ((uint32_t)SectionNumber >= SparseChunks.size())
+ fatal("broken object file: " + getName());
+
// Nothing else to do without a section chunk.
- auto *SC = cast_or_null<SectionChunk>(SparseChunks[Sym.getSectionNumber()]);
+ auto *SC = cast_or_null<SectionChunk>(SparseChunks[SectionNumber]);
if (!SC)
return nullptr;
@@ -250,7 +258,7 @@ void ObjectFile::initializeSEH() {
ArrayRef<uint8_t> A;
COFFObj->getSectionContents(SXData, A);
if (A.size() % 4 != 0)
- error(".sxdata must be an array of symbol table indices");
+ fatal(".sxdata must be an array of symbol table indices");
auto *I = reinterpret_cast<const ulittle32_t *>(A.data());
auto *E = reinterpret_cast<const ulittle32_t *>(A.data() + A.size());
for (; I != E; ++I)
@@ -276,11 +284,11 @@ void ImportFile::parse() {
// Check if the total size is valid.
if ((size_t)(End - Buf) != (sizeof(*Hdr) + Hdr->SizeOfData))
- error("broken import library");
+ fatal("broken import library");
// Read names and create an __imp_ symbol.
StringRef Name = StringAlloc.save(StringRef(Buf + sizeof(*Hdr)));
- StringRef ImpName = StringAlloc.save(Twine("__imp_") + Name);
+ StringRef ImpName = StringAlloc.save("__imp_" + Name);
const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1;
DLLName = StringRef(NameStart);
StringRef ExtName;
@@ -315,11 +323,10 @@ void BitcodeFile::parse() {
// Usually parse() is thread-safe, but bitcode file is an exception.
std::lock_guard<std::mutex> Lock(Mu);
- ErrorOr<std::unique_ptr<LTOModule>> ModOrErr =
- LTOModule::createFromBuffer(llvm::getGlobalContext(), MB.getBufferStart(),
- MB.getBufferSize(), llvm::TargetOptions());
- error(ModOrErr, "Could not create lto module");
- M = std::move(*ModOrErr);
+ Context.enableDebugTypeODRUniquing();
+ ErrorOr<std::unique_ptr<LTOModule>> ModOrErr = LTOModule::createFromBuffer(
+ Context, MB.getBufferStart(), MB.getBufferSize(), llvm::TargetOptions());
+ M = check(std::move(ModOrErr), "could not create LTO module");
llvm::StringSaver Saver(Alloc);
for (unsigned I = 0, E = M->getSymbolCount(); I != E; ++I) {
diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h
index 6a263fbaddf6..0ec01b5075f9 100644
--- a/COFF/InputFiles.h
+++ b/COFF/InputFiles.h
@@ -12,7 +12,8 @@
#include "lld/Core/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/LTO/LTOModule.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/LTO/legacy/LTOModule.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/StringSaver.h"
@@ -103,7 +104,7 @@ public:
// All symbols returned by ArchiveFiles are of Lazy type.
std::vector<SymbolBody *> &getSymbols() override {
- llvm_unreachable("internal error");
+ llvm_unreachable("internal fatal");
}
private:
@@ -147,7 +148,6 @@ private:
Defined *createDefined(COFFSymbolRef Sym, const void *Aux, bool IsFirst);
Undefined *createUndefined(COFFSymbolRef Sym);
- Undefined *createWeakExternal(COFFSymbolRef Sym, const void *Aux);
std::unique_ptr<COFFObjectFile> COFFObj;
llvm::BumpPtrAllocator Alloc;
@@ -204,9 +204,10 @@ public:
static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
std::vector<SymbolBody *> &getSymbols() override { return SymbolBodies; }
MachineTypes getMachineType() override;
-
std::unique_ptr<LTOModule> takeModule() { return std::move(M); }
+ static llvm::LLVMContext Context;
+
private:
void parse() override;
diff --git a/COFF/Librarian.cpp b/COFF/Librarian.cpp
new file mode 100644
index 000000000000..25fb4a87b3eb
--- /dev/null
+++ b/COFF/Librarian.cpp
@@ -0,0 +1,489 @@
+//===- 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> 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);
+ assert(Pos != StringRef::npos);
+ 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,
+ ImportNameType NameType, bool isData);
+};
+}
+
+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;
+
+ // COFF Header
+ coff_file_header Header{
+ u16(Config->Machine), u16(NumberOfSections), u32(0),
+ u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
+ // .idata$5
+ sizeof(export_address_table_entry) +
+ // .idata$4
+ sizeof(export_address_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', '$', '5'},
+ u32(0),
+ u32(0),
+ u32(sizeof(export_address_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)},
+ {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
+ u32(0),
+ u32(0),
+ u32(sizeof(export_address_table_entry)),
+ u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
+ sizeof(export_address_table_entry)),
+ 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$5
+ static const export_address_table_entry ILT{u32(0)};
+ append(Buffer, ILT);
+
+ // .idata$4
+ static const export_address_table_entry IAT{u32(0)};
+ append(Buffer, IAT);
+
+ // 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,
+ ImportNameType NameType,
+ bool isData) {
+ 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 = (isData ? IMPORT_DATA : IMPORT_CODE);
+ Imp->TypeInfo |= NameType << 2;
+
+ // 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 = llvm::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;
+
+ ImportNameType Type = 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, Type, E.Data));
+ }
+
+ 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
index d117e961f89a..5e393f45d184 100644
--- a/COFF/ModuleDef.cpp
+++ b/COFF/ModuleDef.cpp
@@ -134,13 +134,13 @@ private:
void readAsInt(uint64_t *I) {
read();
if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
- error("integer expected");
+ fatal("integer expected");
}
void expect(Kind Expected, StringRef Msg) {
read();
if (Tok.K != Expected)
- error(Msg);
+ fatal(Msg);
}
void unget() { Stack.push_back(Tok); }
@@ -177,7 +177,7 @@ private:
parseVersion(&Config->MajorImageVersion, &Config->MinorImageVersion);
return;
default:
- error(Twine("unknown directive: ") + Tok.Value);
+ fatal("unknown directive: " + Tok.Value);
}
}
@@ -188,7 +188,7 @@ private:
if (Tok.K == Equal) {
read();
if (Tok.K != Identifier)
- error(Twine("identifier expected, but got ") + Tok.Value);
+ fatal("identifier expected, but got " + Tok.Value);
E.ExtName = E.Name;
E.Name = Tok.Value;
} else {
@@ -264,15 +264,15 @@ private:
void parseVersion(uint32_t *Major, uint32_t *Minor) {
read();
if (Tok.K != Identifier)
- error(Twine("identifier expected, but got ") + Tok.Value);
+ fatal("identifier expected, but got " + Tok.Value);
StringRef V1, V2;
std::tie(V1, V2) = Tok.Value.split('.');
if (V1.getAsInteger(10, *Major))
- error(Twine("integer expected, but got ") + Tok.Value);
+ fatal("integer expected, but got " + Tok.Value);
if (V2.empty())
*Minor = 0;
else if (V2.getAsInteger(10, *Minor))
- error(Twine("integer expected, but got ") + Tok.Value);
+ fatal("integer expected, but got " + Tok.Value);
}
Lexer Lex;
diff --git a/COFF/Options.td b/COFF/Options.td
index a21b8de76afb..e5c9c5b4635b 100644
--- a/COFF/Options.td
+++ b/COFF/Options.td
@@ -48,6 +48,7 @@ def manifestuac : P<"manifestuac", "User access control">;
def manifestfile : P<"manifestfile", "Manifest file path">;
def manifestdependency : P<"manifestdependency",
"Attributes for <dependency> in manifest file">;
+def manifestinput : P<"manifestinput", "Specify manifest file">;
// We cannot use multiclass P because class name "incl" is different
// from its command line option name. We do this because "include" is
@@ -110,6 +111,7 @@ def no_incremental : F<"incremental:no">;
def nologo : F<"nologo">;
def throwingnew : F<"throwingnew">;
def editandcontinue : F<"editandcontinue">;
+def fastfail : F<"fastfail">;
def delay : QF<"delay">;
def errorreport : QF<"errorreport">;
diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp
index 786d28798bab..7606ccc680d3 100644
--- a/COFF/PDB.cpp
+++ b/COFF/PDB.cpp
@@ -38,7 +38,8 @@ void lld::coff::createPDB(StringRef Path) {
size_t FileSize = PageSize * 3;
ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
FileOutputBuffer::create(Path, FileSize);
- error(BufferOrErr, Twine("failed to open ") + Path);
+ if (auto EC = BufferOrErr.getError())
+ fatal(EC, "failed to open " + Path);
std::unique_ptr<FileOutputBuffer> Buffer = std::move(*BufferOrErr);
// Write the file header.
diff --git a/COFF/README.md b/COFF/README.md
index c1be560f4405..f1bfc9c15263 100644
--- a/COFF/README.md
+++ b/COFF/README.md
@@ -1,265 +1 @@
-The PE/COFF Linker
-==================
-
-This directory contains a linker for Windows operating system.
-Because the fundamental design of this port is different from
-the other ports of LLD, this port is separated to this directory.
-
-The linker is command-line compatible with MSVC linker and is
-generally 2x faster than that. It can be used to link real-world
-programs such as LLD itself or Clang, or even web browsers which
-are probably the largest open-source programs for Windows.
-
-This document is also applicable to ELF linker because the linker
-shares the same design as this COFF linker.
-
-Overall Design
---------------
-
-This is a list of important data types in this linker.
-
-* SymbolBody
-
- SymbolBody is a class for symbols. They may be created for symbols
- in object files or in archive file headers. The linker may create
- them out of nothing.
-
- There are mainly three types of SymbolBodies: Defined, Undefined, or
- Lazy. Defined symbols are for all symbols that are considered as
- "resolved", including real defined symbols, COMDAT symbols, common
- symbols, absolute symbols, linker-created symbols, etc. Undefined
- symbols are for undefined symbols, which need to be replaced by
- Defined symbols by the resolver. Lazy symbols represent symbols we
- found in archive file headers -- which can turn into Defined symbols
- if we read archieve members, but we haven't done that yet.
-
-* Symbol
-
- Symbol is a pointer to a SymbolBody. There's only one Symbol for
- each unique symbol name (this uniqueness is guaranteed by the symbol
- table). Because SymbolBodies are created for each file
- independently, there can be many SymbolBodies for the same
- name. Thus, the relationship between Symbols and SymbolBodies is 1:N.
-
- The resolver keeps the Symbol's pointer to always point to the "best"
- SymbolBody. Pointer mutation is the resolve operation in this
- linker.
-
- SymbolBodies have pointers to their Symbols. That means you can
- always find the best SymbolBody from any SymbolBody by following
- pointers twice. This structure makes it very easy to find
- replacements for symbols. For example, if you have an Undefined
- SymbolBody, you can find a Defined SymbolBody for that symbol just
- by going to its Symbol and then to SymbolBody, assuming the resolver
- have successfully resolved all undefined symbols.
-
-* Chunk
-
- Chunk represents a chunk of data that will occupy space in an
- output. Each regular section becomes a chunk.
- Chunks created for common or BSS symbols are not backed by sections.
- The linker may create chunks out of nothing to append additional
- data to an output.
-
- Chunks know about their size, how to copy their data to mmap'ed
- outputs, and how to apply relocations to them. Specifically,
- section-based chunks know how to read relocation tables and how to
- apply them.
-
-* SymbolTable
-
- SymbolTable is basically a hash table from strings to Symbols, with
- a logic to resolve symbol conflicts. It resolves conflicts by symbol
- type. For example, if we add Undefined and Defined symbols, the
- symbol table will keep the latter. If we add Defined and Lazy
- symbols, it will keep the former. If we add Lazy and Undefined, it
- will keep the former, but it will also trigger the Lazy symbol to
- load the archive member to actually resolve the symbol.
-
-* OutputSection
-
- OutputSection is a container of Chunks. A Chunk belongs to at most
- one OutputSection.
-
-There are mainly three actors in this linker.
-
-* InputFile
-
- InputFile is a superclass of file readers. We have a different
- subclass for each input file type, such as regular object file,
- archive file, etc. They are responsible for creating and owning
- SymbolBodies and Chunks.
-
-* Writer
-
- The writer is responsible for writing file headers and Chunks to a
- file. It creates OutputSections, put all Chunks into them, assign
- unique, non-overlapping addresses and file offsets to them, and then
- write them down to a file.
-
-* Driver
-
- The linking process is drived by the driver. The driver
-
- - processes command line options,
- - creates a symbol table,
- - creates an InputFile for each input file and put all symbols in it
- into the symbol table,
- - checks if there's no remaining undefined symbols,
- - creates a writer,
- - and passes the symbol table to the writer to write the result to a
- file.
-
-Performance
------------
-
-It's generally 2x faster than MSVC link.exe. It takes 3.5 seconds to
-self-host on my Xeon 2580 machine. MSVC linker takes 7.0 seconds to
-link the same executable. The resulting output is 65MB.
-The old LLD is buggy that it produces 120MB executable for some reason,
-and it takes 30 seconds to do that.
-
-We believe the performance difference comes from simplification and
-optimizations we made to the new port. Notable differences are listed
-below.
-
-* Reduced number of relocation table reads
-
- In the old design, relocation tables are read from beginning to
- construct graphs because they consist of graph edges. In the new
- design, they are not read until we actually apply relocations.
-
- This simplification has two benefits. One is that we don't create
- additional objects for relocations but instead consume relocation
- tables directly. The other is that it reduces number of relocation
- entries we have to read, because we won't read relocations for
- dead-stripped COMDAT sections. Large C++ programs tend to consist of
- lots of COMDAT sections. In the old design, the time to process
- relocation table is linear to size of input. In this new model, it's
- linear to size of output.
-
-* Reduced number of symbol table lookup
-
- Symbol table lookup can be a heavy operation because number of
- symbols can be very large and each symbol name can be very long
- (think of C++ mangled symbols -- time to compute a hash value for a
- string is linear to the length.)
-
- We look up the symbol table exactly only once for each symbol in the
- new design. This is I believe the minimum possible number. This is
- achieved by the separation of Symbol and SymbolBody. Once you get a
- pointer to a Symbol by looking up the symbol table, you can always
- get the latest symbol resolution result by just dereferencing a
- pointer. (I'm not sure if the idea is new to the linker. At least,
- all other linkers I've investigated so far seem to look up hash
- tables or sets more than once for each new symbol, but I may be
- wrong.)
-
-* Reduced number of file visits
-
- The symbol table implements the Windows linker semantics. We treat
- the symbol table as a bucket of all known symbols, including symbols
- in archive file headers. We put all symbols into one bucket as we
- visit new files. That means we visit each file only once.
-
- This is different from the Unix linker semantics, in which we only
- keep undefined symbols and visit each file one by one until we
- resolve all undefined symbols. In the Unix model, we have to visit
- archive files many times if there are circular dependencies between
- archives.
-
-* Avoiding creating additional objects or copying data
-
- The data structures described in the previous section are all thin
- wrappers for classes that LLVM libObject provides. We avoid copying
- data from libObject's objects to our objects. We read much less data
- than before. For example, we don't read symbol values until we apply
- relocations because these values are not relevant to symbol
- resolution. Again, COMDAT symbols may be discarded during symbol
- resolution, so reading their attributes too early could result in a
- waste. We use underlying objects directly where doing so makes
- sense.
-
-Parallelism
------------
-
-The abovementioned data structures are also chosen with
-multi-threading in mind. It should relatively be easy to make the
-symbol table a concurrent hash map, so that we let multiple workers
-work on symbol table concurrently. Symbol resolution in this design is
-a single pointer mutation, which allows the resolver work concurrently
-in a lock-free manner using atomic pointer compare-and-swap.
-
-It should also be easy to apply relocations and write chunks concurrently.
-
-We created an experimental multi-threaded linker using the Microsoft
-ConcRT concurrency library, and it was able to link itself in 0.5
-seconds, so we think the design is promising.
-
-Link-Time Optimization
-----------------------
-
-LTO is implemented by handling LLVM bitcode files as object files.
-The linker resolves symbols in bitcode files normally. If all symbols
-are successfully resolved, it then calls an LLVM libLTO function
-with all bitcode files to convert them to one big regular COFF file.
-Finally, the linker replaces bitcode symbols with COFF symbols,
-so that we can link the input files as if they were in the native
-format from the beginning.
-
-The details are described in this document.
-http://llvm.org/docs/LinkTimeOptimization.html
-
-Glossary
---------
-
-* RVA
-
- Short for Relative Virtual Address.
-
- Windows executables or DLLs are not position-independent; they are
- linked against a fixed address called an image base. RVAs are
- offsets from an image base.
-
- Default image bases are 0x140000000 for executables and 0x18000000
- for DLLs. For example, when we are creating an executable, we assume
- that the executable will be loaded at address 0x140000000 by the
- loader, so we apply relocations accordingly. Result texts and data
- will contain raw absolute addresses.
-
-* VA
-
- Short for Virtual Address. Equivalent to RVA + image base. It is
- rarely used. We almost always use RVAs instead.
-
-* Base relocations
-
- Relocation information for the loader. If the loader decides to map
- an executable or a DLL to a different address than their image
- bases, it fixes up binaries using information contained in the base
- relocation table. A base relocation table consists of a list of
- locations containing addresses. The loader adds a difference between
- RVA and actual load address to all locations listed there.
-
- Note that this run-time relocation mechanism is much simpler than ELF.
- There's no PLT or GOT. Images are relocated as a whole just
- by shifting entire images in memory by some offsets. Although doing
- this breaks text sharing, I think this mechanism is not actually bad
- on today's computers.
-
-* ICF
-
- Short for Identical COMDAT Folding.
-
- ICF is an optimization to reduce output size by merging COMDAT sections
- by not only their names but by their contents. If two COMDAT sections
- happen to have the same metadata, actual contents and relocations,
- they are merged by ICF. It is known as an effective technique,
- and it usually reduces C++ program's size by a few percent or more.
-
- Note that this is not entirely sound optimization. C/C++ require
- different functions have different addresses. If a program depends on
- that property, it would fail at runtime. However, that's not really an
- issue on Windows because MSVC link.exe enabled the optimization by
- default. As long as your program works with the linker's default
- settings, your program should be safe with ICF.
+See docs/NewLLD.rst
diff --git a/COFF/SymbolTable.cpp b/COFF/SymbolTable.cpp
index 5b7b89cd360a..df9da4c36650 100644
--- a/COFF/SymbolTable.cpp
+++ b/COFF/SymbolTable.cpp
@@ -14,7 +14,7 @@
#include "Symbols.h"
#include "lld/Core/Parallel.h"
#include "llvm/IR/LLVMContext.h"
-#include "llvm/LTO/LTOCodeGenerator.h"
+#include "llvm/LTO/legacy/LTOCodeGenerator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <utility>
@@ -164,7 +164,7 @@ void SymbolTable::reportRemainingUndefines(bool Resolve) {
llvm::errs() << File->getShortName() << ": undefined symbol: "
<< Sym->getName() << "\n";
if (!Config->Force)
- error("Link failed");
+ fatal("link failed");
}
void SymbolTable::addLazy(Lazy *New, std::vector<Symbol *> *Accum) {
@@ -211,7 +211,7 @@ void SymbolTable::addSymbol(SymbolBody *New) {
// equivalent (conflicting), or more preferable, respectively.
int Comp = Existing->compare(New);
if (Comp == 0)
- error(Twine("duplicate symbol: ") + Existing->getDebugName() + " and " +
+ fatal("duplicate symbol: " + Existing->getDebugName() + " and " +
New->getDebugName());
if (Comp < 0)
Sym->Body = New;
@@ -338,21 +338,25 @@ void SymbolTable::addCombinedLTOObject(ObjectFile *Obj) {
// diagnose them later in reportRemainingUndefines().
StringRef Name = Body->getName();
Symbol *Sym = insert(Body);
+ SymbolBody *Existing = Sym->Body;
+
+ if (Existing == Body)
+ continue;
- if (isa<DefinedBitcode>(Sym->Body)) {
+ if (isa<DefinedBitcode>(Existing)) {
Sym->Body = Body;
continue;
}
- if (auto *L = dyn_cast<Lazy>(Sym->Body)) {
+ if (auto *L = dyn_cast<Lazy>(Existing)) {
// We may see new references to runtime library symbols such as __chkstk
// here. These symbols must be wholly defined in non-bitcode files.
addMemberFile(L);
continue;
}
- SymbolBody *Existing = Sym->Body;
+
int Comp = Existing->compare(Body);
if (Comp == 0)
- error(Twine("LTO: unexpected duplicate symbol: ") + Name);
+ fatal("LTO: unexpected duplicate symbol: " + Name);
if (Comp < 0)
Sym->Body = Body;
}
@@ -369,7 +373,7 @@ void SymbolTable::addCombinedLTOObjects() {
// Create an object file and add it to the symbol table by replacing any
// DefinedBitcode symbols with the definitions in the object file.
- LTOCodeGenerator CG(getGlobalContext());
+ LTOCodeGenerator CG(BitcodeFile::Context);
CG.setOptLevel(Config->LTOOptLevel);
std::vector<ObjectFile *> Objs = createLTOObjects(&CG);
@@ -379,7 +383,7 @@ void SymbolTable::addCombinedLTOObjects() {
size_t NumBitcodeFiles = BitcodeFiles.size();
run();
if (BitcodeFiles.size() != NumBitcodeFiles)
- error("LTO: late loaded symbol created new bitcode reference");
+ fatal("LTO: late loaded symbol created new bitcode reference");
}
// Combine and compile bitcode files and then return the result
@@ -414,24 +418,23 @@ std::vector<ObjectFile *> SymbolTable::createLTOObjects(LTOCodeGenerator *CG) {
DisableVerify = false;
#endif
if (!CG->optimize(DisableVerify, false, false, false))
- error(""); // optimize() should have emitted any error message.
+ fatal(""); // optimize() should have emitted any error message.
Objs.resize(Config->LTOJobs);
// Use std::list to avoid invalidation of pointers in OSPtrs.
std::list<raw_svector_ostream> OSs;
std::vector<raw_pwrite_stream *> OSPtrs;
- for (SmallVector<char, 0> &Obj : Objs) {
+ for (SmallString<0> &Obj : Objs) {
OSs.emplace_back(Obj);
OSPtrs.push_back(&OSs.back());
}
if (!CG->compileOptimized(OSPtrs))
- error(""); // compileOptimized() should have emitted any error message.
+ fatal(""); // compileOptimized() should have emitted any error message.
std::vector<ObjectFile *> ObjFiles;
- for (SmallVector<char, 0> &Obj : Objs) {
- auto *ObjFile = new ObjectFile(
- MemoryBufferRef(StringRef(Obj.data(), Obj.size()), "<LTO object>"));
+ for (SmallString<0> &Obj : Objs) {
+ auto *ObjFile = new ObjectFile(MemoryBufferRef(Obj, "<LTO object>"));
Files.emplace_back(ObjFile);
ObjectFiles.push_back(ObjFile);
ObjFile->parse();
diff --git a/COFF/SymbolTable.h b/COFF/SymbolTable.h
index ce305bfa8743..8bf4387cdfff 100644
--- a/COFF/SymbolTable.h
+++ b/COFF/SymbolTable.h
@@ -115,7 +115,7 @@ private:
std::vector<std::future<InputFile *>> ObjectQueue;
std::vector<BitcodeFile *> BitcodeFiles;
- std::vector<SmallVector<char, 0>> Objs;
+ std::vector<SmallString<0>> Objs;
llvm::BumpPtrAllocator Alloc;
};
diff --git a/COFF/Symbols.cpp b/COFF/Symbols.cpp
index d732d76cfb06..6e2db6631ce7 100644
--- a/COFF/Symbols.cpp
+++ b/COFF/Symbols.cpp
@@ -162,32 +162,6 @@ std::string SymbolBody::getDebugName() {
return N;
}
-uint64_t Defined::getFileOff() {
- switch (kind()) {
- case DefinedImportDataKind:
- return cast<DefinedImportData>(this)->getFileOff();
- case DefinedImportThunkKind:
- return cast<DefinedImportThunk>(this)->getFileOff();
- case DefinedLocalImportKind:
- return cast<DefinedLocalImport>(this)->getFileOff();
- case DefinedCommonKind:
- return cast<DefinedCommon>(this)->getFileOff();
- case DefinedRegularKind:
- return cast<DefinedRegular>(this)->getFileOff();
-
- case DefinedBitcodeKind:
- llvm_unreachable("There is no file offset for a bitcode symbol.");
- case DefinedAbsoluteKind:
- llvm_unreachable("Cannot get a file offset for an absolute symbol.");
- case DefinedRelativeKind:
- llvm_unreachable("Cannot get a file offset for a relative symbol.");
- case LazyKind:
- case UndefinedKind:
- llvm_unreachable("Cannot get a file offset for an undefined symbol.");
- }
- llvm_unreachable("unknown symbol kind");
-}
-
COFFSymbolRef DefinedCOFF::getCOFFSymbol() {
size_t SymSize = File->getCOFFObj()->getSymbolTableEntrySize();
if (SymSize == sizeof(coff_symbol16))
@@ -225,7 +199,7 @@ std::unique_ptr<InputFile> Lazy::getMember() {
else if (Magic == file_magic::bitcode)
Obj.reset(new BitcodeFile(MBRef));
else
- error(Twine(File->getName()) + ": unknown file type");
+ fatal("unknown file type: " + File->getName());
Obj->setParentName(File->getName());
return Obj;
diff --git a/COFF/Symbols.h b/COFF/Symbols.h
index 7059fbc8bb15..f96c1fb3cc1d 100644
--- a/COFF/Symbols.h
+++ b/COFF/Symbols.h
@@ -125,10 +125,6 @@ public:
// writer sets and uses RVAs.
uint64_t getRVA();
- // Returns the file offset of this symbol in the final executable.
- // The writer uses this information to apply relocations.
- uint64_t getFileOff();
-
// Returns the RVA relative to the beginning of the output section.
// Used to implement SECREL relocation type.
uint64_t getSecrel();
diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp
index 5575c8d6b320..d8077df95701 100644
--- a/COFF/Writer.cpp
+++ b/COFF/Writer.cpp
@@ -59,6 +59,7 @@ private:
void openFile(StringRef OutputPath);
template <typename PEHeaderTy> void writeHeader();
void fixSafeSEHSymbols();
+ void setSectionPermissions();
void writeSections();
void sortExceptionTable();
void applyRelocations();
@@ -114,6 +115,7 @@ public:
StringRef getName() { return Name; }
std::vector<Chunk *> &getChunks() { return Chunks; }
void addPermissions(uint32_t C);
+ void setPermissions(uint32_t C);
uint32_t getPermissions() { return Header.Characteristics & PermMask; }
uint32_t getCharacteristics() { return Header.Characteristics; }
uint64_t getRVA() { return Header.VirtualAddress; }
@@ -163,19 +165,23 @@ void OutputSection::addChunk(Chunk *C) {
Chunks.push_back(C);
C->setOutputSection(this);
uint64_t Off = Header.VirtualSize;
- Off = align(Off, C->getAlign());
+ Off = alignTo(Off, C->getAlign());
C->setRVA(Off);
C->setOutputSectionOff(Off);
Off += C->getSize();
Header.VirtualSize = Off;
if (C->hasData())
- Header.SizeOfRawData = align(Off, SectorSize);
+ Header.SizeOfRawData = alignTo(Off, SectorSize);
}
void OutputSection::addPermissions(uint32_t C) {
Header.Characteristics |= C & PermMask;
}
+void OutputSection::setPermissions(uint32_t C) {
+ Header.Characteristics = C & PermMask;
+}
+
// Write the section header to a given buffer.
void OutputSection::writeHeaderTo(uint8_t *Buf) {
auto *Hdr = reinterpret_cast<coff_section *>(Buf);
@@ -193,13 +199,13 @@ void OutputSection::writeHeaderTo(uint8_t *Buf) {
uint64_t Defined::getSecrel() {
if (auto *D = dyn_cast<DefinedRegular>(this))
return getRVA() - D->getChunk()->getOutputSection()->getRVA();
- error("SECREL relocation points to a non-regular symbol");
+ fatal("SECREL relocation points to a non-regular symbol");
}
uint64_t Defined::getSectionIndex() {
if (auto *D = dyn_cast<DefinedRegular>(this))
return D->getChunk()->getOutputSection()->SectionIndex;
- error("SECTION relocation points to a non-regular symbol");
+ fatal("SECTION relocation points to a non-regular symbol");
}
bool Defined::isExecutable() {
@@ -222,6 +228,7 @@ void Writer::run() {
createSection(".reloc");
assignAddresses();
removeEmptySections();
+ setSectionPermissions();
createSymbolAndStringTable();
openFile(Config->OutputFile);
if (Config->is64()) {
@@ -232,7 +239,8 @@ void Writer::run() {
fixSafeSEHSymbols();
writeSections();
sortExceptionTable();
- error(Buffer->commit(), "Failed to write the output file");
+ if (auto EC = Buffer->commit())
+ fatal(EC, "failed to write the output file");
}
static StringRef getOutputSection(StringRef Name) {
@@ -447,15 +455,15 @@ void Writer::createSymbolAndStringTable() {
OutputSection *LastSection = OutputSections.back();
// We position the symbol table to be adjacent to the end of the last section.
- uint64_t FileOff =
- LastSection->getFileOff() + align(LastSection->getRawSize(), SectorSize);
+ uint64_t FileOff = LastSection->getFileOff() +
+ alignTo(LastSection->getRawSize(), SectorSize);
if (!OutputSymtab.empty()) {
PointerToSymbolTable = FileOff;
FileOff += OutputSymtab.size() * sizeof(coff_symbol16);
}
if (!Strtab.empty())
FileOff += Strtab.size() + 4;
- FileSize = align(FileOff, SectorSize);
+ FileSize = alignTo(FileOff, SectorSize);
}
// Visits all sections to assign incremental, non-overlapping RVAs and
@@ -466,7 +474,7 @@ void Writer::assignAddresses() {
sizeof(coff_section) * OutputSections.size();
SizeOfHeaders +=
Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header);
- SizeOfHeaders = align(SizeOfHeaders, SectorSize);
+ SizeOfHeaders = alignTo(SizeOfHeaders, SectorSize);
uint64_t RVA = 0x1000; // The first page is kept unmapped.
FileSize = SizeOfHeaders;
// Move DISCARDABLE (or non-memory-mapped) sections to the end of file because
@@ -480,10 +488,10 @@ void Writer::assignAddresses() {
addBaserels(Sec);
Sec->setRVA(RVA);
Sec->setFileOffset(FileSize);
- RVA += align(Sec->getVirtualSize(), PageSize);
- FileSize += align(Sec->getRawSize(), SectorSize);
+ RVA += alignTo(Sec->getVirtualSize(), PageSize);
+ FileSize += alignTo(Sec->getRawSize(), SectorSize);
}
- SizeOfImage = SizeOfHeaders + align(RVA - 0x1000, PageSize);
+ SizeOfImage = SizeOfHeaders + alignTo(RVA - 0x1000, PageSize);
}
template <typename PEHeaderTy> void Writer::writeHeader() {
@@ -596,13 +604,26 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) {
if (Defined *B = dyn_cast<Defined>(Sym->Body)) {
Dir[TLS_TABLE].RelativeVirtualAddress = B->getRVA();
- Dir[TLS_TABLE].Size = 40;
+ Dir[TLS_TABLE].Size = Config->is64()
+ ? sizeof(object::coff_tls_directory64)
+ : sizeof(object::coff_tls_directory32);
}
}
if (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) {
- if (Defined *B = dyn_cast<Defined>(Sym->Body)) {
+ if (auto *B = dyn_cast<DefinedRegular>(Sym->Body)) {
+ SectionChunk *SC = B->getChunk();
+ assert(B->getRVA() >= SC->getRVA());
+ uint64_t OffsetInChunk = B->getRVA() - SC->getRVA();
+ if (!SC->hasData() || OffsetInChunk + 4 > SC->getSize())
+ fatal("_load_config_used is malformed");
+
+ ArrayRef<uint8_t> SecContents = SC->getContents();
+ uint32_t LoadConfigSize =
+ *reinterpret_cast<const ulittle32_t *>(&SecContents[OffsetInChunk]);
+ if (OffsetInChunk + LoadConfigSize > SC->getSize())
+ fatal("_load_config_used is too large");
Dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = B->getRVA();
- Dir[LOAD_CONFIG_TABLE].Size = Config->is64() ? 112 : 64;
+ Dir[LOAD_CONFIG_TABLE].Size = LoadConfigSize;
}
}
@@ -626,14 +647,14 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
// The first 4 bytes is length including itself.
Buf = reinterpret_cast<uint8_t *>(&SymbolTable[NumberOfSymbols]);
write32le(Buf, Strtab.size() + 4);
- memcpy(Buf + 4, Strtab.data(), Strtab.size());
+ if (!Strtab.empty())
+ memcpy(Buf + 4, Strtab.data(), Strtab.size());
}
void Writer::openFile(StringRef Path) {
- ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
- FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable);
- error(BufferOrErr, Twine("failed to open ") + Path);
- Buffer = std::move(*BufferOrErr);
+ Buffer = check(
+ FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable),
+ "failed to open " + Path);
}
void Writer::fixSafeSEHSymbols() {
@@ -643,6 +664,17 @@ void Writer::fixSafeSEHSymbols() {
Config->SEHCount->setVA(SEHTable->getSize() / 4);
}
+// Handles /section options to allow users to overwrite
+// section attributes.
+void Writer::setSectionPermissions() {
+ for (auto &P : Config->Section) {
+ StringRef Name = P.first;
+ uint32_t Perm = P.second;
+ if (auto *Sec = findSection(Name))
+ Sec->setPermissions(Perm);
+ }
+}
+
// Write section contents to a mmap'ed file.
void Writer::writeSections() {
uint8_t *Buf = Buffer->getBufferStart();