aboutsummaryrefslogtreecommitdiffstats
path: root/COFF
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-12-30 11:57:38 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-12-30 11:57:38 +0000
commit5a5c549fe9a3fef595297bd21d36bed8409dc37d (patch)
treea964c8f5ac85b7b641cac022c5f9bf4eed3d2b9b /COFF
parentfb911942f1434f3d1750f83f25f5e42c80e60638 (diff)
downloadsrc-5a5c549fe9a3fef595297bd21d36bed8409dc37d.tar.gz
src-5a5c549fe9a3fef595297bd21d36bed8409dc37d.zip
Vendor import of lld trunk r256633:vendor/lld/lld-trunk-r256633
Notes
Notes: svn path=/vendor/lld/dist/; revision=292934 svn path=/vendor/lld/lld-trunk-r256633/; revision=292935; tag=vendor/lld/lld-trunk-r256633
Diffstat (limited to 'COFF')
-rw-r--r--COFF/CMakeLists.txt33
-rw-r--r--COFF/Chunks.cpp340
-rw-r--r--COFF/Chunks.h332
-rw-r--r--COFF/Config.h140
-rw-r--r--COFF/DLL.cpp556
-rw-r--r--COFF/DLL.h84
-rw-r--r--COFF/Driver.cpp677
-rw-r--r--COFF/Driver.h180
-rw-r--r--COFF/DriverUtils.cpp718
-rw-r--r--COFF/Error.cpp30
-rw-r--r--COFF/Error.h28
-rw-r--r--COFF/ICF.cpp244
-rw-r--r--COFF/InputFiles.cpp367
-rw-r--r--COFF/InputFiles.h222
-rw-r--r--COFF/MarkLive.cpp61
-rw-r--r--COFF/ModuleDef.cpp291
-rw-r--r--COFF/Options.td125
-rw-r--r--COFF/PDB.cpp60
-rw-r--r--COFF/README.md265
-rw-r--r--COFF/SymbolTable.cpp445
-rw-r--r--COFF/SymbolTable.h125
-rw-r--r--COFF/Symbols.cpp243
-rw-r--r--COFF/Symbols.h407
-rw-r--r--COFF/Writer.cpp765
-rw-r--r--COFF/Writer.h26
25 files changed, 6764 insertions, 0 deletions
diff --git a/COFF/CMakeLists.txt b/COFF/CMakeLists.txt
new file mode 100644
index 000000000000..78dc34eff96e
--- /dev/null
+++ b/COFF/CMakeLists.txt
@@ -0,0 +1,33 @@
+set(LLVM_TARGET_DEFINITIONS Options.td)
+tablegen(LLVM Options.inc -gen-opt-parser-defs)
+add_public_tablegen_target(COFFOptionsTableGen)
+
+add_llvm_library(lldCOFF
+ Chunks.cpp
+ DLL.cpp
+ Driver.cpp
+ DriverUtils.cpp
+ Error.cpp
+ ICF.cpp
+ InputFiles.cpp
+ MarkLive.cpp
+ ModuleDef.cpp
+ PDB.cpp
+ SymbolTable.cpp
+ Symbols.cpp
+ Writer.cpp
+
+ LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ Core
+ LTO
+ LibDriver
+ Object
+ MC
+ MCDisassembler
+ Target
+ Option
+ Support
+ )
+
+add_dependencies(lldCOFF COFFOptionsTableGen)
diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp
new file mode 100644
index 000000000000..50bf55be269b
--- /dev/null
+++ b/COFF/Chunks.cpp
@@ -0,0 +1,340 @@
+//===- Chunks.cpp ---------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Chunks.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/COFF.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::COFF;
+using llvm::support::ulittle32_t;
+
+namespace lld {
+namespace coff {
+
+SectionChunk::SectionChunk(ObjectFile *F, const coff_section *H)
+ : Chunk(SectionKind), Repl(this), File(F), Header(H),
+ Relocs(File->getCOFFObj()->getRelocations(Header)),
+ NumRelocs(std::distance(Relocs.begin(), Relocs.end())) {
+ // 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);
+
+ // Only COMDAT sections are subject of dead-stripping.
+ Live = !isCOMDAT();
+}
+
+static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); }
+static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
+static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); }
+static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); }
+
+void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym,
+ uint64_t P) const {
+ uint64_t S = Sym->getRVA();
+ switch (Type) {
+ case IMAGE_REL_AMD64_ADDR32: add32(Off, S + Config->ImageBase); break;
+ case IMAGE_REL_AMD64_ADDR64: add64(Off, S + Config->ImageBase); break;
+ case IMAGE_REL_AMD64_ADDR32NB: add32(Off, S); break;
+ case IMAGE_REL_AMD64_REL32: add32(Off, S - P - 4); break;
+ case IMAGE_REL_AMD64_REL32_1: add32(Off, S - P - 5); break;
+ case IMAGE_REL_AMD64_REL32_2: add32(Off, S - P - 6); break;
+ case IMAGE_REL_AMD64_REL32_3: add32(Off, S - P - 7); break;
+ case IMAGE_REL_AMD64_REL32_4: add32(Off, S - P - 8); break;
+ case IMAGE_REL_AMD64_REL32_5: add32(Off, S - P - 9); break;
+ 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");
+ }
+}
+
+void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym,
+ uint64_t P) const {
+ uint64_t S = Sym->getRVA();
+ switch (Type) {
+ case IMAGE_REL_I386_ABSOLUTE: break;
+ case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break;
+ case IMAGE_REL_I386_DIR32NB: add32(Off, S); break;
+ case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break;
+ 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");
+ }
+}
+
+static void applyMOV(uint8_t *Off, uint16_t V) {
+ or16(Off, ((V & 0x800) >> 1) | ((V >> 12) & 0xf));
+ or16(Off + 2, ((V & 0x700) << 4) | (V & 0xff));
+}
+
+static void applyMOV32T(uint8_t *Off, uint32_t V) {
+ applyMOV(Off, V); // set MOVW operand
+ applyMOV(Off + 4, V >> 16); // set MOVT operand
+}
+
+static void applyBranch20T(uint8_t *Off, int32_t V) {
+ uint32_t S = V < 0 ? 1 : 0;
+ uint32_t J1 = (V >> 19) & 1;
+ uint32_t J2 = (V >> 18) & 1;
+ or16(Off, (S << 10) | ((V >> 12) & 0x3f));
+ or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff));
+}
+
+static void applyBranch24T(uint8_t *Off, int32_t V) {
+ uint32_t S = V < 0 ? 1 : 0;
+ uint32_t J1 = ((~V >> 23) & 1) ^ S;
+ uint32_t J2 = ((~V >> 22) & 1) ^ S;
+ or16(Off, (S << 10) | ((V >> 12) & 0x3ff));
+ or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff));
+}
+
+void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym,
+ uint64_t P) const {
+ uint64_t S = Sym->getRVA();
+ // Pointer to thumb code must have the LSB set.
+ if (Sym->isExecutable())
+ S |= 1;
+ switch (Type) {
+ case IMAGE_REL_ARM_ADDR32: add32(Off, S + Config->ImageBase); break;
+ case IMAGE_REL_ARM_ADDR32NB: add32(Off, S); break;
+ case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, S + Config->ImageBase); break;
+ case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, S - P - 4); break;
+ 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");
+ }
+}
+
+void SectionChunk::writeTo(uint8_t *Buf) const {
+ if (!hasData())
+ return;
+ // Copy section contents from source object file to output file.
+ ArrayRef<uint8_t> A = getContents();
+ memcpy(Buf + OutputSectionOff, A.data(), A.size());
+
+ // Apply relocations.
+ for (const coff_relocation &Rel : Relocs) {
+ uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress;
+ SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex)->repl();
+ Defined *Sym = cast<Defined>(Body);
+ uint64_t P = RVA + Rel.VirtualAddress;
+ switch (Config->Machine) {
+ case AMD64:
+ applyRelX64(Off, Rel.Type, Sym, P);
+ break;
+ case I386:
+ applyRelX86(Off, Rel.Type, Sym, P);
+ break;
+ case ARMNT:
+ applyRelARM(Off, Rel.Type, Sym, P);
+ break;
+ default:
+ llvm_unreachable("unknown machine type");
+ }
+ }
+}
+
+void SectionChunk::addAssociative(SectionChunk *Child) {
+ AssocChildren.push_back(Child);
+}
+
+static uint8_t getBaserelType(const coff_relocation &Rel) {
+ switch (Config->Machine) {
+ case AMD64:
+ if (Rel.Type == IMAGE_REL_AMD64_ADDR64)
+ return IMAGE_REL_BASED_DIR64;
+ return IMAGE_REL_BASED_ABSOLUTE;
+ case I386:
+ if (Rel.Type == IMAGE_REL_I386_DIR32)
+ return IMAGE_REL_BASED_HIGHLOW;
+ return IMAGE_REL_BASED_ABSOLUTE;
+ case ARMNT:
+ if (Rel.Type == IMAGE_REL_ARM_ADDR32)
+ return IMAGE_REL_BASED_HIGHLOW;
+ if (Rel.Type == IMAGE_REL_ARM_MOV32T)
+ return IMAGE_REL_BASED_ARM_MOV32T;
+ return IMAGE_REL_BASED_ABSOLUTE;
+ default:
+ llvm_unreachable("unknown machine type");
+ }
+}
+
+// Windows-specific.
+// Collect all locations that contain absolute addresses, which need to be
+// fixed by the loader if load-time relocation is needed.
+// Only called when base relocation is enabled.
+void SectionChunk::getBaserels(std::vector<Baserel> *Res) {
+ for (const coff_relocation &Rel : Relocs) {
+ uint8_t Ty = getBaserelType(Rel);
+ if (Ty == IMAGE_REL_BASED_ABSOLUTE)
+ continue;
+ SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex)->repl();
+ if (isa<DefinedAbsolute>(Body))
+ continue;
+ Res->emplace_back(RVA + Rel.VirtualAddress, Ty);
+ }
+}
+
+bool SectionChunk::hasData() const {
+ return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA);
+}
+
+uint32_t SectionChunk::getPermissions() const {
+ return Header->Characteristics & PermMask;
+}
+
+bool SectionChunk::isCOMDAT() const {
+ return Header->Characteristics & IMAGE_SCN_LNK_COMDAT;
+}
+
+void SectionChunk::printDiscardedMessage() const {
+ // Removed by dead-stripping. If it's removed by ICF, ICF already
+ // printed out the name, so don't repeat that here.
+ if (Sym && this == Repl)
+ llvm::outs() << "Discarded " << Sym->getName() << "\n";
+}
+
+StringRef SectionChunk::getDebugName() {
+ if (Sym)
+ return Sym->getName();
+ return "";
+}
+
+ArrayRef<uint8_t> SectionChunk::getContents() const {
+ ArrayRef<uint8_t> A;
+ File->getCOFFObj()->getSectionContents(Header, A);
+ return A;
+}
+
+void SectionChunk::replace(SectionChunk *Other) {
+ Other->Repl = Repl;
+ Other->Live = false;
+}
+
+CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) {
+ // Common symbols are aligned on natural boundaries up to 32 bytes.
+ // This is what MSVC link.exe does.
+ Align = std::min(uint64_t(32), NextPowerOf2(Sym.getValue()));
+}
+
+uint32_t CommonChunk::getPermissions() const {
+ return IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ |
+ IMAGE_SCN_MEM_WRITE;
+}
+
+void StringChunk::writeTo(uint8_t *Buf) const {
+ memcpy(Buf + OutputSectionOff, Str.data(), Str.size());
+}
+
+ImportThunkChunkX64::ImportThunkChunkX64(Defined *S) : ImpSymbol(S) {
+ // Intel Optimization Manual says that all branch targets
+ // should be 16-byte aligned. MSVC linker does this too.
+ Align = 16;
+}
+
+void ImportThunkChunkX64::writeTo(uint8_t *Buf) const {
+ memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86));
+ // The first two bytes is a JMP instruction. Fill its operand.
+ write32le(Buf + OutputSectionOff + 2, ImpSymbol->getRVA() - RVA - getSize());
+}
+
+void ImportThunkChunkX86::getBaserels(std::vector<Baserel> *Res) {
+ Res->emplace_back(getRVA() + 2);
+}
+
+void ImportThunkChunkX86::writeTo(uint8_t *Buf) const {
+ memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86));
+ // The first two bytes is a JMP instruction. Fill its operand.
+ write32le(Buf + OutputSectionOff + 2,
+ ImpSymbol->getRVA() + Config->ImageBase);
+}
+
+void ImportThunkChunkARM::getBaserels(std::vector<Baserel> *Res) {
+ Res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T);
+}
+
+void ImportThunkChunkARM::writeTo(uint8_t *Buf) const {
+ memcpy(Buf + OutputSectionOff, ImportThunkARM, sizeof(ImportThunkARM));
+ // Fix mov.w and mov.t operands.
+ applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase);
+}
+
+void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) {
+ Res->emplace_back(getRVA());
+}
+
+size_t LocalImportChunk::getSize() const {
+ return Config->is64() ? 8 : 4;
+}
+
+void LocalImportChunk::writeTo(uint8_t *Buf) const {
+ if (Config->is64()) {
+ write64le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase);
+ } else {
+ write32le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase);
+ }
+}
+
+void SEHTableChunk::writeTo(uint8_t *Buf) const {
+ ulittle32_t *Begin = reinterpret_cast<ulittle32_t *>(Buf + OutputSectionOff);
+ size_t Cnt = 0;
+ for (Defined *D : Syms)
+ Begin[Cnt++] = D->getRVA();
+ std::sort(Begin, Begin + Cnt);
+}
+
+// Windows-specific.
+// This class represents a block in .reloc section.
+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(RoundUpToAlignment((End - Begin) * 2 + 8, 4));
+ uint8_t *P = Data.data();
+ write32le(P, Page);
+ write32le(P + 4, Data.size());
+ P += 8;
+ for (Baserel *I = Begin; I != End; ++I) {
+ write16le(P, (I->Type << 12) | (I->RVA - Page));
+ P += 2;
+ }
+}
+
+void BaserelChunk::writeTo(uint8_t *Buf) const {
+ memcpy(Buf + OutputSectionOff, Data.data(), Data.size());
+}
+
+uint8_t Baserel::getDefaultType() {
+ switch (Config->Machine) {
+ case AMD64:
+ return IMAGE_REL_BASED_DIR64;
+ case I386:
+ return IMAGE_REL_BASED_HIGHLOW;
+ default:
+ llvm_unreachable("unknown machine type");
+ }
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/Chunks.h b/COFF/Chunks.h
new file mode 100644
index 000000000000..60b8e76f8230
--- /dev/null
+++ b/COFF/Chunks.h
@@ -0,0 +1,332 @@
+//===- Chunks.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_CHUNKS_H
+#define LLD_COFF_CHUNKS_H
+
+#include "Config.h"
+#include "InputFiles.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Object/COFF.h"
+#include <atomic>
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+using llvm::COFF::ImportDirectoryTableEntry;
+using llvm::object::COFFSymbolRef;
+using llvm::object::SectionRef;
+using llvm::object::coff_relocation;
+using llvm::object::coff_section;
+using llvm::sys::fs::file_magic;
+
+class Baserel;
+class Defined;
+class DefinedImportData;
+class DefinedRegular;
+class ObjectFile;
+class OutputSection;
+class SymbolBody;
+
+// Mask for section types (code, data, bss, disacardable, etc.)
+// and permissions (writable, readable or executable).
+const uint32_t PermMask = 0xFF0000F0;
+
+// A Chunk represents a chunk of data that will occupy space in the
+// output (if the resolver chose that). It may or may not be backed by
+// a section of an input file. It could be linker-created data, or
+// doesn't even have actual data (if common or bss).
+class Chunk {
+public:
+ enum Kind { SectionKind, OtherKind };
+ Kind kind() const { return ChunkKind; }
+ virtual ~Chunk() = default;
+
+ // Returns the size of this chunk (even if this is a common or BSS.)
+ virtual size_t getSize() const = 0;
+
+ // Write this chunk to a mmap'ed file, assuming Buf is pointing to
+ // beginning of the file. Because this function may use RVA values
+ // of other chunks for relocations, you need to set them properly
+ // before calling this function.
+ virtual void writeTo(uint8_t *Buf) const {}
+
+ // The writer sets and uses the addresses.
+ uint64_t getRVA() const { return RVA; }
+ uint32_t getAlign() const { return Align; }
+ void setRVA(uint64_t V) { RVA = V; }
+ void setOutputSectionOff(uint64_t V) { OutputSectionOff = V; }
+
+ // Returns true if this has non-zero data. BSS chunks return
+ // false. If false is returned, the space occupied by this chunk
+ // will be filled with zeros.
+ virtual bool hasData() const { return true; }
+
+ // Returns readable/writable/executable bits.
+ virtual uint32_t getPermissions() const { return 0; }
+
+ // Returns the section name if this is a section chunk.
+ // It is illegal to call this function on non-section chunks.
+ virtual StringRef getSectionName() const {
+ llvm_unreachable("unimplemented getSectionName");
+ }
+
+ // An output section has pointers to chunks in the section, and each
+ // chunk has a back pointer to an output section.
+ void setOutputSection(OutputSection *O) { Out = O; }
+ OutputSection *getOutputSection() { return Out; }
+
+ // Windows-specific.
+ // Collect all locations that contain absolute addresses for base relocations.
+ virtual void getBaserels(std::vector<Baserel> *Res) {}
+
+ // Returns a human-readable name of this chunk. Chunks are unnamed chunks of
+ // bytes, so this is used only for logging or debugging.
+ virtual StringRef getDebugName() { return ""; }
+
+protected:
+ Chunk(Kind K = OtherKind) : ChunkKind(K) {}
+ const Kind ChunkKind;
+
+ // The RVA of this chunk in the output. The writer sets a value.
+ uint64_t RVA = 0;
+
+ // The offset from beginning of the output section. The writer sets a value.
+ uint64_t OutputSectionOff = 0;
+
+ // The output section for this chunk.
+ OutputSection *Out = nullptr;
+
+ // The alignment of this chunk. The writer uses the value.
+ uint32_t Align = 1;
+};
+
+// A chunk corresponding a section of an input file.
+class SectionChunk : public Chunk {
+ // Identical COMDAT Folding feature accesses section internal data.
+ friend class ICF;
+
+public:
+ class symbol_iterator : public llvm::iterator_adaptor_base<
+ symbol_iterator, const coff_relocation *,
+ std::random_access_iterator_tag, SymbolBody *> {
+ friend SectionChunk;
+
+ ObjectFile *File;
+
+ symbol_iterator(ObjectFile *File, const coff_relocation *I)
+ : symbol_iterator::iterator_adaptor_base(I), File(File) {}
+
+ public:
+ symbol_iterator() = default;
+
+ SymbolBody *operator*() const {
+ return File->getSymbolBody(I->SymbolTableIndex);
+ }
+ };
+
+ 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; }
+ void writeTo(uint8_t *Buf) const override;
+ bool hasData() const override;
+ uint32_t getPermissions() const override;
+ StringRef getSectionName() const override { return SectionName; }
+ void getBaserels(std::vector<Baserel> *Res) override;
+ bool isCOMDAT() const;
+ void applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const;
+ void applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const;
+ void applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const;
+
+ // Called if the garbage collector decides to not include this chunk
+ // in a final output. It's supposed to print out a log message to stdout.
+ void printDiscardedMessage() const;
+
+ // Adds COMDAT associative sections to this COMDAT section. A chunk
+ // and its children are treated as a group by the garbage collector.
+ void addAssociative(SectionChunk *Child);
+
+ StringRef getDebugName() override;
+ void setSymbol(DefinedRegular *S) { if (!Sym) Sym = S; }
+
+ // Used by the garbage collector.
+ bool isLive() { return !Config->DoGC || Live; }
+ void markLive() {
+ assert(!isLive() && "Cannot mark an already live section!");
+ Live = true;
+ }
+
+ // Allow iteration over the bodies of this chunk's relocated symbols.
+ llvm::iterator_range<symbol_iterator> symbols() const {
+ return llvm::make_range(symbol_iterator(File, Relocs.begin()),
+ symbol_iterator(File, Relocs.end()));
+ }
+
+ // Allow iteration over the associated child chunks for this section.
+ ArrayRef<SectionChunk *> children() const { return AssocChildren; }
+
+ // A pointer pointing to a replacement for this chunk.
+ // Initially it points to "this" object. If this chunk is merged
+ // with other chunk by ICF, it points to another chunk,
+ // and this chunk is considrered as dead.
+ SectionChunk *Repl;
+
+ // The CRC of the contents as described in the COFF spec 4.5.5.
+ // Auxiliary Format 5: Section Definitions. Used for ICF.
+ uint32_t Checksum = 0;
+
+private:
+ ArrayRef<uint8_t> getContents() const;
+
+ // A file this chunk was created from.
+ ObjectFile *File;
+
+ const coff_section *Header;
+ StringRef SectionName;
+ std::vector<SectionChunk *> AssocChildren;
+ llvm::iterator_range<const coff_relocation *> Relocs;
+ size_t NumRelocs;
+
+ // Used by the garbage collector.
+ bool Live;
+
+ // Used for ICF (Identical COMDAT Folding)
+ void replace(SectionChunk *Other);
+ std::atomic<uint64_t> GroupID = { 0 };
+
+ // Sym points to a section symbol if this is a COMDAT chunk.
+ DefinedRegular *Sym = nullptr;
+};
+
+// A chunk for common symbols. Common chunks don't have actual data.
+class CommonChunk : public Chunk {
+public:
+ CommonChunk(const COFFSymbolRef Sym);
+ size_t getSize() const override { return Sym.getValue(); }
+ bool hasData() const override { return false; }
+ uint32_t getPermissions() const override;
+ StringRef getSectionName() const override { return ".bss"; }
+
+private:
+ const COFFSymbolRef Sym;
+};
+
+// A chunk for linker-created strings.
+class StringChunk : public Chunk {
+public:
+ explicit StringChunk(StringRef S) : Str(S) {}
+ size_t getSize() const override { return Str.size() + 1; }
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ StringRef Str;
+};
+
+static const uint8_t ImportThunkX86[] = {
+ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0
+};
+
+static const uint8_t ImportThunkARM[] = {
+ 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0
+ 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0
+ 0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip]
+};
+
+// Windows-specific.
+// A chunk for DLL import jump table entry. In a final output, it's
+// contents will be a JMP instruction to some __imp_ symbol.
+class ImportThunkChunkX64 : public Chunk {
+public:
+ explicit ImportThunkChunkX64(Defined *S);
+ size_t getSize() const override { return sizeof(ImportThunkX86); }
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ Defined *ImpSymbol;
+};
+
+class ImportThunkChunkX86 : public Chunk {
+public:
+ explicit ImportThunkChunkX86(Defined *S) : ImpSymbol(S) {}
+ size_t getSize() const override { return sizeof(ImportThunkX86); }
+ void getBaserels(std::vector<Baserel> *Res) override;
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ Defined *ImpSymbol;
+};
+
+class ImportThunkChunkARM : public Chunk {
+public:
+ explicit ImportThunkChunkARM(Defined *S) : ImpSymbol(S) {}
+ size_t getSize() const override { return sizeof(ImportThunkARM); }
+ void getBaserels(std::vector<Baserel> *Res) override;
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ Defined *ImpSymbol;
+};
+
+// Windows-specific.
+// See comments for DefinedLocalImport class.
+class LocalImportChunk : public Chunk {
+public:
+ explicit LocalImportChunk(Defined *S) : Sym(S) {}
+ size_t getSize() const override;
+ void getBaserels(std::vector<Baserel> *Res) override;
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ Defined *Sym;
+};
+
+// Windows-specific.
+// A chunk for SEH table which contains RVAs of safe exception handler
+// functions. x86-only.
+class SEHTableChunk : public Chunk {
+public:
+ explicit SEHTableChunk(std::set<Defined *> S) : Syms(S) {}
+ size_t getSize() const override { return Syms.size() * 4; }
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ std::set<Defined *> Syms;
+};
+
+// Windows-specific.
+// This class represents a block in .reloc section.
+// See the PE/COFF spec 5.6 for details.
+class BaserelChunk : public Chunk {
+public:
+ BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End);
+ size_t getSize() const override { return Data.size(); }
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ std::vector<uint8_t> Data;
+};
+
+class Baserel {
+public:
+ Baserel(uint32_t V, uint8_t Ty) : RVA(V), Type(Ty) {}
+ explicit Baserel(uint32_t V) : Baserel(V, getDefaultType()) {}
+ uint8_t getDefaultType();
+
+ uint32_t RVA;
+ uint8_t Type;
+};
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/Config.h b/COFF/Config.h
new file mode 100644
index 000000000000..409ede648636
--- /dev/null
+++ b/COFF/Config.h
@@ -0,0 +1,140 @@
+//===- Config.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_CONFIG_H
+#define LLD_COFF_CONFIG_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/COFF.h"
+#include <cstdint>
+#include <map>
+#include <set>
+#include <string>
+
+namespace lld {
+namespace coff {
+
+using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
+using llvm::COFF::WindowsSubsystem;
+using llvm::StringRef;
+class DefinedAbsolute;
+class DefinedRelative;
+class Undefined;
+
+// Short aliases.
+static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64;
+static const auto ARMNT = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT;
+static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386;
+
+// Represents an /export option.
+struct Export {
+ StringRef Name; // N in /export:N or /export:E=N
+ StringRef ExtName; // E in /export:E=N
+ Undefined *Sym = nullptr;
+ uint16_t Ordinal = 0;
+ bool Noname = false;
+ bool Data = false;
+ bool Private = false;
+
+ // True if this /export option was in .drectves section.
+ bool Directives = false;
+ StringRef SymbolName;
+ StringRef ExportName; // Name in DLL
+
+ bool operator==(const Export &E) {
+ return (Name == E.Name && ExtName == E.ExtName &&
+ Ordinal == E.Ordinal && Noname == E.Noname &&
+ Data == E.Data && Private == E.Private);
+ }
+};
+
+// Global configuration.
+struct Configuration {
+ enum ManifestKind { SideBySide, Embed, No };
+ bool is64() { return Machine == AMD64; }
+
+ llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN;
+ bool Verbose = false;
+ WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
+ Undefined *Entry = nullptr;
+ bool NoEntry = false;
+ std::string OutputFile;
+ bool DoGC = true;
+ bool DoICF = true;
+ bool Relocatable = true;
+ bool Force = false;
+ bool Debug = false;
+ bool WriteSymtab = true;
+
+ // Symbols in this set are considered as live by the garbage collector.
+ std::set<Undefined *> GCRoot;
+
+ std::set<StringRef> NoDefaultLibs;
+ bool NoDefaultLibAll = false;
+
+ // True if we are creating a DLL.
+ bool DLL = false;
+ StringRef Implib;
+ std::vector<Export> Exports;
+ std::set<std::string> DelayLoads;
+ std::map<std::string, int> DLLOrder;
+ Undefined *DelayLoadHelper = nullptr;
+
+ // Used for SafeSEH.
+ DefinedRelative *SEHTable = nullptr;
+ DefinedAbsolute *SEHCount = nullptr;
+
+ // Used for /opt:lldlto=N
+ unsigned LTOOptLevel = 2;
+
+ // Used for /opt:lldltojobs=N
+ unsigned LTOJobs = 1;
+
+ // Used for /merge:from=to (e.g. /merge:.rdata=.text)
+ std::map<StringRef, StringRef> Merge;
+
+ // Options for manifest files.
+ ManifestKind Manifest = SideBySide;
+ int ManifestID = 1;
+ StringRef ManifestDependency;
+ bool ManifestUAC = true;
+ StringRef ManifestLevel = "'asInvoker'";
+ StringRef ManifestUIAccess = "'false'";
+ StringRef ManifestFile;
+
+ // Used for /failifmismatch.
+ std::map<StringRef, StringRef> MustMatch;
+
+ // Used for /alternatename.
+ std::map<StringRef, StringRef> AlternateNames;
+
+ uint64_t ImageBase = -1;
+ uint64_t StackReserve = 1024 * 1024;
+ uint64_t StackCommit = 4096;
+ uint64_t HeapReserve = 1024 * 1024;
+ uint64_t HeapCommit = 4096;
+ uint32_t MajorImageVersion = 0;
+ uint32_t MinorImageVersion = 0;
+ uint32_t MajorOSVersion = 6;
+ uint32_t MinorOSVersion = 0;
+ bool DynamicBase = true;
+ bool AllowBind = true;
+ bool NxCompat = true;
+ bool AllowIsolation = true;
+ bool TerminalServerAware = true;
+ bool LargeAddressAware = false;
+ bool HighEntropyVA = false;
+};
+
+extern Configuration *Config;
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/DLL.cpp b/COFF/DLL.cpp
new file mode 100644
index 000000000000..40ca5cf61dc2
--- /dev/null
+++ b/COFF/DLL.cpp
@@ -0,0 +1,556 @@
+//===- DLL.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines various types of chunks for the DLL import or export
+// descriptor tables. They are inherently Windows-specific.
+// You need to read Microsoft PE/COFF spec to understand details
+// about the data structures.
+//
+// If you are not particularly interested in linking against Windows
+// DLL, you can skip this file, and you should still be able to
+// understand the rest of the linker.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Chunks.h"
+#include "DLL.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Path.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::COFF;
+
+namespace lld {
+namespace coff {
+namespace {
+
+// Import table
+
+static int ptrSize() { return Config->is64() ? 8 : 4; }
+
+// A chunk for the import descriptor table.
+class HintNameChunk : public Chunk {
+public:
+ HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {}
+
+ size_t getSize() const override {
+ // Starts with 2 byte Hint field, followed by a null-terminated string,
+ // ends with 0 or 1 byte padding.
+ return RoundUpToAlignment(Name.size() + 3, 2);
+ }
+
+ void writeTo(uint8_t *Buf) const override {
+ write16le(Buf + OutputSectionOff, Hint);
+ memcpy(Buf + OutputSectionOff + 2, Name.data(), Name.size());
+ }
+
+private:
+ StringRef Name;
+ uint16_t Hint;
+};
+
+// A chunk for the import descriptor table.
+class LookupChunk : public Chunk {
+public:
+ explicit LookupChunk(Chunk *C) : HintName(C) {}
+ size_t getSize() const override { return ptrSize(); }
+
+ void writeTo(uint8_t *Buf) const override {
+ write32le(Buf + OutputSectionOff, HintName->getRVA());
+ }
+
+ Chunk *HintName;
+};
+
+// A chunk for the import descriptor table.
+// This chunk represent import-by-ordinal symbols.
+// See Microsoft PE/COFF spec 7.1. Import Header for details.
+class OrdinalOnlyChunk : public Chunk {
+public:
+ explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {}
+ size_t getSize() const override { return ptrSize(); }
+
+ void writeTo(uint8_t *Buf) const override {
+ // An import-by-ordinal slot has MSB 1 to indicate that
+ // this is import-by-ordinal (and not import-by-name).
+ if (Config->is64()) {
+ write64le(Buf + OutputSectionOff, (1ULL << 63) | Ordinal);
+ } else {
+ write32le(Buf + OutputSectionOff, (1ULL << 31) | Ordinal);
+ }
+ }
+
+ uint16_t Ordinal;
+};
+
+// A chunk for the import descriptor table.
+class ImportDirectoryChunk : public Chunk {
+public:
+ explicit ImportDirectoryChunk(Chunk *N) : DLLName(N) {}
+ size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); }
+
+ void writeTo(uint8_t *Buf) const override {
+ auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff);
+ E->ImportLookupTableRVA = LookupTab->getRVA();
+ E->NameRVA = DLLName->getRVA();
+ E->ImportAddressTableRVA = AddressTab->getRVA();
+ }
+
+ Chunk *DLLName;
+ Chunk *LookupTab;
+ Chunk *AddressTab;
+};
+
+// A chunk representing null terminator in the import table.
+// Contents of this chunk is always null bytes.
+class NullChunk : public Chunk {
+public:
+ explicit NullChunk(size_t N) : Size(N) {}
+ bool hasData() const override { return false; }
+ size_t getSize() const override { return Size; }
+ void setAlign(size_t N) { Align = N; }
+
+private:
+ size_t Size;
+};
+
+static std::vector<std::vector<DefinedImportData *>>
+binImports(const std::vector<DefinedImportData *> &Imports) {
+ // Group DLL-imported symbols by DLL name because that's how
+ // symbols are layed out in the import descriptor table.
+ auto Less = [](const std::string &A, const std::string &B) {
+ return Config->DLLOrder[A] < Config->DLLOrder[B];
+ };
+ std::map<std::string, std::vector<DefinedImportData *>,
+ bool(*)(const std::string &, const std::string &)> M(Less);
+ for (DefinedImportData *Sym : Imports)
+ M[Sym->getDLLName().lower()].push_back(Sym);
+
+ std::vector<std::vector<DefinedImportData *>> V;
+ for (auto &P : M) {
+ // Sort symbols by name for each group.
+ std::vector<DefinedImportData *> &Syms = P.second;
+ std::sort(Syms.begin(), Syms.end(),
+ [](DefinedImportData *A, DefinedImportData *B) {
+ return A->getName() < B->getName();
+ });
+ V.push_back(std::move(Syms));
+ }
+ return V;
+}
+
+// Export table
+// See Microsoft PE/COFF spec 4.3 for details.
+
+// A chunk for the delay import descriptor table etnry.
+class DelayDirectoryChunk : public Chunk {
+public:
+ explicit DelayDirectoryChunk(Chunk *N) : DLLName(N) {}
+
+ size_t getSize() const override {
+ return sizeof(delay_import_directory_table_entry);
+ }
+
+ void writeTo(uint8_t *Buf) const override {
+ auto *E = (delay_import_directory_table_entry *)(Buf + OutputSectionOff);
+ E->Attributes = 1;
+ E->Name = DLLName->getRVA();
+ E->ModuleHandle = ModuleHandle->getRVA();
+ E->DelayImportAddressTable = AddressTab->getRVA();
+ E->DelayImportNameTable = NameTab->getRVA();
+ }
+
+ Chunk *DLLName;
+ Chunk *ModuleHandle;
+ Chunk *AddressTab;
+ Chunk *NameTab;
+};
+
+// Initial contents for delay-loaded functions.
+// This code calls __delayLoadHelper2 function to resolve a symbol
+// and then overwrites its jump table slot with the result
+// for subsequent function calls.
+static const uint8_t ThunkX64[] = {
+ 0x51, // push rcx
+ 0x52, // push rdx
+ 0x41, 0x50, // push r8
+ 0x41, 0x51, // push r9
+ 0x48, 0x83, 0xEC, 0x48, // sub rsp, 48h
+ 0x66, 0x0F, 0x7F, 0x04, 0x24, // movdqa xmmword ptr [rsp], xmm0
+ 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1
+ 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2
+ 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3
+ 0x48, 0x8D, 0x15, 0, 0, 0, 0, // lea rdx, [__imp_<FUNCNAME>]
+ 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...]
+ 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2
+ 0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp]
+ 0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa xmm1, xmmword ptr [rsp+10h]
+ 0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa xmm2, xmmword ptr [rsp+20h]
+ 0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa xmm3, xmmword ptr [rsp+30h]
+ 0x48, 0x83, 0xC4, 0x48, // add rsp, 48h
+ 0x41, 0x59, // pop r9
+ 0x41, 0x58, // pop r8
+ 0x5A, // pop rdx
+ 0x59, // pop rcx
+ 0xFF, 0xE0, // jmp rax
+};
+
+static const uint8_t ThunkX86[] = {
+ 0x51, // push ecx
+ 0x52, // push edx
+ 0x68, 0, 0, 0, 0, // push offset ___imp__<FUNCNAME>
+ 0x68, 0, 0, 0, 0, // push offset ___DELAY_IMPORT_DESCRIPTOR_<DLLNAME>_dll
+ 0xE8, 0, 0, 0, 0, // call ___delayLoadHelper2@8
+ 0x5A, // pop edx
+ 0x59, // pop ecx
+ 0xFF, 0xE0, // jmp eax
+};
+
+// A chunk for the delay import thunk.
+class ThunkChunkX64 : public Chunk {
+public:
+ ThunkChunkX64(Defined *I, Chunk *D, Defined *H)
+ : Imp(I), Desc(D), Helper(H) {}
+
+ size_t getSize() const override { return sizeof(ThunkX64); }
+
+ void writeTo(uint8_t *Buf) const override {
+ memcpy(Buf + OutputSectionOff, ThunkX64, sizeof(ThunkX64));
+ write32le(Buf + OutputSectionOff + 36, Imp->getRVA() - RVA - 40);
+ write32le(Buf + OutputSectionOff + 43, Desc->getRVA() - RVA - 47);
+ write32le(Buf + OutputSectionOff + 48, Helper->getRVA() - RVA - 52);
+ }
+
+ Defined *Imp = nullptr;
+ Chunk *Desc = nullptr;
+ Defined *Helper = nullptr;
+};
+
+class ThunkChunkX86 : public Chunk {
+public:
+ ThunkChunkX86(Defined *I, Chunk *D, Defined *H)
+ : Imp(I), Desc(D), Helper(H) {}
+
+ size_t getSize() const override { return sizeof(ThunkX86); }
+
+ void writeTo(uint8_t *Buf) const override {
+ memcpy(Buf + OutputSectionOff, ThunkX86, sizeof(ThunkX86));
+ write32le(Buf + OutputSectionOff + 3, Imp->getRVA() + Config->ImageBase);
+ write32le(Buf + OutputSectionOff + 8, Desc->getRVA() + Config->ImageBase);
+ write32le(Buf + OutputSectionOff + 13, Helper->getRVA() - RVA - 17);
+ }
+
+ void getBaserels(std::vector<Baserel> *Res) override {
+ Res->emplace_back(RVA + 3);
+ Res->emplace_back(RVA + 8);
+ }
+
+ Defined *Imp = nullptr;
+ Chunk *Desc = nullptr;
+ Defined *Helper = nullptr;
+};
+
+// A chunk for the import descriptor table.
+class DelayAddressChunk : public Chunk {
+public:
+ explicit DelayAddressChunk(Chunk *C) : Thunk(C) {}
+ size_t getSize() const override { return ptrSize(); }
+
+ void writeTo(uint8_t *Buf) const override {
+ if (Config->is64()) {
+ write64le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase);
+ } else {
+ write32le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase);
+ }
+ }
+
+ void getBaserels(std::vector<Baserel> *Res) override {
+ Res->emplace_back(RVA);
+ }
+
+ Chunk *Thunk;
+};
+
+// Export table
+// Read Microsoft PE/COFF spec 5.3 for details.
+
+// A chunk for the export descriptor table.
+class ExportDirectoryChunk : public Chunk {
+public:
+ ExportDirectoryChunk(int I, int J, Chunk *D, Chunk *A, Chunk *N, Chunk *O)
+ : MaxOrdinal(I), NameTabSize(J), DLLName(D), AddressTab(A), NameTab(N),
+ OrdinalTab(O) {}
+
+ size_t getSize() const override {
+ return sizeof(export_directory_table_entry);
+ }
+
+ void writeTo(uint8_t *Buf) const override {
+ auto *E = (export_directory_table_entry *)(Buf + OutputSectionOff);
+ E->NameRVA = DLLName->getRVA();
+ E->OrdinalBase = 0;
+ E->AddressTableEntries = MaxOrdinal + 1;
+ E->NumberOfNamePointers = NameTabSize;
+ E->ExportAddressTableRVA = AddressTab->getRVA();
+ E->NamePointerRVA = NameTab->getRVA();
+ E->OrdinalTableRVA = OrdinalTab->getRVA();
+ }
+
+ uint16_t MaxOrdinal;
+ uint16_t NameTabSize;
+ Chunk *DLLName;
+ Chunk *AddressTab;
+ Chunk *NameTab;
+ Chunk *OrdinalTab;
+};
+
+class AddressTableChunk : public Chunk {
+public:
+ explicit AddressTableChunk(size_t MaxOrdinal) : Size(MaxOrdinal + 1) {}
+ size_t getSize() const override { return Size * 4; }
+
+ void writeTo(uint8_t *Buf) const override {
+ for (Export &E : Config->Exports) {
+ auto *D = cast<Defined>(E.Sym->repl());
+ write32le(Buf + OutputSectionOff + E.Ordinal * 4, D->getRVA());
+ }
+ }
+
+private:
+ size_t Size;
+};
+
+class NamePointersChunk : public Chunk {
+public:
+ explicit NamePointersChunk(std::vector<Chunk *> &V) : Chunks(V) {}
+ size_t getSize() const override { return Chunks.size() * 4; }
+
+ void writeTo(uint8_t *Buf) const override {
+ uint8_t *P = Buf + OutputSectionOff;
+ for (Chunk *C : Chunks) {
+ write32le(P, C->getRVA());
+ P += 4;
+ }
+ }
+
+private:
+ std::vector<Chunk *> Chunks;
+};
+
+class ExportOrdinalChunk : public Chunk {
+public:
+ explicit ExportOrdinalChunk(size_t I) : Size(I) {}
+ size_t getSize() const override { return Size * 2; }
+
+ void writeTo(uint8_t *Buf) const override {
+ uint8_t *P = Buf + OutputSectionOff;
+ for (Export &E : Config->Exports) {
+ if (E.Noname)
+ continue;
+ write16le(P, E.Ordinal);
+ P += 2;
+ }
+ }
+
+private:
+ size_t Size;
+};
+
+} // anonymous namespace
+
+uint64_t IdataContents::getDirSize() {
+ return Dirs.size() * sizeof(ImportDirectoryTableEntry);
+}
+
+uint64_t IdataContents::getIATSize() {
+ return Addresses.size() * ptrSize();
+}
+
+// Returns a list of .idata contents.
+// See Microsoft PE/COFF spec 5.4 for details.
+std::vector<Chunk *> IdataContents::getChunks() {
+ create();
+ std::vector<Chunk *> V;
+ // The loader assumes a specific order of data.
+ // Add each type in the correct order.
+ for (std::unique_ptr<Chunk> &C : Dirs)
+ V.push_back(C.get());
+ for (std::unique_ptr<Chunk> &C : Lookups)
+ V.push_back(C.get());
+ for (std::unique_ptr<Chunk> &C : Addresses)
+ V.push_back(C.get());
+ for (std::unique_ptr<Chunk> &C : Hints)
+ V.push_back(C.get());
+ for (auto &P : DLLNames) {
+ std::unique_ptr<Chunk> &C = P.second;
+ V.push_back(C.get());
+ }
+ return V;
+}
+
+void IdataContents::create() {
+ std::vector<std::vector<DefinedImportData *>> V = binImports(Imports);
+
+ // 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();
+ for (DefinedImportData *S : Syms) {
+ uint16_t Ord = S->getOrdinal();
+ if (S->getExternalName().empty()) {
+ Lookups.push_back(make_unique<OrdinalOnlyChunk>(Ord));
+ Addresses.push_back(make_unique<OrdinalOnlyChunk>(Ord));
+ continue;
+ }
+ auto C = make_unique<HintNameChunk>(S->getExternalName(), Ord);
+ Lookups.push_back(make_unique<LookupChunk>(C.get()));
+ Addresses.push_back(make_unique<LookupChunk>(C.get()));
+ Hints.push_back(std::move(C));
+ }
+ // Terminate with null values.
+ Lookups.push_back(make_unique<NullChunk>(ptrSize()));
+ Addresses.push_back(make_unique<NullChunk>(ptrSize()));
+
+ for (int I = 0, E = Syms.size(); I < E; ++I)
+ Syms[I]->setLocation(Addresses[Base + I].get());
+
+ // Create the import table header.
+ if (!DLLNames.count(Name))
+ DLLNames[Name] = make_unique<StringChunk>(Name);
+ auto Dir = make_unique<ImportDirectoryChunk>(DLLNames[Name].get());
+ Dir->LookupTab = Lookups[Base].get();
+ Dir->AddressTab = Addresses[Base].get();
+ Dirs.push_back(std::move(Dir));
+ }
+ // Add null terminator.
+ Dirs.push_back(make_unique<NullChunk>(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());
+ }
+ 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());
+ return V;
+}
+
+uint64_t DelayLoadContents::getDirSize() {
+ return Dirs.size() * sizeof(delay_import_directory_table_entry);
+}
+
+void DelayLoadContents::create(Defined *H) {
+ Helper = H;
+ std::vector<std::vector<DefinedImportData *>> V = binImports(Imports);
+
+ // 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());
+
+ 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));
+ StringRef ExtName = S->getExternalName();
+ if (ExtName.empty()) {
+ Names.push_back(make_unique<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));
+ }
+ }
+ // Terminate with null values.
+ Addresses.push_back(make_unique<NullChunk>(8));
+ Names.push_back(make_unique<NullChunk>(8));
+
+ for (int I = 0, E = Syms.size(); I < E; ++I)
+ Syms[I]->setLocation(Addresses[Base + I].get());
+ auto *MH = new NullChunk(8);
+ MH->setAlign(8);
+ ModuleHandles.push_back(std::unique_ptr<Chunk>(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));
+ }
+ // Add null terminator.
+ Dirs.push_back(
+ make_unique<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);
+ case I386:
+ return new ThunkChunkX86(S, Dir, Helper);
+ default:
+ llvm_unreachable("unsupported machine type");
+ }
+}
+
+EdataContents::EdataContents() {
+ uint16_t MaxOrdinal = 0;
+ 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);
+ std::vector<Chunk *> Names;
+ for (Export &E : Config->Exports)
+ if (!E.Noname)
+ Names.push_back(new StringChunk(E.ExportName));
+ 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));
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/DLL.h b/COFF/DLL.h
new file mode 100644
index 000000000000..83a12df185c2
--- /dev/null
+++ b/COFF/DLL.h
@@ -0,0 +1,84 @@
+//===- DLL.h ----------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_DLL_H
+#define LLD_COFF_DLL_H
+
+#include "Chunks.h"
+#include "Symbols.h"
+
+namespace lld {
+namespace coff {
+
+// Windows-specific.
+// IdataContents creates all chunks for the DLL import table.
+// You are supposed to call add() to add symbols and then
+// call getChunks() to get a list of chunks.
+class IdataContents {
+public:
+ void add(DefinedImportData *Sym) { Imports.push_back(Sym); }
+ bool empty() { return Imports.empty(); }
+ std::vector<Chunk *> getChunks();
+
+ uint64_t getDirRVA() { return Dirs[0]->getRVA(); }
+ uint64_t getDirSize();
+ uint64_t getIATRVA() { return Addresses[0]->getRVA(); }
+ uint64_t getIATSize();
+
+private:
+ void create();
+
+ std::vector<DefinedImportData *> Imports;
+ std::vector<std::unique_ptr<Chunk>> Dirs;
+ std::vector<std::unique_ptr<Chunk>> Lookups;
+ std::vector<std::unique_ptr<Chunk>> Addresses;
+ std::vector<std::unique_ptr<Chunk>> Hints;
+ std::map<StringRef, std::unique_ptr<Chunk>> DLLNames;
+};
+
+// Windows-specific.
+// DelayLoadContents creates all chunks for the delay-load DLL import table.
+class DelayLoadContents {
+public:
+ void add(DefinedImportData *Sym) { Imports.push_back(Sym); }
+ bool empty() { return Imports.empty(); }
+ void create(Defined *Helper);
+ std::vector<Chunk *> getChunks();
+ std::vector<Chunk *> getDataChunks();
+ std::vector<std::unique_ptr<Chunk>> &getCodeChunks() { return Thunks; }
+
+ uint64_t getDirRVA() { return Dirs[0]->getRVA(); }
+ uint64_t getDirSize();
+
+private:
+ Chunk *newThunkChunk(DefinedImportData *S, Chunk *Dir);
+
+ 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;
+};
+
+// Windows-specific.
+// EdataContents creates all chunks for the DLL export table.
+class EdataContents {
+public:
+ EdataContents();
+ std::vector<std::unique_ptr<Chunk>> Chunks;
+};
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp
new file mode 100644
index 000000000000..f528dafd9857
--- /dev/null
+++ b/COFF/Driver.cpp
@@ -0,0 +1,677 @@
+//===- Driver.cpp ---------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Config.h"
+#include "Driver.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "Writer.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/LibDriver/LibDriver.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <memory>
+
+using namespace llvm;
+using namespace llvm::COFF;
+using llvm::sys::Process;
+using llvm::sys::fs::OpenFlags;
+using llvm::sys::fs::file_magic;
+using llvm::sys::fs::identify_magic;
+
+namespace lld {
+namespace coff {
+
+Configuration *Config;
+LinkerDriver *Driver;
+
+void link(llvm::ArrayRef<const char *> Args) {
+ Configuration C;
+ LinkerDriver D;
+ Config = &C;
+ Driver = &D;
+ return Driver->link(Args);
+}
+
+// Drop directory components and replace extension with ".exe".
+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();
+}
+
+// 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;
+ MemoryBufferRef MBRef = MB->getMemBufferRef();
+ OwningMBs.push_back(std::move(MB)); // take ownership
+ return MBRef;
+}
+
+static std::unique_ptr<InputFile> createFile(MemoryBufferRef MB) {
+ // File type is detected by contents, not by file extension.
+ file_magic Magic = identify_magic(MB.getBuffer());
+ if (Magic == file_magic::archive)
+ return std::unique_ptr<InputFile>(new ArchiveFile(MB));
+ if (Magic == file_magic::bitcode)
+ return std::unique_ptr<InputFile>(new BitcodeFile(MB));
+ if (Config->OutputFile == "")
+ Config->OutputFile = getOutputPath(MB.getBufferIdentifier());
+ return std::unique_ptr<InputFile>(new ObjectFile(MB));
+}
+
+static bool isDecorated(StringRef Sym) {
+ return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?");
+}
+
+// Parses .drectve section contents and returns a list of files
+// specified by /defaultlib.
+void LinkerDriver::parseDirectives(StringRef S) {
+ llvm::opt::InputArgList Args = Parser.parse(S);
+
+ for (auto *Arg : Args) {
+ switch (Arg->getOption().getID()) {
+ case OPT_alternatename:
+ parseAlternateName(Arg->getValue());
+ break;
+ case OPT_defaultlib:
+ if (Optional<StringRef> Path = findLib(Arg->getValue())) {
+ MemoryBufferRef MB = openFile(*Path);
+ Symtab.addFile(createFile(MB));
+ }
+ break;
+ case OPT_export: {
+ Export E = parseExport(Arg->getValue());
+ E.Directives = true;
+ Config->Exports.push_back(E);
+ break;
+ }
+ case OPT_failifmismatch:
+ checkFailIfMismatch(Arg->getValue());
+ break;
+ case OPT_incl:
+ addUndefined(Arg->getValue());
+ break;
+ case OPT_merge:
+ parseMerge(Arg->getValue());
+ break;
+ case OPT_nodefaultlib:
+ Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()));
+ break;
+ case OPT_editandcontinue:
+ case OPT_guardsym:
+ case OPT_throwingnew:
+ break;
+ default:
+ error(Twine(Arg->getSpelling()) + " is not allowed in .drectve");
+ }
+ }
+}
+
+// Find file from search paths. You can omit ".obj", this function takes
+// care of that. Note that the returned path is not guaranteed to exist.
+StringRef LinkerDriver::doFindFile(StringRef Filename) {
+ bool hasPathSep = (Filename.find_first_of("/\\") != StringRef::npos);
+ if (hasPathSep)
+ return Filename;
+ bool hasExt = (Filename.find('.') != StringRef::npos);
+ for (StringRef Dir : SearchPaths) {
+ SmallString<128> Path = Dir;
+ llvm::sys::path::append(Path, Filename);
+ if (llvm::sys::fs::exists(Path.str()))
+ return Alloc.save(Path.str());
+ if (!hasExt) {
+ Path.append(".obj");
+ if (llvm::sys::fs::exists(Path.str()))
+ return Alloc.save(Path.str());
+ }
+ }
+ return Filename;
+}
+
+// Resolves a file path. This never returns the same path
+// (in that case, it returns None).
+Optional<StringRef> LinkerDriver::findFile(StringRef Filename) {
+ StringRef Path = doFindFile(Filename);
+ bool Seen = !VisitedFiles.insert(Path.lower()).second;
+ if (Seen)
+ return None;
+ return Path;
+}
+
+// Find library file from search path.
+StringRef LinkerDriver::doFindLib(StringRef Filename) {
+ // Add ".lib" to Filename if that has no file extension.
+ bool hasExt = (Filename.find('.') != StringRef::npos);
+ if (!hasExt)
+ Filename = Alloc.save(Filename + ".lib");
+ return doFindFile(Filename);
+}
+
+// Resolves a library path. /nodefaultlib options are taken into
+// consideration. This never returns the same path (in that case,
+// it returns None).
+Optional<StringRef> LinkerDriver::findLib(StringRef Filename) {
+ if (Config->NoDefaultLibAll)
+ return None;
+ StringRef Path = doFindLib(Filename);
+ if (Config->NoDefaultLibs.count(Path))
+ return None;
+ bool Seen = !VisitedFiles.insert(Path.lower()).second;
+ if (Seen)
+ return None;
+ return Path;
+}
+
+// Parses LIB environment which contains a list of search paths.
+void LinkerDriver::addLibSearchPaths() {
+ Optional<std::string> EnvOpt = Process::GetEnv("LIB");
+ if (!EnvOpt.hasValue())
+ return;
+ StringRef Env = Alloc.save(*EnvOpt);
+ while (!Env.empty()) {
+ StringRef Path;
+ std::tie(Path, Env) = Env.split(';');
+ SearchPaths.push_back(Path);
+ }
+}
+
+Undefined *LinkerDriver::addUndefined(StringRef Name) {
+ Undefined *U = Symtab.addUndefined(Name);
+ Config->GCRoot.insert(U);
+ return U;
+}
+
+// Symbol names are mangled by appending "_" prefix on x86.
+StringRef LinkerDriver::mangle(StringRef Sym) {
+ assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN);
+ if (Config->Machine == I386)
+ return Alloc.save("_" + Sym);
+ return Sym;
+}
+
+// Windows specific -- find default entry point name.
+StringRef LinkerDriver::findDefaultEntry() {
+ // User-defined main functions and their corresponding entry points.
+ static const char *Entries[][2] = {
+ {"main", "mainCRTStartup"},
+ {"wmain", "wmainCRTStartup"},
+ {"WinMain", "WinMainCRTStartup"},
+ {"wWinMain", "wWinMainCRTStartup"},
+ };
+ for (auto E : Entries) {
+ StringRef Entry = Symtab.findMangle(mangle(E[0]));
+ if (!Entry.empty() && !isa<Undefined>(Symtab.find(Entry)->Body))
+ return mangle(E[1]);
+ }
+ return "";
+}
+
+WindowsSubsystem LinkerDriver::inferSubsystem() {
+ if (Config->DLL)
+ return IMAGE_SUBSYSTEM_WINDOWS_GUI;
+ if (Symtab.findUnderscore("main") || Symtab.findUnderscore("wmain"))
+ return IMAGE_SUBSYSTEM_WINDOWS_CUI;
+ if (Symtab.findUnderscore("WinMain") || Symtab.findUnderscore("wWinMain"))
+ return IMAGE_SUBSYSTEM_WINDOWS_GUI;
+ return IMAGE_SUBSYSTEM_UNKNOWN;
+}
+
+static uint64_t getDefaultImageBase() {
+ if (Config->is64())
+ return Config->DLL ? 0x180000000 : 0x140000000;
+ return Config->DLL ? 0x10000000 : 0x400000;
+}
+
+void LinkerDriver::link(llvm::ArrayRef<const char *> ArgsArr) {
+ // If the first command line argument is "/lib", link.exe acts like lib.exe.
+ // 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");
+ return;
+ }
+
+ // Needed for LTO.
+ llvm::InitializeAllTargetInfos();
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmParsers();
+ llvm::InitializeAllAsmPrinters();
+ llvm::InitializeAllDisassemblers();
+
+ // Parse command line options.
+ llvm::opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1));
+
+ // Handle /help
+ if (Args.hasArg(OPT_help)) {
+ printHelp(ArgsArr[0]);
+ return;
+ }
+
+ if (Args.filtered_begin(OPT_INPUT) == Args.filtered_end())
+ error("no input files.");
+
+ // Construct search path list.
+ SearchPaths.push_back("");
+ for (auto *Arg : Args.filtered(OPT_libpath))
+ SearchPaths.push_back(Arg->getValue());
+ addLibSearchPaths();
+
+ // Handle /out
+ if (auto *Arg = Args.getLastArg(OPT_out))
+ Config->OutputFile = Arg->getValue();
+
+ // Handle /verbose
+ if (Args.hasArg(OPT_verbose))
+ Config->Verbose = true;
+
+ // Handle /force or /force:unresolved
+ if (Args.hasArg(OPT_force) || Args.hasArg(OPT_force_unresolved))
+ Config->Force = true;
+
+ // Handle /debug
+ if (Args.hasArg(OPT_debug))
+ Config->Debug = true;
+
+ // Handle /noentry
+ if (Args.hasArg(OPT_noentry)) {
+ if (!Args.hasArg(OPT_dll))
+ error("/noentry must be specified with /dll");
+ Config->NoEntry = true;
+ }
+
+ // Handle /dll
+ if (Args.hasArg(OPT_dll)) {
+ Config->DLL = true;
+ Config->ManifestID = 2;
+ }
+
+ // Handle /fixed
+ if (Args.hasArg(OPT_fixed)) {
+ if (Args.hasArg(OPT_dynamicbase))
+ error("/fixed must not be specified with /dynamicbase");
+ Config->Relocatable = false;
+ Config->DynamicBase = false;
+ }
+
+ // Handle /machine
+ if (auto *Arg = Args.getLastArg(OPT_machine))
+ Config->Machine = getMachineType(Arg->getValue());
+
+ // Handle /nodefaultlib:<filename>
+ for (auto *Arg : Args.filtered(OPT_nodefaultlib))
+ Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()));
+
+ // Handle /nodefaultlib
+ if (Args.hasArg(OPT_nodefaultlib_all))
+ Config->NoDefaultLibAll = true;
+
+ // Handle /base
+ if (auto *Arg = Args.getLastArg(OPT_base))
+ parseNumbers(Arg->getValue(), &Config->ImageBase);
+
+ // Handle /stack
+ if (auto *Arg = Args.getLastArg(OPT_stack))
+ parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit);
+
+ // Handle /heap
+ if (auto *Arg = Args.getLastArg(OPT_heap))
+ parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit);
+
+ // Handle /version
+ if (auto *Arg = Args.getLastArg(OPT_version))
+ parseVersion(Arg->getValue(), &Config->MajorImageVersion,
+ &Config->MinorImageVersion);
+
+ // Handle /subsystem
+ if (auto *Arg = Args.getLastArg(OPT_subsystem))
+ parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion,
+ &Config->MinorOSVersion);
+
+ // Handle /alternatename
+ for (auto *Arg : Args.filtered(OPT_alternatename))
+ parseAlternateName(Arg->getValue());
+
+ // Handle /include
+ for (auto *Arg : Args.filtered(OPT_incl))
+ addUndefined(Arg->getValue());
+
+ // Handle /implib
+ if (auto *Arg = Args.getLastArg(OPT_implib))
+ Config->Implib = Arg->getValue();
+
+ // Handle /opt
+ for (auto *Arg : Args.filtered(OPT_opt)) {
+ std::string Str = StringRef(Arg->getValue()).lower();
+ SmallVector<StringRef, 1> Vec;
+ StringRef(Str).split(Vec, ',');
+ for (StringRef S : Vec) {
+ if (S == "noref") {
+ Config->DoGC = false;
+ Config->DoICF = false;
+ continue;
+ }
+ if (S == "icf" || StringRef(S).startswith("icf=")) {
+ Config->DoICF = true;
+ continue;
+ }
+ if (S == "noicf") {
+ Config->DoICF = false;
+ continue;
+ }
+ if (StringRef(S).startswith("lldlto=")) {
+ StringRef OptLevel = StringRef(S).substr(7);
+ if (OptLevel.getAsInteger(10, Config->LTOOptLevel) ||
+ Config->LTOOptLevel > 3)
+ error("/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);
+ continue;
+ }
+ if (S != "ref" && S != "lbr" && S != "nolbr")
+ error(Twine("/opt: unknown option: ") + S);
+ }
+ }
+
+ // Handle /failifmismatch
+ for (auto *Arg : Args.filtered(OPT_failifmismatch))
+ checkFailIfMismatch(Arg->getValue());
+
+ // Handle /merge
+ for (auto *Arg : Args.filtered(OPT_merge))
+ parseMerge(Arg->getValue());
+
+ // Handle /manifest
+ if (auto *Arg = Args.getLastArg(OPT_manifest_colon))
+ parseManifest(Arg->getValue());
+
+ // Handle /manifestuac
+ if (auto *Arg = Args.getLastArg(OPT_manifestuac))
+ parseManifestUAC(Arg->getValue());
+
+ // Handle /manifestdependency
+ if (auto *Arg = Args.getLastArg(OPT_manifestdependency))
+ Config->ManifestDependency = Arg->getValue();
+
+ // Handle /manifestfile
+ if (auto *Arg = Args.getLastArg(OPT_manifestfile))
+ Config->ManifestFile = 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))
+ Config->DynamicBase = false;
+ if (Args.hasArg(OPT_nxcompat_no))
+ Config->NxCompat = false;
+ if (Args.hasArg(OPT_tsaware_no))
+ Config->TerminalServerAware = false;
+ if (Args.hasArg(OPT_nosymtab))
+ Config->WriteSymtab = false;
+
+ // Create a list of input files. Files can be given as arguments
+ // for /defaultlib option.
+ std::vector<StringRef> Paths;
+ std::vector<MemoryBufferRef> MBs;
+ for (auto *Arg : Args.filtered(OPT_INPUT))
+ if (Optional<StringRef> Path = findFile(Arg->getValue()))
+ Paths.push_back(*Path);
+ for (auto *Arg : Args.filtered(OPT_defaultlib))
+ if (Optional<StringRef> Path = findLib(Arg->getValue()))
+ Paths.push_back(*Path);
+ for (StringRef Path : Paths)
+ MBs.push_back(openFile(Path));
+
+ // Windows specific -- Create a resource file containing a manifest file.
+ if (Config->Manifest == Configuration::Embed) {
+ std::unique_ptr<MemoryBuffer> MB = createManifestRes();
+ MBs.push_back(MB->getMemBufferRef());
+ OwningMBs.push_back(std::move(MB)); // take ownership
+ }
+
+ // Windows specific -- Input files can be Windows resource files (.res files).
+ // We invoke cvtres.exe to convert resource files to a regular COFF file
+ // then link the result file normally.
+ std::vector<MemoryBufferRef> Resources;
+ auto NotResource = [](MemoryBufferRef MB) {
+ return identify_magic(MB.getBuffer()) != file_magic::windows_resource;
+ };
+ auto It = std::stable_partition(MBs.begin(), MBs.end(), NotResource);
+ if (It != MBs.end()) {
+ Resources.insert(Resources.end(), It, MBs.end());
+ MBs.erase(It, MBs.end());
+ }
+
+ // Read all input files given via the command line. Note that step()
+ // doesn't read files that are specified by directive sections.
+ for (MemoryBufferRef MB : MBs)
+ Symtab.addFile(createFile(MB));
+ Symtab.step();
+
+ // Determine machine type and check if all object files are
+ // for the same CPU type. Note that this needs to be done before
+ // any call to mangle().
+ for (std::unique_ptr<InputFile> &File : Symtab.getFiles()) {
+ MachineTypes MT = File->getMachineType();
+ if (MT == IMAGE_FILE_MACHINE_UNKNOWN)
+ continue;
+ if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
+ Config->Machine = MT;
+ continue;
+ }
+ if (Config->Machine != MT)
+ error(Twine(File->getShortName()) + ": machine type " + machineToStr(MT) +
+ " conflicts with " + machineToStr(Config->Machine));
+ }
+ if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
+ llvm::errs() << "warning: /machine is not specified. x64 is assumed.\n";
+ Config->Machine = AMD64;
+ }
+
+ // Windows specific -- Convert Windows resource files to a COFF file.
+ if (!Resources.empty()) {
+ std::unique_ptr<MemoryBuffer> MB = convertResToCOFF(Resources);
+ Symtab.addFile(createFile(MB->getMemBufferRef()));
+ OwningMBs.push_back(std::move(MB)); // take ownership
+ }
+
+ // Handle /largeaddressaware
+ if (Config->is64() || Args.hasArg(OPT_largeaddressaware))
+ Config->LargeAddressAware = true;
+
+ // Handle /highentropyva
+ if (Config->is64() && !Args.hasArg(OPT_highentropyva_no))
+ Config->HighEntropyVA = true;
+
+ // Handle /entry and /dll
+ if (auto *Arg = Args.getLastArg(OPT_entry)) {
+ Config->Entry = addUndefined(mangle(Arg->getValue()));
+ } else if (Args.hasArg(OPT_dll) && !Config->NoEntry) {
+ StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12"
+ : "_DllMainCRTStartup";
+ Config->Entry = addUndefined(S);
+ } else if (!Config->NoEntry) {
+ // Windows specific -- If entry point name is not given, we need to
+ // infer that from user-defined entry name.
+ StringRef S = findDefaultEntry();
+ if (S.empty())
+ error("entry point must be defined");
+ Config->Entry = addUndefined(S);
+ if (Config->Verbose)
+ llvm::outs() << "Entry name inferred: " << S << "\n";
+ }
+
+ // Handle /export
+ for (auto *Arg : Args.filtered(OPT_export)) {
+ Export E = parseExport(Arg->getValue());
+ if (Config->Machine == I386) {
+ if (!isDecorated(E.Name))
+ E.Name = Alloc.save("_" + E.Name);
+ if (!E.ExtName.empty() && !isDecorated(E.ExtName))
+ E.ExtName = Alloc.save("_" + E.ExtName);
+ }
+ Config->Exports.push_back(E);
+ }
+
+ // Handle /def
+ if (auto *Arg = Args.getLastArg(OPT_deffile)) {
+ MemoryBufferRef MB = openFile(Arg->getValue());
+ // parseModuleDefs mutates Config object.
+ parseModuleDefs(MB, &Alloc);
+ }
+
+ // Handle /delayload
+ for (auto *Arg : Args.filtered(OPT_delayload)) {
+ Config->DelayLoads.insert(StringRef(Arg->getValue()).lower());
+ if (Config->Machine == I386) {
+ Config->DelayLoadHelper = addUndefined("___delayLoadHelper2@8");
+ } else {
+ Config->DelayLoadHelper = addUndefined("__delayLoadHelper2");
+ }
+ }
+
+ // Set default image base if /base is not given.
+ if (Config->ImageBase == uint64_t(-1))
+ Config->ImageBase = getDefaultImageBase();
+
+ Symtab.addRelative(mangle("__ImageBase"), 0);
+ if (Config->Machine == I386) {
+ Config->SEHTable = Symtab.addRelative("___safe_se_handler_table", 0);
+ Config->SEHCount = Symtab.addAbsolute("___safe_se_handler_count", 0);
+ }
+
+ // We do not support /guard:cf (control flow protection) yet.
+ // Define CFG symbols anyway so that we can link MSVC 2015 CRT.
+ Symtab.addAbsolute(mangle("__guard_fids_table"), 0);
+ Symtab.addAbsolute(mangle("__guard_fids_count"), 0);
+ Symtab.addAbsolute(mangle("__guard_flags"), 0x100);
+
+ // Read as much files as we can from directives sections.
+ Symtab.run();
+
+ // Resolve auxiliary symbols until we get a convergence.
+ // (Trying to resolve a symbol may trigger a Lazy symbol to load a new file.
+ // A new file may contain a directive section to add new command line options.
+ // That's why we have to repeat until converge.)
+ for (;;) {
+ // Windows specific -- if entry point is not found,
+ // search for its mangled names.
+ if (Config->Entry)
+ Symtab.mangleMaybe(Config->Entry);
+
+ // Windows specific -- Make sure we resolve all dllexported symbols.
+ for (Export &E : Config->Exports) {
+ E.Sym = addUndefined(E.Name);
+ if (!E.Directives)
+ Symtab.mangleMaybe(E.Sym);
+ }
+
+ // Add weak aliases. Weak aliases is a mechanism to give remaining
+ // undefined symbols final chance to be resolved successfully.
+ for (auto Pair : Config->AlternateNames) {
+ StringRef From = Pair.first;
+ StringRef To = Pair.second;
+ Symbol *Sym = Symtab.find(From);
+ if (!Sym)
+ continue;
+ if (auto *U = dyn_cast<Undefined>(Sym->Body))
+ if (!U->WeakAlias)
+ U->WeakAlias = Symtab.addUndefined(To);
+ }
+
+ // Windows specific -- if __load_config_used can be resolved, resolve it.
+ if (Symtab.findUnderscore("_load_config_used"))
+ addUndefined(mangle("_load_config_used"));
+
+ if (Symtab.queueEmpty())
+ break;
+ Symtab.run();
+ }
+
+ // Do LTO by compiling bitcode input files to a set of native COFF files then
+ // link those files.
+ Symtab.addCombinedLTOObjects();
+
+ // Make sure we have resolved all symbols.
+ Symtab.reportRemainingUndefines(/*Resolve=*/true);
+
+ // Windows specific -- if no /subsystem is given, we need to infer
+ // that from entry point name.
+ if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
+ Config->Subsystem = inferSubsystem();
+ if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
+ error("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");
+
+ // Windows specific -- when we are creating a .dll file, we also
+ // need to create a .lib file.
+ if (!Config->Exports.empty() || Config->DLL) {
+ fixupExports();
+ writeImportLibrary();
+ assignExportOrdinals();
+ }
+
+ // Windows specific -- Create a side-by-side manifest file.
+ if (Config->Manifest == Configuration::SideBySide)
+ createSideBySideManifest();
+
+ // Create a dummy PDB file to satisfy build sytem rules.
+ if (auto *Arg = Args.getLastArg(OPT_pdb))
+ createPDB(Arg->getValue());
+
+ // Identify unreferenced COMDAT sections.
+ if (Config->DoGC)
+ markLive(Symtab.getChunks());
+
+ // Identify identical COMDAT sections to merge them.
+ if (Config->DoICF)
+ doICF(Symtab.getChunks());
+
+ // Write the result.
+ writeResult(&Symtab);
+
+ // Create a symbol map file containing symbol VAs and their names
+ // to help debugging.
+ 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");
+ Symtab.printMap(Out);
+ }
+ // Call exit to avoid calling destructors.
+ exit(0);
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/Driver.h b/COFF/Driver.h
new file mode 100644
index 000000000000..e50da20cbb04
--- /dev/null
+++ b/COFF/Driver.h
@@ -0,0 +1,180 @@
+//===- Driver.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_DRIVER_H
+#define LLD_COFF_DRIVER_H
+
+#include "Config.h"
+#include "SymbolTable.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/StringSaver.h"
+#include <memory>
+#include <set>
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+class LinkerDriver;
+extern LinkerDriver *Driver;
+
+using llvm::COFF::MachineTypes;
+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);
+
+// Implemented in ICF.cpp.
+void doICF(const std::vector<Chunk *> &Chunks);
+
+class ArgParser {
+public:
+ ArgParser() : Alloc(AllocAux) {}
+ // Parses command line options.
+ llvm::opt::InputArgList parse(llvm::ArrayRef<const char *> Args);
+
+ // Concatenate LINK environment varirable and given arguments and parse them.
+ llvm::opt::InputArgList parseLINK(llvm::ArrayRef<const char *> Args);
+
+ // Tokenizes a given string and then parses as command line options.
+ llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); }
+
+private:
+ std::vector<const char *> tokenize(StringRef S);
+
+ std::vector<const char *> replaceResponseFiles(std::vector<const char *>);
+
+ llvm::BumpPtrAllocator AllocAux;
+ llvm::StringSaver Alloc;
+};
+
+class LinkerDriver {
+public:
+ LinkerDriver() : Alloc(AllocAux) {}
+ void link(llvm::ArrayRef<const char *> Args);
+
+ // Used by the resolver to parse .drectve section contents.
+ void parseDirectives(StringRef S);
+
+private:
+ llvm::BumpPtrAllocator AllocAux;
+ llvm::StringSaver Alloc;
+ ArgParser Parser;
+ SymbolTable Symtab;
+
+ // Opens a file. Path has to be resolved already.
+ MemoryBufferRef openFile(StringRef Path);
+
+ // Searches a file from search paths.
+ Optional<StringRef> findFile(StringRef Filename);
+ Optional<StringRef> findLib(StringRef Filename);
+ StringRef doFindFile(StringRef Filename);
+ StringRef doFindLib(StringRef Filename);
+
+ // Parses LIB environment which contains a list of search paths.
+ void addLibSearchPaths();
+
+ // Library search path. The first element is always "" (current directory).
+ std::vector<StringRef> SearchPaths;
+ std::set<std::string> VisitedFiles;
+
+ Undefined *addUndefined(StringRef Sym);
+ StringRef mangle(StringRef Sym);
+
+ // Windows specific -- "main" is not the only main function in Windows.
+ // You can choose one from these four -- {w,}{WinMain,main}.
+ // There are four different entry point functions for them,
+ // {w,}{WinMain,main}CRTStartup, respectively. The linker needs to
+ // choose the right one depending on which "main" function is defined.
+ // This function looks up the symbol table and resolve corresponding
+ // entry point name.
+ StringRef findDefaultEntry();
+ WindowsSubsystem inferSubsystem();
+
+ // Driver is the owner of all opened files.
+ // InputFiles have MemoryBufferRefs to them.
+ std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
+};
+
+void parseModuleDefs(MemoryBufferRef MB, llvm::StringSaver *Alloc);
+void writeImportLibrary();
+
+// Functions below this line are defined in DriverUtils.cpp.
+
+void printHelp(const char *Argv0);
+
+// For /machine option.
+MachineTypes getMachineType(StringRef Arg);
+StringRef machineToStr(MachineTypes MT);
+
+// Parses a string in the form of "<integer>[,<integer>]".
+void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr);
+
+// Parses a string in the form of "<integer>[.<integer>]".
+// Minor's default value is 0.
+void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor);
+
+// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
+void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
+ uint32_t *Minor);
+
+void parseAlternateName(StringRef);
+void parseMerge(StringRef);
+
+// Parses a string in the form of "EMBED[,=<integer>]|NO".
+void parseManifest(StringRef Arg);
+
+// Parses a string in the form of "level=<string>|uiAccess=<string>"
+void parseManifestUAC(StringRef Arg);
+
+// Create a resource file containing a manifest XML.
+std::unique_ptr<MemoryBuffer> createManifestRes();
+void createSideBySideManifest();
+
+// Used for dllexported symbols.
+Export parseExport(StringRef Arg);
+void fixupExports();
+void assignExportOrdinals();
+
+// Parses a string in the form of "key=value" and check
+// if value matches previous values for the key.
+// This feature used in the directive section to reject
+// incompatible objects.
+void checkFailIfMismatch(StringRef Arg);
+
+// Convert Windows resource files (.res files) to a .obj file
+// using cvtres.exe.
+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
+enum {
+ OPT_INVALID = 0,
+#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) OPT_##ID,
+#include "Options.inc"
+#undef OPTION
+};
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp
new file mode 100644
index 000000000000..391a8ab66420
--- /dev/null
+++ b/COFF/DriverUtils.cpp
@@ -0,0 +1,718 @@
+//===- DriverUtils.cpp ----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains utility functions for the driver. Because there
+// are so many small functions, we created this separate file to make
+// Driver.cpp less cluttered.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Config.h"
+#include "Driver.h"
+#include "Error.h"
+#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"
+#include <memory>
+
+using namespace llvm::COFF;
+using namespace llvm;
+using llvm::cl::ExpandResponseFiles;
+using llvm::cl::TokenizeWindowsCommandLine;
+using llvm::sys::Process;
+
+namespace lld {
+namespace coff {
+namespace {
+
+class Executor {
+public:
+ explicit Executor(StringRef S) : Saver(Alloc), 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)); }
+ void add(const char *S) { Args.push_back(Saver.save(S)); }
+
+ void run() {
+ ErrorOr<std::string> ExeOrErr = llvm::sys::findProgramByName(Prog);
+ error(ExeOrErr, Twine("unable to find ") + Prog + " in PATH: ");
+ const char *Exe = Saver.save(*ExeOrErr);
+ Args.insert(Args.begin(), Exe);
+ Args.push_back(nullptr);
+ if (llvm::sys::ExecuteAndWait(Args[0], Args.data()) != 0) {
+ for (const char *S : Args)
+ if (S)
+ llvm::errs() << S << " ";
+ error("failed");
+ }
+ }
+
+private:
+ llvm::BumpPtrAllocator Alloc;
+ llvm::StringSaver Saver;
+ StringRef Prog;
+ std::vector<const char *> Args;
+};
+
+} // anonymous namespace
+
+// Returns /machine's value.
+MachineTypes getMachineType(StringRef S) {
+ MachineTypes MT = StringSwitch<MachineTypes>(S.lower())
+ .Case("x64", AMD64)
+ .Case("amd64", AMD64)
+ .Case("x86", I386)
+ .Case("i386", I386)
+ .Case("arm", ARMNT)
+ .Default(IMAGE_FILE_MACHINE_UNKNOWN);
+ if (MT != IMAGE_FILE_MACHINE_UNKNOWN)
+ return MT;
+ error(Twine("unknown /machine argument: ") + S);
+}
+
+StringRef machineToStr(MachineTypes MT) {
+ switch (MT) {
+ case ARMNT:
+ return "arm";
+ case AMD64:
+ return "x64";
+ case I386:
+ return "x86";
+ default:
+ llvm_unreachable("unknown machine type");
+ }
+}
+
+// Parses a string in the form of "<integer>[,<integer>]".
+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);
+ if (Size && !S2.empty() && S2.getAsInteger(0, *Size))
+ error(Twine("invalid number: ") + S2);
+}
+
+// Parses a string in the form of "<integer>[.<integer>]".
+// If second number is not present, Minor is set to 0.
+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);
+ *Minor = 0;
+ if (!S2.empty() && S2.getAsInteger(0, *Minor))
+ error(Twine("invalid number: ") + S2);
+}
+
+// Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]".
+void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major,
+ uint32_t *Minor) {
+ StringRef SysStr, Ver;
+ std::tie(SysStr, Ver) = Arg.split(',');
+ *Sys = StringSwitch<WindowsSubsystem>(SysStr.lower())
+ .Case("boot_application", IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
+ .Case("console", IMAGE_SUBSYSTEM_WINDOWS_CUI)
+ .Case("efi_application", IMAGE_SUBSYSTEM_EFI_APPLICATION)
+ .Case("efi_boot_service_driver", IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)
+ .Case("efi_rom", IMAGE_SUBSYSTEM_EFI_ROM)
+ .Case("efi_runtime_driver", IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)
+ .Case("native", IMAGE_SUBSYSTEM_NATIVE)
+ .Case("posix", IMAGE_SUBSYSTEM_POSIX_CUI)
+ .Case("windows", IMAGE_SUBSYSTEM_WINDOWS_GUI)
+ .Default(IMAGE_SUBSYSTEM_UNKNOWN);
+ if (*Sys == IMAGE_SUBSYSTEM_UNKNOWN)
+ error(Twine("unknown subsystem: ") + SysStr);
+ if (!Ver.empty())
+ parseVersion(Ver, Major, Minor);
+}
+
+// Parse a string of the form of "<from>=<to>".
+// Results are directly written to Config.
+void parseAlternateName(StringRef S) {
+ StringRef From, To;
+ std::tie(From, To) = S.split('=');
+ if (From.empty() || To.empty())
+ error(Twine("/alternatename: invalid argument: ") + S);
+ auto It = Config->AlternateNames.find(From);
+ if (It != Config->AlternateNames.end() && It->second != To)
+ error(Twine("/alternatename: conflicts: ") + S);
+ Config->AlternateNames.insert(It, std::make_pair(From, To));
+}
+
+// Parse a string of the form of "<from>=<to>".
+// Results are directly written to Config.
+void parseMerge(StringRef S) {
+ StringRef From, To;
+ std::tie(From, To) = S.split('=');
+ if (From.empty() || To.empty())
+ error(Twine("/merge: invalid argument: ") + S);
+ auto Pair = Config->Merge.insert(std::make_pair(From, To));
+ bool Inserted = Pair.second;
+ if (!Inserted) {
+ StringRef Existing = Pair.first->second;
+ if (Existing != To)
+ llvm::errs() << "warning: " << S << ": already merged into "
+ << Existing << "\n";
+ }
+}
+
+// Parses a string in the form of "EMBED[,=<integer>]|NO".
+// Results are directly written to Config.
+void parseManifest(StringRef Arg) {
+ if (Arg.equals_lower("no")) {
+ Config->Manifest = Configuration::No;
+ return;
+ }
+ if (!Arg.startswith_lower("embed"))
+ error(Twine("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);
+ Arg = Arg.substr(strlen(",id="));
+ if (Arg.getAsInteger(0, Config->ManifestID))
+ error(Twine("Invalid option ") + Arg);
+}
+
+// Parses a string in the form of "level=<string>|uiAccess=<string>|NO".
+// Results are directly written to Config.
+void parseManifestUAC(StringRef Arg) {
+ if (Arg.equals_lower("no")) {
+ Config->ManifestUAC = false;
+ return;
+ }
+ for (;;) {
+ Arg = Arg.ltrim();
+ if (Arg.empty())
+ return;
+ if (Arg.startswith_lower("level=")) {
+ Arg = Arg.substr(strlen("level="));
+ std::tie(Config->ManifestLevel, Arg) = Arg.split(" ");
+ continue;
+ }
+ if (Arg.startswith_lower("uiaccess=")) {
+ Arg = Arg.substr(strlen("uiaccess="));
+ std::tie(Config->ManifestUIAccess, Arg) = Arg.split(" ");
+ continue;
+ }
+ error(Twine("Invalid option ") + Arg);
+ }
+}
+
+// Quote each line with "". Existing double-quote is converted
+// to two double-quotes.
+static void quoteAndPrint(raw_ostream &Out, StringRef S) {
+ while (!S.empty()) {
+ StringRef Line;
+ std::tie(Line, S) = S.split("\n");
+ if (Line.empty())
+ continue;
+ Out << '\"';
+ for (int I = 0, E = Line.size(); I != E; ++I) {
+ if (Line[I] == '\"') {
+ Out << "\"\"";
+ } else {
+ Out << Line[I];
+ }
+ }
+ Out << "\"\n";
+ }
+}
+
+// Create a manifest file contents.
+static std::string createManifestXml() {
+ std::string S;
+ llvm::raw_string_ostream OS(S);
+ // 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"
+ << "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\"\n"
+ << " manifestVersion=\"1.0\">\n";
+ if (Config->ManifestUAC) {
+ OS << " <trustInfo>\n"
+ << " <security>\n"
+ << " <requestedPrivileges>\n"
+ << " <requestedExecutionLevel level=" << Config->ManifestLevel
+ << " uiAccess=" << Config->ManifestUIAccess << "/>\n"
+ << " </requestedPrivileges>\n"
+ << " </security>\n"
+ << " </trustInfo>\n";
+ if (!Config->ManifestDependency.empty()) {
+ OS << " <dependency>\n"
+ << " <dependentAssembly>\n"
+ << " <assemblyIdentity " << Config->ManifestDependency << " />\n"
+ << " </dependentAssembly>\n"
+ << " </dependency>\n";
+ }
+ }
+ OS << "</assembly>\n";
+ OS.flush();
+ return S;
+}
+
+// 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");
+ FileRemover RCRemover(RCPath);
+
+ // Open the temporary file for writing.
+ llvm::raw_fd_ostream Out(RCPath, EC, sys::fs::F_Text);
+ error(EC, Twine("failed to open ") + RCPath);
+
+ // Write resource script to the RC file.
+ Out << "#define LANG_ENGLISH 9\n"
+ << "#define SUBLANG_DEFAULT 1\n"
+ << "#define APP_MANIFEST " << Config->ManifestID << "\n"
+ << "#define RT_MANIFEST 24\n"
+ << "LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT\n"
+ << "APP_MANIFEST RT_MANIFEST {\n";
+ quoteAndPrint(Out, createManifestXml());
+ Out << "}\n";
+ Out.close();
+
+ // Create output resource file.
+ SmallString<128> ResPath;
+ EC = sys::fs::createTemporaryFile("tmp", "res", ResPath);
+ error(EC, "cannot create a temporary file");
+
+ Executor E("rc.exe");
+ E.add("/fo");
+ E.add(ResPath.str());
+ 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);
+}
+
+void createSideBySideManifest() {
+ std::string Path = Config->ManifestFile;
+ if (Path == "")
+ Path = (Twine(Config->OutputFile) + ".manifest").str();
+ std::error_code EC;
+ llvm::raw_fd_ostream Out(Path, EC, llvm::sys::fs::F_Text);
+ error(EC, "failed to create manifest");
+ Out << createManifestXml();
+}
+
+// Parse a string in the form of
+// "<name>[=<internalname>][,@ordinal[,NONAME]][,DATA][,PRIVATE]".
+// Used for parsing /export arguments.
+Export parseExport(StringRef Arg) {
+ Export E;
+ StringRef Rest;
+ std::tie(E.Name, Rest) = Arg.split(",");
+ if (E.Name.empty())
+ goto err;
+ if (E.Name.find('=') != StringRef::npos) {
+ std::tie(E.ExtName, E.Name) = E.Name.split("=");
+ if (E.Name.empty())
+ goto err;
+ }
+
+ while (!Rest.empty()) {
+ StringRef Tok;
+ std::tie(Tok, Rest) = Rest.split(",");
+ if (Tok.equals_lower("noname")) {
+ if (E.Ordinal == 0)
+ goto err;
+ E.Noname = true;
+ continue;
+ }
+ if (Tok.equals_lower("data")) {
+ E.Data = true;
+ continue;
+ }
+ if (Tok.equals_lower("private")) {
+ E.Private = true;
+ continue;
+ }
+ if (Tok.startswith("@")) {
+ int32_t Ord;
+ if (Tok.substr(1).getAsInteger(0, Ord))
+ goto err;
+ if (Ord <= 0 || 65535 < Ord)
+ goto err;
+ E.Ordinal = Ord;
+ continue;
+ }
+ goto err;
+ }
+ return E;
+
+err:
+ error(Twine("invalid /export: ") + Arg);
+}
+
+static StringRef undecorate(StringRef Sym) {
+ if (Config->Machine != I386)
+ return Sym;
+ return Sym.startswith("_") ? Sym.substr(1) : Sym;
+}
+
+// Performs error checking on all /export arguments.
+// It also sets ordinals.
+void fixupExports() {
+ // Symbol ordinals must be unique.
+ std::set<uint16_t> Ords;
+ for (Export &E : Config->Exports) {
+ if (E.Ordinal == 0)
+ continue;
+ if (!Ords.insert(E.Ordinal).second)
+ error("duplicate export ordinal: " + E.Name);
+ }
+
+ for (Export &E : Config->Exports) {
+ if (Undefined *U = cast_or_null<Undefined>(E.Sym->WeakAlias)) {
+ E.SymbolName = U->getName();
+ } else {
+ E.SymbolName = E.Sym->getName();
+ }
+ }
+
+ for (Export &E : Config->Exports)
+ E.ExportName = undecorate(E.ExtName.empty() ? E.Name : E.ExtName);
+
+ // Uniquefy by name.
+ std::map<StringRef, Export *> Map;
+ std::vector<Export> V;
+ for (Export &E : Config->Exports) {
+ auto Pair = Map.insert(std::make_pair(E.ExportName, &E));
+ bool Inserted = Pair.second;
+ if (Inserted) {
+ V.push_back(E);
+ continue;
+ }
+ Export *Existing = Pair.first->second;
+ if (E == *Existing || E.Name != Existing->Name)
+ continue;
+ llvm::errs() << "warning: duplicate /export option: " << E.Name << "\n";
+ }
+ Config->Exports = std::move(V);
+
+ // Sort by name.
+ std::sort(Config->Exports.begin(), Config->Exports.end(),
+ [](const Export &A, const Export &B) {
+ return A.ExportName < B.ExportName;
+ });
+}
+
+void assignExportOrdinals() {
+ // Assign unique ordinals if default (= 0).
+ uint16_t Max = 0;
+ for (Export &E : Config->Exports)
+ Max = std::max(Max, E.Ordinal);
+ for (Export &E : Config->Exports)
+ if (E.Ordinal == 0)
+ E.Ordinal = ++Max;
+}
+
+// Parses a string in the form of "key=value" and check
+// if value matches previous values for the same key.
+void checkFailIfMismatch(StringRef Arg) {
+ StringRef K, V;
+ std::tie(K, V) = Arg.split('=');
+ if (K.empty() || V.empty())
+ error(Twine("/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);
+ Config->MustMatch[K] = V;
+}
+
+// Convert Windows resource files (.res files) to a .obj file
+// using cvtres.exe.
+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");
+
+ // Execute cvtres.exe.
+ Executor E("cvtres.exe");
+ E.add("/machine:" + machineToStr(Config->Machine));
+ E.add("/readonly");
+ E.add("/nologo");
+ E.add("/out:" + Path);
+ 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);
+}
+
+// Create OptTable
+
+// Create prefix string literals used in Options.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "Options.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in Options.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \
+ { \
+ X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, X8, X7, \
+ OPT_##GROUP, OPT_##ALIAS, X6 \
+ },
+#include "Options.inc"
+#undef OPTION
+};
+
+class COFFOptTable : public llvm::opt::OptTable {
+public:
+ COFFOptTable() : OptTable(infoTable, true) {}
+};
+
+// Parses a given list of options.
+llvm::opt::InputArgList ArgParser::parse(ArrayRef<const char *> ArgsArr) {
+ // First, replace respnose files (@<file>-style options).
+ std::vector<const char *> Argv = replaceResponseFiles(ArgsArr);
+
+ // Make InputArgList from string vectors.
+ COFFOptTable Table;
+ unsigned MissingIndex;
+ unsigned MissingCount;
+ llvm::opt::InputArgList Args =
+ Table.ParseArgs(Argv, MissingIndex, MissingCount);
+
+ // Print the real command line if response files are expanded.
+ if (Args.hasArg(OPT_verbose) && ArgsArr.size() != Argv.size()) {
+ llvm::outs() << "Command line:";
+ for (const char *S : Argv)
+ llvm::outs() << " " << S;
+ llvm::outs() << "\n";
+ }
+
+ if (MissingCount)
+ error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) +
+ "\", expected " + Twine(MissingCount) +
+ (MissingCount == 1 ? " argument." : " arguments."));
+ for (auto *Arg : Args.filtered(OPT_UNKNOWN))
+ llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n";
+ return Args;
+}
+
+llvm::opt::InputArgList ArgParser::parseLINK(ArrayRef<const char *> Args) {
+ // Concatenate LINK env and given arguments and parse them.
+ Optional<std::string> Env = Process::GetEnv("LINK");
+ if (!Env)
+ return parse(Args);
+ std::vector<const char *> V = tokenize(*Env);
+ V.insert(V.end(), Args.begin(), Args.end());
+ return parse(V);
+}
+
+std::vector<const char *> ArgParser::tokenize(StringRef S) {
+ SmallVector<const char *, 16> Tokens;
+ StringSaver Saver(AllocAux);
+ llvm::cl::TokenizeWindowsCommandLine(S, Saver, Tokens);
+ return std::vector<const char *>(Tokens.begin(), Tokens.end());
+}
+
+// Creates a new command line by replacing options starting with '@'
+// character. '@<filename>' is replaced by the file's contents.
+std::vector<const char *>
+ArgParser::replaceResponseFiles(std::vector<const char *> Argv) {
+ SmallVector<const char *, 256> Tokens(Argv.data(), Argv.data() + Argv.size());
+ StringSaver Saver(AllocAux);
+ ExpandResponseFiles(Saver, TokenizeWindowsCommandLine, Tokens);
+ return std::vector<const char *>(Tokens.begin(), Tokens.end());
+}
+
+void printHelp(const char *Argv0) {
+ COFFOptTable Table;
+ Table.PrintHelp(llvm::outs(), Argv0, "LLVM Linker", false);
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/Error.cpp b/COFF/Error.cpp
new file mode 100644
index 000000000000..255d9bbad9d8
--- /dev/null
+++ b/COFF/Error.cpp
@@ -0,0 +1,30 @@
+//===- Error.cpp ----------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace lld {
+namespace coff {
+
+void error(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());
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/Error.h b/COFF/Error.h
new file mode 100644
index 000000000000..cb0a185f0917
--- /dev/null
+++ b/COFF/Error.h
@@ -0,0 +1,28 @@
+//===- Error.h --------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_ERROR_H
+#define LLD_COFF_ERROR_H
+
+#include "lld/Core/LLVM.h"
+
+namespace lld {
+namespace coff {
+
+LLVM_ATTRIBUTE_NORETURN void error(const Twine &Msg);
+void error(std::error_code EC, const Twine &Prefix);
+
+template <typename T> void error(const ErrorOr<T> &V, const Twine &Prefix) {
+ error(V.getError(), Prefix);
+}
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/ICF.cpp b/COFF/ICF.cpp
new file mode 100644
index 000000000000..f99b41624a84
--- /dev/null
+++ b/COFF/ICF.cpp
@@ -0,0 +1,244 @@
+//===- ICF.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Identical COMDAT Folding is a feature to merge COMDAT sections not by
+// name (which is regular COMDAT handling) but by contents. If two COMDAT
+// sections have the same data, relocations, attributes, etc., then the two
+// are considered identical and merged by the linker. This optimization
+// makes outputs smaller.
+//
+// ICF is theoretically a problem of reducing graphs by merging as many
+// identical subgraphs as possible, if we consider sections as vertices and
+// relocations as edges. This may be a bit more complicated problem than you
+// might think. The order of processing sections matters since merging two
+// sections can make other sections, whose relocations now point to the same
+// section, mergeable. Graphs may contain cycles, which is common in COFF.
+// We need a sophisticated algorithm to do this properly and efficiently.
+//
+// What we do in this file is this. We split sections into groups. Sections
+// in the same group are considered identical.
+//
+// First, all sections are grouped by their "constant" values. Constant
+// values are values that are never changed by ICF, such as section contents,
+// section name, number of relocations, type and offset of each relocation,
+// etc. Because we do not care about some relocation targets in this step,
+// two sections in the same group may not be identical, but at least two
+// sections in different groups can never be identical.
+//
+// Then, we try to split each group by relocation targets. Relocations are
+// considered identical if and only if the relocation targets are in the
+// same group. Splitting a group may make more groups to be splittable,
+// because two relocations that were previously considered identical might
+// now point to different groups. We repeat this step until the convergence
+// is obtained.
+//
+// This algorithm is so-called "optimistic" algorithm described in
+// http://research.google.com/pubs/pub36912.html.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Chunks.h"
+#include "Symbols.h"
+#include "lld/Core/Parallel.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <atomic>
+#include <vector>
+
+using namespace llvm;
+
+namespace lld {
+namespace coff {
+
+typedef std::vector<SectionChunk *>::iterator ChunkIterator;
+typedef bool (*Comparator)(const SectionChunk *, const SectionChunk *);
+
+class ICF {
+public:
+ void run(const std::vector<Chunk *> &V);
+
+private:
+ static uint64_t getHash(SectionChunk *C);
+ 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);
+
+ std::atomic<uint64_t> NextID = { 1 };
+};
+
+// Entry point to ICF.
+void doICF(const std::vector<Chunk *> &Chunks) {
+ ICF().run(Chunks);
+}
+
+uint64_t ICF::getHash(SectionChunk *C) {
+ return hash_combine(C->getPermissions(),
+ hash_value(C->SectionName),
+ C->NumRelocs,
+ C->getAlign(),
+ uint32_t(C->Header->SizeOfRawData),
+ C->Checksum);
+}
+
+bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) {
+ if (A->AssocChildren.size() != B->AssocChildren.size() ||
+ A->NumRelocs != B->NumRelocs) {
+ return false;
+ }
+
+ // Compare associative sections.
+ for (size_t I = 0, E = A->AssocChildren.size(); I != E; ++I)
+ if (A->AssocChildren[I]->GroupID != B->AssocChildren[I]->GroupID)
+ return false;
+
+ // Compare relocations.
+ auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) {
+ if (R1.Type != R2.Type ||
+ R1.VirtualAddress != R2.VirtualAddress) {
+ return false;
+ }
+ SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex)->repl();
+ SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex)->repl();
+ if (B1 == B2)
+ return true;
+ if (auto *D1 = dyn_cast<DefinedRegular>(B1))
+ if (auto *D2 = dyn_cast<DefinedRegular>(B2))
+ return D1->getValue() == D2->getValue() &&
+ D1->getChunk()->GroupID == D2->getChunk()->GroupID;
+ return false;
+ };
+ if (!std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq))
+ return false;
+
+ // Compare section attributes and contents.
+ return A->getPermissions() == B->getPermissions() &&
+ A->SectionName == B->SectionName &&
+ A->getAlign() == B->getAlign() &&
+ A->Header->SizeOfRawData == B->Header->SizeOfRawData &&
+ A->Checksum == B->Checksum &&
+ A->getContents() == B->getContents();
+}
+
+bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) {
+ // Compare associative sections.
+ for (size_t I = 0, E = A->AssocChildren.size(); I != E; ++I)
+ if (A->AssocChildren[I]->GroupID != B->AssocChildren[I]->GroupID)
+ return false;
+
+ // Compare relocations.
+ auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) {
+ SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex)->repl();
+ SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex)->repl();
+ if (B1 == B2)
+ return true;
+ if (auto *D1 = dyn_cast<DefinedRegular>(B1))
+ if (auto *D2 = dyn_cast<DefinedRegular>(B2))
+ return D1->getChunk()->GroupID == D2->getChunk()->GroupID;
+ return false;
+ };
+ return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq);
+}
+
+bool ICF::partition(ChunkIterator Begin, ChunkIterator End, Comparator Eq) {
+ bool R = false;
+ for (auto It = Begin;;) {
+ SectionChunk *Head = *It;
+ auto Bound = std::partition(It + 1, End, [&](SectionChunk *SC) {
+ return Eq(Head, SC);
+ });
+ if (Bound == End)
+ return R;
+ uint64_t ID = NextID++;
+ std::for_each(It, Bound, [&](SectionChunk *SC) { SC->GroupID = ID; });
+ It = Bound;
+ R = true;
+ }
+}
+
+bool ICF::forEachGroup(std::vector<SectionChunk *> &Chunks, Comparator Eq) {
+ bool R = false;
+ for (auto It = Chunks.begin(), End = Chunks.end(); It != End;) {
+ SectionChunk *Head = *It;
+ auto Bound = std::find_if(It + 1, End, [&](SectionChunk *SC) {
+ return SC->GroupID != Head->GroupID;
+ });
+ if (partition(It, Bound, Eq))
+ R = true;
+ It = Bound;
+ }
+ return R;
+}
+
+// Merge identical COMDAT sections.
+// Two sections are considered the same if their section headers,
+// contents and relocations are all the same.
+void ICF::run(const std::vector<Chunk *> &Vec) {
+ // Collect only mergeable sections and group by hash value.
+ parallel_for_each(Vec.begin(), Vec.end(), [&](Chunk *C) {
+ if (auto *SC = dyn_cast<SectionChunk>(C)) {
+ bool Global = SC->Sym && SC->Sym->isExternal();
+ bool Writable = SC->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
+ if (SC->isCOMDAT() && SC->isLive() && Global && !Writable)
+ SC->GroupID = getHash(SC) | (uint64_t(1) << 63);
+ }
+ });
+ std::vector<SectionChunk *> Chunks;
+ for (Chunk *C : Vec) {
+ if (auto *SC = dyn_cast<SectionChunk>(C)) {
+ if (SC->GroupID) {
+ Chunks.push_back(SC);
+ } else {
+ SC->GroupID = NextID++;
+ }
+ }
+ }
+
+ // From now on, sections in Chunks are ordered so that sections in
+ // the same group are consecutive in the vector.
+ std::sort(Chunks.begin(), Chunks.end(),
+ [](SectionChunk *A, SectionChunk *B) {
+ return A->GroupID < B->GroupID;
+ });
+
+ // Split groups until we get a convergence.
+ int Cnt = 1;
+ forEachGroup(Chunks, equalsConstant);
+
+ for (;;) {
+ if (!forEachGroup(Chunks, equalsVariable))
+ break;
+ ++Cnt;
+ }
+ if (Config->Verbose)
+ llvm::outs() << "\nICF needed " << Cnt << " iterations.\n";
+
+ // Merge sections in the same group.
+ for (auto It = Chunks.begin(), End = Chunks.end(); It != End;) {
+ SectionChunk *Head = *It++;
+ auto Bound = std::find_if(It, End, [&](SectionChunk *SC) {
+ return Head->GroupID != SC->GroupID;
+ });
+ if (It == Bound)
+ continue;
+ if (Config->Verbose)
+ llvm::outs() << "Selected " << Head->getDebugName() << "\n";
+ while (It != Bound) {
+ SectionChunk *SC = *It++;
+ if (Config->Verbose)
+ llvm::outs() << " Removed " << SC->getDebugName() << "\n";
+ Head->replace(SC);
+ }
+ }
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp
new file mode 100644
index 000000000000..23fc2a085122
--- /dev/null
+++ b/COFF/InputFiles.cpp
@@ -0,0 +1,367 @@
+//===- InputFiles.cpp -----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Chunks.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/LTO/LTOModule.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/COFF.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm::COFF;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using llvm::RoundUpToAlignment;
+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;
+
+// Returns the last element of a path, which is supposed to be a filename.
+static StringRef getBasename(StringRef Path) {
+ size_t Pos = Path.find_last_of("\\/");
+ if (Pos == StringRef::npos)
+ return Path;
+ return Path.substr(Pos + 1);
+}
+
+// Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)".
+std::string InputFile::getShortName() {
+ if (ParentName == "")
+ return getName().lower();
+ std::string Res = (getBasename(ParentName) + "(" +
+ getBasename(getName()) + ")").str();
+ return StringRef(Res).lower();
+}
+
+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);
+
+ // Allocate a buffer for Lazy objects.
+ size_t NumSyms = File->getNumberOfSymbols();
+ LazySymbols.reserve(NumSyms);
+
+ // Read the symbol table to construct Lazy objects.
+ for (const Archive::Symbol &Sym : File->symbols())
+ LazySymbols.emplace_back(this, Sym);
+
+ // 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;
+ Seen[Child.getChildOffset()].clear();
+ }
+}
+
+// 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;
+
+ // 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;
+}
+
+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);
+
+ if (auto *Obj = dyn_cast<COFFObjectFile>(Bin.get())) {
+ Bin.release();
+ COFFObj.reset(Obj);
+ } else {
+ error(Twine(getName()) + " is not a COFF file.");
+ }
+
+ // Read section and symbol tables.
+ initializeChunks();
+ initializeSymbols();
+ initializeSEH();
+}
+
+void ObjectFile::initializeChunks() {
+ uint32_t NumSections = COFFObj->getNumberOfSections();
+ Chunks.reserve(NumSections);
+ SparseChunks.resize(NumSections + 1);
+ 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 (Name == ".sxdata") {
+ SXData = Sec;
+ continue;
+ }
+ if (Name == ".drectve") {
+ ArrayRef<uint8_t> Data;
+ COFFObj->getSectionContents(Sec, Data);
+ Directives = std::string((const char *)Data.data(), Data.size());
+ continue;
+ }
+ // Skip non-DWARF debug info. MSVC linker converts the sections into
+ // a PDB file, but we don't support that.
+ if (Name == ".debug" || Name.startswith(".debug$"))
+ continue;
+ // We want to preserve DWARF debug sections only when /debug is on.
+ if (!Config->Debug && Name.startswith(".debug"))
+ continue;
+ if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE)
+ continue;
+ auto *C = new (Alloc) SectionChunk(this, Sec);
+ Chunks.push_back(C);
+ SparseChunks[I] = C;
+ }
+}
+
+void ObjectFile::initializeSymbols() {
+ uint32_t NumSymbols = COFFObj->getNumberOfSymbols();
+ SymbolBodies.reserve(NumSymbols);
+ SparseSymbolBodies.resize(NumSymbols);
+ llvm::SmallVector<Undefined *, 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;
+
+ const void *AuxP = nullptr;
+ if (Sym.getNumberOfAuxSymbols())
+ AuxP = COFFObj->getSymbol(I + 1)->getRawPtr();
+ bool IsFirst = (LastSectionNumber != Sym.getSectionNumber());
+
+ SymbolBody *Body = nullptr;
+ if (Sym.isUndefined()) {
+ Body = createUndefined(Sym);
+ } else if (Sym.isWeakExternal()) {
+ Body = createWeakExternal(Sym, AuxP);
+ WeakAliases.push_back((Undefined *)Body);
+ } else {
+ Body = createDefined(Sym, AuxP, IsFirst);
+ }
+ if (Body) {
+ SymbolBodies.push_back(Body);
+ SparseSymbolBodies[I] = Body;
+ }
+ I += Sym.getNumberOfAuxSymbols();
+ LastSectionNumber = Sym.getSectionNumber();
+ }
+ for (Undefined *U : WeakAliases)
+ U->WeakAlias = SparseSymbolBodies[(uintptr_t)U->WeakAlias];
+}
+
+Undefined *ObjectFile::createUndefined(COFFSymbolRef Sym) {
+ StringRef Name;
+ COFFObj->getSymbolName(Sym, Name);
+ 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;
+ if (Sym.isCommon()) {
+ auto *C = new (Alloc) CommonChunk(Sym);
+ Chunks.push_back(C);
+ return new (Alloc) DefinedCommon(this, Sym, C);
+ }
+ if (Sym.isAbsolute()) {
+ COFFObj->getSymbolName(Sym, Name);
+ // Skip special symbols.
+ if (Name == "@comp.id")
+ return nullptr;
+ // COFF spec 5.10.1. The .sxdata section.
+ if (Name == "@feat.00") {
+ if (Sym.getValue() & 1)
+ SEHCompat = true;
+ return nullptr;
+ }
+ return new (Alloc) DefinedAbsolute(Name, Sym);
+ }
+ if (Sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_DEBUG)
+ return nullptr;
+
+ // Nothing else to do without a section chunk.
+ auto *SC = cast_or_null<SectionChunk>(SparseChunks[Sym.getSectionNumber()]);
+ if (!SC)
+ return nullptr;
+
+ // Handle section definitions
+ if (IsFirst && AuxP) {
+ auto *Aux = reinterpret_cast<const coff_aux_section_definition *>(AuxP);
+ if (Aux->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE)
+ if (auto *ParentSC = cast_or_null<SectionChunk>(
+ SparseChunks[Aux->getNumber(Sym.isBigObj())]))
+ ParentSC->addAssociative(SC);
+ SC->Checksum = Aux->CheckSum;
+ }
+
+ auto *B = new (Alloc) DefinedRegular(this, Sym, SC);
+ if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP)
+ SC->setSymbol(B);
+
+ return B;
+}
+
+void ObjectFile::initializeSEH() {
+ if (!SEHCompat || !SXData)
+ return;
+ ArrayRef<uint8_t> A;
+ COFFObj->getSectionContents(SXData, A);
+ if (A.size() % 4 != 0)
+ error(".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)
+ SEHandlers.insert(SparseSymbolBodies[*I]);
+}
+
+MachineTypes ObjectFile::getMachineType() {
+ if (COFFObj)
+ return static_cast<MachineTypes>(COFFObj->getMachine());
+ return IMAGE_FILE_MACHINE_UNKNOWN;
+}
+
+StringRef ltrim1(StringRef S, const char *Chars) {
+ if (!S.empty() && strchr(Chars, S[0]))
+ return S.substr(1);
+ return S;
+}
+
+void ImportFile::parse() {
+ const char *Buf = MB.getBufferStart();
+ const char *End = MB.getBufferEnd();
+ const auto *Hdr = reinterpret_cast<const coff_import_header *>(Buf);
+
+ // Check if the total size is valid.
+ if ((size_t)(End - Buf) != (sizeof(*Hdr) + Hdr->SizeOfData))
+ error("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);
+ const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1;
+ DLLName = StringRef(NameStart);
+ StringRef ExtName;
+ switch (Hdr->getNameType()) {
+ case IMPORT_ORDINAL:
+ ExtName = "";
+ break;
+ case IMPORT_NAME:
+ ExtName = Name;
+ break;
+ case IMPORT_NAME_NOPREFIX:
+ ExtName = ltrim1(Name, "?@_");
+ break;
+ case IMPORT_NAME_UNDECORATE:
+ ExtName = ltrim1(Name, "?@_");
+ ExtName = ExtName.substr(0, ExtName.find('@'));
+ break;
+ }
+ ImpSym = new (Alloc) DefinedImportData(DLLName, ImpName, ExtName, Hdr);
+ SymbolBodies.push_back(ImpSym);
+
+ // If type is function, we need to create a thunk which jump to an
+ // address pointed by the __imp_ symbol. (This allows you to call
+ // DLL functions just like regular non-DLL functions.)
+ if (Hdr->getType() != llvm::COFF::IMPORT_CODE)
+ return;
+ ThunkSym = new (Alloc) DefinedImportThunk(Name, ImpSym, Hdr->Machine);
+ SymbolBodies.push_back(ThunkSym);
+}
+
+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);
+
+ llvm::StringSaver Saver(Alloc);
+ for (unsigned I = 0, E = M->getSymbolCount(); I != E; ++I) {
+ lto_symbol_attributes Attrs = M->getSymbolAttributes(I);
+ if ((Attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL)
+ continue;
+
+ StringRef SymName = Saver.save(M->getSymbolName(I));
+ int SymbolDef = Attrs & LTO_SYMBOL_DEFINITION_MASK;
+ if (SymbolDef == LTO_SYMBOL_DEFINITION_UNDEFINED) {
+ SymbolBodies.push_back(new (Alloc) Undefined(SymName));
+ } else {
+ bool Replaceable =
+ (SymbolDef == LTO_SYMBOL_DEFINITION_TENTATIVE || // common
+ (Attrs & LTO_SYMBOL_COMDAT) || // comdat
+ (SymbolDef == LTO_SYMBOL_DEFINITION_WEAK && // weak external
+ (Attrs & LTO_SYMBOL_ALIAS)));
+ SymbolBodies.push_back(new (Alloc) DefinedBitcode(this, SymName,
+ Replaceable));
+ }
+ }
+
+ Directives = M->getLinkerOpts();
+}
+
+MachineTypes BitcodeFile::getMachineType() {
+ if (!M)
+ return IMAGE_FILE_MACHINE_UNKNOWN;
+ switch (Triple(M->getTargetTriple()).getArch()) {
+ case Triple::x86_64:
+ return AMD64;
+ case Triple::x86:
+ return I386;
+ case Triple::arm:
+ return ARMNT;
+ default:
+ return IMAGE_FILE_MACHINE_UNKNOWN;
+ }
+}
+
+std::mutex BitcodeFile::Mu;
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h
new file mode 100644
index 000000000000..6a263fbaddf6
--- /dev/null
+++ b/COFF/InputFiles.h
@@ -0,0 +1,222 @@
+//===- InputFiles.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_INPUT_FILES_H
+#define LLD_COFF_INPUT_FILES_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/LTO/LTOModule.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/StringSaver.h"
+#include <memory>
+#include <mutex>
+#include <set>
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+using llvm::LTOModule;
+using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
+using llvm::COFF::MachineTypes;
+using llvm::object::Archive;
+using llvm::object::COFFObjectFile;
+using llvm::object::COFFSymbolRef;
+using llvm::object::coff_section;
+
+class Chunk;
+class Defined;
+class DefinedImportData;
+class DefinedImportThunk;
+class Lazy;
+class SymbolBody;
+class Undefined;
+
+// The root class of input files.
+class InputFile {
+public:
+ enum Kind { ArchiveKind, ObjectKind, ImportKind, BitcodeKind };
+ Kind kind() const { return FileKind; }
+ virtual ~InputFile() {}
+
+ // Returns the filename.
+ StringRef getName() { return MB.getBufferIdentifier(); }
+
+ // Returns symbols defined by this file.
+ virtual std::vector<SymbolBody *> &getSymbols() = 0;
+
+ // Reads a file (the constructor doesn't do that).
+ virtual void parse() = 0;
+
+ // Returns the CPU type this file was compiled to.
+ virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; }
+
+ // Returns a short, human-friendly filename. If this is a member of
+ // an archive file, a returned value includes parent's filename.
+ // Used for logging or debugging.
+ std::string getShortName();
+
+ // Sets a parent filename if this file is created from an archive.
+ void setParentName(StringRef N) { ParentName = N; }
+
+ // Returns .drectve section contents if exist.
+ StringRef getDirectives() { return StringRef(Directives).trim(); }
+
+ // Each file has a unique index. The index number is used to
+ // resolve ties in symbol resolution.
+ int Index;
+ static int NextIndex;
+
+protected:
+ InputFile(Kind K, MemoryBufferRef M)
+ : Index(NextIndex++), MB(M), FileKind(K) {}
+
+ MemoryBufferRef MB;
+ std::string Directives;
+
+private:
+ const Kind FileKind;
+ StringRef ParentName;
+};
+
+// .lib or .a file.
+class ArchiveFile : public InputFile {
+public:
+ explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
+ static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
+ void parse() override;
+
+ // Returns a memory buffer for a given symbol. An empty memory buffer
+ // is returned if we have already returned the same memory buffer.
+ // (So that we don't instantiate same members more than once.)
+ MemoryBufferRef getMember(const Archive::Symbol *Sym);
+
+ llvm::MutableArrayRef<Lazy> getLazySymbols() { return LazySymbols; }
+
+ // All symbols returned by ArchiveFiles are of Lazy type.
+ std::vector<SymbolBody *> &getSymbols() override {
+ llvm_unreachable("internal error");
+ }
+
+private:
+ std::unique_ptr<Archive> File;
+ std::string Filename;
+ std::vector<Lazy> LazySymbols;
+ std::map<uint64_t, std::atomic_flag> Seen;
+};
+
+// .obj or .o file. This may be a member of an archive file.
+class ObjectFile : public InputFile {
+public:
+ explicit ObjectFile(MemoryBufferRef M) : InputFile(ObjectKind, M) {}
+ static bool classof(const InputFile *F) { return F->kind() == ObjectKind; }
+ void parse() override;
+ MachineTypes getMachineType() override;
+ std::vector<Chunk *> &getChunks() { return Chunks; }
+ std::vector<SymbolBody *> &getSymbols() override { return SymbolBodies; }
+
+ // Returns a SymbolBody object for the SymbolIndex'th symbol in the
+ // underlying object file.
+ SymbolBody *getSymbolBody(uint32_t SymbolIndex) {
+ return SparseSymbolBodies[SymbolIndex];
+ }
+
+ // Returns the underying COFF file.
+ COFFObjectFile *getCOFFObj() { return COFFObj.get(); }
+
+ // True if this object file is compatible with SEH.
+ // COFF-specific and x86-only.
+ bool SEHCompat = false;
+
+ // The list of safe exception handlers listed in .sxdata section.
+ // COFF-specific and x86-only.
+ std::set<SymbolBody *> SEHandlers;
+
+private:
+ void initializeChunks();
+ void initializeSymbols();
+ void initializeSEH();
+
+ 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;
+ const coff_section *SXData = nullptr;
+
+ // List of all chunks defined by this file. This includes both section
+ // chunks and non-section chunks for common symbols.
+ std::vector<Chunk *> Chunks;
+
+ // This vector contains the same chunks as Chunks, but they are
+ // indexed such that you can get a SectionChunk by section index.
+ // Nonexistent section indices are filled with null pointers.
+ // (Because section number is 1-based, the first slot is always a
+ // null pointer.)
+ std::vector<Chunk *> SparseChunks;
+
+ // List of all symbols referenced or defined by this file.
+ std::vector<SymbolBody *> SymbolBodies;
+
+ // This vector contains the same symbols as SymbolBodies, but they
+ // are indexed such that you can get a SymbolBody by symbol
+ // index. Nonexistent indices (which are occupied by auxiliary
+ // symbols in the real symbol table) are filled with null pointers.
+ std::vector<SymbolBody *> SparseSymbolBodies;
+};
+
+// This type represents import library members that contain DLL names
+// and symbols exported from the DLLs. See Microsoft PE/COFF spec. 7
+// for details about the format.
+class ImportFile : public InputFile {
+public:
+ explicit ImportFile(MemoryBufferRef M)
+ : InputFile(ImportKind, M), StringAlloc(StringAllocAux) {}
+ static bool classof(const InputFile *F) { return F->kind() == ImportKind; }
+ std::vector<SymbolBody *> &getSymbols() override { return SymbolBodies; }
+
+ DefinedImportData *ImpSym = nullptr;
+ DefinedImportThunk *ThunkSym = nullptr;
+ std::string DLLName;
+
+private:
+ void parse() override;
+
+ std::vector<SymbolBody *> SymbolBodies;
+ llvm::BumpPtrAllocator Alloc;
+ llvm::BumpPtrAllocator StringAllocAux;
+ llvm::StringSaver StringAlloc;
+};
+
+// Used for LTO.
+class BitcodeFile : public InputFile {
+public:
+ explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {}
+ 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); }
+
+private:
+ void parse() override;
+
+ std::vector<SymbolBody *> SymbolBodies;
+ llvm::BumpPtrAllocator Alloc;
+ std::unique_ptr<LTOModule> M;
+ static std::mutex Mu;
+};
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/MarkLive.cpp b/COFF/MarkLive.cpp
new file mode 100644
index 000000000000..0870986ad81a
--- /dev/null
+++ b/COFF/MarkLive.cpp
@@ -0,0 +1,61 @@
+//===- MarkLive.cpp -------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Chunks.h"
+#include "Symbols.h"
+#include "llvm/ADT/STLExtras.h"
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+// Set live bit on for each reachable chunk. Unmarked (unreachable)
+// COMDAT chunks will be ignored by Writer, so they will be excluded
+// from the final output.
+void markLive(const std::vector<Chunk *> &Chunks) {
+ // We build up a worklist of sections which have been marked as live. We only
+ // push into the worklist when we discover an unmarked section, and we mark
+ // as we push, so sections never appear twice in the list.
+ SmallVector<SectionChunk *, 256> Worklist;
+
+ // COMDAT section chunks are dead by default. Add non-COMDAT chunks.
+ for (Chunk *C : Chunks)
+ if (auto *SC = dyn_cast<SectionChunk>(C))
+ if (SC->isLive())
+ Worklist.push_back(SC);
+
+ auto Enqueue = [&](SectionChunk *C) {
+ if (C->isLive())
+ return;
+ C->markLive();
+ Worklist.push_back(C);
+ };
+
+ // Add GC root chunks.
+ for (Undefined *U : Config->GCRoot)
+ if (auto *D = dyn_cast<DefinedRegular>(U->repl()))
+ Enqueue(D->getChunk());
+
+ while (!Worklist.empty()) {
+ SectionChunk *SC = Worklist.pop_back_val();
+ assert(SC->isLive() && "We mark as live when pushing onto the worklist!");
+
+ // Mark all symbols listed in the relocation table for this section.
+ for (SymbolBody *S : SC->symbols())
+ if (auto *D = dyn_cast<DefinedRegular>(S->repl()))
+ Enqueue(D->getChunk());
+
+ // Mark associative sections if any.
+ for (SectionChunk *C : SC->children())
+ Enqueue(C);
+ }
+}
+
+}
+}
diff --git a/COFF/ModuleDef.cpp b/COFF/ModuleDef.cpp
new file mode 100644
index 000000000000..d117e961f89a
--- /dev/null
+++ b/COFF/ModuleDef.cpp
@@ -0,0 +1,291 @@
+//===- 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 "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,
+ 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("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, StringSaver *A) : Lex(S), Alloc(A) {}
+
+ 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))
+ error("integer expected");
+ }
+
+ void expect(Kind Expected, StringRef Msg) {
+ read();
+ if (Tok.K != Expected)
+ error(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 KwLibrary:
+ parseName(&Config->OutputFile, &Config->ImageBase);
+ if (!StringRef(Config->OutputFile).endswith_lower(".dll"))
+ Config->OutputFile += ".dll";
+ return;
+ case KwStacksize:
+ parseNumbers(&Config->StackReserve, &Config->StackCommit);
+ return;
+ case KwName:
+ parseName(&Config->OutputFile, &Config->ImageBase);
+ return;
+ case KwVersion:
+ parseVersion(&Config->MajorImageVersion, &Config->MinorImageVersion);
+ return;
+ default:
+ error(Twine("unknown directive: ") + Tok.Value);
+ }
+ }
+
+ void parseExport() {
+ Export E;
+ E.Name = Tok.Value;
+ read();
+ if (Tok.K == Equal) {
+ read();
+ if (Tok.K != Identifier)
+ error(Twine("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 = Alloc->save("_" + E.Name);
+ if (!E.ExtName.empty() && !isDecorated(E.ExtName))
+ E.ExtName = Alloc->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 == 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)
+ error(Twine("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);
+ if (V2.empty())
+ *Minor = 0;
+ else if (V2.getAsInteger(10, *Minor))
+ error(Twine("integer expected, but got ") + Tok.Value);
+ }
+
+ Lexer Lex;
+ Token Tok;
+ std::vector<Token> Stack;
+ StringSaver *Alloc;
+};
+
+} // anonymous namespace
+
+void parseModuleDefs(MemoryBufferRef MB, StringSaver *Alloc) {
+ Parser(MB.getBuffer(), Alloc).parse();
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/Options.td b/COFF/Options.td
new file mode 100644
index 000000000000..a21b8de76afb
--- /dev/null
+++ b/COFF/Options.td
@@ -0,0 +1,125 @@
+include "llvm/Option/OptParser.td"
+
+// link.exe accepts options starting with either a dash or a slash.
+
+// Flag that takes no arguments.
+class F<string name> : Flag<["/", "-", "-?"], name>;
+
+// Flag that takes one argument after ":".
+class P<string name, string help> :
+ Joined<["/", "-", "-?"], name#":">, HelpText<help>;
+
+// Boolean flag suffixed by ":no".
+multiclass B<string name, string help> {
+ def "" : F<name>;
+ def _no : F<name#":no">, HelpText<help>;
+}
+
+def align : P<"align", "Section alignment">;
+def alternatename : P<"alternatename", "Define weak alias">;
+def base : P<"base", "Base address of the program">;
+def defaultlib : P<"defaultlib", "Add the library to the list of input files">;
+def delayload : P<"delayload", "Delay loaded DLL name">;
+def entry : P<"entry", "Name of entry point symbol">;
+def export : P<"export", "Export a function">;
+// No help text because /failifmismatch is not intended to be used by the user.
+def failifmismatch : P<"failifmismatch", "">;
+def heap : P<"heap", "Size of the heap">;
+def implib : P<"implib", "Import library name">;
+def libpath : P<"libpath", "Additional library search path">;
+def machine : P<"machine", "Specify target platform">;
+def merge : P<"merge", "Combine sections">;
+def mllvm : P<"mllvm", "Options to pass to LLVM">;
+def nodefaultlib : P<"nodefaultlib", "Remove a default library">;
+def opt : P<"opt", "Control optimizations">;
+def out : P<"out", "Path to file to write output">;
+def pdb : P<"pdb", "PDB file path">;
+def section : P<"section", "Specify section attributes">;
+def stack : P<"stack", "Size of the stack">;
+def stub : P<"stub", "Specify DOS stub file">;
+def subsystem : P<"subsystem", "Specify subsystem">;
+def version : P<"version", "Specify a version number in the PE header">;
+
+def disallowlib : Joined<["/", "-", "-?"], "disallowlib:">, Alias<nodefaultlib>;
+
+def manifest : F<"manifest">;
+def manifest_colon : P<"manifest", "Create manifest file">;
+def manifestuac : P<"manifestuac", "User access control">;
+def manifestfile : P<"manifestfile", "Manifest file path">;
+def manifestdependency : P<"manifestdependency",
+ "Attributes for <dependency> in 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
+// a reserved keyword in tablegen.
+def incl : Joined<["/", "-"], "include:">,
+ HelpText<"Force symbol to be added to symbol table as undefined one">;
+
+// "def" is also a keyword.
+def deffile : Joined<["/", "-"], "def:">,
+ HelpText<"Use module-definition file">;
+
+def debug : F<"debug">, HelpText<"Embed a symbol table in the image">;
+def dll : F<"dll">, HelpText<"Create a DLL">;
+def nodefaultlib_all : F<"nodefaultlib">;
+def noentry : F<"noentry">;
+def profile : F<"profile">;
+def swaprun_cd : F<"swaprun:cd">;
+def swaprun_net : F<"swaprun:net">;
+def verbose : F<"verbose">;
+
+def force : F<"force">,
+ HelpText<"Allow undefined symbols when creating executables">;
+def force_unresolved : F<"force:unresolved">;
+
+defm allowbind: B<"allowbind", "Disable DLL binding">;
+defm allowisolation : B<"allowisolation", "Set NO_ISOLATION bit">;
+defm dynamicbase : B<"dynamicbase",
+ "Disable address space layout randomization">;
+defm fixed : B<"fixed", "Enable base relocations">;
+defm highentropyva : B<"highentropyva", "Set HIGH_ENTROPY_VA bit">;
+defm largeaddressaware : B<"largeaddressaware", "Disable large addresses">;
+defm nxcompat : B<"nxcompat", "Disable data execution provention">;
+defm safeseh : B<"safeseh", "Produce an image with Safe Exception Handler">;
+defm tsaware : B<"tsaware", "Create non-Terminal Server aware executable">;
+
+def help : F<"help">;
+def help_q : Flag<["/?", "-?"], "">, Alias<help>;
+
+// LLD extensions
+def nosymtab : F<"nosymtab">;
+
+// Flags for debugging
+def lldmap : Joined<["/", "-"], "lldmap:">;
+
+//==============================================================================
+// The flags below do nothing. They are defined only for link.exe compatibility.
+//==============================================================================
+
+class QF<string name> : Joined<["/", "-", "-?"], name#":">;
+
+multiclass QB<string name> {
+ def "" : F<name>;
+ def _no : F<name#":no">;
+}
+
+def functionpadmin : F<"functionpadmin">;
+def ignoreidl : F<"ignoreidl">;
+def incremental : F<"incremental">;
+def no_incremental : F<"incremental:no">;
+def nologo : F<"nologo">;
+def throwingnew : F<"throwingnew">;
+def editandcontinue : F<"editandcontinue">;
+
+def delay : QF<"delay">;
+def errorreport : QF<"errorreport">;
+def idlout : QF<"idlout">;
+def ignore : QF<"ignore">;
+def maxilksize : QF<"maxilksize">;
+def pdbaltpath : QF<"pdbaltpath">;
+def tlbid : QF<"tlbid">;
+def tlbout : QF<"tlbout">;
+def verbose_all : QF<"verbose">;
+def guardsym : QF<"guardsym">;
+
+defm wx : QB<"wx">;
diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp
new file mode 100644
index 000000000000..786d28798bab
--- /dev/null
+++ b/COFF/PDB.cpp
@@ -0,0 +1,60 @@
+//===- PDB.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Driver.h"
+#include "Error.h"
+#include "Symbols.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include <memory>
+
+using namespace llvm;
+using namespace llvm::support;
+using namespace llvm::support::endian;
+
+const int PageSize = 4096;
+const uint8_t Magic[32] = "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0";
+
+namespace {
+struct PDBHeader {
+ uint8_t Magic[32];
+ ulittle32_t PageSize;
+ ulittle32_t FpmPage;
+ ulittle32_t PageCount;
+ ulittle32_t RootSize;
+ ulittle32_t Reserved;
+ ulittle32_t RootPointer;
+};
+}
+
+void lld::coff::createPDB(StringRef Path) {
+ // Create a file.
+ size_t FileSize = PageSize * 3;
+ ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+ FileOutputBuffer::create(Path, FileSize);
+ error(BufferOrErr, Twine("failed to open ") + Path);
+ std::unique_ptr<FileOutputBuffer> Buffer = std::move(*BufferOrErr);
+
+ // Write the file header.
+ uint8_t *Buf = Buffer->getBufferStart();
+ auto *Hdr = reinterpret_cast<PDBHeader *>(Buf);
+ memcpy(Hdr->Magic, Magic, sizeof(Magic));
+ Hdr->PageSize = PageSize;
+ // I don't know what FpmPage field means, but it must not be 0.
+ Hdr->FpmPage = 1;
+ Hdr->PageCount = FileSize / PageSize;
+ // Root directory is empty, containing only the length field.
+ Hdr->RootSize = 4;
+ // Root directory is on page 1.
+ Hdr->RootPointer = 1;
+
+ // Write the root directory. Root stream is on page 2.
+ write32le(Buf + PageSize, 2);
+ Buffer->commit();
+}
diff --git a/COFF/README.md b/COFF/README.md
new file mode 100644
index 000000000000..c1be560f4405
--- /dev/null
+++ b/COFF/README.md
@@ -0,0 +1,265 @@
+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.
diff --git a/COFF/SymbolTable.cpp b/COFF/SymbolTable.cpp
new file mode 100644
index 000000000000..5b7b89cd360a
--- /dev/null
+++ b/COFF/SymbolTable.cpp
@@ -0,0 +1,445 @@
+//===- SymbolTable.cpp ----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Config.h"
+#include "Driver.h"
+#include "Error.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "lld/Core/Parallel.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/LTO/LTOCodeGenerator.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include <utility>
+
+using namespace llvm;
+
+namespace lld {
+namespace coff {
+
+void SymbolTable::addFile(std::unique_ptr<InputFile> FileP) {
+#if LLVM_ENABLE_THREADS
+ std::launch Policy = std::launch::async;
+#else
+ std::launch Policy = std::launch::deferred;
+#endif
+
+ InputFile *File = FileP.get();
+ Files.push_back(std::move(FileP));
+ if (auto *F = dyn_cast<ArchiveFile>(File)) {
+ ArchiveQueue.push_back(
+ std::async(Policy, [=]() { F->parse(); return F; }));
+ return;
+ }
+ ObjectQueue.push_back(
+ std::async(Policy, [=]() { File->parse(); return File; }));
+ if (auto *F = dyn_cast<ObjectFile>(File)) {
+ ObjectFiles.push_back(F);
+ } else if (auto *F = dyn_cast<BitcodeFile>(File)) {
+ BitcodeFiles.push_back(F);
+ } else {
+ ImportFiles.push_back(cast<ImportFile>(File));
+ }
+}
+
+void SymbolTable::step() {
+ if (queueEmpty())
+ return;
+ readObjects();
+ readArchives();
+}
+
+void SymbolTable::run() {
+ while (!queueEmpty())
+ step();
+}
+
+void SymbolTable::readArchives() {
+ if (ArchiveQueue.empty())
+ return;
+
+ // Add lazy symbols to the symbol table. Lazy symbols that conflict
+ // with existing undefined symbols are accumulated in LazySyms.
+ std::vector<Symbol *> LazySyms;
+ for (std::future<ArchiveFile *> &Future : ArchiveQueue) {
+ ArchiveFile *File = Future.get();
+ if (Config->Verbose)
+ llvm::outs() << "Reading " << File->getShortName() << "\n";
+ for (Lazy &Sym : File->getLazySymbols())
+ addLazy(&Sym, &LazySyms);
+ }
+ ArchiveQueue.clear();
+
+ // Add archive member files to ObjectQueue that should resolve
+ // existing undefined symbols.
+ for (Symbol *Sym : LazySyms)
+ addMemberFile(cast<Lazy>(Sym->Body));
+}
+
+void SymbolTable::readObjects() {
+ if (ObjectQueue.empty())
+ return;
+
+ // Add defined and undefined symbols to the symbol table.
+ std::vector<StringRef> Directives;
+ for (size_t I = 0; I < ObjectQueue.size(); ++I) {
+ InputFile *File = ObjectQueue[I].get();
+ if (Config->Verbose)
+ llvm::outs() << "Reading " << File->getShortName() << "\n";
+ // Adding symbols may add more files to ObjectQueue
+ // (but not to ArchiveQueue).
+ for (SymbolBody *Sym : File->getSymbols())
+ if (Sym->isExternal())
+ addSymbol(Sym);
+ StringRef S = File->getDirectives();
+ if (!S.empty()) {
+ Directives.push_back(S);
+ if (Config->Verbose)
+ llvm::outs() << "Directives: " << File->getShortName()
+ << ": " << S << "\n";
+ }
+ }
+ ObjectQueue.clear();
+
+ // Parse directive sections. This may add files to
+ // ArchiveQueue and ObjectQueue.
+ for (StringRef S : Directives)
+ Driver->parseDirectives(S);
+}
+
+bool SymbolTable::queueEmpty() {
+ return ArchiveQueue.empty() && ObjectQueue.empty();
+}
+
+void SymbolTable::reportRemainingUndefines(bool Resolve) {
+ llvm::SmallPtrSet<SymbolBody *, 8> Undefs;
+ for (auto &I : Symtab) {
+ Symbol *Sym = I.second;
+ auto *Undef = dyn_cast<Undefined>(Sym->Body);
+ if (!Undef)
+ continue;
+ StringRef Name = Undef->getName();
+ // A weak alias may have been resolved, so check for that.
+ if (Defined *D = Undef->getWeakAlias()) {
+ if (Resolve)
+ Sym->Body = D;
+ continue;
+ }
+ // If we can resolve a symbol by removing __imp_ prefix, do that.
+ // This odd rule is for compatibility with MSVC linker.
+ if (Name.startswith("__imp_")) {
+ Symbol *Imp = find(Name.substr(strlen("__imp_")));
+ if (Imp && isa<Defined>(Imp->Body)) {
+ if (!Resolve)
+ continue;
+ auto *D = cast<Defined>(Imp->Body);
+ auto *S = new (Alloc) DefinedLocalImport(Name, D);
+ LocalImportChunks.push_back(S->getChunk());
+ Sym->Body = S;
+ continue;
+ }
+ }
+ // Remaining undefined symbols are not fatal if /force is specified.
+ // They are replaced with dummy defined symbols.
+ if (Config->Force && Resolve)
+ Sym->Body = new (Alloc) DefinedAbsolute(Name, 0);
+ Undefs.insert(Sym->Body);
+ }
+ if (Undefs.empty())
+ return;
+ for (Undefined *U : Config->GCRoot)
+ if (Undefs.count(U->repl()))
+ llvm::errs() << "<root>: undefined symbol: " << U->getName() << "\n";
+ for (std::unique_ptr<InputFile> &File : Files)
+ if (!isa<ArchiveFile>(File.get()))
+ for (SymbolBody *Sym : File->getSymbols())
+ if (Undefs.count(Sym->repl()))
+ llvm::errs() << File->getShortName() << ": undefined symbol: "
+ << Sym->getName() << "\n";
+ if (!Config->Force)
+ error("Link failed");
+}
+
+void SymbolTable::addLazy(Lazy *New, std::vector<Symbol *> *Accum) {
+ Symbol *Sym = insert(New);
+ if (Sym->Body == New)
+ return;
+ SymbolBody *Existing = Sym->Body;
+ if (isa<Defined>(Existing))
+ return;
+ if (Lazy *L = dyn_cast<Lazy>(Existing))
+ if (L->getFileIndex() < New->getFileIndex())
+ return;
+ Sym->Body = New;
+ New->setBackref(Sym);
+ if (isa<Undefined>(Existing))
+ Accum->push_back(Sym);
+}
+
+void SymbolTable::addSymbol(SymbolBody *New) {
+ // Find an existing symbol or create and insert a new one.
+ assert(isa<Defined>(New) || isa<Undefined>(New));
+ Symbol *Sym = insert(New);
+ if (Sym->Body == New)
+ return;
+ SymbolBody *Existing = Sym->Body;
+
+ // If we have an undefined symbol and a lazy symbol,
+ // let the lazy symbol to read a member file.
+ if (auto *L = dyn_cast<Lazy>(Existing)) {
+ // Undefined symbols with weak aliases need not to be resolved,
+ // since they would be replaced with weak aliases if they remain
+ // undefined.
+ if (auto *U = dyn_cast<Undefined>(New)) {
+ if (!U->WeakAlias) {
+ addMemberFile(L);
+ return;
+ }
+ }
+ Sym->Body = New;
+ return;
+ }
+
+ // compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
+ // equivalent (conflicting), or more preferable, respectively.
+ int Comp = Existing->compare(New);
+ if (Comp == 0)
+ error(Twine("duplicate symbol: ") + Existing->getDebugName() + " and " +
+ New->getDebugName());
+ if (Comp < 0)
+ Sym->Body = New;
+}
+
+Symbol *SymbolTable::insert(SymbolBody *New) {
+ Symbol *&Sym = Symtab[New->getName()];
+ if (Sym) {
+ New->setBackref(Sym);
+ return Sym;
+ }
+ Sym = new (Alloc) Symbol(New);
+ New->setBackref(Sym);
+ return Sym;
+}
+
+// Reads an archive member file pointed by a given symbol.
+void SymbolTable::addMemberFile(Lazy *Body) {
+ std::unique_ptr<InputFile> File = Body->getMember();
+
+ // getMember returns an empty buffer if the member was already
+ // read from the library.
+ if (!File)
+ return;
+ if (Config->Verbose)
+ llvm::outs() << "Loaded " << File->getShortName() << " for "
+ << Body->getName() << "\n";
+ addFile(std::move(File));
+}
+
+std::vector<Chunk *> SymbolTable::getChunks() {
+ std::vector<Chunk *> Res;
+ for (ObjectFile *File : ObjectFiles) {
+ std::vector<Chunk *> &V = File->getChunks();
+ Res.insert(Res.end(), V.begin(), V.end());
+ }
+ return Res;
+}
+
+Symbol *SymbolTable::find(StringRef Name) {
+ auto It = Symtab.find(Name);
+ if (It == Symtab.end())
+ return nullptr;
+ return It->second;
+}
+
+Symbol *SymbolTable::findUnderscore(StringRef Name) {
+ if (Config->Machine == I386)
+ return find(("_" + Name).str());
+ return find(Name);
+}
+
+StringRef SymbolTable::findByPrefix(StringRef Prefix) {
+ for (auto Pair : Symtab) {
+ StringRef Name = Pair.first;
+ if (Name.startswith(Prefix))
+ return Name;
+ }
+ return "";
+}
+
+StringRef SymbolTable::findMangle(StringRef Name) {
+ if (Symbol *Sym = find(Name))
+ if (!isa<Undefined>(Sym->Body))
+ return Name;
+ if (Config->Machine != I386)
+ return findByPrefix(("?" + Name + "@@Y").str());
+ if (!Name.startswith("_"))
+ return "";
+ // Search for x86 C function.
+ StringRef S = findByPrefix((Name + "@").str());
+ if (!S.empty())
+ return S;
+ // Search for x86 C++ non-member function.
+ return findByPrefix(("?" + Name.substr(1) + "@@Y").str());
+}
+
+void SymbolTable::mangleMaybe(Undefined *U) {
+ if (U->WeakAlias)
+ return;
+ if (!isa<Undefined>(U->repl()))
+ return;
+ StringRef Alias = findMangle(U->getName());
+ if (!Alias.empty())
+ U->WeakAlias = addUndefined(Alias);
+}
+
+Undefined *SymbolTable::addUndefined(StringRef Name) {
+ auto *New = new (Alloc) Undefined(Name);
+ addSymbol(New);
+ if (auto *U = dyn_cast<Undefined>(New->repl()))
+ return U;
+ return New;
+}
+
+DefinedRelative *SymbolTable::addRelative(StringRef Name, uint64_t VA) {
+ auto *New = new (Alloc) DefinedRelative(Name, VA);
+ addSymbol(New);
+ return New;
+}
+
+DefinedAbsolute *SymbolTable::addAbsolute(StringRef Name, uint64_t VA) {
+ auto *New = new (Alloc) DefinedAbsolute(Name, VA);
+ addSymbol(New);
+ return New;
+}
+
+void SymbolTable::printMap(llvm::raw_ostream &OS) {
+ for (ObjectFile *File : ObjectFiles) {
+ OS << File->getShortName() << ":\n";
+ for (SymbolBody *Body : File->getSymbols())
+ if (auto *R = dyn_cast<DefinedRegular>(Body))
+ if (R->getChunk()->isLive())
+ OS << Twine::utohexstr(Config->ImageBase + R->getRVA())
+ << " " << R->getName() << "\n";
+ }
+}
+
+void SymbolTable::addCombinedLTOObject(ObjectFile *Obj) {
+ for (SymbolBody *Body : Obj->getSymbols()) {
+ if (!Body->isExternal())
+ continue;
+ // We should not see any new undefined symbols at this point, but we'll
+ // diagnose them later in reportRemainingUndefines().
+ StringRef Name = Body->getName();
+ Symbol *Sym = insert(Body);
+
+ if (isa<DefinedBitcode>(Sym->Body)) {
+ Sym->Body = Body;
+ continue;
+ }
+ if (auto *L = dyn_cast<Lazy>(Sym->Body)) {
+ // 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);
+ if (Comp < 0)
+ Sym->Body = Body;
+ }
+}
+
+void SymbolTable::addCombinedLTOObjects() {
+ if (BitcodeFiles.empty())
+ return;
+
+ // Diagnose any undefined symbols early, but do not resolve weak externals,
+ // as resolution breaks the invariant that each Symbol points to a unique
+ // SymbolBody, which we rely on to replace DefinedBitcode symbols correctly.
+ reportRemainingUndefines(/*Resolve=*/false);
+
+ // 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());
+ CG.setOptLevel(Config->LTOOptLevel);
+ std::vector<ObjectFile *> Objs = createLTOObjects(&CG);
+
+ for (ObjectFile *Obj : Objs)
+ addCombinedLTOObject(Obj);
+
+ size_t NumBitcodeFiles = BitcodeFiles.size();
+ run();
+ if (BitcodeFiles.size() != NumBitcodeFiles)
+ error("LTO: late loaded symbol created new bitcode reference");
+}
+
+// Combine and compile bitcode files and then return the result
+// as a vector of regular COFF object files.
+std::vector<ObjectFile *> SymbolTable::createLTOObjects(LTOCodeGenerator *CG) {
+ // All symbols referenced by non-bitcode objects must be preserved.
+ for (ObjectFile *File : ObjectFiles)
+ for (SymbolBody *Body : File->getSymbols())
+ if (auto *S = dyn_cast<DefinedBitcode>(Body->repl()))
+ CG->addMustPreserveSymbol(S->getName());
+
+ // Likewise for bitcode symbols which we initially resolved to non-bitcode.
+ for (BitcodeFile *File : BitcodeFiles)
+ for (SymbolBody *Body : File->getSymbols())
+ if (isa<DefinedBitcode>(Body) && !isa<DefinedBitcode>(Body->repl()))
+ CG->addMustPreserveSymbol(Body->getName());
+
+ // Likewise for other symbols that must be preserved.
+ for (Undefined *U : Config->GCRoot) {
+ if (auto *S = dyn_cast<DefinedBitcode>(U->repl()))
+ CG->addMustPreserveSymbol(S->getName());
+ else if (auto *S = dyn_cast_or_null<DefinedBitcode>(U->getWeakAlias()))
+ CG->addMustPreserveSymbol(S->getName());
+ }
+
+ CG->setModule(BitcodeFiles[0]->takeModule());
+ for (unsigned I = 1, E = BitcodeFiles.size(); I != E; ++I)
+ CG->addModule(BitcodeFiles[I]->takeModule().get());
+
+ bool DisableVerify = true;
+#ifdef NDEBUG
+ DisableVerify = false;
+#endif
+ if (!CG->optimize(DisableVerify, false, false, false))
+ error(""); // 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) {
+ OSs.emplace_back(Obj);
+ OSPtrs.push_back(&OSs.back());
+ }
+
+ if (!CG->compileOptimized(OSPtrs))
+ error(""); // 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>"));
+ Files.emplace_back(ObjFile);
+ ObjectFiles.push_back(ObjFile);
+ ObjFile->parse();
+ ObjFiles.push_back(ObjFile);
+ }
+
+ return ObjFiles;
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/SymbolTable.h b/COFF/SymbolTable.h
new file mode 100644
index 000000000000..ce305bfa8743
--- /dev/null
+++ b/COFF/SymbolTable.h
@@ -0,0 +1,125 @@
+//===- SymbolTable.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_SYMBOL_TABLE_H
+#define LLD_COFF_SYMBOL_TABLE_H
+
+#include "InputFiles.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/raw_ostream.h"
+
+#ifdef _MSC_VER
+// <future> depends on <eh.h> for __uncaught_exception.
+#include <eh.h>
+#endif
+
+#include <future>
+
+namespace llvm {
+struct LTOCodeGenerator;
+}
+
+namespace lld {
+namespace coff {
+
+class Chunk;
+class Defined;
+class Lazy;
+class SymbolBody;
+struct Symbol;
+
+// SymbolTable is a bucket of all known symbols, including defined,
+// undefined, or lazy symbols (the last one is symbols in archive
+// files whose archive members are not yet loaded).
+//
+// We put all symbols of all files to a SymbolTable, and the
+// SymbolTable selects the "best" symbols if there are name
+// conflicts. For example, obviously, a defined symbol is better than
+// an undefined symbol. Or, if there's a conflict between a lazy and a
+// undefined, it'll read an archive member to read a real definition
+// to replace the lazy symbol. The logic is implemented in resolve().
+class SymbolTable {
+public:
+ void addFile(std::unique_ptr<InputFile> File);
+ std::vector<std::unique_ptr<InputFile>> &getFiles() { return Files; }
+ void step();
+ void run();
+ bool queueEmpty();
+
+ // Print an error message on undefined symbols. If Resolve is true, try to
+ // resolve any undefined symbols and update the symbol table accordingly.
+ void reportRemainingUndefines(bool Resolve);
+
+ // Returns a list of chunks of selected symbols.
+ std::vector<Chunk *> getChunks();
+
+ // Returns a symbol for a given name. Returns a nullptr if not found.
+ Symbol *find(StringRef Name);
+ Symbol *findUnderscore(StringRef Name);
+
+ // Occasionally we have to resolve an undefined symbol to its
+ // mangled symbol. This function tries to find a mangled name
+ // for U from the symbol table, and if found, set the symbol as
+ // a weak alias for U.
+ void mangleMaybe(Undefined *U);
+ StringRef findMangle(StringRef Name);
+
+ // Print a layout map to OS.
+ void printMap(llvm::raw_ostream &OS);
+
+ // Build a set of COFF objects representing the combined contents of
+ // BitcodeFiles and add them to the symbol table. Called after all files are
+ // added and before the writer writes results to a file.
+ void addCombinedLTOObjects();
+
+ // The writer needs to handle DLL import libraries specially in
+ // order to create the import descriptor table.
+ std::vector<ImportFile *> ImportFiles;
+
+ // The writer needs to infer the machine type from the object files.
+ std::vector<ObjectFile *> ObjectFiles;
+
+ // Creates an Undefined symbol for a given name.
+ Undefined *addUndefined(StringRef Name);
+ DefinedRelative *addRelative(StringRef Name, uint64_t VA);
+ DefinedAbsolute *addAbsolute(StringRef Name, uint64_t VA);
+
+ // A list of chunks which to be added to .rdata.
+ std::vector<Chunk *> LocalImportChunks;
+
+private:
+ void readArchives();
+ void readObjects();
+
+ void addSymbol(SymbolBody *New);
+ void addLazy(Lazy *New, std::vector<Symbol *> *Accum);
+ Symbol *insert(SymbolBody *New);
+ StringRef findByPrefix(StringRef Prefix);
+
+ void addMemberFile(Lazy *Body);
+ void addCombinedLTOObject(ObjectFile *Obj);
+ std::vector<ObjectFile *> createLTOObjects(llvm::LTOCodeGenerator *CG);
+
+ llvm::DenseMap<StringRef, Symbol *> Symtab;
+
+ std::vector<std::unique_ptr<InputFile>> Files;
+ std::vector<std::future<ArchiveFile *>> ArchiveQueue;
+ std::vector<std::future<InputFile *>> ObjectQueue;
+
+ std::vector<BitcodeFile *> BitcodeFiles;
+ std::vector<SmallVector<char, 0>> Objs;
+ llvm::BumpPtrAllocator Alloc;
+};
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/Symbols.cpp b/COFF/Symbols.cpp
new file mode 100644
index 000000000000..d732d76cfb06
--- /dev/null
+++ b/COFF/Symbols.cpp
@@ -0,0 +1,243 @@
+//===- Symbols.cpp --------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm::object;
+using llvm::sys::fs::identify_magic;
+using llvm::sys::fs::file_magic;
+
+namespace lld {
+namespace coff {
+
+StringRef SymbolBody::getName() {
+ // DefinedCOFF names are read lazily for a performance reason.
+ // Non-external symbol names are never used by the linker except for logging
+ // or debugging. Their internal references are resolved not by name but by
+ // symbol index. And because they are not external, no one can refer them by
+ // name. Object files contain lots of non-external symbols, and creating
+ // StringRefs for them (which involves lots of strlen() on the string table)
+ // is a waste of time.
+ if (Name.empty()) {
+ auto *D = cast<DefinedCOFF>(this);
+ D->File->getCOFFObj()->getSymbolName(D->Sym, Name);
+ }
+ return Name;
+}
+
+// Returns 1, 0 or -1 if this symbol should take precedence
+// over the Other, tie or lose, respectively.
+int SymbolBody::compare(SymbolBody *Other) {
+ Kind LK = kind(), RK = Other->kind();
+
+ // Normalize so that the smaller kind is on the left.
+ if (LK > RK)
+ return -Other->compare(this);
+
+ // First handle comparisons between two different kinds.
+ if (LK != RK) {
+ if (RK > LastDefinedKind) {
+ if (LK == LazyKind && cast<Undefined>(Other)->WeakAlias)
+ return -1;
+
+ // The LHS is either defined or lazy and so it wins.
+ assert((LK <= LastDefinedKind || LK == LazyKind) && "Bad kind!");
+ return 1;
+ }
+
+ // Bitcode has special complexities.
+ if (RK == DefinedBitcodeKind) {
+ auto *RHS = cast<DefinedBitcode>(Other);
+
+ switch (LK) {
+ case DefinedCommonKind:
+ return 1;
+
+ case DefinedRegularKind:
+ // As an approximation, regular symbols win over bitcode symbols,
+ // but we definitely have a conflict if the regular symbol is not
+ // replaceable and neither is the bitcode symbol. We do not
+ // replicate the rest of the symbol resolution logic here; symbol
+ // resolution will be done accurately after lowering bitcode symbols
+ // to regular symbols in addCombinedLTOObject().
+ if (cast<DefinedRegular>(this)->isCOMDAT() || RHS->IsReplaceable)
+ return 1;
+
+ // Fallthrough to the default of a tie otherwise.
+ default:
+ return 0;
+ }
+ }
+
+ // Either of the object file kind will trump a higher kind.
+ if (LK <= LastDefinedCOFFKind)
+ return 1;
+
+ // The remaining kind pairs are ties amongst defined symbols.
+ return 0;
+ }
+
+ // Now handle the case where the kinds are the same.
+ switch (LK) {
+ case DefinedRegularKind: {
+ auto *LHS = cast<DefinedRegular>(this);
+ auto *RHS = cast<DefinedRegular>(Other);
+ if (LHS->isCOMDAT() && RHS->isCOMDAT())
+ return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1;
+ return 0;
+ }
+
+ case DefinedCommonKind: {
+ auto *LHS = cast<DefinedCommon>(this);
+ auto *RHS = cast<DefinedCommon>(Other);
+ if (LHS->getSize() == RHS->getSize())
+ return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1;
+ return LHS->getSize() > RHS->getSize() ? 1 : -1;
+ }
+
+ case DefinedBitcodeKind: {
+ auto *LHS = cast<DefinedBitcode>(this);
+ auto *RHS = cast<DefinedBitcode>(Other);
+ // If both are non-replaceable, we have a tie.
+ if (!LHS->IsReplaceable && !RHS->IsReplaceable)
+ return 0;
+
+ // Non-replaceable symbols win, but even two replaceable symboles don't
+ // tie. If both symbols are replaceable, choice is arbitrary.
+ if (RHS->IsReplaceable && LHS->IsReplaceable)
+ return uintptr_t(LHS) < uintptr_t(RHS) ? 1 : -1;
+ return LHS->IsReplaceable ? -1 : 1;
+ }
+
+ case LazyKind: {
+ // Don't tie, pick the earliest.
+ auto *LHS = cast<Lazy>(this);
+ auto *RHS = cast<Lazy>(Other);
+ return LHS->getFileIndex() < RHS->getFileIndex() ? 1 : -1;
+ }
+
+ case UndefinedKind: {
+ auto *LHS = cast<Undefined>(this);
+ auto *RHS = cast<Undefined>(Other);
+ // Tie if both undefined symbols have different weak aliases.
+ if (LHS->WeakAlias && RHS->WeakAlias) {
+ if (LHS->WeakAlias->getName() != RHS->WeakAlias->getName())
+ return 0;
+ return uintptr_t(LHS) < uintptr_t(RHS) ? 1 : -1;
+ }
+ return LHS->WeakAlias ? 1 : -1;
+ }
+
+ case DefinedLocalImportKind:
+ case DefinedImportThunkKind:
+ case DefinedImportDataKind:
+ case DefinedAbsoluteKind:
+ case DefinedRelativeKind:
+ // These all simply tie.
+ return 0;
+ }
+ llvm_unreachable("unknown symbol kind");
+}
+
+std::string SymbolBody::getDebugName() {
+ std::string N = getName().str();
+ if (auto *D = dyn_cast<DefinedCOFF>(this)) {
+ N += " ";
+ N += D->File->getShortName();
+ } else if (auto *D = dyn_cast<DefinedBitcode>(this)) {
+ N += " ";
+ N += D->File->getShortName();
+ }
+ 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))
+ return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(Sym));
+ assert(SymSize == sizeof(coff_symbol32));
+ return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(Sym));
+}
+
+DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S,
+ uint16_t Machine)
+ : Defined(DefinedImportThunkKind, Name) {
+ switch (Machine) {
+ case AMD64: Data.reset(new ImportThunkChunkX64(S)); return;
+ case I386: Data.reset(new ImportThunkChunkX86(S)); return;
+ case ARMNT: Data.reset(new ImportThunkChunkARM(S)); return;
+ default: llvm_unreachable("unknown machine type");
+ }
+}
+
+std::unique_ptr<InputFile> Lazy::getMember() {
+ MemoryBufferRef MBRef = File->getMember(&Sym);
+
+ // getMember returns an empty buffer if the member was already
+ // read from the library.
+ if (MBRef.getBuffer().empty())
+ return std::unique_ptr<InputFile>(nullptr);
+
+ file_magic Magic = identify_magic(MBRef.getBuffer());
+ if (Magic == file_magic::coff_import_library)
+ return std::unique_ptr<InputFile>(new ImportFile(MBRef));
+
+ std::unique_ptr<InputFile> Obj;
+ if (Magic == file_magic::coff_object)
+ Obj.reset(new ObjectFile(MBRef));
+ else if (Magic == file_magic::bitcode)
+ Obj.reset(new BitcodeFile(MBRef));
+ else
+ error(Twine(File->getName()) + ": unknown file type");
+
+ Obj->setParentName(File->getName());
+ return Obj;
+}
+
+Defined *Undefined::getWeakAlias() {
+ // A weak alias may be a weak alias to another symbol, so check recursively.
+ for (SymbolBody *A = WeakAlias; A; A = cast<Undefined>(A)->WeakAlias)
+ if (auto *D = dyn_cast<Defined>(A->repl()))
+ return D;
+ return nullptr;
+}
+
+} // namespace coff
+} // namespace lld
diff --git a/COFF/Symbols.h b/COFF/Symbols.h
new file mode 100644
index 000000000000..7059fbc8bb15
--- /dev/null
+++ b/COFF/Symbols.h
@@ -0,0 +1,407 @@
+//===- Symbols.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_SYMBOLS_H
+#define LLD_COFF_SYMBOLS_H
+
+#include "Chunks.h"
+#include "Config.h"
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/COFF.h"
+#include <atomic>
+#include <memory>
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+using llvm::object::Archive;
+using llvm::object::COFFSymbolRef;
+using llvm::object::coff_import_header;
+using llvm::object::coff_symbol_generic;
+
+class ArchiveFile;
+class BitcodeFile;
+class InputFile;
+class ObjectFile;
+class SymbolBody;
+
+// A real symbol object, SymbolBody, is usually accessed indirectly
+// through a Symbol. There's always one Symbol for each symbol name.
+// The resolver updates SymbolBody pointers as it resolves symbols.
+struct Symbol {
+ explicit Symbol(SymbolBody *P) : Body(P) {}
+ SymbolBody *Body;
+};
+
+// The base class for real symbol classes.
+class SymbolBody {
+public:
+ enum Kind {
+ // The order of these is significant. We start with the regular defined
+ // symbols as those are the most prevelant and the zero tag is the cheapest
+ // to set. Among the defined kinds, the lower the kind is preferred over
+ // the higher kind when testing wether one symbol should take precedence
+ // over another.
+ DefinedRegularKind = 0,
+ DefinedCommonKind,
+ DefinedLocalImportKind,
+ DefinedImportThunkKind,
+ DefinedImportDataKind,
+ DefinedAbsoluteKind,
+ DefinedRelativeKind,
+ DefinedBitcodeKind,
+
+ UndefinedKind,
+ LazyKind,
+
+ LastDefinedCOFFKind = DefinedCommonKind,
+ LastDefinedKind = DefinedBitcodeKind,
+ };
+
+ Kind kind() const { return static_cast<Kind>(SymbolKind); }
+
+ // Returns true if this is an external symbol.
+ bool isExternal() { return IsExternal; }
+
+ // Returns the symbol name.
+ StringRef getName();
+
+ // A SymbolBody has a backreference to a Symbol. Originally they are
+ // doubly-linked. A backreference will never change. But the pointer
+ // in the Symbol may be mutated by the resolver. If you have a
+ // pointer P to a SymbolBody and are not sure whether the resolver
+ // has chosen the object among other objects having the same name,
+ // you can access P->Backref->Body to get the resolver's result.
+ void setBackref(Symbol *P) { Backref = P; }
+ SymbolBody *repl() { return Backref ? Backref->Body : this; }
+
+ // Decides which symbol should "win" in the symbol table, this or
+ // the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if
+ // they are duplicate (conflicting) symbols.
+ int compare(SymbolBody *Other);
+
+ // Returns a name of this symbol including source file name.
+ // Used only for debugging and logging.
+ std::string getDebugName();
+
+protected:
+ explicit SymbolBody(Kind K, StringRef N = "")
+ : SymbolKind(K), IsExternal(true), IsCOMDAT(false),
+ IsReplaceable(false), Name(N) {}
+
+ const unsigned SymbolKind : 8;
+ unsigned IsExternal : 1;
+
+ // This bit is used by the \c DefinedRegular subclass.
+ unsigned IsCOMDAT : 1;
+
+ // This bit is used by the \c DefinedBitcode subclass.
+ unsigned IsReplaceable : 1;
+
+ StringRef Name;
+ Symbol *Backref = nullptr;
+};
+
+// The base class for any defined symbols, including absolute symbols,
+// etc.
+class Defined : public SymbolBody {
+public:
+ Defined(Kind K, StringRef N = "") : SymbolBody(K, N) {}
+
+ static bool classof(const SymbolBody *S) {
+ return S->kind() <= LastDefinedKind;
+ }
+
+ // Returns the RVA (relative virtual address) of this symbol. The
+ // 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();
+
+ // Returns the output section index.
+ // Used to implement SECTION relocation type.
+ uint64_t getSectionIndex();
+
+ // Returns true if this symbol points to an executable (e.g. .text) section.
+ // Used to implement ARM relocations.
+ bool isExecutable();
+};
+
+// Symbols defined via a COFF object file.
+class DefinedCOFF : public Defined {
+ friend SymbolBody;
+public:
+ DefinedCOFF(Kind K, ObjectFile *F, COFFSymbolRef S)
+ : Defined(K), File(F), Sym(S.getGeneric()) {}
+
+ static bool classof(const SymbolBody *S) {
+ return S->kind() <= LastDefinedCOFFKind;
+ }
+
+ int getFileIndex() { return File->Index; }
+
+ COFFSymbolRef getCOFFSymbol();
+
+protected:
+ ObjectFile *File;
+ const coff_symbol_generic *Sym;
+};
+
+// Regular defined symbols read from object file symbol tables.
+class DefinedRegular : public DefinedCOFF {
+public:
+ DefinedRegular(ObjectFile *F, COFFSymbolRef S, SectionChunk *C)
+ : DefinedCOFF(DefinedRegularKind, F, S), Data(&C->Repl) {
+ IsExternal = S.isExternal();
+ IsCOMDAT = C->isCOMDAT();
+ }
+
+ static bool classof(const SymbolBody *S) {
+ return S->kind() == DefinedRegularKind;
+ }
+
+ uint64_t getRVA() { return (*Data)->getRVA() + Sym->Value; }
+ bool isCOMDAT() { return IsCOMDAT; }
+ SectionChunk *getChunk() { return *Data; }
+ uint32_t getValue() { return Sym->Value; }
+
+private:
+ SectionChunk **Data;
+};
+
+class DefinedCommon : public DefinedCOFF {
+public:
+ DefinedCommon(ObjectFile *F, COFFSymbolRef S, CommonChunk *C)
+ : DefinedCOFF(DefinedCommonKind, F, S), Data(C) {
+ IsExternal = S.isExternal();
+ }
+
+ static bool classof(const SymbolBody *S) {
+ return S->kind() == DefinedCommonKind;
+ }
+
+ uint64_t getRVA() { return Data->getRVA(); }
+
+private:
+ friend SymbolBody;
+ uint64_t getSize() { return Sym->Value; }
+ CommonChunk *Data;
+};
+
+// Absolute symbols.
+class DefinedAbsolute : public Defined {
+public:
+ DefinedAbsolute(StringRef N, COFFSymbolRef S)
+ : Defined(DefinedAbsoluteKind, N), VA(S.getValue()) {
+ IsExternal = S.isExternal();
+ }
+
+ DefinedAbsolute(StringRef N, uint64_t V)
+ : Defined(DefinedAbsoluteKind, N), VA(V) {}
+
+ static bool classof(const SymbolBody *S) {
+ return S->kind() == DefinedAbsoluteKind;
+ }
+
+ uint64_t getRVA() { return VA - Config->ImageBase; }
+ void setVA(uint64_t V) { VA = V; }
+
+private:
+ uint64_t VA;
+};
+
+// This is a kind of absolute symbol but relative to the image base.
+// Unlike absolute symbols, relocations referring this kind of symbols
+// are subject of the base relocation. This type is used rarely --
+// mainly for __ImageBase.
+class DefinedRelative : public Defined {
+public:
+ explicit DefinedRelative(StringRef Name, uint64_t V = 0)
+ : Defined(DefinedRelativeKind, Name), RVA(V) {}
+
+ static bool classof(const SymbolBody *S) {
+ return S->kind() == DefinedRelativeKind;
+ }
+
+ uint64_t getRVA() { return RVA; }
+ void setRVA(uint64_t V) { RVA = V; }
+
+private:
+ uint64_t RVA;
+};
+
+// This class represents a symbol defined in an archive file. It is
+// created from an archive file header, and it knows how to load an
+// object file from an archive to replace itself with a defined
+// symbol. If the resolver finds both Undefined and Lazy for
+// the same name, it will ask the Lazy to load a file.
+class Lazy : public SymbolBody {
+public:
+ Lazy(ArchiveFile *F, const Archive::Symbol S)
+ : SymbolBody(LazyKind, S.getName()), File(F), Sym(S) {}
+
+ static bool classof(const SymbolBody *S) { return S->kind() == LazyKind; }
+
+ // Returns an object file for this symbol, or a nullptr if the file
+ // was already returned.
+ std::unique_ptr<InputFile> getMember();
+
+ int getFileIndex() { return File->Index; }
+
+private:
+ ArchiveFile *File;
+ const Archive::Symbol Sym;
+};
+
+// Undefined symbols.
+class Undefined : public SymbolBody {
+public:
+ explicit Undefined(StringRef N) : SymbolBody(UndefinedKind, N) {}
+
+ static bool classof(const SymbolBody *S) {
+ return S->kind() == UndefinedKind;
+ }
+
+ // An undefined symbol can have a fallback symbol which gives an
+ // undefined symbol a second chance if it would remain undefined.
+ // If it remains undefined, it'll be replaced with whatever the
+ // Alias pointer points to.
+ SymbolBody *WeakAlias = nullptr;
+
+ // If this symbol is external weak, try to resolve it to a defined
+ // symbol by searching the chain of fallback symbols. Returns the symbol if
+ // successful, otherwise returns null.
+ Defined *getWeakAlias();
+};
+
+// Windows-specific classes.
+
+// This class represents a symbol imported from a DLL. This has two
+// names for internal use and external use. The former is used for
+// name resolution, and the latter is used for the import descriptor
+// table in an output. The former has "__imp_" prefix.
+class DefinedImportData : public Defined {
+public:
+ DefinedImportData(StringRef D, StringRef N, StringRef E,
+ const coff_import_header *H)
+ : Defined(DefinedImportDataKind, N), DLLName(D), ExternalName(E), Hdr(H) {
+ }
+
+ static bool classof(const SymbolBody *S) {
+ return S->kind() == DefinedImportDataKind;
+ }
+
+ uint64_t getRVA() { return Location->getRVA(); }
+ StringRef getDLLName() { return DLLName; }
+ StringRef getExternalName() { return ExternalName; }
+ void setLocation(Chunk *AddressTable) { Location = AddressTable; }
+ uint16_t getOrdinal() { return Hdr->OrdinalHint; }
+
+private:
+ StringRef DLLName;
+ StringRef ExternalName;
+ const coff_import_header *Hdr;
+ Chunk *Location = nullptr;
+};
+
+// This class represents a symbol for a jump table entry which jumps
+// to a function in a DLL. Linker are supposed to create such symbols
+// without "__imp_" prefix for all function symbols exported from
+// DLLs, so that you can call DLL functions as regular functions with
+// a regular name. A function pointer is given as a DefinedImportData.
+class DefinedImportThunk : public Defined {
+public:
+ DefinedImportThunk(StringRef Name, DefinedImportData *S, uint16_t Machine);
+
+ static bool classof(const SymbolBody *S) {
+ return S->kind() == DefinedImportThunkKind;
+ }
+
+ uint64_t getRVA() { return Data->getRVA(); }
+ Chunk *getChunk() { return Data.get(); }
+
+private:
+ std::unique_ptr<Chunk> Data;
+};
+
+// If you have a symbol "__imp_foo" in your object file, a symbol name
+// "foo" becomes automatically available as a pointer to "__imp_foo".
+// This class is for such automatically-created symbols.
+// Yes, this is an odd feature. We didn't intend to implement that.
+// This is here just for compatibility with MSVC.
+class DefinedLocalImport : public Defined {
+public:
+ DefinedLocalImport(StringRef N, Defined *S)
+ : Defined(DefinedLocalImportKind, N), Data(S) {}
+
+ static bool classof(const SymbolBody *S) {
+ return S->kind() == DefinedLocalImportKind;
+ }
+
+ uint64_t getRVA() { return Data.getRVA(); }
+ Chunk *getChunk() { return &Data; }
+
+private:
+ LocalImportChunk Data;
+};
+
+class DefinedBitcode : public Defined {
+ friend SymbolBody;
+public:
+ DefinedBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable)
+ : Defined(DefinedBitcodeKind, N), File(F) {
+ this->IsReplaceable = IsReplaceable;
+ }
+
+ static bool classof(const SymbolBody *S) {
+ return S->kind() == DefinedBitcodeKind;
+ }
+
+private:
+ BitcodeFile *File;
+};
+
+inline uint64_t Defined::getRVA() {
+ switch (kind()) {
+ case DefinedAbsoluteKind:
+ return cast<DefinedAbsolute>(this)->getRVA();
+ case DefinedRelativeKind:
+ return cast<DefinedRelative>(this)->getRVA();
+ case DefinedImportDataKind:
+ return cast<DefinedImportData>(this)->getRVA();
+ case DefinedImportThunkKind:
+ return cast<DefinedImportThunk>(this)->getRVA();
+ case DefinedLocalImportKind:
+ return cast<DefinedLocalImport>(this)->getRVA();
+ case DefinedCommonKind:
+ return cast<DefinedCommon>(this)->getRVA();
+ case DefinedRegularKind:
+ return cast<DefinedRegular>(this)->getRVA();
+ case DefinedBitcodeKind:
+ llvm_unreachable("There is no address for a bitcode symbol.");
+ case LazyKind:
+ case UndefinedKind:
+ llvm_unreachable("Cannot get the address for an undefined symbol.");
+ }
+ llvm_unreachable("unknown symbol kind");
+}
+
+} // namespace coff
+} // namespace lld
+
+#endif
diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp
new file mode 100644
index 000000000000..a74b316b87a4
--- /dev/null
+++ b/COFF/Writer.cpp
@@ -0,0 +1,765 @@
+//===- Writer.cpp ---------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Config.h"
+#include "DLL.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "SymbolTable.h"
+#include "Symbols.h"
+#include "Writer.h"
+#include "lld/Core/Parallel.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstdio>
+#include <map>
+#include <memory>
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::COFF;
+using namespace llvm::object;
+using namespace llvm::support;
+using namespace llvm::support::endian;
+using namespace lld;
+using namespace lld::coff;
+
+static const int PageSize = 4096;
+static const int SectorSize = 512;
+static const int DOSStubSize = 64;
+static const int NumberfOfDataDirectory = 16;
+
+namespace {
+// The writer writes a SymbolTable result to a file.
+class Writer {
+public:
+ Writer(SymbolTable *T) : Symtab(T) {}
+ void run();
+
+private:
+ void createSections();
+ void createMiscChunks();
+ void createImportTables();
+ void createExportTable();
+ void assignAddresses();
+ void removeEmptySections();
+ void createSymbolAndStringTable();
+ void openFile(StringRef OutputPath);
+ template <typename PEHeaderTy> void writeHeader();
+ void fixSafeSEHSymbols();
+ void writeSections();
+ void sortExceptionTable();
+ void applyRelocations();
+
+ llvm::Optional<coff_symbol16> createSymbol(Defined *D);
+ size_t addEntryToStringTable(StringRef Str);
+
+ OutputSection *findSection(StringRef Name);
+ OutputSection *createSection(StringRef Name);
+ void addBaserels(OutputSection *Dest);
+ void addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V);
+
+ uint32_t getSizeOfInitializedData();
+ std::map<StringRef, std::vector<DefinedImportData *>> binImports();
+
+ SymbolTable *Symtab;
+ std::unique_ptr<llvm::FileOutputBuffer> Buffer;
+ llvm::SpecificBumpPtrAllocator<OutputSection> CAlloc;
+ llvm::SpecificBumpPtrAllocator<BaserelChunk> BAlloc;
+ std::vector<OutputSection *> OutputSections;
+ std::vector<char> Strtab;
+ std::vector<llvm::object::coff_symbol16> OutputSymtab;
+ IdataContents Idata;
+ DelayLoadContents DelayIdata;
+ EdataContents Edata;
+ std::unique_ptr<SEHTableChunk> SEHTable;
+
+ uint64_t FileSize;
+ uint32_t PointerToSymbolTable = 0;
+ uint64_t SizeOfImage;
+ uint64_t SizeOfHeaders;
+
+ std::vector<std::unique_ptr<Chunk>> Chunks;
+};
+} // anonymous namespace
+
+namespace lld {
+namespace coff {
+
+void writeResult(SymbolTable *T) { Writer(T).run(); }
+
+// OutputSection represents a section in an output file. It's a
+// container of chunks. OutputSection and Chunk are 1:N relationship.
+// Chunks cannot belong to more than one OutputSections. The writer
+// creates multiple OutputSections and assign them unique,
+// non-overlapping file offsets and RVAs.
+class OutputSection {
+public:
+ OutputSection(StringRef N) : Name(N), Header({}) {}
+ void setRVA(uint64_t);
+ void setFileOffset(uint64_t);
+ void addChunk(Chunk *C);
+ StringRef getName() { return Name; }
+ std::vector<Chunk *> &getChunks() { return Chunks; }
+ void addPermissions(uint32_t C);
+ uint32_t getPermissions() { return Header.Characteristics & PermMask; }
+ uint32_t getCharacteristics() { return Header.Characteristics; }
+ uint64_t getRVA() { return Header.VirtualAddress; }
+ uint64_t getFileOff() { return Header.PointerToRawData; }
+ void writeHeaderTo(uint8_t *Buf);
+
+ // Returns the size of this section in an executable memory image.
+ // This may be smaller than the raw size (the raw size is multiple
+ // of disk sector size, so there may be padding at end), or may be
+ // larger (if that's the case, the loader reserves spaces after end
+ // of raw data).
+ uint64_t getVirtualSize() { return Header.VirtualSize; }
+
+ // Returns the size of the section in the output file.
+ uint64_t getRawSize() { return Header.SizeOfRawData; }
+
+ // Set offset into the string table storing this section name.
+ // Used only when the name is longer than 8 bytes.
+ void setStringTableOff(uint32_t V) { StringTableOff = V; }
+
+ // N.B. The section index is one based.
+ uint32_t SectionIndex = 0;
+
+private:
+ StringRef Name;
+ coff_section Header;
+ uint32_t StringTableOff = 0;
+ std::vector<Chunk *> Chunks;
+};
+
+void OutputSection::setRVA(uint64_t RVA) {
+ Header.VirtualAddress = RVA;
+ for (Chunk *C : Chunks)
+ C->setRVA(C->getRVA() + RVA);
+}
+
+void OutputSection::setFileOffset(uint64_t Off) {
+ // If a section has no actual data (i.e. BSS section), we want to
+ // set 0 to its PointerToRawData. Otherwise the output is rejected
+ // by the loader.
+ if (Header.SizeOfRawData == 0)
+ return;
+ Header.PointerToRawData = Off;
+}
+
+void OutputSection::addChunk(Chunk *C) {
+ Chunks.push_back(C);
+ C->setOutputSection(this);
+ uint64_t Off = Header.VirtualSize;
+ Off = RoundUpToAlignment(Off, C->getAlign());
+ C->setRVA(Off);
+ C->setOutputSectionOff(Off);
+ Off += C->getSize();
+ Header.VirtualSize = Off;
+ if (C->hasData())
+ Header.SizeOfRawData = RoundUpToAlignment(Off, SectorSize);
+}
+
+void OutputSection::addPermissions(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);
+ *Hdr = Header;
+ if (StringTableOff) {
+ // If name is too long, write offset into the string table as a name.
+ sprintf(Hdr->Name, "/%d", StringTableOff);
+ } else {
+ assert(!Config->Debug || Name.size() <= COFF::NameSize);
+ strncpy(Hdr->Name, Name.data(),
+ std::min(Name.size(), (size_t)COFF::NameSize));
+ }
+}
+
+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");
+}
+
+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");
+}
+
+bool Defined::isExecutable() {
+ const auto X = IMAGE_SCN_MEM_EXECUTE;
+ if (auto *D = dyn_cast<DefinedRegular>(this))
+ return D->getChunk()->getOutputSection()->getPermissions() & X;
+ return isa<DefinedImportThunk>(this);
+}
+
+} // namespace coff
+} // namespace lld
+
+// The main function of the writer.
+void Writer::run() {
+ createSections();
+ createMiscChunks();
+ createImportTables();
+ createExportTable();
+ if (Config->Relocatable)
+ createSection(".reloc");
+ assignAddresses();
+ removeEmptySections();
+ createSymbolAndStringTable();
+ openFile(Config->OutputFile);
+ if (Config->is64()) {
+ writeHeader<pe32plus_header>();
+ } else {
+ writeHeader<pe32_header>();
+ }
+ fixSafeSEHSymbols();
+ writeSections();
+ sortExceptionTable();
+ error(Buffer->commit(), "Failed to write the output file");
+}
+
+static StringRef getOutputSection(StringRef Name) {
+ StringRef S = Name.split('$').first;
+ auto It = Config->Merge.find(S);
+ if (It == Config->Merge.end())
+ return S;
+ return It->second;
+}
+
+// Create output section objects and add them to OutputSections.
+void Writer::createSections() {
+ // First, bin chunks by name.
+ std::map<StringRef, std::vector<Chunk *>> Map;
+ for (Chunk *C : Symtab->getChunks()) {
+ auto *SC = dyn_cast<SectionChunk>(C);
+ if (SC && !SC->isLive()) {
+ if (Config->Verbose)
+ SC->printDiscardedMessage();
+ continue;
+ }
+ Map[C->getSectionName()].push_back(C);
+ }
+
+ // Then create an OutputSection for each section.
+ // '$' and all following characters in input section names are
+ // discarded when determining output section. So, .text$foo
+ // contributes to .text, for example. See PE/COFF spec 3.2.
+ SmallDenseMap<StringRef, OutputSection *> Sections;
+ for (auto Pair : Map) {
+ StringRef Name = getOutputSection(Pair.first);
+ OutputSection *&Sec = Sections[Name];
+ if (!Sec) {
+ Sec = new (CAlloc.Allocate()) OutputSection(Name);
+ OutputSections.push_back(Sec);
+ }
+ std::vector<Chunk *> &Chunks = Pair.second;
+ for (Chunk *C : Chunks) {
+ Sec->addChunk(C);
+ Sec->addPermissions(C->getPermissions());
+ }
+ }
+}
+
+void Writer::createMiscChunks() {
+ // Create thunks for locally-dllimported symbols.
+ if (!Symtab->LocalImportChunks.empty()) {
+ OutputSection *Sec = createSection(".rdata");
+ for (Chunk *C : Symtab->LocalImportChunks)
+ Sec->addChunk(C);
+ }
+
+ // Create SEH table. x86-only.
+ if (Config->Machine != I386)
+ return;
+ std::set<Defined *> Handlers;
+ for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) {
+ if (!File->SEHCompat)
+ return;
+ for (SymbolBody *B : File->SEHandlers)
+ Handlers.insert(cast<Defined>(B->repl()));
+ }
+ SEHTable.reset(new SEHTableChunk(Handlers));
+ createSection(".rdata")->addChunk(SEHTable.get());
+}
+
+// Create .idata section for the DLL-imported symbol table.
+// The format of this section is inherently Windows-specific.
+// IdataContents class abstracted away the details for us,
+// so we just let it create chunks and add them to the section.
+void Writer::createImportTables() {
+ if (Symtab->ImportFiles.empty())
+ return;
+
+ // Initialize DLLOrder so that import entries are ordered in
+ // the same order as in the command line. (That affects DLL
+ // initialization order, and this ordering is MSVC-compatible.)
+ for (ImportFile *File : Symtab->ImportFiles) {
+ std::string DLL = StringRef(File->DLLName).lower();
+ if (Config->DLLOrder.count(DLL) == 0)
+ Config->DLLOrder[DLL] = Config->DLLOrder.size();
+ }
+
+ OutputSection *Text = createSection(".text");
+ for (ImportFile *File : Symtab->ImportFiles) {
+ if (DefinedImportThunk *Thunk = File->ThunkSym)
+ Text->addChunk(Thunk->getChunk());
+ if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) {
+ DelayIdata.add(File->ImpSym);
+ } else {
+ Idata.add(File->ImpSym);
+ }
+ }
+ if (!Idata.empty()) {
+ OutputSection *Sec = createSection(".idata");
+ for (Chunk *C : Idata.getChunks())
+ Sec->addChunk(C);
+ }
+ if (!DelayIdata.empty()) {
+ Defined *Helper = cast<Defined>(Config->DelayLoadHelper->repl());
+ DelayIdata.create(Helper);
+ OutputSection *Sec = createSection(".didat");
+ for (Chunk *C : DelayIdata.getChunks())
+ Sec->addChunk(C);
+ Sec = createSection(".data");
+ for (Chunk *C : DelayIdata.getDataChunks())
+ Sec->addChunk(C);
+ Sec = createSection(".text");
+ for (std::unique_ptr<Chunk> &C : DelayIdata.getCodeChunks())
+ Sec->addChunk(C.get());
+ }
+}
+
+void Writer::createExportTable() {
+ if (Config->Exports.empty())
+ return;
+ OutputSection *Sec = createSection(".edata");
+ for (std::unique_ptr<Chunk> &C : Edata.Chunks)
+ Sec->addChunk(C.get());
+}
+
+// The Windows loader doesn't seem to like empty sections,
+// so we remove them if any.
+void Writer::removeEmptySections() {
+ auto IsEmpty = [](OutputSection *S) { return S->getVirtualSize() == 0; };
+ OutputSections.erase(
+ std::remove_if(OutputSections.begin(), OutputSections.end(), IsEmpty),
+ OutputSections.end());
+ uint32_t Idx = 1;
+ for (OutputSection *Sec : OutputSections)
+ Sec->SectionIndex = Idx++;
+}
+
+size_t Writer::addEntryToStringTable(StringRef Str) {
+ assert(Str.size() > COFF::NameSize);
+ size_t OffsetOfEntry = Strtab.size() + 4; // +4 for the size field
+ Strtab.insert(Strtab.end(), Str.begin(), Str.end());
+ Strtab.push_back('\0');
+ return OffsetOfEntry;
+}
+
+Optional<coff_symbol16> Writer::createSymbol(Defined *Def) {
+ if (auto *D = dyn_cast<DefinedRegular>(Def))
+ if (!D->getChunk()->isLive())
+ return None;
+
+ coff_symbol16 Sym;
+ StringRef Name = Def->getName();
+ if (Name.size() > COFF::NameSize) {
+ Sym.Name.Offset.Zeroes = 0;
+ Sym.Name.Offset.Offset = addEntryToStringTable(Name);
+ } else {
+ memset(Sym.Name.ShortName, 0, COFF::NameSize);
+ memcpy(Sym.Name.ShortName, Name.data(), Name.size());
+ }
+
+ if (auto *D = dyn_cast<DefinedCOFF>(Def)) {
+ COFFSymbolRef Ref = D->getCOFFSymbol();
+ Sym.Type = Ref.getType();
+ Sym.StorageClass = Ref.getStorageClass();
+ } else {
+ Sym.Type = IMAGE_SYM_TYPE_NULL;
+ Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
+ }
+ Sym.NumberOfAuxSymbols = 0;
+
+ switch (Def->kind()) {
+ case SymbolBody::DefinedAbsoluteKind:
+ case SymbolBody::DefinedRelativeKind:
+ Sym.Value = Def->getRVA();
+ Sym.SectionNumber = IMAGE_SYM_ABSOLUTE;
+ break;
+ default: {
+ uint64_t RVA = Def->getRVA();
+ OutputSection *Sec = nullptr;
+ for (OutputSection *S : OutputSections) {
+ if (S->getRVA() > RVA)
+ break;
+ Sec = S;
+ }
+ Sym.Value = RVA - Sec->getRVA();
+ Sym.SectionNumber = Sec->SectionIndex;
+ break;
+ }
+ }
+ return Sym;
+}
+
+void Writer::createSymbolAndStringTable() {
+ if (!Config->Debug || !Config->WriteSymtab)
+ return;
+
+ // Name field in the section table is 8 byte long. Longer names need
+ // to be written to the string table. First, construct string table.
+ for (OutputSection *Sec : OutputSections) {
+ StringRef Name = Sec->getName();
+ if (Name.size() <= COFF::NameSize)
+ continue;
+ Sec->setStringTableOff(addEntryToStringTable(Name));
+ }
+
+ for (lld::coff::ObjectFile *File : Symtab->ObjectFiles)
+ for (SymbolBody *B : File->getSymbols())
+ if (auto *D = dyn_cast<Defined>(B))
+ if (Optional<coff_symbol16> Sym = createSymbol(D))
+ OutputSymtab.push_back(*Sym);
+
+ for (ImportFile *File : Symtab->ImportFiles)
+ for (SymbolBody *B : File->getSymbols())
+ if (Optional<coff_symbol16> Sym = createSymbol(cast<Defined>(B)))
+ OutputSymtab.push_back(*Sym);
+
+ OutputSection *LastSection = OutputSections.back();
+ // We position the symbol table to be adjacent to the end of the last section.
+ uint64_t FileOff =
+ LastSection->getFileOff() +
+ RoundUpToAlignment(LastSection->getRawSize(), SectorSize);
+ if (!OutputSymtab.empty()) {
+ PointerToSymbolTable = FileOff;
+ FileOff += OutputSymtab.size() * sizeof(coff_symbol16);
+ }
+ if (!Strtab.empty())
+ FileOff += Strtab.size() + 4;
+ FileSize = RoundUpToAlignment(FileOff, SectorSize);
+}
+
+// Visits all sections to assign incremental, non-overlapping RVAs and
+// file offsets.
+void Writer::assignAddresses() {
+ SizeOfHeaders = DOSStubSize + sizeof(PEMagic) + sizeof(coff_file_header) +
+ sizeof(data_directory) * NumberfOfDataDirectory +
+ sizeof(coff_section) * OutputSections.size();
+ SizeOfHeaders +=
+ Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header);
+ SizeOfHeaders = RoundUpToAlignment(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
+ // the loader cannot handle holes.
+ std::stable_partition(
+ OutputSections.begin(), OutputSections.end(), [](OutputSection *S) {
+ return (S->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0;
+ });
+ for (OutputSection *Sec : OutputSections) {
+ if (Sec->getName() == ".reloc")
+ addBaserels(Sec);
+ Sec->setRVA(RVA);
+ Sec->setFileOffset(FileSize);
+ RVA += RoundUpToAlignment(Sec->getVirtualSize(), PageSize);
+ FileSize += RoundUpToAlignment(Sec->getRawSize(), SectorSize);
+ }
+ SizeOfImage = SizeOfHeaders + RoundUpToAlignment(RVA - 0x1000, PageSize);
+}
+
+template <typename PEHeaderTy> void Writer::writeHeader() {
+ // Write DOS stub
+ uint8_t *Buf = Buffer->getBufferStart();
+ auto *DOS = reinterpret_cast<dos_header *>(Buf);
+ Buf += DOSStubSize;
+ DOS->Magic[0] = 'M';
+ DOS->Magic[1] = 'Z';
+ DOS->AddressOfRelocationTable = sizeof(dos_header);
+ DOS->AddressOfNewExeHeader = DOSStubSize;
+
+ // Write PE magic
+ memcpy(Buf, PEMagic, sizeof(PEMagic));
+ Buf += sizeof(PEMagic);
+
+ // Write COFF header
+ auto *COFF = reinterpret_cast<coff_file_header *>(Buf);
+ Buf += sizeof(*COFF);
+ COFF->Machine = Config->Machine;
+ COFF->NumberOfSections = OutputSections.size();
+ COFF->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
+ if (Config->LargeAddressAware)
+ COFF->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
+ if (!Config->is64())
+ COFF->Characteristics |= IMAGE_FILE_32BIT_MACHINE;
+ if (Config->DLL)
+ COFF->Characteristics |= IMAGE_FILE_DLL;
+ if (!Config->Relocatable)
+ COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
+ COFF->SizeOfOptionalHeader =
+ sizeof(PEHeaderTy) + sizeof(data_directory) * NumberfOfDataDirectory;
+
+ // Write PE header
+ auto *PE = reinterpret_cast<PEHeaderTy *>(Buf);
+ Buf += sizeof(*PE);
+ PE->Magic = Config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32;
+ PE->ImageBase = Config->ImageBase;
+ PE->SectionAlignment = PageSize;
+ PE->FileAlignment = SectorSize;
+ PE->MajorImageVersion = Config->MajorImageVersion;
+ PE->MinorImageVersion = Config->MinorImageVersion;
+ PE->MajorOperatingSystemVersion = Config->MajorOSVersion;
+ PE->MinorOperatingSystemVersion = Config->MinorOSVersion;
+ PE->MajorSubsystemVersion = Config->MajorOSVersion;
+ PE->MinorSubsystemVersion = Config->MinorOSVersion;
+ PE->Subsystem = Config->Subsystem;
+ PE->SizeOfImage = SizeOfImage;
+ PE->SizeOfHeaders = SizeOfHeaders;
+ if (!Config->NoEntry) {
+ Defined *Entry = cast<Defined>(Config->Entry->repl());
+ PE->AddressOfEntryPoint = Entry->getRVA();
+ // Pointer to thumb code must have the LSB set, so adjust it.
+ if (Config->Machine == ARMNT)
+ PE->AddressOfEntryPoint |= 1;
+ }
+ PE->SizeOfStackReserve = Config->StackReserve;
+ PE->SizeOfStackCommit = Config->StackCommit;
+ PE->SizeOfHeapReserve = Config->HeapReserve;
+ PE->SizeOfHeapCommit = Config->HeapCommit;
+ 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)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION;
+ if (Config->TerminalServerAware)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE;
+ PE->NumberOfRvaAndSize = NumberfOfDataDirectory;
+ if (OutputSection *Text = findSection(".text")) {
+ PE->BaseOfCode = Text->getRVA();
+ PE->SizeOfCode = Text->getRawSize();
+ }
+ PE->SizeOfInitializedData = getSizeOfInitializedData();
+
+ // Write data directory
+ auto *Dir = reinterpret_cast<data_directory *>(Buf);
+ Buf += sizeof(*Dir) * NumberfOfDataDirectory;
+ if (OutputSection *Sec = findSection(".edata")) {
+ Dir[EXPORT_TABLE].RelativeVirtualAddress = Sec->getRVA();
+ Dir[EXPORT_TABLE].Size = Sec->getVirtualSize();
+ }
+ if (!Idata.empty()) {
+ Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA();
+ Dir[IMPORT_TABLE].Size = Idata.getDirSize();
+ Dir[IAT].RelativeVirtualAddress = Idata.getIATRVA();
+ Dir[IAT].Size = Idata.getIATSize();
+ }
+ if (!DelayIdata.empty()) {
+ Dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress =
+ DelayIdata.getDirRVA();
+ Dir[DELAY_IMPORT_DESCRIPTOR].Size = DelayIdata.getDirSize();
+ }
+ if (OutputSection *Sec = findSection(".rsrc")) {
+ Dir[RESOURCE_TABLE].RelativeVirtualAddress = Sec->getRVA();
+ Dir[RESOURCE_TABLE].Size = Sec->getVirtualSize();
+ }
+ if (OutputSection *Sec = findSection(".reloc")) {
+ Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = Sec->getRVA();
+ Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize();
+ }
+ if (OutputSection *Sec = findSection(".pdata")) {
+ Dir[EXCEPTION_TABLE].RelativeVirtualAddress = Sec->getRVA();
+ Dir[EXCEPTION_TABLE].Size = Sec->getVirtualSize();
+ }
+ 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;
+ }
+ }
+ if (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) {
+ if (Defined *B = dyn_cast<Defined>(Sym->Body)) {
+ Dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = B->getRVA();
+ Dir[LOAD_CONFIG_TABLE].Size = Config->is64() ? 112 : 64;
+ }
+ }
+
+ // Write section table
+ for (OutputSection *Sec : OutputSections) {
+ Sec->writeHeaderTo(Buf);
+ Buf += sizeof(coff_section);
+ }
+
+ if (OutputSymtab.empty())
+ return;
+
+ COFF->PointerToSymbolTable = PointerToSymbolTable;
+ uint32_t NumberOfSymbols = OutputSymtab.size();
+ COFF->NumberOfSymbols = NumberOfSymbols;
+ auto *SymbolTable = reinterpret_cast<coff_symbol16 *>(
+ Buffer->getBufferStart() + COFF->PointerToSymbolTable);
+ for (size_t I = 0; I != NumberOfSymbols; ++I)
+ SymbolTable[I] = OutputSymtab[I];
+ // Create the string table, it follows immediately after the symbol table.
+ // 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());
+}
+
+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);
+}
+
+void Writer::fixSafeSEHSymbols() {
+ if (!SEHTable)
+ return;
+ Config->SEHTable->setRVA(SEHTable->getRVA());
+ Config->SEHCount->setVA(SEHTable->getSize() / 4);
+}
+
+// Write section contents to a mmap'ed file.
+void Writer::writeSections() {
+ uint8_t *Buf = Buffer->getBufferStart();
+ for (OutputSection *Sec : OutputSections) {
+ uint8_t *SecBuf = Buf + Sec->getFileOff();
+ // Fill gaps between functions in .text with INT3 instructions
+ // instead of leaving as NUL bytes (which can be interpreted as
+ // ADD instructions).
+ if (Sec->getPermissions() & IMAGE_SCN_CNT_CODE)
+ memset(SecBuf, 0xCC, Sec->getRawSize());
+ parallel_for_each(Sec->getChunks().begin(), Sec->getChunks().end(),
+ [&](Chunk *C) { C->writeTo(SecBuf); });
+ }
+}
+
+// Sort .pdata section contents according to PE/COFF spec 5.5.
+void Writer::sortExceptionTable() {
+ OutputSection *Sec = findSection(".pdata");
+ if (!Sec)
+ return;
+ // We assume .pdata contains function table entries only.
+ uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff();
+ uint8_t *End = Begin + Sec->getVirtualSize();
+ if (Config->Machine == AMD64) {
+ struct Entry { ulittle32_t Begin, End, Unwind; };
+ parallel_sort(
+ (Entry *)Begin, (Entry *)End,
+ [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
+ return;
+ }
+ if (Config->Machine == ARMNT) {
+ struct Entry { ulittle32_t Begin, Unwind; };
+ parallel_sort(
+ (Entry *)Begin, (Entry *)End,
+ [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; });
+ return;
+ }
+ errs() << "warning: don't know how to handle .pdata.\n";
+}
+
+OutputSection *Writer::findSection(StringRef Name) {
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->getName() == Name)
+ return Sec;
+ return nullptr;
+}
+
+uint32_t Writer::getSizeOfInitializedData() {
+ uint32_t Res = 0;
+ for (OutputSection *S : OutputSections)
+ if (S->getPermissions() & IMAGE_SCN_CNT_INITIALIZED_DATA)
+ Res += S->getRawSize();
+ return Res;
+}
+
+// Returns an existing section or create a new one if not found.
+OutputSection *Writer::createSection(StringRef Name) {
+ if (auto *Sec = findSection(Name))
+ return Sec;
+ const auto DATA = IMAGE_SCN_CNT_INITIALIZED_DATA;
+ const auto BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+ const auto CODE = IMAGE_SCN_CNT_CODE;
+ const auto DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE;
+ const auto R = IMAGE_SCN_MEM_READ;
+ const auto W = IMAGE_SCN_MEM_WRITE;
+ const auto X = IMAGE_SCN_MEM_EXECUTE;
+ uint32_t Perms = StringSwitch<uint32_t>(Name)
+ .Case(".bss", BSS | R | W)
+ .Case(".data", DATA | R | W)
+ .Case(".didat", DATA | R)
+ .Case(".edata", DATA | R)
+ .Case(".idata", DATA | R)
+ .Case(".rdata", DATA | R)
+ .Case(".reloc", DATA | DISCARDABLE | R)
+ .Case(".text", CODE | R | X)
+ .Default(0);
+ if (!Perms)
+ llvm_unreachable("unknown section name");
+ auto Sec = new (CAlloc.Allocate()) OutputSection(Name);
+ Sec->addPermissions(Perms);
+ OutputSections.push_back(Sec);
+ return Sec;
+}
+
+// Dest is .reloc section. Add contents to that section.
+void Writer::addBaserels(OutputSection *Dest) {
+ std::vector<Baserel> V;
+ for (OutputSection *Sec : OutputSections) {
+ if (Sec == Dest)
+ continue;
+ // Collect all locations for base relocations.
+ for (Chunk *C : Sec->getChunks())
+ C->getBaserels(&V);
+ // Add the addresses to .reloc section.
+ if (!V.empty())
+ addBaserelBlocks(Dest, V);
+ V.clear();
+ }
+}
+
+// Add addresses to .reloc section. Note that addresses are grouped by page.
+void Writer::addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V) {
+ const uint32_t Mask = ~uint32_t(PageSize - 1);
+ uint32_t Page = V[0].RVA & Mask;
+ size_t I = 0, J = 1;
+ for (size_t E = V.size(); J < E; ++J) {
+ uint32_t P = V[J].RVA & Mask;
+ if (P == Page)
+ continue;
+ BaserelChunk *Buf = BAlloc.Allocate();
+ Dest->addChunk(new (Buf) BaserelChunk(Page, &V[I], &V[0] + J));
+ I = J;
+ Page = P;
+ }
+ if (I == J)
+ return;
+ BaserelChunk *Buf = BAlloc.Allocate();
+ Dest->addChunk(new (Buf) BaserelChunk(Page, &V[I], &V[0] + J));
+}
diff --git a/COFF/Writer.h b/COFF/Writer.h
new file mode 100644
index 000000000000..0473315ae50a
--- /dev/null
+++ b/COFF/Writer.h
@@ -0,0 +1,26 @@
+//===- Writer.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_WRITER_H
+#define LLD_COFF_WRITER_H
+
+#include <vector>
+
+namespace lld {
+namespace coff {
+
+class Chunk;
+class OutputSection;
+
+void writeResult(SymbolTable *T);
+
+}
+}
+
+#endif