Index: COFF/Chunks.h =================================================================== --- COFF/Chunks.h +++ /dev/null @@ -1,327 +0,0 @@ -//===- Chunks.h -----------------------------------------------------------===// -// -// 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 "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 -#include - -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) {} - - // The writer sets and uses the addresses. - uint64_t getRVA() { return RVA; } - uint64_t getFileOff() { return FileOff; } - uint32_t getAlign() { return Align; } - void setRVA(uint64_t V) { RVA = V; } - void setFileOff(uint64_t V) { FileOff = 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 *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 file. The writer sets a value. - uint64_t FileOff = 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 { -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) override; - bool hasData() const override; - uint32_t getPermissions() const override; - StringRef getSectionName() const override { return SectionName; } - void getBaserels(std::vector *Res) override; - bool isCOMDAT() const; - void applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P); - void applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P); - void applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P); - - // 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 Live; } - void markLive() { - assert(!Live && "Cannot mark an already live section!"); - Live = true; - } - - // Allow iteration over the bodies of this chunk's relocated symbols. - llvm::iterator_range 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 children() const { return AssocChildren; } - - // Used for ICF (Identical COMDAT Folding) - void replaceWith(SectionChunk *Other); - uint64_t getHash() const; - bool equals(const SectionChunk *Other) const; - - // 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 *Ptr; - -private: - ArrayRef getContents() const; - - // A file this chunk was created from. - ObjectFile *File; - - const coff_section *Header; - StringRef SectionName; - std::vector AssocChildren; - llvm::iterator_range Relocs; - size_t NumRelocs; - - // Used by the garbage collector. - bool Live = false; - - // Chunks are basically unnamed chunks of bytes. - // Symbols are associated for debugging and logging purposs only. - 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) 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) 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 *Res) override; - void writeTo(uint8_t *Buf) 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 *Res) override; - void writeTo(uint8_t *Buf) 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 *Res) override; - void writeTo(uint8_t *Buf) 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 S) : Syms(S) {} - size_t getSize() const override { return Syms.size() * 4; } - void writeTo(uint8_t *Buf) override; - -private: - std::set 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) override; - -private: - std::vector 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 Index: COFF/Chunks.cpp =================================================================== --- COFF/Chunks.cpp +++ COFF/Chunks.cpp @@ -7,10 +7,10 @@ // //===----------------------------------------------------------------------===// -#include "Chunks.h" -#include "Error.h" -#include "InputFiles.h" -#include "Symbols.h" +#include "lld/COFF/Chunks.h" +#include "lld/COFF/Error.h" +#include "lld/COFF/InputFiles.h" +#include "lld/COFF/Symbols.h" #include "llvm/Object/COFF.h" #include "llvm/Support/COFF.h" #include "llvm/Support/Debug.h" Index: COFF/Config.h =================================================================== --- COFF/Config.h +++ /dev/null @@ -1,131 +0,0 @@ -//===- Config.h -----------------------------------------------------------===// -// -// 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 -#include -#include -#include - -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 - StringRef ExtDLLName; // Symbol name written to a DLL export table - StringRef ExtLibName; // Symbol name written to a import library - Undefined *Sym = nullptr; - uint16_t Ordinal = 0; - bool Noname = false; - bool Data = false; - bool Private = false; - - 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 Relocatable = true; - bool Force = false; - bool Debug = false; - - // Symbols in this set are considered as live by the garbage collector. - std::set GCRoot; - - std::set NoDefaultLibs; - bool NoDefaultLibAll = false; - - // True if we are creating a DLL. - bool DLL = false; - StringRef Implib; - std::vector Exports; - std::set DelayLoads; - Undefined *DelayLoadHelper = nullptr; - - // Used for SafeSEH. - DefinedRelative *SEHTable = nullptr; - DefinedAbsolute *SEHCount = nullptr; - - // Used for /opt:icf - bool ICF = false; - - // Used for /merge:from=to (e.g. /merge:.rdata=.text) - std::map 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 MustMatch; - - // Used for /alternatename. - std::map 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 Index: COFF/DLL.h =================================================================== --- COFF/DLL.h +++ /dev/null @@ -1,84 +0,0 @@ -//===- DLL.h -------------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_COFF_DLL_H -#define LLD_COFF_DLL_H - -#include "Chunks.h" -#include "Symbols.h" - -namespace lld { -namespace coff { - -// Windows-specific. -// IdataContents creates all chunks for the 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 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 Imports; - std::vector> Dirs; - std::vector> Lookups; - std::vector> Addresses; - std::vector> Hints; - std::map> 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 getChunks(); - std::vector getDataChunks(); - std::vector> &getCodeChunks() { return Thunks; } - - uint64_t getDirRVA() { return Dirs[0]->getRVA(); } - uint64_t getDirSize(); - -private: - Chunk *newThunkChunk(DefinedImportData *S, Chunk *Dir); - - Defined *Helper; - std::vector Imports; - std::vector> Dirs; - std::vector> ModuleHandles; - std::vector> Addresses; - std::vector> Names; - std::vector> HintNames; - std::vector> Thunks; - std::map> DLLNames; -}; - -// Windows-specific. -// EdataContents creates all chunks for the DLL export table. -class EdataContents { -public: - EdataContents(); - std::vector> Chunks; -}; - -} // namespace coff -} // namespace lld - -#endif Index: COFF/DLL.cpp =================================================================== --- COFF/DLL.cpp +++ COFF/DLL.cpp @@ -18,8 +18,8 @@ // //===----------------------------------------------------------------------===// -#include "Chunks.h" -#include "DLL.h" +#include "lld/COFF/Chunks.h" +#include "lld/COFF/DLL.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Object/COFF.h" #include "llvm/Support/Endian.h" Index: COFF/Driver.h =================================================================== --- COFF/Driver.h +++ COFF/Driver.h @@ -10,8 +10,8 @@ #ifndef LLD_COFF_DRIVER_H #define LLD_COFF_DRIVER_H -#include "Config.h" -#include "SymbolTable.h" +#include "lld/COFF/Config.h" +#include "lld/COFF/SymbolTable.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -7,13 +7,13 @@ // //===----------------------------------------------------------------------===// -#include "Config.h" +#include "lld/COFF/Config.h" #include "Driver.h" -#include "Error.h" -#include "InputFiles.h" -#include "SymbolTable.h" -#include "Symbols.h" -#include "Writer.h" +#include "lld/COFF/Error.h" +#include "lld/COFF/InputFiles.h" +#include "lld/COFF/SymbolTable.h" +#include "lld/COFF/Symbols.h" +#include "lld/COFF/Writer.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" Index: COFF/DriverUtils.cpp =================================================================== --- COFF/DriverUtils.cpp +++ COFF/DriverUtils.cpp @@ -13,10 +13,10 @@ // //===----------------------------------------------------------------------===// -#include "Config.h" +#include "lld/COFF/Config.h" #include "Driver.h" -#include "Error.h" -#include "Symbols.h" +#include "lld/COFF/Error.h" +#include "lld/COFF/Symbols.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" Index: COFF/Error.h =================================================================== --- COFF/Error.h +++ /dev/null @@ -1,28 +0,0 @@ -//===- Error.h ------------------------------------------------------------===// -// -// 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 void error(const ErrorOr &V, const Twine &Prefix) { - error(V.getError(), Prefix); -} - -} // namespace coff -} // namespace lld - -#endif Index: COFF/Error.cpp =================================================================== --- COFF/Error.cpp +++ COFF/Error.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" +#include "lld/COFF/Error.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/raw_ostream.h" Index: COFF/ICF.cpp =================================================================== --- COFF/ICF.cpp +++ COFF/ICF.cpp @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#include "Chunks.h" -#include "Symbols.h" +#include "lld/COFF/Chunks.h" +#include "lld/COFF/Symbols.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/STLExtras.h" #include Index: COFF/InputFiles.h =================================================================== --- COFF/InputFiles.h +++ /dev/null @@ -1,216 +0,0 @@ -//===- InputFiles.h -------------------------------------------------------===// -// -// 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 -#include -#include - -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 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 &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); - - std::vector &getLazySymbols() { return LazySymbols; } - - // All symbols returned by ArchiveFiles are of Lazy type. - std::vector &getSymbols() override { - llvm_unreachable("internal error"); - } - -private: - std::unique_ptr File; - std::string Filename; - std::vector LazySymbols; - std::map Seen; - llvm::MallocAllocator Alloc; -}; - -// .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 &getChunks() { return Chunks; } - std::vector &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 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 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 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 SparseChunks; - - // List of all symbols referenced or defined by this file. - std::vector 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 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 &getSymbols() override { return SymbolBodies; } - -private: - void parse() override; - - std::vector 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 &getSymbols() override { return SymbolBodies; } - MachineTypes getMachineType() override; - - LTOModule *getModule() const { return M.get(); } - LTOModule *releaseModule() { return M.release(); } - -private: - void parse() override; - - std::vector SymbolBodies; - llvm::BumpPtrAllocator Alloc; - std::unique_ptr M; -}; - -} // namespace coff -} // namespace lld - -#endif Index: COFF/InputFiles.cpp =================================================================== --- COFF/InputFiles.cpp +++ COFF/InputFiles.cpp @@ -7,10 +7,10 @@ // //===----------------------------------------------------------------------===// -#include "Chunks.h" -#include "Error.h" -#include "InputFiles.h" -#include "Symbols.h" +#include "lld/COFF/Chunks.h" +#include "lld/COFF/Error.h" +#include "lld/COFF/InputFiles.h" +#include "lld/COFF/Symbols.h" #include "llvm/ADT/STLExtras.h" #include "llvm/LTO/LTOModule.h" #include "llvm/Object/COFF.h" Index: COFF/ModuleDef.cpp =================================================================== --- COFF/ModuleDef.cpp +++ COFF/ModuleDef.cpp @@ -16,8 +16,8 @@ // //===----------------------------------------------------------------------===// -#include "Config.h" -#include "Error.h" +#include "lld/COFF/Config.h" +#include "lld/COFF/Error.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/StringSaver.h" Index: COFF/SymbolTable.h =================================================================== --- COFF/SymbolTable.h +++ /dev/null @@ -1,117 +0,0 @@ -//===- SymbolTable.h ------------------------------------------------------===// -// -// 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" - -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 File); - std::vector> &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 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 COFF object representing the combined contents of BitcodeFiles - // and add it to the symbol table. Called after all files are added and - // before the writer writes results to a file. - void addCombinedLTOObject(); - - // The writer needs to handle DLL import libraries specially in - // order to create the import descriptor table. - std::vector ImportFiles; - - // The writer needs to infer the machine type from the object files. - std::vector 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 LocalImportChunks; - -private: - void readArchives(); - void readObjects(); - - void addSymbol(SymbolBody *New); - void addLazy(Lazy *New, std::vector *Accum); - Symbol *insert(SymbolBody *New); - StringRef findByPrefix(StringRef Prefix); - - void addMemberFile(Lazy *Body); - ObjectFile *createLTOObject(llvm::LTOCodeGenerator *CG); - - llvm::DenseMap Symtab; - - std::vector> Files; - std::vector ArchiveQueue; - std::vector ObjectQueue; - - std::vector BitcodeFiles; - std::unique_ptr LTOMB; - llvm::BumpPtrAllocator Alloc; -}; - -} // namespace coff -} // namespace lld - -#endif Index: COFF/SymbolTable.cpp =================================================================== --- COFF/SymbolTable.cpp +++ COFF/SymbolTable.cpp @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "Config.h" +#include "lld/COFF/Config.h" #include "Driver.h" -#include "Error.h" -#include "SymbolTable.h" -#include "Symbols.h" +#include "lld/COFF/Error.h" +#include "lld/COFF/SymbolTable.h" +#include "lld/COFF/Symbols.h" #include "llvm/ADT/STLExtras.h" #include "llvm/LTO/LTOCodeGenerator.h" #include "llvm/Support/Debug.h" Index: COFF/Symbols.h =================================================================== --- COFF/Symbols.h +++ /dev/null @@ -1,430 +0,0 @@ -//===- Symbols.h ----------------------------------------------------------===// -// -// 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 -#include -#include - -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) {} - std::atomic 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(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.load() : 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->Ptr) { - IsExternal = S.isExternal(); - IsCOMDAT = C->isCOMDAT(); - } - - static bool classof(const SymbolBody *S) { - return S->kind() == DefinedRegularKind; - } - - uint64_t getFileOff() { - return (*Data)->getFileOff() + Sym->Value; - } - - uint64_t getRVA() { return (*Data)->getRVA() + Sym->Value; } - bool isCOMDAT() { return IsCOMDAT; } - bool isLive() const { return (*Data)->isLive(); } - void markLive() { (*Data)->markLive(); } - 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(); } - uint64_t getFileOff() { return Data->getFileOff(); } - -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 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(); } - uint64_t getFileOff() { return Location->getFileOff(); } - - 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(); } - uint64_t getFileOff() { return Data->getFileOff(); } - Chunk *getChunk() { return Data.get(); } - -private: - std::unique_ptr 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(); } - uint64_t getFileOff() { return Data.getFileOff(); } - - 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(this)->getRVA(); - case DefinedRelativeKind: - return cast(this)->getRVA(); - case DefinedImportDataKind: - return cast(this)->getRVA(); - case DefinedImportThunkKind: - return cast(this)->getRVA(); - case DefinedLocalImportKind: - return cast(this)->getRVA(); - case DefinedCommonKind: - return cast(this)->getRVA(); - case DefinedRegularKind: - return cast(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 - -// Support isa<>, cast<> and dyn_cast<> for Symbol::Body. -namespace llvm { -template -struct simplify_type> { - typedef T *SimpleType; - static T *getSimplifiedValue(std::atomic &A) { return A.load(); } -}; -} - -#endif Index: COFF/Symbols.cpp =================================================================== --- COFF/Symbols.cpp +++ COFF/Symbols.cpp @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" -#include "InputFiles.h" -#include "Symbols.h" +#include "lld/COFF/Error.h" +#include "lld/COFF/InputFiles.h" +#include "lld/COFF/Symbols.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" Index: COFF/Writer.h =================================================================== --- COFF/Writer.h +++ /dev/null @@ -1,29 +0,0 @@ -//===- Writer.h -----------------------------------------------------------===// -// -// 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 - -namespace lld { -namespace coff { - -class Chunk; -class OutputSection; - -void writeResult(SymbolTable *T); - -// Implemented in ICF.cpp. -void doICF(const std::vector &Chunks); - -} -} - -#endif Index: COFF/Writer.cpp =================================================================== --- COFF/Writer.cpp +++ COFF/Writer.cpp @@ -7,13 +7,13 @@ // //===----------------------------------------------------------------------===// -#include "Config.h" -#include "DLL.h" -#include "Error.h" -#include "InputFiles.h" -#include "SymbolTable.h" -#include "Symbols.h" -#include "Writer.h" +#include "lld/COFF/Config.h" +#include "lld/COFF/DLL.h" +#include "lld/COFF/Error.h" +#include "lld/COFF/InputFiles.h" +#include "lld/COFF/SymbolTable.h" +#include "lld/COFF/Symbols.h" +#include "lld/COFF/Writer.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" Index: include/lld/COFF/Chunks.h =================================================================== --- /dev/null +++ include/lld/COFF/Chunks.h @@ -0,0 +1,327 @@ +//===- Chunks.h -----------------------------------------------------------===// +// +// 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 "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 +#include + +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) {} + + // The writer sets and uses the addresses. + uint64_t getRVA() { return RVA; } + uint64_t getFileOff() { return FileOff; } + uint32_t getAlign() { return Align; } + void setRVA(uint64_t V) { RVA = V; } + void setFileOff(uint64_t V) { FileOff = 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 *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 file. The writer sets a value. + uint64_t FileOff = 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 { +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) override; + bool hasData() const override; + uint32_t getPermissions() const override; + StringRef getSectionName() const override { return SectionName; } + void getBaserels(std::vector *Res) override; + bool isCOMDAT() const; + void applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P); + void applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P); + void applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P); + + // 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 Live; } + void markLive() { + assert(!Live && "Cannot mark an already live section!"); + Live = true; + } + + // Allow iteration over the bodies of this chunk's relocated symbols. + llvm::iterator_range 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 children() const { return AssocChildren; } + + // Used for ICF (Identical COMDAT Folding) + void replaceWith(SectionChunk *Other); + uint64_t getHash() const; + bool equals(const SectionChunk *Other) const; + + // 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 *Ptr; + +private: + ArrayRef getContents() const; + + // A file this chunk was created from. + ObjectFile *File; + + const coff_section *Header; + StringRef SectionName; + std::vector AssocChildren; + llvm::iterator_range Relocs; + size_t NumRelocs; + + // Used by the garbage collector. + bool Live = false; + + // Chunks are basically unnamed chunks of bytes. + // Symbols are associated for debugging and logging purposs only. + 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) 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) 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 *Res) override; + void writeTo(uint8_t *Buf) 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 *Res) override; + void writeTo(uint8_t *Buf) 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 *Res) override; + void writeTo(uint8_t *Buf) 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 S) : Syms(S) {} + size_t getSize() const override { return Syms.size() * 4; } + void writeTo(uint8_t *Buf) override; + +private: + std::set 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) override; + +private: + std::vector 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 Index: include/lld/COFF/Config.h =================================================================== --- /dev/null +++ include/lld/COFF/Config.h @@ -0,0 +1,131 @@ +//===- Config.h -----------------------------------------------------------===// +// +// 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 +#include +#include +#include + +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 + StringRef ExtDLLName; // Symbol name written to a DLL export table + StringRef ExtLibName; // Symbol name written to a import library + Undefined *Sym = nullptr; + uint16_t Ordinal = 0; + bool Noname = false; + bool Data = false; + bool Private = false; + + 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 Relocatable = true; + bool Force = false; + bool Debug = false; + + // Symbols in this set are considered as live by the garbage collector. + std::set GCRoot; + + std::set NoDefaultLibs; + bool NoDefaultLibAll = false; + + // True if we are creating a DLL. + bool DLL = false; + StringRef Implib; + std::vector Exports; + std::set DelayLoads; + Undefined *DelayLoadHelper = nullptr; + + // Used for SafeSEH. + DefinedRelative *SEHTable = nullptr; + DefinedAbsolute *SEHCount = nullptr; + + // Used for /opt:icf + bool ICF = false; + + // Used for /merge:from=to (e.g. /merge:.rdata=.text) + std::map 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 MustMatch; + + // Used for /alternatename. + std::map 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 Index: include/lld/COFF/DLL.h =================================================================== --- /dev/null +++ include/lld/COFF/DLL.h @@ -0,0 +1,84 @@ +//===- DLL.h -------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_DLL_H +#define LLD_COFF_DLL_H + +#include "Chunks.h" +#include "Symbols.h" + +namespace lld { +namespace coff { + +// Windows-specific. +// IdataContents creates all chunks for the 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 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 Imports; + std::vector> Dirs; + std::vector> Lookups; + std::vector> Addresses; + std::vector> Hints; + std::map> 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 getChunks(); + std::vector getDataChunks(); + std::vector> &getCodeChunks() { return Thunks; } + + uint64_t getDirRVA() { return Dirs[0]->getRVA(); } + uint64_t getDirSize(); + +private: + Chunk *newThunkChunk(DefinedImportData *S, Chunk *Dir); + + Defined *Helper; + std::vector Imports; + std::vector> Dirs; + std::vector> ModuleHandles; + std::vector> Addresses; + std::vector> Names; + std::vector> HintNames; + std::vector> Thunks; + std::map> DLLNames; +}; + +// Windows-specific. +// EdataContents creates all chunks for the DLL export table. +class EdataContents { +public: + EdataContents(); + std::vector> Chunks; +}; + +} // namespace coff +} // namespace lld + +#endif Index: include/lld/COFF/Error.h =================================================================== --- /dev/null +++ include/lld/COFF/Error.h @@ -0,0 +1,28 @@ +//===- Error.h ------------------------------------------------------------===// +// +// 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 void error(const ErrorOr &V, const Twine &Prefix) { + error(V.getError(), Prefix); +} + +} // namespace coff +} // namespace lld + +#endif Index: include/lld/COFF/InputFiles.h =================================================================== --- /dev/null +++ include/lld/COFF/InputFiles.h @@ -0,0 +1,216 @@ +//===- InputFiles.h -------------------------------------------------------===// +// +// 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 +#include +#include + +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 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 &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); + + std::vector &getLazySymbols() { return LazySymbols; } + + // All symbols returned by ArchiveFiles are of Lazy type. + std::vector &getSymbols() override { + llvm_unreachable("internal error"); + } + +private: + std::unique_ptr File; + std::string Filename; + std::vector LazySymbols; + std::map Seen; + llvm::MallocAllocator Alloc; +}; + +// .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 &getChunks() { return Chunks; } + std::vector &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 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 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 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 SparseChunks; + + // List of all symbols referenced or defined by this file. + std::vector 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 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 &getSymbols() override { return SymbolBodies; } + +private: + void parse() override; + + std::vector 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 &getSymbols() override { return SymbolBodies; } + MachineTypes getMachineType() override; + + LTOModule *getModule() const { return M.get(); } + LTOModule *releaseModule() { return M.release(); } + +private: + void parse() override; + + std::vector SymbolBodies; + llvm::BumpPtrAllocator Alloc; + std::unique_ptr M; +}; + +} // namespace coff +} // namespace lld + +#endif Index: include/lld/COFF/SymbolTable.h =================================================================== --- /dev/null +++ include/lld/COFF/SymbolTable.h @@ -0,0 +1,117 @@ +//===- SymbolTable.h ------------------------------------------------------===// +// +// 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" + +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 File); + std::vector> &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 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 COFF object representing the combined contents of BitcodeFiles + // and add it to the symbol table. Called after all files are added and + // before the writer writes results to a file. + void addCombinedLTOObject(); + + // The writer needs to handle DLL import libraries specially in + // order to create the import descriptor table. + std::vector ImportFiles; + + // The writer needs to infer the machine type from the object files. + std::vector 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 LocalImportChunks; + +private: + void readArchives(); + void readObjects(); + + void addSymbol(SymbolBody *New); + void addLazy(Lazy *New, std::vector *Accum); + Symbol *insert(SymbolBody *New); + StringRef findByPrefix(StringRef Prefix); + + void addMemberFile(Lazy *Body); + ObjectFile *createLTOObject(llvm::LTOCodeGenerator *CG); + + llvm::DenseMap Symtab; + + std::vector> Files; + std::vector ArchiveQueue; + std::vector ObjectQueue; + + std::vector BitcodeFiles; + std::unique_ptr LTOMB; + llvm::BumpPtrAllocator Alloc; +}; + +} // namespace coff +} // namespace lld + +#endif Index: include/lld/COFF/Symbols.h =================================================================== --- /dev/null +++ include/lld/COFF/Symbols.h @@ -0,0 +1,430 @@ +//===- Symbols.h ----------------------------------------------------------===// +// +// 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 +#include +#include + +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) {} + std::atomic 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(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.load() : 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->Ptr) { + IsExternal = S.isExternal(); + IsCOMDAT = C->isCOMDAT(); + } + + static bool classof(const SymbolBody *S) { + return S->kind() == DefinedRegularKind; + } + + uint64_t getFileOff() { + return (*Data)->getFileOff() + Sym->Value; + } + + uint64_t getRVA() { return (*Data)->getRVA() + Sym->Value; } + bool isCOMDAT() { return IsCOMDAT; } + bool isLive() const { return (*Data)->isLive(); } + void markLive() { (*Data)->markLive(); } + 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(); } + uint64_t getFileOff() { return Data->getFileOff(); } + +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 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(); } + uint64_t getFileOff() { return Location->getFileOff(); } + + 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(); } + uint64_t getFileOff() { return Data->getFileOff(); } + Chunk *getChunk() { return Data.get(); } + +private: + std::unique_ptr 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(); } + uint64_t getFileOff() { return Data.getFileOff(); } + + 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(this)->getRVA(); + case DefinedRelativeKind: + return cast(this)->getRVA(); + case DefinedImportDataKind: + return cast(this)->getRVA(); + case DefinedImportThunkKind: + return cast(this)->getRVA(); + case DefinedLocalImportKind: + return cast(this)->getRVA(); + case DefinedCommonKind: + return cast(this)->getRVA(); + case DefinedRegularKind: + return cast(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 + +// Support isa<>, cast<> and dyn_cast<> for Symbol::Body. +namespace llvm { +template +struct simplify_type> { + typedef T *SimpleType; + static T *getSimplifiedValue(std::atomic &A) { return A.load(); } +}; +} + +#endif Index: include/lld/COFF/Writer.h =================================================================== --- /dev/null +++ include/lld/COFF/Writer.h @@ -0,0 +1,29 @@ +//===- Writer.h -----------------------------------------------------------===// +// +// 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 + +namespace lld { +namespace coff { + +class Chunk; +class OutputSection; + +void writeResult(SymbolTable *T); + +// Implemented in ICF.cpp. +void doICF(const std::vector &Chunks); + +} +} + +#endif Index: include/lld/LinkDriver/LinkDriver.h =================================================================== --- /dev/null +++ include/lld/LinkDriver/LinkDriver.h @@ -0,0 +1,182 @@ +//===- lld/LinkDriver/LinkDriver.h - link.exe-compatible driver -*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines an interface to a link.exe-compatible driver. +// Used by lld-link. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_LINKDRIVER_LINKDRIVER_H +#define LLD_LINKDRIVER_LINKDRIVER_H + +#include "llvm/ADT/ArrayRef.h" + +#include "lld/COFF/Config.h" +#include "lld/COFF/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 +#include +#include +#include + +using namespace lld::coff; + +namespace lld { + +class LinkerDriver; +extern LinkerDriver *Driver; + +using llvm::COFF::MachineTypes; +using llvm::COFF::WindowsSubsystem; +using llvm::Optional; +class InputFile; + +// Entry point of the LINK linker. +// Uses exit(0) so no need to return type int. +void linkDriverMain(llvm::ArrayRef Args); + +class ArgParser { +public: + ArgParser() : Alloc(AllocAux) {} + // Parses command line options. + llvm::opt::InputArgList parse(llvm::ArrayRef Args); + + // Concatenate LINK environment varirable and given arguments and parse them. + llvm::opt::InputArgList parseLINK(llvm::ArrayRef 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 tokenize(StringRef S); + + std::vector replaceResponseFiles(std::vector); + + llvm::BumpPtrAllocator AllocAux; + llvm::StringSaver Alloc; +}; + +class LinkerDriver { +public: + LinkerDriver() : Alloc(AllocAux) {} + void link(llvm::ArrayRef 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 findFile(StringRef Filename); + Optional 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 SearchPaths; + std::set 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> 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 "[,]". +void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr); + +// Parses a string in the form of "[.]". +// Minor's default value is 0. +void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor); + +// Parses a string in the form of "[,[.]]". +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[,=]|NO". +void parseManifest(StringRef Arg); + +// Parses a string in the form of "level=|uiAccess=" +void parseManifestUAC(StringRef Arg); + +// Create a resource file containing a manifest XML. +std::unique_ptr 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 +convertResToCOFF(const std::vector &MBs); + +void touchFile(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 lld + +#endif Index: lib/CMakeLists.txt =================================================================== --- lib/CMakeLists.txt +++ lib/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(Config) add_subdirectory(Core) add_subdirectory(Driver) +add_subdirectory(LinkDriver) add_subdirectory(ReaderWriter) Index: lib/LinkDriver/CMakeLists.txt =================================================================== --- /dev/null +++ lib/LinkDriver/CMakeLists.txt @@ -0,0 +1,9 @@ +set(LLVM_TARGET_DEFINITIONS Options.td) +tablegen(LLVM Options.inc -gen-opt-parser-defs) +add_public_tablegen_target(LinkOptionsTableGen) + +add_llvm_library(LLDLinkDriver + LinkDriver.cpp + DriverUtils.cpp + ) +add_dependencies(LLDLinkDriver LinkOptionsTableGen) Index: lib/LinkDriver/DriverUtils.cpp =================================================================== --- /dev/null +++ lib/LinkDriver/DriverUtils.cpp @@ -0,0 +1,605 @@ +//===- 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 LinkDriver. +// This is because there are too many small functions. +// We created this separate file to make LinkDriver.cpp less cluttered. +// +//===----------------------------------------------------------------------===// + +#include "lld/LinkDriver/LinkDriver.h" +#include "lld/COFF/Config.h" +#include "lld/COFF/Error.h" +#include "lld/COFF/Symbols.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.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 + +using namespace llvm::COFF; +using namespace llvm; +using llvm::cl::ExpandResponseFiles; +using llvm::cl::TokenizeWindowsCommandLine; +using llvm::sys::Process; + +namespace lld { +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 ExeOrErr = llvm::sys::findProgramByName(Prog); + error(ExeOrErr, Twine("unable to find ") + Prog + " in PATH: "); + const char *Exe = Saver.save(ExeOrErr.get()); + 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 Args; +}; + +} // anonymous namespace + +// Returns /machine's value. +MachineTypes getMachineType(StringRef S) { + MachineTypes MT = StringSwitch(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 "[,]". +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 "[.]". +// 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 "[,[.]]". +void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, + uint32_t *Minor) { + StringRef SysStr, Ver; + std::tie(SysStr, Ver) = Arg.split(','); + *Sys = StringSwitch(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 "=". +// 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 "=". +// 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[,=]|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=|uiAccess=|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 << "\n" + << "\n"; + if (Config->ManifestUAC) { + OS << " \n" + << " \n" + << " \n" + << " \n" + << " \n" + << " \n" + << " \n"; + if (!Config->ManifestDependency.empty()) { + OS << " \n" + << " \n" + << " ManifestDependency << " />\n" + << " \n" + << " \n"; + } + } + OS << "\n"; + OS.flush(); + return S; +} + +// Create a resource file containing a manifest XML. +std::unique_ptr 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> 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 +// "[=][,@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); +} + +// Performs error checking on all /export arguments. +// It also sets ordinals. +void fixupExports() { + // Symbol ordinals must be unique. + std::set Ords; + for (Export &E : Config->Exports) { + if (E.Ordinal == 0) + continue; + if (!Ords.insert(E.Ordinal).second) + error(Twine("duplicate export ordinal: ") + E.Name); + } + + for (Export &E : Config->Exports) { + if (!E.ExtName.empty()) { + E.ExtDLLName = E.ExtName; + E.ExtLibName = E.ExtName; + continue; + } + StringRef S = E.Sym->repl()->getName(); + if (Config->Machine == I386 && S.startswith("_")) { + E.ExtDLLName = S.substr(1).split('@').first; + E.ExtLibName = S.substr(1); + continue; + } + E.ExtDLLName = S; + E.ExtLibName = S; + } + + // Uniquefy by name. + std::map Map; + std::vector V; + for (Export &E : Config->Exports) { + auto Pair = Map.insert(std::make_pair(E.ExtLibName, &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.ExtDLLName < B.ExtDLLName; + }); +} + +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 +convertResToCOFF(const std::vector &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> 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(); +} + +/// Creates a .def file containing the list of exported symbols. +static std::string createModuleDefinitionFile() { + std::string S; + llvm::raw_string_ostream OS(S); + OS << "LIBRARY \"" << llvm::sys::path::filename(Config->OutputFile) << "\"\n" + << "EXPORTS\n"; + for (Export &E : Config->Exports) { + OS << " " << E.ExtLibName; + if (E.Ordinal > 0) + OS << " @" << E.Ordinal; + if (E.Noname) + OS << " NONAME"; + if (E.Data) + OS << " DATA"; + if (E.Private) + OS << " PRIVATE"; + OS << "\n"; + } + OS.flush(); + return S; +} + +// Creates a .def file and runs lib.exe on it to create an import library. +void writeImportLibrary() { + std::string Contents = createModuleDefinitionFile(); + std::string Def = writeToTempFile(Contents); + llvm::FileRemover TempFile(Def); + + Executor E("lib.exe"); + E.add("/nologo"); + E.add("/machine:" + machineToStr(Config->Machine)); + E.add(Twine("/def:") + Def); + if (Config->Implib.empty()) { + SmallString<128> Out = StringRef(Config->OutputFile); + sys::path::replace_extension(Out, ".lib"); + E.add("/out:" + Out); + } else { + E.add("/out:" + Config->Implib); + } + E.run(); +} + +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); +} + +// 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, llvm::array_lengthof(infoTable), true) {} +}; + +// Parses a given list of options. +llvm::opt::InputArgList ArgParser::parse(ArrayRef ArgsArr) { + // First, replace respnose files (@-style options). + std::vector Argv = replaceResponseFiles(ArgsArr); + + // Make InputArgList from string vectors. + COFFOptTable Table; + unsigned MissingIndex; + unsigned MissingCount; + llvm::opt::InputArgList Args = + Table.ParseArgs(Argv, MissingIndex, MissingCount); + 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 Args) { + // Concatenate LINK env and given arguments and parse them. + Optional Env = Process::GetEnv("LINK"); + if (!Env) + return parse(Args); + std::vector V = tokenize(*Env); + V.insert(V.end(), Args.begin(), Args.end()); + return parse(V); +} + +std::vector ArgParser::tokenize(StringRef S) { + SmallVector Tokens; + StringSaver Saver(AllocAux); + llvm::cl::TokenizeWindowsCommandLine(S, Saver, Tokens); + return std::vector(Tokens.begin(), Tokens.end()); +} + +// Creates a new command line by replacing options starting with '@' +// character. '@' is replaced by the file's contents. +std::vector +ArgParser::replaceResponseFiles(std::vector Argv) { + SmallVector Tokens(Argv.data(), Argv.data() + Argv.size()); + StringSaver Saver(AllocAux); + ExpandResponseFiles(Saver, TokenizeWindowsCommandLine, Tokens); + return std::vector(Tokens.begin(), Tokens.end()); +} + +void printHelp(const char *Argv0) { + COFFOptTable Table; + Table.PrintHelp(llvm::outs(), Argv0, "LLVM Linker", false); +} + +} // namespace lld Index: lib/LinkDriver/LinkDriver.cpp =================================================================== --- /dev/null +++ lib/LinkDriver/LinkDriver.cpp @@ -0,0 +1,650 @@ +//===- LinkDriver.cpp - link.exe-compatible driver ------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines a link.exe-compatible driver +// Used by lld-link. +// +//===----------------------------------------------------------------------===// + +#include "lld/LinkDriver/LinkDriver.h" +#include "lld/COFF/Error.h" +#include "lld/COFF/InputFiles.h" +#include "lld/COFF/SymbolTable.h" +#include "lld/COFF/Symbols.h" +#include "lld/COFF/Writer.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/LibDriver/LibDriver.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/CommandLine.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 +#include + +using namespace llvm; +using namespace llvm::COFF; +using namespace lld; +using namespace lld::coff; +using llvm::sys::Process; +using llvm::sys::fs::OpenFlags; +using llvm::sys::fs::file_magic; +using llvm::sys::fs::identify_magic; + +namespace lld { + +Configuration *Config; +LinkerDriver *Driver; + +void linkDriverMain(llvm::ArrayRef Args) { + auto C = make_unique(); + Config = C.get(); + auto D = make_unique(); + Driver = D.get(); + 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 &MB = *MBOrErr; + MemoryBufferRef MBRef = MB->getMemBufferRef(); + OwningMBs.push_back(std::move(MB)); // take ownership + return MBRef; +} + +static std::unique_ptr 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(new lld::coff::ArchiveFile(MB)); + if (Magic == file_magic::bitcode) + return std::unique_ptr(new lld::coff::BitcodeFile(MB)); + if (Config->OutputFile == "") + Config->OutputFile = getOutputPath(MB.getBufferIdentifier()); + return std::unique_ptr(new lld::coff::ObjectFile(MB)); +} + +// 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 Path = findLib(Arg->getValue())) { + MemoryBufferRef MB = openFile(*Path); + Symtab.addFile(createFile(MB)); + } + break; + case OPT_export: { + Export E = parseExport(Arg->getValue()); + if (Config->Machine == I386 && E.ExtName.startswith("_")) + E.ExtName = E.ExtName.substr(1); + 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_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 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 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 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(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 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: + 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 S = StringRef(Arg->getValue()).lower(); + if (S == "noref") { + Config->DoGC = false; + continue; + } + if (S == "lldicf") { + Config->ICF = true; + continue; + } + if (S != "ref" && S != "icf" && S != "noicf" && + S != "lbr" && S != "nolbr" && + !StringRef(S).startswith("icf=")) { + 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; + + // Create a list of input files. Files can be given as arguments + // for /defaultlib option. + std::vector Paths; + std::vector MBs; + for (auto *Arg : Args.filtered(OPT_INPUT)) + if (Optional Path = findFile(Arg->getValue())) + Paths.push_back(*Path); + for (auto *Arg : Args.filtered(OPT_defaultlib)) + if (Optional 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 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 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 &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 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 && !E.Name.startswith("_@?")) + E.Name = mangle(E.Name); + 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); + 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(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 native COFF file + // then link that file. + Symtab.addCombinedLTOObject(); + + // 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) + continue; + error(Twine("/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()) { + 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)) + touchFile(Arg->getValue()); + + // 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 lld Index: lib/LinkDriver/Options.td =================================================================== --- /dev/null +++ lib/LinkDriver/Options.td @@ -0,0 +1,121 @@ +include "llvm/Option/OptParser.td" + +// link.exe accepts options starting with either a dash or a slash. + +// Flag that takes no arguments. +class F : Flag<["/", "-", "-?"], name>; + +// Flag that takes one argument after ":". +class P : + Joined<["/", "-", "-?"], name#":">, HelpText; + +// Boolean flag suffixed by ":no". +multiclass B { + def "" : F; + def _no : F, HelpText; +} + +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; + +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 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; + +// Flags for debugging +def lldmap : Joined<["/", "-"], "lldmap:">; + +//============================================================================== +// The flags below do nothing. They are defined only for link.exe compatibility. +//============================================================================== + +class QF : Joined<["/", "-", "-?"], name#":">; + +multiclass QB { + def "" : F; + def _no : F; +} + +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">; + +defm wx : QB<"wx">; Index: tools/lld/CMakeLists.txt =================================================================== --- tools/lld/CMakeLists.txt +++ tools/lld/CMakeLists.txt @@ -11,16 +11,18 @@ install(TARGETS lld RUNTIME DESTINATION bin) -# Create the lld-link[.exe] symlink in the build directory. If symlink is not -# supported by the operating system, create a copy instead. if(UNIX) - set(command create_symlink) - # Make relative symlink - set(src "lld${CMAKE_EXECUTABLE_SUFFIX}") + set(LLD_LINK_OR_COPY create_symlink) + set(lld_binary "lld${CMAKE_EXECUTABLE_SUFFIX}") else() - set(command copy) - set(src "${LLVM_RUNTIME_OUTPUT_INTDIR}/lld${CMAKE_EXECUTABLE_SUFFIX}") + set(LLD_LINK_OR_COPY copy) + set(lld_binary "${LLVM_RUNTIME_OUTPUT_INTDIR}/lld${CMAKE_EXECUTABLE_SUFFIX}") endif() -set(dst "${LLVM_RUNTIME_OUTPUT_INTDIR}/lld-link${CMAKE_EXECUTABLE_SUFFIX}") -add_custom_command(TARGET lld POST_BUILD - COMMAND ${CMAKE_COMMAND} -E ${command} ${src} ${dst}) + +set(lld_link "${LLVM_RUNTIME_OUTPUT_INTDIR}/lld-link${CMAKE_EXECUTABLE_SUFFIX}") + +add_custom_command(OUTPUT ${lld_link} + COMMAND ${CMAKE_COMMAND} -E ${LLD_LINK_OR_COPY} "${lld_binary}" "${lld_link}" + DEPENDS lld) + +install(SCRIPT install_symlink.cmake -DCMAKE_INSTALL_PREFIX=\"${CMAKE_INSTALL_PREFIX}\") Index: tools/lld/install_symlink.cmake =================================================================== --- /dev/null +++ tools/lld/install_symlink.cmake @@ -0,0 +1,25 @@ +# We need to execute this script at installation time because the +# DESTDIR environment variable may be unset at configuration time. +# See PR8397. + +if(UNIX) + set(LINK_OR_COPY create_symlink) + set(DESTDIR $ENV{DESTDIR}) +else() + set(LINK_OR_COPY copy) +endif() + +# CMAKE_EXECUTABLE_SUFFIX is undefined on cmake scripts. See PR9286. +if( WIN32 ) + set(EXECUTABLE_SUFFIX ".exe") +else() + set(EXECUTABLE_SUFFIX "") +endif() + +set(bindir "${DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/") + +message("Creating lld-link") + +execute_process( + COMMAND "${CMAKE_COMMAND}" -E ${LINK_OR_COPY} "lld${EXECUTABLE_SUFFIX}" "lld-link${EXECUTABLE_SUFFIX}" + WORKING_DIRECTORY "${bindir}")