Index: vendor/lld/dist/CMakeLists.txt =================================================================== --- vendor/lld/dist/CMakeLists.txt (revision 293845) +++ vendor/lld/dist/CMakeLists.txt (revision 293846) @@ -1,99 +1,106 @@ set(LLD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(LLD_INCLUDE_DIR ${LLD_SOURCE_DIR}/include ) set(LLD_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) # Compute the LLD version from the LLVM version. string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" LLD_VERSION ${PACKAGE_VERSION}) message(STATUS "LLD version: ${LLD_VERSION}") string(REGEX REPLACE "([0-9]+)\\.[0-9]+(\\.[0-9]+)?" "\\1" LLD_VERSION_MAJOR ${LLD_VERSION}) string(REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.[0-9]+)?" "\\1" LLD_VERSION_MINOR ${LLD_VERSION}) # Determine LLD revision and repository. # TODO: Figure out a way to get the revision and the repository on windows. if ( NOT CMAKE_SYSTEM_NAME MATCHES "Windows" ) execute_process(COMMAND ${CMAKE_SOURCE_DIR}/utils/GetSourceVersion ${LLD_SOURCE_DIR} OUTPUT_VARIABLE LLD_REVISION) execute_process(COMMAND ${CMAKE_SOURCE_DIR}/utils/GetRepositoryPath ${LLD_SOURCE_DIR} OUTPUT_VARIABLE LLD_REPOSITORY) if ( LLD_REPOSITORY ) # Replace newline characters with spaces string(REGEX REPLACE "(\r?\n)+" " " LLD_REPOSITORY ${LLD_REPOSITORY}) # Remove leading spaces STRING(REGEX REPLACE "^[ \t\r\n]+" "" LLD_REPOSITORY "${LLD_REPOSITORY}" ) # Remove trailing spaces string(REGEX REPLACE "(\ )+$" "" LLD_REPOSITORY ${LLD_REPOSITORY}) endif() if ( LLD_REVISION ) # Replace newline characters with spaces string(REGEX REPLACE "(\r?\n)+" " " LLD_REVISION ${LLD_REVISION}) # Remove leading spaces STRING(REGEX REPLACE "^[ \t\r\n]+" "" LLD_REVISION "${LLD_REVISION}" ) # Remove trailing spaces string(REGEX REPLACE "(\ )+$" "" LLD_REVISION ${LLD_REVISION}) endif() endif () # Configure the Version.inc file. configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/include/lld/Config/Version.inc.in ${CMAKE_CURRENT_BINARY_DIR}/include/lld/Config/Version.inc) if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) message(FATAL_ERROR "In-source builds are not allowed. CMake would overwrite " "the makefiles distributed with LLVM. Please create a directory and run cmake " "from there, passing the path to this source directory as the last argument. " "This process created the file `CMakeCache.txt' and the directory " "`CMakeFiles'. Please delete them.") endif() list (APPEND CMAKE_MODULE_PATH "${LLD_SOURCE_DIR}/cmake/modules") option(LLD_USE_VTUNE "Enable VTune user task tracking." OFF) if (LLD_USE_VTUNE) find_package(VTune) if (VTUNE_FOUND) include_directories(${VTune_INCLUDE_DIRS}) list(APPEND LLVM_COMMON_LIBS ${VTune_LIBRARIES}) add_definitions(-DLLD_HAS_VTUNE) endif() endif() if (MSVC) add_definitions(-wd4530) # Suppress 'warning C4530: C++ exception handler used, but unwind semantics are not enabled.' add_definitions(-wd4062) # Suppress 'warning C4062: enumerator X in switch of enum Y is not handled' from system header. endif() include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/include ) if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) install(DIRECTORY include/ DESTINATION include FILES_MATCHING PATTERN "*.h" PATTERN ".svn" EXCLUDE ) endif() + +macro(add_lld_library name) + add_llvm_library(${name} ${ARGN}) + set_target_properties(${name} PROPERTIES FOLDER "lld libraries") +endmacro(add_lld_library) + add_subdirectory(lib) add_subdirectory(tools) if (LLVM_INCLUDE_TESTS) add_subdirectory(test) add_subdirectory(unittests) endif() add_subdirectory(docs) add_subdirectory(COFF) add_subdirectory(ELF) Index: vendor/lld/dist/COFF/CMakeLists.txt =================================================================== --- vendor/lld/dist/COFF/CMakeLists.txt (revision 293845) +++ vendor/lld/dist/COFF/CMakeLists.txt (revision 293846) @@ -1,33 +1,33 @@ set(LLVM_TARGET_DEFINITIONS Options.td) tablegen(LLVM Options.inc -gen-opt-parser-defs) add_public_tablegen_target(COFFOptionsTableGen) -add_llvm_library(lldCOFF +add_lld_library(lldCOFF Chunks.cpp DLL.cpp Driver.cpp DriverUtils.cpp Error.cpp ICF.cpp InputFiles.cpp MarkLive.cpp ModuleDef.cpp PDB.cpp SymbolTable.cpp Symbols.cpp Writer.cpp LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} Core LTO LibDriver Object MC MCDisassembler Target Option Support ) add_dependencies(lldCOFF COFFOptionsTableGen) Index: vendor/lld/dist/COFF/Chunks.cpp =================================================================== --- vendor/lld/dist/COFF/Chunks.cpp (revision 293845) +++ vendor/lld/dist/COFF/Chunks.cpp (revision 293846) @@ -1,340 +1,340 @@ //===- Chunks.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Chunks.h" #include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "llvm/Object/COFF.h" #include "llvm/Support/COFF.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" #include "llvm/Support/raw_ostream.h" #include using namespace llvm; using namespace llvm::object; using namespace llvm::support::endian; using namespace llvm::COFF; using llvm::support::ulittle32_t; namespace lld { namespace coff { SectionChunk::SectionChunk(ObjectFile *F, const coff_section *H) : Chunk(SectionKind), Repl(this), File(F), Header(H), Relocs(File->getCOFFObj()->getRelocations(Header)), NumRelocs(std::distance(Relocs.begin(), Relocs.end())) { // Initialize SectionName. File->getCOFFObj()->getSectionName(Header, SectionName); // Bit [20:24] contains section alignment. Both 0 and 1 mean alignment 1. unsigned Shift = (Header->Characteristics >> 20) & 0xF; if (Shift > 0) Align = uint32_t(1) << (Shift - 1); // Only COMDAT sections are subject of dead-stripping. Live = !isCOMDAT(); } static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); } static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); } static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); } static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); } void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const { uint64_t S = Sym->getRVA(); switch (Type) { case IMAGE_REL_AMD64_ADDR32: add32(Off, S + Config->ImageBase); break; case IMAGE_REL_AMD64_ADDR64: add64(Off, S + Config->ImageBase); break; case IMAGE_REL_AMD64_ADDR32NB: add32(Off, S); break; case IMAGE_REL_AMD64_REL32: add32(Off, S - P - 4); break; case IMAGE_REL_AMD64_REL32_1: add32(Off, S - P - 5); break; case IMAGE_REL_AMD64_REL32_2: add32(Off, S - P - 6); break; case IMAGE_REL_AMD64_REL32_3: add32(Off, S - P - 7); break; case IMAGE_REL_AMD64_REL32_4: add32(Off, S - P - 8); break; case IMAGE_REL_AMD64_REL32_5: add32(Off, S - P - 9); break; case IMAGE_REL_AMD64_SECTION: add16(Off, Sym->getSectionIndex()); break; case IMAGE_REL_AMD64_SECREL: add32(Off, Sym->getSecrel()); break; default: error("Unsupported relocation type"); } } void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const { uint64_t S = Sym->getRVA(); switch (Type) { case IMAGE_REL_I386_ABSOLUTE: break; case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break; case IMAGE_REL_I386_DIR32NB: add32(Off, S); break; case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break; case IMAGE_REL_I386_SECTION: add16(Off, Sym->getSectionIndex()); break; case IMAGE_REL_I386_SECREL: add32(Off, Sym->getSecrel()); break; default: error("Unsupported relocation type"); } } static void applyMOV(uint8_t *Off, uint16_t V) { or16(Off, ((V & 0x800) >> 1) | ((V >> 12) & 0xf)); or16(Off + 2, ((V & 0x700) << 4) | (V & 0xff)); } static void applyMOV32T(uint8_t *Off, uint32_t V) { applyMOV(Off, V); // set MOVW operand applyMOV(Off + 4, V >> 16); // set MOVT operand } static void applyBranch20T(uint8_t *Off, int32_t V) { uint32_t S = V < 0 ? 1 : 0; uint32_t J1 = (V >> 19) & 1; uint32_t J2 = (V >> 18) & 1; or16(Off, (S << 10) | ((V >> 12) & 0x3f)); or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); } static void applyBranch24T(uint8_t *Off, int32_t V) { uint32_t S = V < 0 ? 1 : 0; uint32_t J1 = ((~V >> 23) & 1) ^ S; uint32_t J2 = ((~V >> 22) & 1) ^ S; or16(Off, (S << 10) | ((V >> 12) & 0x3ff)); or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); } void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const { uint64_t S = Sym->getRVA(); // Pointer to thumb code must have the LSB set. if (Sym->isExecutable()) S |= 1; switch (Type) { case IMAGE_REL_ARM_ADDR32: add32(Off, S + Config->ImageBase); break; case IMAGE_REL_ARM_ADDR32NB: add32(Off, S); break; case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, S + Config->ImageBase); break; case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, S - P - 4); break; case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, S - P - 4); break; case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, S - P - 4); break; default: error("Unsupported relocation type"); } } void SectionChunk::writeTo(uint8_t *Buf) const { if (!hasData()) return; // Copy section contents from source object file to output file. ArrayRef A = getContents(); memcpy(Buf + OutputSectionOff, A.data(), A.size()); // Apply relocations. for (const coff_relocation &Rel : Relocs) { uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress; SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex)->repl(); Defined *Sym = cast(Body); uint64_t P = RVA + Rel.VirtualAddress; switch (Config->Machine) { case AMD64: applyRelX64(Off, Rel.Type, Sym, P); break; case I386: applyRelX86(Off, Rel.Type, Sym, P); break; case ARMNT: applyRelARM(Off, Rel.Type, Sym, P); break; default: llvm_unreachable("unknown machine type"); } } } void SectionChunk::addAssociative(SectionChunk *Child) { AssocChildren.push_back(Child); } static uint8_t getBaserelType(const coff_relocation &Rel) { switch (Config->Machine) { case AMD64: if (Rel.Type == IMAGE_REL_AMD64_ADDR64) return IMAGE_REL_BASED_DIR64; return IMAGE_REL_BASED_ABSOLUTE; case I386: if (Rel.Type == IMAGE_REL_I386_DIR32) return IMAGE_REL_BASED_HIGHLOW; return IMAGE_REL_BASED_ABSOLUTE; case ARMNT: if (Rel.Type == IMAGE_REL_ARM_ADDR32) return IMAGE_REL_BASED_HIGHLOW; if (Rel.Type == IMAGE_REL_ARM_MOV32T) return IMAGE_REL_BASED_ARM_MOV32T; return IMAGE_REL_BASED_ABSOLUTE; default: llvm_unreachable("unknown machine type"); } } // Windows-specific. // Collect all locations that contain absolute addresses, which need to be // fixed by the loader if load-time relocation is needed. // Only called when base relocation is enabled. void SectionChunk::getBaserels(std::vector *Res) { for (const coff_relocation &Rel : Relocs) { uint8_t Ty = getBaserelType(Rel); if (Ty == IMAGE_REL_BASED_ABSOLUTE) continue; SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex)->repl(); if (isa(Body)) continue; Res->emplace_back(RVA + Rel.VirtualAddress, Ty); } } bool SectionChunk::hasData() const { return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA); } uint32_t SectionChunk::getPermissions() const { return Header->Characteristics & PermMask; } bool SectionChunk::isCOMDAT() const { return Header->Characteristics & IMAGE_SCN_LNK_COMDAT; } void SectionChunk::printDiscardedMessage() const { // Removed by dead-stripping. If it's removed by ICF, ICF already // printed out the name, so don't repeat that here. if (Sym && this == Repl) llvm::outs() << "Discarded " << Sym->getName() << "\n"; } StringRef SectionChunk::getDebugName() { if (Sym) return Sym->getName(); return ""; } ArrayRef SectionChunk::getContents() const { ArrayRef A; File->getCOFFObj()->getSectionContents(Header, A); return A; } void SectionChunk::replace(SectionChunk *Other) { Other->Repl = Repl; Other->Live = false; } CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) { // Common symbols are aligned on natural boundaries up to 32 bytes. // This is what MSVC link.exe does. Align = std::min(uint64_t(32), NextPowerOf2(Sym.getValue())); } uint32_t CommonChunk::getPermissions() const { return IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; } void StringChunk::writeTo(uint8_t *Buf) const { memcpy(Buf + OutputSectionOff, Str.data(), Str.size()); } ImportThunkChunkX64::ImportThunkChunkX64(Defined *S) : ImpSymbol(S) { // Intel Optimization Manual says that all branch targets // should be 16-byte aligned. MSVC linker does this too. Align = 16; } void ImportThunkChunkX64::writeTo(uint8_t *Buf) const { memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86)); // The first two bytes is a JMP instruction. Fill its operand. write32le(Buf + OutputSectionOff + 2, ImpSymbol->getRVA() - RVA - getSize()); } void ImportThunkChunkX86::getBaserels(std::vector *Res) { Res->emplace_back(getRVA() + 2); } void ImportThunkChunkX86::writeTo(uint8_t *Buf) const { memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86)); // The first two bytes is a JMP instruction. Fill its operand. write32le(Buf + OutputSectionOff + 2, ImpSymbol->getRVA() + Config->ImageBase); } void ImportThunkChunkARM::getBaserels(std::vector *Res) { Res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T); } void ImportThunkChunkARM::writeTo(uint8_t *Buf) const { memcpy(Buf + OutputSectionOff, ImportThunkARM, sizeof(ImportThunkARM)); // Fix mov.w and mov.t operands. applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase); } void LocalImportChunk::getBaserels(std::vector *Res) { Res->emplace_back(getRVA()); } size_t LocalImportChunk::getSize() const { return Config->is64() ? 8 : 4; } void LocalImportChunk::writeTo(uint8_t *Buf) const { if (Config->is64()) { write64le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); } else { write32le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); } } void SEHTableChunk::writeTo(uint8_t *Buf) const { ulittle32_t *Begin = reinterpret_cast(Buf + OutputSectionOff); size_t Cnt = 0; for (Defined *D : Syms) Begin[Cnt++] = D->getRVA(); std::sort(Begin, Begin + Cnt); } // Windows-specific. // This class represents a block in .reloc section. BaserelChunk::BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End) { // Block header consists of 4 byte page RVA and 4 byte block size. // Each entry is 2 byte. Last entry may be padding. - Data.resize(RoundUpToAlignment((End - Begin) * 2 + 8, 4)); + Data.resize(align((End - Begin) * 2 + 8, 4)); uint8_t *P = Data.data(); write32le(P, Page); write32le(P + 4, Data.size()); P += 8; for (Baserel *I = Begin; I != End; ++I) { write16le(P, (I->Type << 12) | (I->RVA - Page)); P += 2; } } void BaserelChunk::writeTo(uint8_t *Buf) const { memcpy(Buf + OutputSectionOff, Data.data(), Data.size()); } uint8_t Baserel::getDefaultType() { switch (Config->Machine) { case AMD64: return IMAGE_REL_BASED_DIR64; case I386: return IMAGE_REL_BASED_HIGHLOW; default: llvm_unreachable("unknown machine type"); } } } // namespace coff } // namespace lld Index: vendor/lld/dist/COFF/Chunks.h =================================================================== --- vendor/lld/dist/COFF/Chunks.h (revision 293845) +++ vendor/lld/dist/COFF/Chunks.h (revision 293846) @@ -1,332 +1,336 @@ //===- Chunks.h -------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_COFF_CHUNKS_H #define LLD_COFF_CHUNKS_H #include "Config.h" #include "InputFiles.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Object/COFF.h" #include #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) const {} // The writer sets and uses the addresses. uint64_t getRVA() const { return RVA; } uint32_t getAlign() const { return Align; } void setRVA(uint64_t V) { RVA = V; } void setOutputSectionOff(uint64_t V) { OutputSectionOff = V; } // Returns true if this has non-zero data. BSS chunks return // false. If false is returned, the space occupied by this chunk // will be filled with zeros. virtual bool hasData() const { return true; } // Returns readable/writable/executable bits. virtual uint32_t getPermissions() const { return 0; } // Returns the section name if this is a section chunk. // It is illegal to call this function on non-section chunks. virtual StringRef getSectionName() const { llvm_unreachable("unimplemented getSectionName"); } // An output section has pointers to chunks in the section, and each // chunk has a back pointer to an output section. void setOutputSection(OutputSection *O) { Out = O; } OutputSection *getOutputSection() { return Out; } // Windows-specific. // Collect all locations that contain absolute addresses for base relocations. virtual void getBaserels(std::vector *Res) {} // Returns a human-readable name of this chunk. Chunks are unnamed chunks of // bytes, so this is used only for logging or debugging. virtual StringRef getDebugName() { return ""; } protected: Chunk(Kind K = OtherKind) : ChunkKind(K) {} const Kind ChunkKind; // The RVA of this chunk in the output. The writer sets a value. uint64_t RVA = 0; // The offset from beginning of the output section. The writer sets a value. uint64_t OutputSectionOff = 0; // The output section for this chunk. OutputSection *Out = nullptr; // The alignment of this chunk. The writer uses the value. uint32_t Align = 1; }; // A chunk corresponding a section of an input file. class SectionChunk : public Chunk { // Identical COMDAT Folding feature accesses section internal data. friend class ICF; public: class symbol_iterator : public llvm::iterator_adaptor_base< symbol_iterator, const coff_relocation *, std::random_access_iterator_tag, SymbolBody *> { friend SectionChunk; ObjectFile *File; symbol_iterator(ObjectFile *File, const coff_relocation *I) : symbol_iterator::iterator_adaptor_base(I), File(File) {} public: symbol_iterator() = default; SymbolBody *operator*() const { return File->getSymbolBody(I->SymbolTableIndex); } }; SectionChunk(ObjectFile *File, const coff_section *Header); static bool classof(const Chunk *C) { return C->kind() == SectionKind; } size_t getSize() const override { return Header->SizeOfRawData; } void writeTo(uint8_t *Buf) const override; bool hasData() const override; uint32_t getPermissions() const override; StringRef getSectionName() const override { return SectionName; } void getBaserels(std::vector *Res) override; bool isCOMDAT() const; void applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const; void applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const; void applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const; // Called if the garbage collector decides to not include this chunk // in a final output. It's supposed to print out a log message to stdout. void printDiscardedMessage() const; // Adds COMDAT associative sections to this COMDAT section. A chunk // and its children are treated as a group by the garbage collector. void addAssociative(SectionChunk *Child); StringRef getDebugName() override; void setSymbol(DefinedRegular *S) { if (!Sym) Sym = S; } // Used by the garbage collector. bool isLive() { return !Config->DoGC || Live; } void markLive() { assert(!isLive() && "Cannot mark an already live section!"); Live = true; } // Allow iteration over the bodies of this chunk's relocated symbols. llvm::iterator_range 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; } // A pointer pointing to a replacement for this chunk. // Initially it points to "this" object. If this chunk is merged // with other chunk by ICF, it points to another chunk, // and this chunk is considrered as dead. SectionChunk *Repl; // The CRC of the contents as described in the COFF spec 4.5.5. // Auxiliary Format 5: Section Definitions. Used for ICF. uint32_t Checksum = 0; private: ArrayRef 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; // Used for ICF (Identical COMDAT Folding) void replace(SectionChunk *Other); std::atomic GroupID = { 0 }; // Sym points to a section symbol if this is a COMDAT chunk. DefinedRegular *Sym = nullptr; }; // A chunk for common symbols. Common chunks don't have actual data. class CommonChunk : public Chunk { public: CommonChunk(const COFFSymbolRef Sym); size_t getSize() const override { return Sym.getValue(); } bool hasData() const override { return false; } uint32_t getPermissions() const override; StringRef getSectionName() const override { return ".bss"; } private: const COFFSymbolRef Sym; }; // A chunk for linker-created strings. class StringChunk : public Chunk { public: explicit StringChunk(StringRef S) : Str(S) {} size_t getSize() const override { return Str.size() + 1; } void writeTo(uint8_t *Buf) const override; private: StringRef Str; }; static const uint8_t ImportThunkX86[] = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0 }; static const uint8_t ImportThunkARM[] = { 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip] }; // Windows-specific. // A chunk for DLL import jump table entry. In a final output, it's // contents will be a JMP instruction to some __imp_ symbol. class ImportThunkChunkX64 : public Chunk { public: explicit ImportThunkChunkX64(Defined *S); size_t getSize() const override { return sizeof(ImportThunkX86); } void writeTo(uint8_t *Buf) const override; private: Defined *ImpSymbol; }; class ImportThunkChunkX86 : public Chunk { public: explicit ImportThunkChunkX86(Defined *S) : ImpSymbol(S) {} size_t getSize() const override { return sizeof(ImportThunkX86); } void getBaserels(std::vector *Res) override; void writeTo(uint8_t *Buf) const override; private: Defined *ImpSymbol; }; class ImportThunkChunkARM : public Chunk { public: explicit ImportThunkChunkARM(Defined *S) : ImpSymbol(S) {} size_t getSize() const override { return sizeof(ImportThunkARM); } void getBaserels(std::vector *Res) override; void writeTo(uint8_t *Buf) const override; private: Defined *ImpSymbol; }; // Windows-specific. // See comments for DefinedLocalImport class. class LocalImportChunk : public Chunk { public: explicit LocalImportChunk(Defined *S) : Sym(S) {} size_t getSize() const override; void getBaserels(std::vector *Res) override; void writeTo(uint8_t *Buf) const override; private: Defined *Sym; }; // Windows-specific. // A chunk for SEH table which contains RVAs of safe exception handler // functions. x86-only. class SEHTableChunk : public Chunk { public: explicit SEHTableChunk(std::set S) : Syms(S) {} size_t getSize() const override { return Syms.size() * 4; } void writeTo(uint8_t *Buf) const 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) const 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; }; +inline uint64_t align(uint64_t Value, uint64_t Align) { + return llvm::RoundUpToAlignment(Value, Align); +} + } // namespace coff } // namespace lld #endif Index: vendor/lld/dist/COFF/Config.h =================================================================== --- vendor/lld/dist/COFF/Config.h (revision 293845) +++ vendor/lld/dist/COFF/Config.h (revision 293846) @@ -1,140 +1,147 @@ //===- Config.h -------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_COFF_CONFIG_H #define LLD_COFF_CONFIG_H #include "llvm/ADT/StringRef.h" #include "llvm/Object/COFF.h" #include #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 StringChunk; class Undefined; // Short aliases. static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64; static const auto ARMNT = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT; static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386; // Represents an /export option. struct Export { StringRef Name; // N in /export:N or /export:E=N StringRef ExtName; // E in /export:E=N Undefined *Sym = nullptr; uint16_t Ordinal = 0; bool Noname = false; bool Data = false; bool Private = false; + + // If an export is a form of /export:foo=dllname.bar, that means + // that foo should be exported as an alias to bar in the DLL. + // ForwardTo is set to "dllname.bar" part. Usually empty. + StringRef ForwardTo; + StringChunk *ForwardChunk = nullptr; // True if this /export option was in .drectves section. bool Directives = false; StringRef SymbolName; StringRef ExportName; // Name in DLL bool operator==(const Export &E) { return (Name == E.Name && ExtName == E.ExtName && Ordinal == E.Ordinal && Noname == E.Noname && Data == E.Data && Private == E.Private); } }; // Global configuration. struct Configuration { enum ManifestKind { SideBySide, Embed, No }; bool is64() { return Machine == AMD64; } llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN; bool Verbose = false; WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN; Undefined *Entry = nullptr; bool NoEntry = false; std::string OutputFile; bool DoGC = true; bool DoICF = true; bool Relocatable = true; bool Force = false; bool Debug = false; bool WriteSymtab = true; // Symbols in this set are considered as live by the garbage collector. std::set 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; std::map DLLOrder; Undefined *DelayLoadHelper = nullptr; // Used for SafeSEH. DefinedRelative *SEHTable = nullptr; DefinedAbsolute *SEHCount = nullptr; // Used for /opt:lldlto=N unsigned LTOOptLevel = 2; // Used for /opt:lldltojobs=N unsigned LTOJobs = 1; // Used for /merge:from=to (e.g. /merge:.rdata=.text) std::map 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: vendor/lld/dist/COFF/DLL.cpp =================================================================== --- vendor/lld/dist/COFF/DLL.cpp (revision 293845) +++ vendor/lld/dist/COFF/DLL.cpp (revision 293846) @@ -1,556 +1,571 @@ //===- DLL.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines various types of chunks for the DLL import or export // descriptor tables. They are inherently Windows-specific. // You need to read Microsoft PE/COFF spec to understand details // about the data structures. // // If you are not particularly interested in linking against Windows // DLL, you can skip this file, and you should still be able to // understand the rest of the linker. // //===----------------------------------------------------------------------===// #include "Chunks.h" #include "DLL.h" #include "llvm/Object/COFF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Path.h" using namespace llvm; using namespace llvm::object; using namespace llvm::support::endian; using namespace llvm::COFF; namespace lld { namespace coff { namespace { // Import table static int ptrSize() { return Config->is64() ? 8 : 4; } // A chunk for the import descriptor table. class HintNameChunk : public Chunk { public: HintNameChunk(StringRef N, uint16_t H) : Name(N), Hint(H) {} size_t getSize() const override { // Starts with 2 byte Hint field, followed by a null-terminated string, // ends with 0 or 1 byte padding. - return RoundUpToAlignment(Name.size() + 3, 2); + return align(Name.size() + 3, 2); } void writeTo(uint8_t *Buf) const override { write16le(Buf + OutputSectionOff, Hint); memcpy(Buf + OutputSectionOff + 2, Name.data(), Name.size()); } private: StringRef Name; uint16_t Hint; }; // A chunk for the import descriptor table. class LookupChunk : public Chunk { public: explicit LookupChunk(Chunk *C) : HintName(C) {} size_t getSize() const override { return ptrSize(); } void writeTo(uint8_t *Buf) const override { write32le(Buf + OutputSectionOff, HintName->getRVA()); } Chunk *HintName; }; // A chunk for the import descriptor table. // This chunk represent import-by-ordinal symbols. // See Microsoft PE/COFF spec 7.1. Import Header for details. class OrdinalOnlyChunk : public Chunk { public: explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {} size_t getSize() const override { return ptrSize(); } void writeTo(uint8_t *Buf) const override { // An import-by-ordinal slot has MSB 1 to indicate that // this is import-by-ordinal (and not import-by-name). if (Config->is64()) { write64le(Buf + OutputSectionOff, (1ULL << 63) | Ordinal); } else { write32le(Buf + OutputSectionOff, (1ULL << 31) | Ordinal); } } uint16_t Ordinal; }; // A chunk for the import descriptor table. class ImportDirectoryChunk : public Chunk { public: explicit ImportDirectoryChunk(Chunk *N) : DLLName(N) {} size_t getSize() const override { return sizeof(ImportDirectoryTableEntry); } void writeTo(uint8_t *Buf) const override { auto *E = (coff_import_directory_table_entry *)(Buf + OutputSectionOff); E->ImportLookupTableRVA = LookupTab->getRVA(); E->NameRVA = DLLName->getRVA(); E->ImportAddressTableRVA = AddressTab->getRVA(); } Chunk *DLLName; Chunk *LookupTab; Chunk *AddressTab; }; // A chunk representing null terminator in the import table. // Contents of this chunk is always null bytes. class NullChunk : public Chunk { public: explicit NullChunk(size_t N) : Size(N) {} bool hasData() const override { return false; } size_t getSize() const override { return Size; } void setAlign(size_t N) { Align = N; } private: size_t Size; }; static std::vector> binImports(const std::vector &Imports) { // Group DLL-imported symbols by DLL name because that's how // symbols are layed out in the import descriptor table. auto Less = [](const std::string &A, const std::string &B) { return Config->DLLOrder[A] < Config->DLLOrder[B]; }; std::map, bool(*)(const std::string &, const std::string &)> M(Less); for (DefinedImportData *Sym : Imports) M[Sym->getDLLName().lower()].push_back(Sym); std::vector> V; for (auto &P : M) { // Sort symbols by name for each group. std::vector &Syms = P.second; std::sort(Syms.begin(), Syms.end(), [](DefinedImportData *A, DefinedImportData *B) { return A->getName() < B->getName(); }); V.push_back(std::move(Syms)); } return V; } // Export table // See Microsoft PE/COFF spec 4.3 for details. // A chunk for the delay import descriptor table etnry. class DelayDirectoryChunk : public Chunk { public: explicit DelayDirectoryChunk(Chunk *N) : DLLName(N) {} size_t getSize() const override { return sizeof(delay_import_directory_table_entry); } void writeTo(uint8_t *Buf) const override { auto *E = (delay_import_directory_table_entry *)(Buf + OutputSectionOff); E->Attributes = 1; E->Name = DLLName->getRVA(); E->ModuleHandle = ModuleHandle->getRVA(); E->DelayImportAddressTable = AddressTab->getRVA(); E->DelayImportNameTable = NameTab->getRVA(); } Chunk *DLLName; Chunk *ModuleHandle; Chunk *AddressTab; Chunk *NameTab; }; // Initial contents for delay-loaded functions. // This code calls __delayLoadHelper2 function to resolve a symbol // and then overwrites its jump table slot with the result // for subsequent function calls. static const uint8_t ThunkX64[] = { 0x51, // push rcx 0x52, // push rdx 0x41, 0x50, // push r8 0x41, 0x51, // push r9 0x48, 0x83, 0xEC, 0x48, // sub rsp, 48h 0x66, 0x0F, 0x7F, 0x04, 0x24, // movdqa xmmword ptr [rsp], xmm0 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3 0x48, 0x8D, 0x15, 0, 0, 0, 0, // lea rdx, [__imp_] 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...] 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2 0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp] 0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa xmm1, xmmword ptr [rsp+10h] 0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa xmm2, xmmword ptr [rsp+20h] 0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa xmm3, xmmword ptr [rsp+30h] 0x48, 0x83, 0xC4, 0x48, // add rsp, 48h 0x41, 0x59, // pop r9 0x41, 0x58, // pop r8 0x5A, // pop rdx 0x59, // pop rcx 0xFF, 0xE0, // jmp rax }; static const uint8_t ThunkX86[] = { 0x51, // push ecx 0x52, // push edx 0x68, 0, 0, 0, 0, // push offset ___imp__ 0x68, 0, 0, 0, 0, // push offset ___DELAY_IMPORT_DESCRIPTOR__dll 0xE8, 0, 0, 0, 0, // call ___delayLoadHelper2@8 0x5A, // pop edx 0x59, // pop ecx 0xFF, 0xE0, // jmp eax }; // A chunk for the delay import thunk. class ThunkChunkX64 : public Chunk { public: ThunkChunkX64(Defined *I, Chunk *D, Defined *H) : Imp(I), Desc(D), Helper(H) {} size_t getSize() const override { return sizeof(ThunkX64); } void writeTo(uint8_t *Buf) const override { memcpy(Buf + OutputSectionOff, ThunkX64, sizeof(ThunkX64)); write32le(Buf + OutputSectionOff + 36, Imp->getRVA() - RVA - 40); write32le(Buf + OutputSectionOff + 43, Desc->getRVA() - RVA - 47); write32le(Buf + OutputSectionOff + 48, Helper->getRVA() - RVA - 52); } Defined *Imp = nullptr; Chunk *Desc = nullptr; Defined *Helper = nullptr; }; class ThunkChunkX86 : public Chunk { public: ThunkChunkX86(Defined *I, Chunk *D, Defined *H) : Imp(I), Desc(D), Helper(H) {} size_t getSize() const override { return sizeof(ThunkX86); } void writeTo(uint8_t *Buf) const override { memcpy(Buf + OutputSectionOff, ThunkX86, sizeof(ThunkX86)); write32le(Buf + OutputSectionOff + 3, Imp->getRVA() + Config->ImageBase); write32le(Buf + OutputSectionOff + 8, Desc->getRVA() + Config->ImageBase); write32le(Buf + OutputSectionOff + 13, Helper->getRVA() - RVA - 17); } void getBaserels(std::vector *Res) override { Res->emplace_back(RVA + 3); Res->emplace_back(RVA + 8); } Defined *Imp = nullptr; Chunk *Desc = nullptr; Defined *Helper = nullptr; }; // A chunk for the import descriptor table. class DelayAddressChunk : public Chunk { public: explicit DelayAddressChunk(Chunk *C) : Thunk(C) {} size_t getSize() const override { return ptrSize(); } void writeTo(uint8_t *Buf) const override { if (Config->is64()) { write64le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase); } else { write32le(Buf + OutputSectionOff, Thunk->getRVA() + Config->ImageBase); } } void getBaserels(std::vector *Res) override { Res->emplace_back(RVA); } Chunk *Thunk; }; // Export table // Read Microsoft PE/COFF spec 5.3 for details. // A chunk for the export descriptor table. class ExportDirectoryChunk : public Chunk { public: ExportDirectoryChunk(int I, int J, Chunk *D, Chunk *A, Chunk *N, Chunk *O) : MaxOrdinal(I), NameTabSize(J), DLLName(D), AddressTab(A), NameTab(N), OrdinalTab(O) {} size_t getSize() const override { return sizeof(export_directory_table_entry); } void writeTo(uint8_t *Buf) const override { auto *E = (export_directory_table_entry *)(Buf + OutputSectionOff); E->NameRVA = DLLName->getRVA(); E->OrdinalBase = 0; E->AddressTableEntries = MaxOrdinal + 1; E->NumberOfNamePointers = NameTabSize; E->ExportAddressTableRVA = AddressTab->getRVA(); E->NamePointerRVA = NameTab->getRVA(); E->OrdinalTableRVA = OrdinalTab->getRVA(); } uint16_t MaxOrdinal; uint16_t NameTabSize; Chunk *DLLName; Chunk *AddressTab; Chunk *NameTab; Chunk *OrdinalTab; }; class AddressTableChunk : public Chunk { public: explicit AddressTableChunk(size_t MaxOrdinal) : Size(MaxOrdinal + 1) {} size_t getSize() const override { return Size * 4; } void writeTo(uint8_t *Buf) const override { for (Export &E : Config->Exports) { - auto *D = cast(E.Sym->repl()); - write32le(Buf + OutputSectionOff + E.Ordinal * 4, D->getRVA()); + uint8_t *P = Buf + OutputSectionOff + E.Ordinal * 4; + if (E.ForwardChunk) { + write32le(P, E.ForwardChunk->getRVA()); + } else { + write32le(P, cast(E.Sym->repl())->getRVA()); + } } } private: size_t Size; }; class NamePointersChunk : public Chunk { public: explicit NamePointersChunk(std::vector &V) : Chunks(V) {} size_t getSize() const override { return Chunks.size() * 4; } void writeTo(uint8_t *Buf) const override { uint8_t *P = Buf + OutputSectionOff; for (Chunk *C : Chunks) { write32le(P, C->getRVA()); P += 4; } } private: std::vector Chunks; }; class ExportOrdinalChunk : public Chunk { public: explicit ExportOrdinalChunk(size_t I) : Size(I) {} size_t getSize() const override { return Size * 2; } void writeTo(uint8_t *Buf) const override { uint8_t *P = Buf + OutputSectionOff; for (Export &E : Config->Exports) { if (E.Noname) continue; write16le(P, E.Ordinal); P += 2; } } private: size_t Size; }; } // anonymous namespace uint64_t IdataContents::getDirSize() { return Dirs.size() * sizeof(ImportDirectoryTableEntry); } uint64_t IdataContents::getIATSize() { return Addresses.size() * ptrSize(); } // Returns a list of .idata contents. // See Microsoft PE/COFF spec 5.4 for details. std::vector IdataContents::getChunks() { create(); std::vector V; // The loader assumes a specific order of data. // Add each type in the correct order. for (std::unique_ptr &C : Dirs) V.push_back(C.get()); for (std::unique_ptr &C : Lookups) V.push_back(C.get()); for (std::unique_ptr &C : Addresses) V.push_back(C.get()); for (std::unique_ptr &C : Hints) V.push_back(C.get()); for (auto &P : DLLNames) { std::unique_ptr &C = P.second; V.push_back(C.get()); } return V; } void IdataContents::create() { std::vector> V = binImports(Imports); // Create .idata contents for each DLL. for (std::vector &Syms : V) { StringRef Name = Syms[0]->getDLLName(); // Create lookup and address tables. If they have external names, // we need to create HintName chunks to store the names. // If they don't (if they are import-by-ordinals), we store only // ordinal values to the table. size_t Base = Lookups.size(); for (DefinedImportData *S : Syms) { uint16_t Ord = S->getOrdinal(); if (S->getExternalName().empty()) { Lookups.push_back(make_unique(Ord)); Addresses.push_back(make_unique(Ord)); continue; } auto C = make_unique(S->getExternalName(), Ord); Lookups.push_back(make_unique(C.get())); Addresses.push_back(make_unique(C.get())); Hints.push_back(std::move(C)); } // Terminate with null values. Lookups.push_back(make_unique(ptrSize())); Addresses.push_back(make_unique(ptrSize())); for (int I = 0, E = Syms.size(); I < E; ++I) Syms[I]->setLocation(Addresses[Base + I].get()); // Create the import table header. if (!DLLNames.count(Name)) DLLNames[Name] = make_unique(Name); auto Dir = make_unique(DLLNames[Name].get()); Dir->LookupTab = Lookups[Base].get(); Dir->AddressTab = Addresses[Base].get(); Dirs.push_back(std::move(Dir)); } // Add null terminator. Dirs.push_back(make_unique(sizeof(ImportDirectoryTableEntry))); } std::vector DelayLoadContents::getChunks() { std::vector V; for (std::unique_ptr &C : Dirs) V.push_back(C.get()); for (std::unique_ptr &C : Names) V.push_back(C.get()); for (std::unique_ptr &C : HintNames) V.push_back(C.get()); for (auto &P : DLLNames) { std::unique_ptr &C = P.second; V.push_back(C.get()); } return V; } std::vector DelayLoadContents::getDataChunks() { std::vector V; for (std::unique_ptr &C : ModuleHandles) V.push_back(C.get()); for (std::unique_ptr &C : Addresses) V.push_back(C.get()); return V; } uint64_t DelayLoadContents::getDirSize() { return Dirs.size() * sizeof(delay_import_directory_table_entry); } void DelayLoadContents::create(Defined *H) { Helper = H; std::vector> V = binImports(Imports); // Create .didat contents for each DLL. for (std::vector &Syms : V) { StringRef Name = Syms[0]->getDLLName(); // Create the delay import table header. if (!DLLNames.count(Name)) DLLNames[Name] = make_unique(Name); auto Dir = make_unique(DLLNames[Name].get()); size_t Base = Addresses.size(); for (DefinedImportData *S : Syms) { Chunk *T = newThunkChunk(S, Dir.get()); auto A = make_unique(T); Addresses.push_back(std::move(A)); Thunks.push_back(std::unique_ptr(T)); StringRef ExtName = S->getExternalName(); if (ExtName.empty()) { Names.push_back(make_unique(S->getOrdinal())); } else { auto C = make_unique(ExtName, 0); Names.push_back(make_unique(C.get())); HintNames.push_back(std::move(C)); } } // Terminate with null values. Addresses.push_back(make_unique(8)); Names.push_back(make_unique(8)); for (int I = 0, E = Syms.size(); I < E; ++I) Syms[I]->setLocation(Addresses[Base + I].get()); auto *MH = new NullChunk(8); MH->setAlign(8); ModuleHandles.push_back(std::unique_ptr(MH)); // Fill the delay import table header fields. Dir->ModuleHandle = MH; Dir->AddressTab = Addresses[Base].get(); Dir->NameTab = Names[Base].get(); Dirs.push_back(std::move(Dir)); } // Add null terminator. Dirs.push_back( make_unique(sizeof(delay_import_directory_table_entry))); } Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) { switch (Config->Machine) { case AMD64: return new ThunkChunkX64(S, Dir, Helper); case I386: return new ThunkChunkX86(S, Dir, Helper); default: llvm_unreachable("unsupported machine type"); } } EdataContents::EdataContents() { uint16_t MaxOrdinal = 0; for (Export &E : Config->Exports) MaxOrdinal = std::max(MaxOrdinal, E.Ordinal); auto *DLLName = new StringChunk(sys::path::filename(Config->OutputFile)); auto *AddressTab = new AddressTableChunk(MaxOrdinal); std::vector Names; for (Export &E : Config->Exports) if (!E.Noname) Names.push_back(new StringChunk(E.ExportName)); + + std::vector Forwards; + for (Export &E : Config->Exports) { + if (E.ForwardTo.empty()) + continue; + E.ForwardChunk = new StringChunk(E.ForwardTo); + Forwards.push_back(E.ForwardChunk); + } + auto *NameTab = new NamePointersChunk(Names); auto *OrdinalTab = new ExportOrdinalChunk(Names.size()); auto *Dir = new ExportDirectoryChunk(MaxOrdinal, Names.size(), DLLName, AddressTab, NameTab, OrdinalTab); Chunks.push_back(std::unique_ptr(Dir)); Chunks.push_back(std::unique_ptr(DLLName)); Chunks.push_back(std::unique_ptr(AddressTab)); Chunks.push_back(std::unique_ptr(NameTab)); Chunks.push_back(std::unique_ptr(OrdinalTab)); for (Chunk *C : Names) + Chunks.push_back(std::unique_ptr(C)); + for (Chunk *C : Forwards) Chunks.push_back(std::unique_ptr(C)); } } // namespace coff } // namespace lld Index: vendor/lld/dist/COFF/Driver.cpp =================================================================== --- vendor/lld/dist/COFF/Driver.cpp (revision 293845) +++ vendor/lld/dist/COFF/Driver.cpp (revision 293846) @@ -1,677 +1,679 @@ //===- Driver.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Config.h" #include "Driver.h" #include "Error.h" #include "InputFiles.h" #include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" #include "llvm/ADT/Optional.h" #include "llvm/LibDriver/LibDriver.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" #include #include using namespace llvm; using namespace llvm::COFF; using llvm::sys::Process; using llvm::sys::fs::OpenFlags; using llvm::sys::fs::file_magic; using llvm::sys::fs::identify_magic; namespace lld { namespace coff { Configuration *Config; LinkerDriver *Driver; void link(llvm::ArrayRef Args) { Configuration C; LinkerDriver D; Config = &C; Driver = &D; return Driver->link(Args); } // Drop directory components and replace extension with ".exe". static std::string getOutputPath(StringRef Path) { auto P = Path.find_last_of("\\/"); StringRef S = (P == StringRef::npos) ? Path : Path.substr(P + 1); return (S.substr(0, S.rfind('.')) + ".exe").str(); } // Opens a file. Path has to be resolved already. // Newly created memory buffers are owned by this driver. MemoryBufferRef LinkerDriver::openFile(StringRef Path) { auto MBOrErr = MemoryBuffer::getFile(Path); error(MBOrErr, Twine("Could not open ") + Path); std::unique_ptr &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 ArchiveFile(MB)); if (Magic == file_magic::bitcode) return std::unique_ptr(new BitcodeFile(MB)); if (Config->OutputFile == "") Config->OutputFile = getOutputPath(MB.getBufferIdentifier()); return std::unique_ptr(new ObjectFile(MB)); } static bool isDecorated(StringRef Sym) { return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?"); } // Parses .drectve section contents and returns a list of files // specified by /defaultlib. void LinkerDriver::parseDirectives(StringRef S) { llvm::opt::InputArgList Args = Parser.parse(S); for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_alternatename: parseAlternateName(Arg->getValue()); break; case OPT_defaultlib: if (Optional Path = findLib(Arg->getValue())) { MemoryBufferRef MB = openFile(*Path); Symtab.addFile(createFile(MB)); } break; case OPT_export: { Export E = parseExport(Arg->getValue()); E.Directives = true; Config->Exports.push_back(E); break; } case OPT_failifmismatch: checkFailIfMismatch(Arg->getValue()); break; case OPT_incl: addUndefined(Arg->getValue()); break; case OPT_merge: parseMerge(Arg->getValue()); break; case OPT_nodefaultlib: Config->NoDefaultLibs.insert(doFindLib(Arg->getValue())); break; case OPT_editandcontinue: case OPT_guardsym: case OPT_throwingnew: break; default: error(Twine(Arg->getSpelling()) + " is not allowed in .drectve"); } } } // Find file from search paths. You can omit ".obj", this function takes // care of that. Note that the returned path is not guaranteed to exist. StringRef LinkerDriver::doFindFile(StringRef Filename) { bool hasPathSep = (Filename.find_first_of("/\\") != StringRef::npos); if (hasPathSep) return Filename; bool hasExt = (Filename.find('.') != StringRef::npos); for (StringRef Dir : SearchPaths) { SmallString<128> Path = Dir; llvm::sys::path::append(Path, Filename); if (llvm::sys::fs::exists(Path.str())) return Alloc.save(Path.str()); if (!hasExt) { Path.append(".obj"); if (llvm::sys::fs::exists(Path.str())) return Alloc.save(Path.str()); } } return Filename; } // Resolves a file path. This never returns the same path // (in that case, it returns None). Optional 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 Str = StringRef(Arg->getValue()).lower(); SmallVector Vec; StringRef(Str).split(Vec, ','); for (StringRef S : Vec) { if (S == "noref") { Config->DoGC = false; Config->DoICF = false; continue; } if (S == "icf" || StringRef(S).startswith("icf=")) { Config->DoICF = true; continue; } if (S == "noicf") { Config->DoICF = false; continue; } if (StringRef(S).startswith("lldlto=")) { StringRef OptLevel = StringRef(S).substr(7); if (OptLevel.getAsInteger(10, Config->LTOOptLevel) || Config->LTOOptLevel > 3) error("/opt:lldlto: invalid optimization level: " + OptLevel); continue; } if (StringRef(S).startswith("lldltojobs=")) { StringRef Jobs = StringRef(S).substr(11); if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0) error("/opt:lldltojobs: invalid job count: " + Jobs); continue; } if (S != "ref" && S != "lbr" && S != "nolbr") error(Twine("/opt: unknown option: ") + S); } } // Handle /failifmismatch for (auto *Arg : Args.filtered(OPT_failifmismatch)) checkFailIfMismatch(Arg->getValue()); // Handle /merge for (auto *Arg : Args.filtered(OPT_merge)) parseMerge(Arg->getValue()); // Handle /manifest if (auto *Arg = Args.getLastArg(OPT_manifest_colon)) parseManifest(Arg->getValue()); // Handle /manifestuac if (auto *Arg = Args.getLastArg(OPT_manifestuac)) parseManifestUAC(Arg->getValue()); // Handle /manifestdependency if (auto *Arg = Args.getLastArg(OPT_manifestdependency)) Config->ManifestDependency = Arg->getValue(); // Handle /manifestfile if (auto *Arg = Args.getLastArg(OPT_manifestfile)) Config->ManifestFile = Arg->getValue(); // Handle miscellaneous boolean flags. if (Args.hasArg(OPT_allowbind_no)) Config->AllowBind = false; if (Args.hasArg(OPT_allowisolation_no)) Config->AllowIsolation = false; if (Args.hasArg(OPT_dynamicbase_no)) Config->DynamicBase = false; if (Args.hasArg(OPT_nxcompat_no)) Config->NxCompat = false; if (Args.hasArg(OPT_tsaware_no)) Config->TerminalServerAware = false; if (Args.hasArg(OPT_nosymtab)) Config->WriteSymtab = false; // Create a list of input files. Files can be given as arguments // for /defaultlib option. std::vector 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) { if (!isDecorated(E.Name)) E.Name = Alloc.save("_" + E.Name); if (!E.ExtName.empty() && !isDecorated(E.ExtName)) E.ExtName = Alloc.save("_" + E.ExtName); } Config->Exports.push_back(E); } // Handle /def if (auto *Arg = Args.getLastArg(OPT_deffile)) { MemoryBufferRef MB = openFile(Arg->getValue()); // parseModuleDefs mutates Config object. parseModuleDefs(MB, &Alloc); } // Handle /delayload for (auto *Arg : Args.filtered(OPT_delayload)) { Config->DelayLoads.insert(StringRef(Arg->getValue()).lower()); if (Config->Machine == I386) { Config->DelayLoadHelper = addUndefined("___delayLoadHelper2@8"); } else { Config->DelayLoadHelper = addUndefined("__delayLoadHelper2"); } } // Set default image base if /base is not given. if (Config->ImageBase == uint64_t(-1)) Config->ImageBase = getDefaultImageBase(); Symtab.addRelative(mangle("__ImageBase"), 0); if (Config->Machine == I386) { Config->SEHTable = Symtab.addRelative("___safe_se_handler_table", 0); Config->SEHCount = Symtab.addAbsolute("___safe_se_handler_count", 0); } // We do not support /guard:cf (control flow protection) yet. // Define CFG symbols anyway so that we can link MSVC 2015 CRT. Symtab.addAbsolute(mangle("__guard_fids_table"), 0); Symtab.addAbsolute(mangle("__guard_fids_count"), 0); Symtab.addAbsolute(mangle("__guard_flags"), 0x100); // Read as much files as we can from directives sections. Symtab.run(); // Resolve auxiliary symbols until we get a convergence. // (Trying to resolve a symbol may trigger a Lazy symbol to load a new file. // A new file may contain a directive section to add new command line options. // That's why we have to repeat until converge.) for (;;) { // Windows specific -- if entry point is not found, // search for its mangled names. if (Config->Entry) Symtab.mangleMaybe(Config->Entry); // Windows specific -- Make sure we resolve all dllexported symbols. for (Export &E : Config->Exports) { + if (!E.ForwardTo.empty()) + continue; E.Sym = addUndefined(E.Name); if (!E.Directives) Symtab.mangleMaybe(E.Sym); } // Add weak aliases. Weak aliases is a mechanism to give remaining // undefined symbols final chance to be resolved successfully. for (auto Pair : Config->AlternateNames) { StringRef From = Pair.first; StringRef To = Pair.second; Symbol *Sym = Symtab.find(From); if (!Sym) continue; if (auto *U = dyn_cast(Sym->Body)) if (!U->WeakAlias) U->WeakAlias = Symtab.addUndefined(To); } // Windows specific -- if __load_config_used can be resolved, resolve it. if (Symtab.findUnderscore("_load_config_used")) addUndefined(mangle("_load_config_used")); if (Symtab.queueEmpty()) break; Symtab.run(); } // Do LTO by compiling bitcode input files to a set of native COFF files then // link those files. Symtab.addCombinedLTOObjects(); // Make sure we have resolved all symbols. Symtab.reportRemainingUndefines(/*Resolve=*/true); // Windows specific -- if no /subsystem is given, we need to infer // that from entry point name. if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) { Config->Subsystem = inferSubsystem(); if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) error("subsystem must be defined"); } // Handle /safeseh. if (Args.hasArg(OPT_safeseh)) for (ObjectFile *File : Symtab.ObjectFiles) if (!File->SEHCompat) error("/safeseh: " + File->getName() + " is not compatible with SEH"); // Windows specific -- when we are creating a .dll file, we also // need to create a .lib file. if (!Config->Exports.empty() || Config->DLL) { fixupExports(); writeImportLibrary(); assignExportOrdinals(); } // Windows specific -- Create a side-by-side manifest file. if (Config->Manifest == Configuration::SideBySide) createSideBySideManifest(); // Create a dummy PDB file to satisfy build sytem rules. if (auto *Arg = Args.getLastArg(OPT_pdb)) createPDB(Arg->getValue()); // Identify unreferenced COMDAT sections. if (Config->DoGC) markLive(Symtab.getChunks()); // Identify identical COMDAT sections to merge them. if (Config->DoICF) doICF(Symtab.getChunks()); // Write the result. writeResult(&Symtab); // Create a symbol map file containing symbol VAs and their names // to help debugging. if (auto *Arg = Args.getLastArg(OPT_lldmap)) { std::error_code EC; llvm::raw_fd_ostream Out(Arg->getValue(), EC, OpenFlags::F_Text); error(EC, "Could not create the symbol map"); Symtab.printMap(Out); } // Call exit to avoid calling destructors. exit(0); } } // namespace coff } // namespace lld Index: vendor/lld/dist/COFF/DriverUtils.cpp =================================================================== --- vendor/lld/dist/COFF/DriverUtils.cpp (revision 293845) +++ vendor/lld/dist/COFF/DriverUtils.cpp (revision 293846) @@ -1,718 +1,739 @@ //===- DriverUtils.cpp ----------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains utility functions for the driver. Because there // are so many small functions, we created this separate file to make // Driver.cpp less cluttered. // //===----------------------------------------------------------------------===// #include "Config.h" #include "Driver.h" #include "Error.h" #include "Symbols.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/COFF.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" #include using namespace llvm::COFF; using namespace llvm; using llvm::cl::ExpandResponseFiles; using llvm::cl::TokenizeWindowsCommandLine; using llvm::sys::Process; namespace lld { namespace coff { namespace { class Executor { public: explicit Executor(StringRef S) : Saver(Alloc), Prog(Saver.save(S)) {} void add(StringRef S) { Args.push_back(Saver.save(S)); } void add(std::string &S) { Args.push_back(Saver.save(S)); } void add(Twine S) { Args.push_back(Saver.save(S)); } void add(const char *S) { Args.push_back(Saver.save(S)); } void run() { ErrorOr ExeOrErr = llvm::sys::findProgramByName(Prog); error(ExeOrErr, Twine("unable to find ") + Prog + " in PATH: "); const char *Exe = Saver.save(*ExeOrErr); Args.insert(Args.begin(), Exe); Args.push_back(nullptr); if (llvm::sys::ExecuteAndWait(Args[0], Args.data()) != 0) { for (const char *S : Args) if (S) llvm::errs() << S << " "; error("failed"); } } private: llvm::BumpPtrAllocator Alloc; llvm::StringSaver Saver; StringRef Prog; std::vector 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]". +// "[=][,@ordinal[,NONAME]][,DATA][,PRIVATE]" +// or "=.". // 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("="); + StringRef X, Y; + std::tie(X, Y) = E.Name.split("="); + + // If "=.". + if (Y.find(".") != StringRef::npos) { + E.Name = X; + E.ForwardTo = Y; + return E; + } + + E.ExtName = X; + E.Name = Y; if (E.Name.empty()) goto err; } + // If "=[,@ordinal[,NONAME]][,DATA][,PRIVATE]" while (!Rest.empty()) { StringRef Tok; std::tie(Tok, Rest) = Rest.split(","); if (Tok.equals_lower("noname")) { if (E.Ordinal == 0) goto err; E.Noname = true; continue; } if (Tok.equals_lower("data")) { E.Data = true; continue; } if (Tok.equals_lower("private")) { E.Private = true; continue; } if (Tok.startswith("@")) { int32_t Ord; if (Tok.substr(1).getAsInteger(0, Ord)) goto err; if (Ord <= 0 || 65535 < Ord) goto err; E.Ordinal = Ord; continue; } goto err; } return E; err: error(Twine("invalid /export: ") + Arg); } static StringRef undecorate(StringRef Sym) { if (Config->Machine != I386) return Sym; return Sym.startswith("_") ? Sym.substr(1) : Sym; } // Performs error checking on all /export arguments. // It also sets ordinals. void fixupExports() { // Symbol ordinals must be unique. std::set Ords; for (Export &E : Config->Exports) { if (E.Ordinal == 0) continue; if (!Ords.insert(E.Ordinal).second) error("duplicate export ordinal: " + E.Name); } for (Export &E : Config->Exports) { - if (Undefined *U = cast_or_null(E.Sym->WeakAlias)) { + if (!E.ForwardTo.empty()) { + E.SymbolName = E.Name; + } else if (Undefined *U = cast_or_null(E.Sym->WeakAlias)) { E.SymbolName = U->getName(); } else { E.SymbolName = E.Sym->getName(); } } - for (Export &E : Config->Exports) - E.ExportName = undecorate(E.ExtName.empty() ? E.Name : E.ExtName); + for (Export &E : Config->Exports) { + if (!E.ForwardTo.empty()) { + E.ExportName = undecorate(E.Name); + } else { + E.ExportName = undecorate(E.ExtName.empty() ? E.Name : E.ExtName); + } + } // Uniquefy by name. std::map Map; std::vector V; for (Export &E : Config->Exports) { auto Pair = Map.insert(std::make_pair(E.ExportName, &E)); bool Inserted = Pair.second; if (Inserted) { V.push_back(E); continue; } Export *Existing = Pair.first->second; if (E == *Existing || E.Name != Existing->Name) continue; llvm::errs() << "warning: duplicate /export option: " << E.Name << "\n"; } Config->Exports = std::move(V); // Sort by name. std::sort(Config->Exports.begin(), Config->Exports.end(), [](const Export &A, const Export &B) { return A.ExportName < B.ExportName; }); } void assignExportOrdinals() { // Assign unique ordinals if default (= 0). uint16_t Max = 0; for (Export &E : Config->Exports) Max = std::max(Max, E.Ordinal); for (Export &E : Config->Exports) if (E.Ordinal == 0) E.Ordinal = ++Max; } // Parses a string in the form of "key=value" and check // if value matches previous values for the same key. void checkFailIfMismatch(StringRef Arg) { StringRef K, V; std::tie(K, V) = Arg.split('='); if (K.empty() || V.empty()) error(Twine("/failifmismatch: invalid argument: ") + Arg); StringRef Existing = Config->MustMatch[K]; if (!Existing.empty() && V != Existing) error(Twine("/failifmismatch: mismatch detected: ") + Existing + " and " + V + " for key " + K); Config->MustMatch[K] = V; } // Convert Windows resource files (.res files) to a .obj file // using cvtres.exe. std::unique_ptr 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(); } void touchFile(StringRef Path) { int FD; std::error_code EC = sys::fs::openFileForWrite(Path, FD, sys::fs::F_Append); error(EC, "failed to create a file"); sys::Process::SafelyCloseFileDescriptor(FD); } static std::string getImplibPath() { if (!Config->Implib.empty()) return Config->Implib; SmallString<128> Out = StringRef(Config->OutputFile); sys::path::replace_extension(Out, ".lib"); return Out.str(); } static std::unique_ptr createEmptyImportLibrary() { std::string S = (Twine("LIBRARY \"") + llvm::sys::path::filename(Config->OutputFile) + "\"\n") .str(); std::string Path1 = writeToTempFile(S); std::string Path2 = getImplibPath(); llvm::FileRemover Remover1(Path1); llvm::FileRemover Remover2(Path2); Executor E("lib.exe"); E.add("/nologo"); E.add("/machine:" + machineToStr(Config->Machine)); E.add(Twine("/def:") + Path1); E.add(Twine("/out:") + Path2); E.run(); ErrorOr> BufOrErr = MemoryBuffer::getFile(Path2, -1, false); error(BufOrErr, Twine("Failed to open ") + Path2); return MemoryBuffer::getMemBufferCopy((*BufOrErr)->getBuffer()); } static std::vector readMembers(const object::Archive &Archive) { std::vector V; for (const auto &ChildOrErr : Archive.children()) { error(ChildOrErr, "Archive::Child::getName failed"); const object::Archive::Child C(*ChildOrErr); ErrorOr NameOrErr = C.getName(); error(NameOrErr, "Archive::Child::getName failed"); V.emplace_back(C, *NameOrErr); } return V; } // This class creates short import files which is described in // PE/COFF spec 7. Import Library Format. class ShortImportCreator { public: ShortImportCreator(object::Archive *A, StringRef S) : Parent(A), DLLName(S) {} NewArchiveIterator create(StringRef Sym, uint16_t Ordinal, ImportNameType NameType, bool isData) { size_t ImpSize = DLLName.size() + Sym.size() + 2; // +2 for NULs size_t Size = sizeof(object::ArchiveMemberHeader) + sizeof(coff_import_header) + ImpSize; char *Buf = Alloc.Allocate(Size); memset(Buf, 0, Size); char *P = Buf; // Write archive member header auto *Hdr = reinterpret_cast(P); P += sizeof(*Hdr); sprintf(Hdr->Name, "%-12s", "dummy"); sprintf(Hdr->LastModified, "%-12d", 0); sprintf(Hdr->UID, "%-6d", 0); sprintf(Hdr->GID, "%-6d", 0); sprintf(Hdr->AccessMode, "%-8d", 0644); sprintf(Hdr->Size, "%-10d", int(sizeof(coff_import_header) + ImpSize)); // Write short import library. auto *Imp = reinterpret_cast(P); P += sizeof(*Imp); Imp->Sig2 = 0xFFFF; Imp->Machine = Config->Machine; Imp->SizeOfData = ImpSize; if (Ordinal > 0) Imp->OrdinalHint = Ordinal; Imp->TypeInfo = (isData ? IMPORT_DATA : IMPORT_CODE); Imp->TypeInfo |= NameType << 2; // Write symbol name and DLL name. memcpy(P, Sym.data(), Sym.size()); P += Sym.size() + 1; memcpy(P, DLLName.data(), DLLName.size()); std::error_code EC; object::Archive::Child C(Parent, Buf, &EC); assert(!EC && "We created an invalid buffer"); return NewArchiveIterator(C, DLLName); } private: BumpPtrAllocator Alloc; object::Archive *Parent; StringRef DLLName; }; static ImportNameType getNameType(StringRef Sym, StringRef ExtName) { if (Sym != ExtName) return IMPORT_NAME_UNDECORATE; if (Config->Machine == I386 && Sym.startswith("_")) return IMPORT_NAME_NOPREFIX; return IMPORT_NAME; } static std::string replace(StringRef S, StringRef From, StringRef To) { size_t Pos = S.find(From); assert(Pos != StringRef::npos); return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str(); } // Creates an import library for a DLL. In this function, we first // create an empty import library using lib.exe and then adds short // import files to that file. void writeImportLibrary() { std::unique_ptr Buf = createEmptyImportLibrary(); std::error_code EC; object::Archive Archive(Buf->getMemBufferRef(), EC); error(EC, "Error reading an empty import file"); std::vector Members = readMembers(Archive); std::string DLLName = llvm::sys::path::filename(Config->OutputFile); ShortImportCreator ShortImport(&Archive, DLLName); for (Export &E : Config->Exports) { if (E.Private) continue; if (E.ExtName.empty()) { Members.push_back(ShortImport.create( E.SymbolName, E.Ordinal, getNameType(E.SymbolName, E.Name), E.Data)); } else { Members.push_back(ShortImport.create( replace(E.SymbolName, E.Name, E.ExtName), E.Ordinal, getNameType(E.SymbolName, E.Name), E.Data)); } } std::string Path = getImplibPath(); std::pair Result = writeArchive(Path, Members, /*WriteSymtab*/ true, object::Archive::K_GNU, /*Deterministic*/ true, /*Thin*/ false); error(Result.second, Twine("Failed to write ") + Path); } // Create OptTable // Create prefix string literals used in Options.td #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; #include "Options.inc" #undef PREFIX // Create table mapping all options defined in Options.td static const llvm::opt::OptTable::Info infoTable[] = { #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \ { \ X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, X8, X7, \ OPT_##GROUP, OPT_##ALIAS, X6 \ }, #include "Options.inc" #undef OPTION }; class COFFOptTable : public llvm::opt::OptTable { public: COFFOptTable() : OptTable(infoTable, true) {} }; // Parses a given list of options. llvm::opt::InputArgList ArgParser::parse(ArrayRef 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); // Print the real command line if response files are expanded. if (Args.hasArg(OPT_verbose) && ArgsArr.size() != Argv.size()) { llvm::outs() << "Command line:"; for (const char *S : Argv) llvm::outs() << " " << S; llvm::outs() << "\n"; } if (MissingCount) error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) + "\", expected " + Twine(MissingCount) + (MissingCount == 1 ? " argument." : " arguments.")); for (auto *Arg : Args.filtered(OPT_UNKNOWN)) llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n"; return Args; } llvm::opt::InputArgList ArgParser::parseLINK(ArrayRef 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 coff } // namespace lld Index: vendor/lld/dist/COFF/InputFiles.cpp =================================================================== --- vendor/lld/dist/COFF/InputFiles.cpp (revision 293845) +++ vendor/lld/dist/COFF/InputFiles.cpp (revision 293846) @@ -1,367 +1,366 @@ //===- InputFiles.cpp -----------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Chunks.h" #include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "llvm/ADT/STLExtras.h" #include "llvm/IR/LLVMContext.h" #include "llvm/LTO/LTOModule.h" #include "llvm/Object/COFF.h" #include "llvm/Support/COFF.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" #include "llvm/Support/raw_ostream.h" using namespace llvm::COFF; using namespace llvm::object; using namespace llvm::support::endian; -using llvm::RoundUpToAlignment; using llvm::Triple; using llvm::support::ulittle32_t; using llvm::sys::fs::file_magic; using llvm::sys::fs::identify_magic; namespace lld { namespace coff { int InputFile::NextIndex = 0; // Returns the last element of a path, which is supposed to be a filename. static StringRef getBasename(StringRef Path) { size_t Pos = Path.find_last_of("\\/"); if (Pos == StringRef::npos) return Path; return Path.substr(Pos + 1); } // Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)". std::string InputFile::getShortName() { if (ParentName == "") return getName().lower(); std::string Res = (getBasename(ParentName) + "(" + getBasename(getName()) + ")").str(); return StringRef(Res).lower(); } void ArchiveFile::parse() { // Parse a MemoryBufferRef as an archive file. auto ArchiveOrErr = Archive::create(MB); error(ArchiveOrErr, "Failed to parse static library"); File = std::move(*ArchiveOrErr); // Allocate a buffer for Lazy objects. size_t NumSyms = File->getNumberOfSymbols(); LazySymbols.reserve(NumSyms); // Read the symbol table to construct Lazy objects. for (const Archive::Symbol &Sym : File->symbols()) LazySymbols.emplace_back(this, Sym); // Seen is a map from member files to boolean values. Initially // all members are mapped to false, which indicates all these files // are not read yet. for (auto &ChildOrErr : File->children()) { error(ChildOrErr, "Failed to parse static library"); const Archive::Child &Child = *ChildOrErr; Seen[Child.getChildOffset()].clear(); } } // Returns a buffer pointing to a member file containing a given symbol. // This function is thread-safe. MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) { auto COrErr = Sym->getMember(); error(COrErr, Twine("Could not get the member for symbol ") + Sym->getName()); const Archive::Child &C = *COrErr; // Return an empty buffer if we have already returned the same buffer. if (Seen[C.getChildOffset()].test_and_set()) return MemoryBufferRef(); ErrorOr Ret = C.getMemoryBufferRef(); error(Ret, Twine("Could not get the buffer for the member defining symbol ") + Sym->getName()); return *Ret; } void ObjectFile::parse() { // Parse a memory buffer as a COFF file. auto BinOrErr = createBinary(MB); error(BinOrErr, "Failed to parse object file"); std::unique_ptr Bin = std::move(*BinOrErr); if (auto *Obj = dyn_cast(Bin.get())) { Bin.release(); COFFObj.reset(Obj); } else { error(Twine(getName()) + " is not a COFF file."); } // Read section and symbol tables. initializeChunks(); initializeSymbols(); initializeSEH(); } void ObjectFile::initializeChunks() { uint32_t NumSections = COFFObj->getNumberOfSections(); Chunks.reserve(NumSections); SparseChunks.resize(NumSections + 1); for (uint32_t I = 1; I < NumSections + 1; ++I) { const coff_section *Sec; StringRef Name; std::error_code EC = COFFObj->getSection(I, Sec); error(EC, Twine("getSection failed: #") + Twine(I)); EC = COFFObj->getSectionName(Sec, Name); error(EC, Twine("getSectionName failed: #") + Twine(I)); if (Name == ".sxdata") { SXData = Sec; continue; } if (Name == ".drectve") { ArrayRef Data; COFFObj->getSectionContents(Sec, Data); Directives = std::string((const char *)Data.data(), Data.size()); continue; } // Skip non-DWARF debug info. MSVC linker converts the sections into // a PDB file, but we don't support that. if (Name == ".debug" || Name.startswith(".debug$")) continue; // We want to preserve DWARF debug sections only when /debug is on. if (!Config->Debug && Name.startswith(".debug")) continue; if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) continue; auto *C = new (Alloc) SectionChunk(this, Sec); Chunks.push_back(C); SparseChunks[I] = C; } } void ObjectFile::initializeSymbols() { uint32_t NumSymbols = COFFObj->getNumberOfSymbols(); SymbolBodies.reserve(NumSymbols); SparseSymbolBodies.resize(NumSymbols); llvm::SmallVector WeakAliases; int32_t LastSectionNumber = 0; for (uint32_t I = 0; I < NumSymbols; ++I) { // Get a COFFSymbolRef object. auto SymOrErr = COFFObj->getSymbol(I); error(SymOrErr, Twine("broken object file: ") + getName()); COFFSymbolRef Sym = *SymOrErr; const void *AuxP = nullptr; if (Sym.getNumberOfAuxSymbols()) AuxP = COFFObj->getSymbol(I + 1)->getRawPtr(); bool IsFirst = (LastSectionNumber != Sym.getSectionNumber()); SymbolBody *Body = nullptr; if (Sym.isUndefined()) { Body = createUndefined(Sym); } else if (Sym.isWeakExternal()) { Body = createWeakExternal(Sym, AuxP); WeakAliases.push_back((Undefined *)Body); } else { Body = createDefined(Sym, AuxP, IsFirst); } if (Body) { SymbolBodies.push_back(Body); SparseSymbolBodies[I] = Body; } I += Sym.getNumberOfAuxSymbols(); LastSectionNumber = Sym.getSectionNumber(); } for (Undefined *U : WeakAliases) U->WeakAlias = SparseSymbolBodies[(uintptr_t)U->WeakAlias]; } Undefined *ObjectFile::createUndefined(COFFSymbolRef Sym) { StringRef Name; COFFObj->getSymbolName(Sym, Name); return new (Alloc) Undefined(Name); } Undefined *ObjectFile::createWeakExternal(COFFSymbolRef Sym, const void *AuxP) { StringRef Name; COFFObj->getSymbolName(Sym, Name); auto *U = new (Alloc) Undefined(Name); auto *Aux = (const coff_aux_weak_external *)AuxP; U->WeakAlias = (Undefined *)(uintptr_t)Aux->TagIndex; return U; } Defined *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, bool IsFirst) { StringRef Name; if (Sym.isCommon()) { auto *C = new (Alloc) CommonChunk(Sym); Chunks.push_back(C); return new (Alloc) DefinedCommon(this, Sym, C); } if (Sym.isAbsolute()) { COFFObj->getSymbolName(Sym, Name); // Skip special symbols. if (Name == "@comp.id") return nullptr; // COFF spec 5.10.1. The .sxdata section. if (Name == "@feat.00") { if (Sym.getValue() & 1) SEHCompat = true; return nullptr; } return new (Alloc) DefinedAbsolute(Name, Sym); } if (Sym.getSectionNumber() == llvm::COFF::IMAGE_SYM_DEBUG) return nullptr; // Nothing else to do without a section chunk. auto *SC = cast_or_null(SparseChunks[Sym.getSectionNumber()]); if (!SC) return nullptr; // Handle section definitions if (IsFirst && AuxP) { auto *Aux = reinterpret_cast(AuxP); if (Aux->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) if (auto *ParentSC = cast_or_null( SparseChunks[Aux->getNumber(Sym.isBigObj())])) ParentSC->addAssociative(SC); SC->Checksum = Aux->CheckSum; } auto *B = new (Alloc) DefinedRegular(this, Sym, SC); if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP) SC->setSymbol(B); return B; } void ObjectFile::initializeSEH() { if (!SEHCompat || !SXData) return; ArrayRef A; COFFObj->getSectionContents(SXData, A); if (A.size() % 4 != 0) error(".sxdata must be an array of symbol table indices"); auto *I = reinterpret_cast(A.data()); auto *E = reinterpret_cast(A.data() + A.size()); for (; I != E; ++I) SEHandlers.insert(SparseSymbolBodies[*I]); } MachineTypes ObjectFile::getMachineType() { if (COFFObj) return static_cast(COFFObj->getMachine()); return IMAGE_FILE_MACHINE_UNKNOWN; } StringRef ltrim1(StringRef S, const char *Chars) { if (!S.empty() && strchr(Chars, S[0])) return S.substr(1); return S; } void ImportFile::parse() { const char *Buf = MB.getBufferStart(); const char *End = MB.getBufferEnd(); const auto *Hdr = reinterpret_cast(Buf); // Check if the total size is valid. if ((size_t)(End - Buf) != (sizeof(*Hdr) + Hdr->SizeOfData)) error("broken import library"); // Read names and create an __imp_ symbol. StringRef Name = StringAlloc.save(StringRef(Buf + sizeof(*Hdr))); StringRef ImpName = StringAlloc.save(Twine("__imp_") + Name); const char *NameStart = Buf + sizeof(coff_import_header) + Name.size() + 1; DLLName = StringRef(NameStart); StringRef ExtName; switch (Hdr->getNameType()) { case IMPORT_ORDINAL: ExtName = ""; break; case IMPORT_NAME: ExtName = Name; break; case IMPORT_NAME_NOPREFIX: ExtName = ltrim1(Name, "?@_"); break; case IMPORT_NAME_UNDECORATE: ExtName = ltrim1(Name, "?@_"); ExtName = ExtName.substr(0, ExtName.find('@')); break; } ImpSym = new (Alloc) DefinedImportData(DLLName, ImpName, ExtName, Hdr); SymbolBodies.push_back(ImpSym); // If type is function, we need to create a thunk which jump to an // address pointed by the __imp_ symbol. (This allows you to call // DLL functions just like regular non-DLL functions.) if (Hdr->getType() != llvm::COFF::IMPORT_CODE) return; ThunkSym = new (Alloc) DefinedImportThunk(Name, ImpSym, Hdr->Machine); SymbolBodies.push_back(ThunkSym); } void BitcodeFile::parse() { // Usually parse() is thread-safe, but bitcode file is an exception. std::lock_guard Lock(Mu); ErrorOr> ModOrErr = LTOModule::createFromBuffer(llvm::getGlobalContext(), MB.getBufferStart(), MB.getBufferSize(), llvm::TargetOptions()); error(ModOrErr, "Could not create lto module"); M = std::move(*ModOrErr); llvm::StringSaver Saver(Alloc); for (unsigned I = 0, E = M->getSymbolCount(); I != E; ++I) { lto_symbol_attributes Attrs = M->getSymbolAttributes(I); if ((Attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL) continue; StringRef SymName = Saver.save(M->getSymbolName(I)); int SymbolDef = Attrs & LTO_SYMBOL_DEFINITION_MASK; if (SymbolDef == LTO_SYMBOL_DEFINITION_UNDEFINED) { SymbolBodies.push_back(new (Alloc) Undefined(SymName)); } else { bool Replaceable = (SymbolDef == LTO_SYMBOL_DEFINITION_TENTATIVE || // common (Attrs & LTO_SYMBOL_COMDAT) || // comdat (SymbolDef == LTO_SYMBOL_DEFINITION_WEAK && // weak external (Attrs & LTO_SYMBOL_ALIAS))); SymbolBodies.push_back(new (Alloc) DefinedBitcode(this, SymName, Replaceable)); } } Directives = M->getLinkerOpts(); } MachineTypes BitcodeFile::getMachineType() { if (!M) return IMAGE_FILE_MACHINE_UNKNOWN; switch (Triple(M->getTargetTriple()).getArch()) { case Triple::x86_64: return AMD64; case Triple::x86: return I386; case Triple::arm: return ARMNT; default: return IMAGE_FILE_MACHINE_UNKNOWN; } } std::mutex BitcodeFile::Mu; } // namespace coff } // namespace lld Index: vendor/lld/dist/COFF/Writer.cpp =================================================================== --- vendor/lld/dist/COFF/Writer.cpp (revision 293845) +++ vendor/lld/dist/COFF/Writer.cpp (revision 293846) @@ -1,765 +1,764 @@ //===- Writer.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Config.h" #include "DLL.h" #include "Error.h" #include "InputFiles.h" #include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" #include "lld/Core/Parallel.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include using namespace llvm; using namespace llvm::COFF; using namespace llvm::object; using namespace llvm::support; using namespace llvm::support::endian; using namespace lld; using namespace lld::coff; static const int PageSize = 4096; static const int SectorSize = 512; static const int DOSStubSize = 64; static const int NumberfOfDataDirectory = 16; namespace { // The writer writes a SymbolTable result to a file. class Writer { public: Writer(SymbolTable *T) : Symtab(T) {} void run(); private: void createSections(); void createMiscChunks(); void createImportTables(); void createExportTable(); void assignAddresses(); void removeEmptySections(); void createSymbolAndStringTable(); void openFile(StringRef OutputPath); template void writeHeader(); void fixSafeSEHSymbols(); void writeSections(); void sortExceptionTable(); void applyRelocations(); llvm::Optional createSymbol(Defined *D); size_t addEntryToStringTable(StringRef Str); OutputSection *findSection(StringRef Name); OutputSection *createSection(StringRef Name); void addBaserels(OutputSection *Dest); void addBaserelBlocks(OutputSection *Dest, std::vector &V); uint32_t getSizeOfInitializedData(); std::map> binImports(); SymbolTable *Symtab; std::unique_ptr Buffer; llvm::SpecificBumpPtrAllocator CAlloc; llvm::SpecificBumpPtrAllocator BAlloc; std::vector OutputSections; std::vector Strtab; std::vector OutputSymtab; IdataContents Idata; DelayLoadContents DelayIdata; EdataContents Edata; std::unique_ptr SEHTable; uint64_t FileSize; uint32_t PointerToSymbolTable = 0; uint64_t SizeOfImage; uint64_t SizeOfHeaders; std::vector> Chunks; }; } // anonymous namespace namespace lld { namespace coff { void writeResult(SymbolTable *T) { Writer(T).run(); } // OutputSection represents a section in an output file. It's a // container of chunks. OutputSection and Chunk are 1:N relationship. // Chunks cannot belong to more than one OutputSections. The writer // creates multiple OutputSections and assign them unique, // non-overlapping file offsets and RVAs. class OutputSection { public: OutputSection(StringRef N) : Name(N), Header({}) {} void setRVA(uint64_t); void setFileOffset(uint64_t); void addChunk(Chunk *C); StringRef getName() { return Name; } std::vector &getChunks() { return Chunks; } void addPermissions(uint32_t C); uint32_t getPermissions() { return Header.Characteristics & PermMask; } uint32_t getCharacteristics() { return Header.Characteristics; } uint64_t getRVA() { return Header.VirtualAddress; } uint64_t getFileOff() { return Header.PointerToRawData; } void writeHeaderTo(uint8_t *Buf); // Returns the size of this section in an executable memory image. // This may be smaller than the raw size (the raw size is multiple // of disk sector size, so there may be padding at end), or may be // larger (if that's the case, the loader reserves spaces after end // of raw data). uint64_t getVirtualSize() { return Header.VirtualSize; } // Returns the size of the section in the output file. uint64_t getRawSize() { return Header.SizeOfRawData; } // Set offset into the string table storing this section name. // Used only when the name is longer than 8 bytes. void setStringTableOff(uint32_t V) { StringTableOff = V; } // N.B. The section index is one based. uint32_t SectionIndex = 0; private: StringRef Name; coff_section Header; uint32_t StringTableOff = 0; std::vector Chunks; }; void OutputSection::setRVA(uint64_t RVA) { Header.VirtualAddress = RVA; for (Chunk *C : Chunks) C->setRVA(C->getRVA() + RVA); } void OutputSection::setFileOffset(uint64_t Off) { // If a section has no actual data (i.e. BSS section), we want to // set 0 to its PointerToRawData. Otherwise the output is rejected // by the loader. if (Header.SizeOfRawData == 0) return; Header.PointerToRawData = Off; } void OutputSection::addChunk(Chunk *C) { Chunks.push_back(C); C->setOutputSection(this); uint64_t Off = Header.VirtualSize; - Off = RoundUpToAlignment(Off, C->getAlign()); + Off = align(Off, C->getAlign()); C->setRVA(Off); C->setOutputSectionOff(Off); Off += C->getSize(); Header.VirtualSize = Off; if (C->hasData()) - Header.SizeOfRawData = RoundUpToAlignment(Off, SectorSize); + Header.SizeOfRawData = align(Off, SectorSize); } void OutputSection::addPermissions(uint32_t C) { Header.Characteristics |= C & PermMask; } // Write the section header to a given buffer. void OutputSection::writeHeaderTo(uint8_t *Buf) { auto *Hdr = reinterpret_cast(Buf); *Hdr = Header; if (StringTableOff) { // If name is too long, write offset into the string table as a name. sprintf(Hdr->Name, "/%d", StringTableOff); } else { assert(!Config->Debug || Name.size() <= COFF::NameSize); strncpy(Hdr->Name, Name.data(), std::min(Name.size(), (size_t)COFF::NameSize)); } } uint64_t Defined::getSecrel() { if (auto *D = dyn_cast(this)) return getRVA() - D->getChunk()->getOutputSection()->getRVA(); error("SECREL relocation points to a non-regular symbol"); } uint64_t Defined::getSectionIndex() { if (auto *D = dyn_cast(this)) return D->getChunk()->getOutputSection()->SectionIndex; error("SECTION relocation points to a non-regular symbol"); } bool Defined::isExecutable() { const auto X = IMAGE_SCN_MEM_EXECUTE; if (auto *D = dyn_cast(this)) return D->getChunk()->getOutputSection()->getPermissions() & X; return isa(this); } } // namespace coff } // namespace lld // The main function of the writer. void Writer::run() { createSections(); createMiscChunks(); createImportTables(); createExportTable(); if (Config->Relocatable) createSection(".reloc"); assignAddresses(); removeEmptySections(); createSymbolAndStringTable(); openFile(Config->OutputFile); if (Config->is64()) { writeHeader(); } else { writeHeader(); } fixSafeSEHSymbols(); writeSections(); sortExceptionTable(); error(Buffer->commit(), "Failed to write the output file"); } static StringRef getOutputSection(StringRef Name) { StringRef S = Name.split('$').first; auto It = Config->Merge.find(S); if (It == Config->Merge.end()) return S; return It->second; } // Create output section objects and add them to OutputSections. void Writer::createSections() { // First, bin chunks by name. std::map> Map; for (Chunk *C : Symtab->getChunks()) { auto *SC = dyn_cast(C); if (SC && !SC->isLive()) { if (Config->Verbose) SC->printDiscardedMessage(); continue; } Map[C->getSectionName()].push_back(C); } // Then create an OutputSection for each section. // '$' and all following characters in input section names are // discarded when determining output section. So, .text$foo // contributes to .text, for example. See PE/COFF spec 3.2. SmallDenseMap Sections; for (auto Pair : Map) { StringRef Name = getOutputSection(Pair.first); OutputSection *&Sec = Sections[Name]; if (!Sec) { Sec = new (CAlloc.Allocate()) OutputSection(Name); OutputSections.push_back(Sec); } std::vector &Chunks = Pair.second; for (Chunk *C : Chunks) { Sec->addChunk(C); Sec->addPermissions(C->getPermissions()); } } } void Writer::createMiscChunks() { // Create thunks for locally-dllimported symbols. if (!Symtab->LocalImportChunks.empty()) { OutputSection *Sec = createSection(".rdata"); for (Chunk *C : Symtab->LocalImportChunks) Sec->addChunk(C); } // Create SEH table. x86-only. if (Config->Machine != I386) return; std::set Handlers; for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) { if (!File->SEHCompat) return; for (SymbolBody *B : File->SEHandlers) Handlers.insert(cast(B->repl())); } SEHTable.reset(new SEHTableChunk(Handlers)); createSection(".rdata")->addChunk(SEHTable.get()); } // Create .idata section for the DLL-imported symbol table. // The format of this section is inherently Windows-specific. // IdataContents class abstracted away the details for us, // so we just let it create chunks and add them to the section. void Writer::createImportTables() { if (Symtab->ImportFiles.empty()) return; // Initialize DLLOrder so that import entries are ordered in // the same order as in the command line. (That affects DLL // initialization order, and this ordering is MSVC-compatible.) for (ImportFile *File : Symtab->ImportFiles) { std::string DLL = StringRef(File->DLLName).lower(); if (Config->DLLOrder.count(DLL) == 0) Config->DLLOrder[DLL] = Config->DLLOrder.size(); } OutputSection *Text = createSection(".text"); for (ImportFile *File : Symtab->ImportFiles) { if (DefinedImportThunk *Thunk = File->ThunkSym) Text->addChunk(Thunk->getChunk()); if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) { DelayIdata.add(File->ImpSym); } else { Idata.add(File->ImpSym); } } if (!Idata.empty()) { OutputSection *Sec = createSection(".idata"); for (Chunk *C : Idata.getChunks()) Sec->addChunk(C); } if (!DelayIdata.empty()) { Defined *Helper = cast(Config->DelayLoadHelper->repl()); DelayIdata.create(Helper); OutputSection *Sec = createSection(".didat"); for (Chunk *C : DelayIdata.getChunks()) Sec->addChunk(C); Sec = createSection(".data"); for (Chunk *C : DelayIdata.getDataChunks()) Sec->addChunk(C); Sec = createSection(".text"); for (std::unique_ptr &C : DelayIdata.getCodeChunks()) Sec->addChunk(C.get()); } } void Writer::createExportTable() { if (Config->Exports.empty()) return; OutputSection *Sec = createSection(".edata"); for (std::unique_ptr &C : Edata.Chunks) Sec->addChunk(C.get()); } // The Windows loader doesn't seem to like empty sections, // so we remove them if any. void Writer::removeEmptySections() { auto IsEmpty = [](OutputSection *S) { return S->getVirtualSize() == 0; }; OutputSections.erase( std::remove_if(OutputSections.begin(), OutputSections.end(), IsEmpty), OutputSections.end()); uint32_t Idx = 1; for (OutputSection *Sec : OutputSections) Sec->SectionIndex = Idx++; } size_t Writer::addEntryToStringTable(StringRef Str) { assert(Str.size() > COFF::NameSize); size_t OffsetOfEntry = Strtab.size() + 4; // +4 for the size field Strtab.insert(Strtab.end(), Str.begin(), Str.end()); Strtab.push_back('\0'); return OffsetOfEntry; } Optional Writer::createSymbol(Defined *Def) { if (auto *D = dyn_cast(Def)) if (!D->getChunk()->isLive()) return None; coff_symbol16 Sym; StringRef Name = Def->getName(); if (Name.size() > COFF::NameSize) { Sym.Name.Offset.Zeroes = 0; Sym.Name.Offset.Offset = addEntryToStringTable(Name); } else { memset(Sym.Name.ShortName, 0, COFF::NameSize); memcpy(Sym.Name.ShortName, Name.data(), Name.size()); } if (auto *D = dyn_cast(Def)) { COFFSymbolRef Ref = D->getCOFFSymbol(); Sym.Type = Ref.getType(); Sym.StorageClass = Ref.getStorageClass(); } else { Sym.Type = IMAGE_SYM_TYPE_NULL; Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; } Sym.NumberOfAuxSymbols = 0; switch (Def->kind()) { case SymbolBody::DefinedAbsoluteKind: case SymbolBody::DefinedRelativeKind: Sym.Value = Def->getRVA(); Sym.SectionNumber = IMAGE_SYM_ABSOLUTE; break; default: { uint64_t RVA = Def->getRVA(); OutputSection *Sec = nullptr; for (OutputSection *S : OutputSections) { if (S->getRVA() > RVA) break; Sec = S; } Sym.Value = RVA - Sec->getRVA(); Sym.SectionNumber = Sec->SectionIndex; break; } } return Sym; } void Writer::createSymbolAndStringTable() { if (!Config->Debug || !Config->WriteSymtab) return; // Name field in the section table is 8 byte long. Longer names need // to be written to the string table. First, construct string table. for (OutputSection *Sec : OutputSections) { StringRef Name = Sec->getName(); if (Name.size() <= COFF::NameSize) continue; Sec->setStringTableOff(addEntryToStringTable(Name)); } for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) for (SymbolBody *B : File->getSymbols()) if (auto *D = dyn_cast(B)) if (Optional Sym = createSymbol(D)) OutputSymtab.push_back(*Sym); for (ImportFile *File : Symtab->ImportFiles) for (SymbolBody *B : File->getSymbols()) if (Optional Sym = createSymbol(cast(B))) OutputSymtab.push_back(*Sym); OutputSection *LastSection = OutputSections.back(); // We position the symbol table to be adjacent to the end of the last section. uint64_t FileOff = - LastSection->getFileOff() + - RoundUpToAlignment(LastSection->getRawSize(), SectorSize); + LastSection->getFileOff() + align(LastSection->getRawSize(), SectorSize); if (!OutputSymtab.empty()) { PointerToSymbolTable = FileOff; FileOff += OutputSymtab.size() * sizeof(coff_symbol16); } if (!Strtab.empty()) FileOff += Strtab.size() + 4; - FileSize = RoundUpToAlignment(FileOff, SectorSize); + FileSize = align(FileOff, SectorSize); } // Visits all sections to assign incremental, non-overlapping RVAs and // file offsets. void Writer::assignAddresses() { SizeOfHeaders = DOSStubSize + sizeof(PEMagic) + sizeof(coff_file_header) + sizeof(data_directory) * NumberfOfDataDirectory + sizeof(coff_section) * OutputSections.size(); SizeOfHeaders += Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); - SizeOfHeaders = RoundUpToAlignment(SizeOfHeaders, SectorSize); + SizeOfHeaders = align(SizeOfHeaders, SectorSize); uint64_t RVA = 0x1000; // The first page is kept unmapped. FileSize = SizeOfHeaders; // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because // the loader cannot handle holes. std::stable_partition( OutputSections.begin(), OutputSections.end(), [](OutputSection *S) { return (S->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0; }); for (OutputSection *Sec : OutputSections) { if (Sec->getName() == ".reloc") addBaserels(Sec); Sec->setRVA(RVA); Sec->setFileOffset(FileSize); - RVA += RoundUpToAlignment(Sec->getVirtualSize(), PageSize); - FileSize += RoundUpToAlignment(Sec->getRawSize(), SectorSize); + RVA += align(Sec->getVirtualSize(), PageSize); + FileSize += align(Sec->getRawSize(), SectorSize); } - SizeOfImage = SizeOfHeaders + RoundUpToAlignment(RVA - 0x1000, PageSize); + SizeOfImage = SizeOfHeaders + align(RVA - 0x1000, PageSize); } template void Writer::writeHeader() { // Write DOS stub uint8_t *Buf = Buffer->getBufferStart(); auto *DOS = reinterpret_cast(Buf); Buf += DOSStubSize; DOS->Magic[0] = 'M'; DOS->Magic[1] = 'Z'; DOS->AddressOfRelocationTable = sizeof(dos_header); DOS->AddressOfNewExeHeader = DOSStubSize; // Write PE magic memcpy(Buf, PEMagic, sizeof(PEMagic)); Buf += sizeof(PEMagic); // Write COFF header auto *COFF = reinterpret_cast(Buf); Buf += sizeof(*COFF); COFF->Machine = Config->Machine; COFF->NumberOfSections = OutputSections.size(); COFF->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; if (Config->LargeAddressAware) COFF->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; if (!Config->is64()) COFF->Characteristics |= IMAGE_FILE_32BIT_MACHINE; if (Config->DLL) COFF->Characteristics |= IMAGE_FILE_DLL; if (!Config->Relocatable) COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; COFF->SizeOfOptionalHeader = sizeof(PEHeaderTy) + sizeof(data_directory) * NumberfOfDataDirectory; // Write PE header auto *PE = reinterpret_cast(Buf); Buf += sizeof(*PE); PE->Magic = Config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32; PE->ImageBase = Config->ImageBase; PE->SectionAlignment = PageSize; PE->FileAlignment = SectorSize; PE->MajorImageVersion = Config->MajorImageVersion; PE->MinorImageVersion = Config->MinorImageVersion; PE->MajorOperatingSystemVersion = Config->MajorOSVersion; PE->MinorOperatingSystemVersion = Config->MinorOSVersion; PE->MajorSubsystemVersion = Config->MajorOSVersion; PE->MinorSubsystemVersion = Config->MinorOSVersion; PE->Subsystem = Config->Subsystem; PE->SizeOfImage = SizeOfImage; PE->SizeOfHeaders = SizeOfHeaders; if (!Config->NoEntry) { Defined *Entry = cast(Config->Entry->repl()); PE->AddressOfEntryPoint = Entry->getRVA(); // Pointer to thumb code must have the LSB set, so adjust it. if (Config->Machine == ARMNT) PE->AddressOfEntryPoint |= 1; } PE->SizeOfStackReserve = Config->StackReserve; PE->SizeOfStackCommit = Config->StackCommit; PE->SizeOfHeapReserve = Config->HeapReserve; PE->SizeOfHeapCommit = Config->HeapCommit; if (Config->DynamicBase) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE; if (Config->HighEntropyVA) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA; if (!Config->AllowBind) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_BIND; if (Config->NxCompat) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; if (!Config->AllowIsolation) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION; if (Config->TerminalServerAware) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE; PE->NumberOfRvaAndSize = NumberfOfDataDirectory; if (OutputSection *Text = findSection(".text")) { PE->BaseOfCode = Text->getRVA(); PE->SizeOfCode = Text->getRawSize(); } PE->SizeOfInitializedData = getSizeOfInitializedData(); // Write data directory auto *Dir = reinterpret_cast(Buf); Buf += sizeof(*Dir) * NumberfOfDataDirectory; if (OutputSection *Sec = findSection(".edata")) { Dir[EXPORT_TABLE].RelativeVirtualAddress = Sec->getRVA(); Dir[EXPORT_TABLE].Size = Sec->getVirtualSize(); } if (!Idata.empty()) { Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA(); Dir[IMPORT_TABLE].Size = Idata.getDirSize(); Dir[IAT].RelativeVirtualAddress = Idata.getIATRVA(); Dir[IAT].Size = Idata.getIATSize(); } if (!DelayIdata.empty()) { Dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress = DelayIdata.getDirRVA(); Dir[DELAY_IMPORT_DESCRIPTOR].Size = DelayIdata.getDirSize(); } if (OutputSection *Sec = findSection(".rsrc")) { Dir[RESOURCE_TABLE].RelativeVirtualAddress = Sec->getRVA(); Dir[RESOURCE_TABLE].Size = Sec->getVirtualSize(); } if (OutputSection *Sec = findSection(".reloc")) { Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = Sec->getRVA(); Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize(); } if (OutputSection *Sec = findSection(".pdata")) { Dir[EXCEPTION_TABLE].RelativeVirtualAddress = Sec->getRVA(); Dir[EXCEPTION_TABLE].Size = Sec->getVirtualSize(); } if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) { if (Defined *B = dyn_cast(Sym->Body)) { Dir[TLS_TABLE].RelativeVirtualAddress = B->getRVA(); Dir[TLS_TABLE].Size = 40; } } if (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) { if (Defined *B = dyn_cast(Sym->Body)) { Dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = B->getRVA(); Dir[LOAD_CONFIG_TABLE].Size = Config->is64() ? 112 : 64; } } // Write section table for (OutputSection *Sec : OutputSections) { Sec->writeHeaderTo(Buf); Buf += sizeof(coff_section); } if (OutputSymtab.empty()) return; COFF->PointerToSymbolTable = PointerToSymbolTable; uint32_t NumberOfSymbols = OutputSymtab.size(); COFF->NumberOfSymbols = NumberOfSymbols; auto *SymbolTable = reinterpret_cast( Buffer->getBufferStart() + COFF->PointerToSymbolTable); for (size_t I = 0; I != NumberOfSymbols; ++I) SymbolTable[I] = OutputSymtab[I]; // Create the string table, it follows immediately after the symbol table. // The first 4 bytes is length including itself. Buf = reinterpret_cast(&SymbolTable[NumberOfSymbols]); write32le(Buf, Strtab.size() + 4); memcpy(Buf + 4, Strtab.data(), Strtab.size()); } void Writer::openFile(StringRef Path) { ErrorOr> BufferOrErr = FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable); error(BufferOrErr, Twine("failed to open ") + Path); Buffer = std::move(*BufferOrErr); } void Writer::fixSafeSEHSymbols() { if (!SEHTable) return; Config->SEHTable->setRVA(SEHTable->getRVA()); Config->SEHCount->setVA(SEHTable->getSize() / 4); } // Write section contents to a mmap'ed file. void Writer::writeSections() { uint8_t *Buf = Buffer->getBufferStart(); for (OutputSection *Sec : OutputSections) { uint8_t *SecBuf = Buf + Sec->getFileOff(); // Fill gaps between functions in .text with INT3 instructions // instead of leaving as NUL bytes (which can be interpreted as // ADD instructions). if (Sec->getPermissions() & IMAGE_SCN_CNT_CODE) memset(SecBuf, 0xCC, Sec->getRawSize()); parallel_for_each(Sec->getChunks().begin(), Sec->getChunks().end(), [&](Chunk *C) { C->writeTo(SecBuf); }); } } // Sort .pdata section contents according to PE/COFF spec 5.5. void Writer::sortExceptionTable() { OutputSection *Sec = findSection(".pdata"); if (!Sec) return; // We assume .pdata contains function table entries only. uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff(); uint8_t *End = Begin + Sec->getVirtualSize(); if (Config->Machine == AMD64) { struct Entry { ulittle32_t Begin, End, Unwind; }; parallel_sort( (Entry *)Begin, (Entry *)End, [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); return; } if (Config->Machine == ARMNT) { struct Entry { ulittle32_t Begin, Unwind; }; parallel_sort( (Entry *)Begin, (Entry *)End, [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); return; } errs() << "warning: don't know how to handle .pdata.\n"; } OutputSection *Writer::findSection(StringRef Name) { for (OutputSection *Sec : OutputSections) if (Sec->getName() == Name) return Sec; return nullptr; } uint32_t Writer::getSizeOfInitializedData() { uint32_t Res = 0; for (OutputSection *S : OutputSections) if (S->getPermissions() & IMAGE_SCN_CNT_INITIALIZED_DATA) Res += S->getRawSize(); return Res; } // Returns an existing section or create a new one if not found. OutputSection *Writer::createSection(StringRef Name) { if (auto *Sec = findSection(Name)) return Sec; const auto DATA = IMAGE_SCN_CNT_INITIALIZED_DATA; const auto BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA; const auto CODE = IMAGE_SCN_CNT_CODE; const auto DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE; const auto R = IMAGE_SCN_MEM_READ; const auto W = IMAGE_SCN_MEM_WRITE; const auto X = IMAGE_SCN_MEM_EXECUTE; uint32_t Perms = StringSwitch(Name) .Case(".bss", BSS | R | W) .Case(".data", DATA | R | W) .Case(".didat", DATA | R) .Case(".edata", DATA | R) .Case(".idata", DATA | R) .Case(".rdata", DATA | R) .Case(".reloc", DATA | DISCARDABLE | R) .Case(".text", CODE | R | X) .Default(0); if (!Perms) llvm_unreachable("unknown section name"); auto Sec = new (CAlloc.Allocate()) OutputSection(Name); Sec->addPermissions(Perms); OutputSections.push_back(Sec); return Sec; } // Dest is .reloc section. Add contents to that section. void Writer::addBaserels(OutputSection *Dest) { std::vector V; for (OutputSection *Sec : OutputSections) { if (Sec == Dest) continue; // Collect all locations for base relocations. for (Chunk *C : Sec->getChunks()) C->getBaserels(&V); // Add the addresses to .reloc section. if (!V.empty()) addBaserelBlocks(Dest, V); V.clear(); } } // Add addresses to .reloc section. Note that addresses are grouped by page. void Writer::addBaserelBlocks(OutputSection *Dest, std::vector &V) { const uint32_t Mask = ~uint32_t(PageSize - 1); uint32_t Page = V[0].RVA & Mask; size_t I = 0, J = 1; for (size_t E = V.size(); J < E; ++J) { uint32_t P = V[J].RVA & Mask; if (P == Page) continue; BaserelChunk *Buf = BAlloc.Allocate(); Dest->addChunk(new (Buf) BaserelChunk(Page, &V[I], &V[0] + J)); I = J; Page = P; } if (I == J) return; BaserelChunk *Buf = BAlloc.Allocate(); Dest->addChunk(new (Buf) BaserelChunk(Page, &V[I], &V[0] + J)); } Index: vendor/lld/dist/ELF/CMakeLists.txt =================================================================== --- vendor/lld/dist/ELF/CMakeLists.txt (revision 293845) +++ vendor/lld/dist/ELF/CMakeLists.txt (revision 293846) @@ -1,26 +1,26 @@ set(LLVM_TARGET_DEFINITIONS Options.td) tablegen(LLVM Options.inc -gen-opt-parser-defs) add_public_tablegen_target(ELFOptionsTableGen) -add_llvm_library(lldELF2 +add_lld_library(lldELF2 Driver.cpp DriverUtils.cpp Error.cpp InputFiles.cpp InputSection.cpp LinkerScript.cpp MarkLive.cpp OutputSections.cpp SymbolTable.cpp Symbols.cpp Target.cpp Writer.cpp LINK_COMPONENTS Object Option MC Support ) add_dependencies(lldELF2 ELFOptionsTableGen) Index: vendor/lld/dist/ELF/Driver.cpp =================================================================== --- vendor/lld/dist/ELF/Driver.cpp (revision 293845) +++ vendor/lld/dist/ELF/Driver.cpp (revision 293846) @@ -1,315 +1,335 @@ //===- Driver.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Driver.h" #include "Config.h" #include "Error.h" #include "InputFiles.h" #include "SymbolTable.h" #include "Target.h" #include "Writer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" #include using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace lld; using namespace lld::elf2; -Configuration *lld::elf2::Config; -LinkerDriver *lld::elf2::Driver; +Configuration *elf2::Config; +LinkerDriver *elf2::Driver; -void lld::elf2::link(ArrayRef Args) { +void elf2::link(ArrayRef Args) { Configuration C; LinkerDriver D; Config = &C; Driver = &D; Driver->main(Args.slice(1)); } static std::pair parseEmulation(StringRef S) { if (S == "elf32btsmip") return {ELF32BEKind, EM_MIPS}; if (S == "elf32ltsmip") return {ELF32LEKind, EM_MIPS}; - if (S == "elf32ppc") + if (S == "elf32ppc" || S == "elf32ppc_fbsd") return {ELF32BEKind, EM_PPC}; - if (S == "elf64ppc") + if (S == "elf64ppc" || S == "elf64ppc_fbsd") return {ELF64BEKind, EM_PPC64}; if (S == "elf_i386") return {ELF32LEKind, EM_386}; if (S == "elf_x86_64") return {ELF64LEKind, EM_X86_64}; if (S == "aarch64linux") return {ELF64LEKind, EM_AARCH64}; if (S == "i386pe" || S == "i386pep" || S == "thumb2pe") error("Windows targets are not supported on the ELF frontend: " + S); error("Unknown emulation: " + S); } // Returns slices of MB by parsing MB as an archive file. // Each slice consists of a member file in the archive. static std::vector getArchiveMembers(MemoryBufferRef MB) { ErrorOr> FileOrErr = Archive::create(MB); error(FileOrErr, "Failed to parse archive"); std::unique_ptr File = std::move(*FileOrErr); std::vector V; for (const ErrorOr &C : File->children()) { error(C, "Could not get the child of the archive " + File->getFileName()); ErrorOr MbOrErr = C->getMemoryBufferRef(); error(MbOrErr, "Could not get the buffer for a child of the archive " + File->getFileName()); V.push_back(*MbOrErr); } return V; } // Opens and parses a file. Path has to be resolved already. // Newly created memory buffers are owned by this driver. void LinkerDriver::addFile(StringRef Path) { using namespace llvm::sys::fs; if (Config->Verbose) llvm::outs() << Path << "\n"; auto MBOrErr = MemoryBuffer::getFile(Path); error(MBOrErr, "cannot open " + Path); std::unique_ptr &MB = *MBOrErr; MemoryBufferRef MBRef = MB->getMemBufferRef(); OwningMBs.push_back(std::move(MB)); // take MB ownership switch (identify_magic(MBRef.getBuffer())) { case file_magic::unknown: readLinkerScript(&Alloc, MBRef); return; case file_magic::archive: if (WholeArchive) { for (MemoryBufferRef MB : getArchiveMembers(MBRef)) Files.push_back(createObjectFile(MB)); return; } Files.push_back(make_unique(MBRef)); return; case file_magic::elf_shared_object: Files.push_back(createSharedFile(MBRef)); return; default: Files.push_back(createObjectFile(MBRef)); } } +// Some command line options or some combinations of them are not allowed. +// This function checks for such errors. +static void checkOptions(opt::InputArgList &Args) { + // Traditional linkers can generate re-linkable object files instead + // of executables or DSOs. We don't support that since the feature + // does not seem to provide more value than the static archiver. + if (Args.hasArg(OPT_relocatable)) + error("-r option is not supported. Use 'ar' command instead."); + + // The MIPS ABI as of 2016 does not support the GNU-style symbol lookup + // table which is a relatively new feature. + if (Config->EMachine == EM_MIPS && Config->GnuHash) + error("The .gnu.hash section is not compatible with the MIPS target."); + + if (Config->EMachine == EM_AMDGPU && !Config->Entry.empty()) + error("-e option is not valid for AMDGPU."); +} + static StringRef getString(opt::InputArgList &Args, unsigned Key, StringRef Default = "") { if (auto *Arg = Args.getLastArg(Key)) return Arg->getValue(); return Default; } static bool hasZOption(opt::InputArgList &Args, StringRef Key) { for (auto *Arg : Args.filtered(OPT_z)) if (Key == Arg->getValue()) return true; return false; } void LinkerDriver::main(ArrayRef ArgsArr) { initSymbols(); opt::InputArgList Args = parseArgs(&Alloc, ArgsArr); + readConfigs(Args); createFiles(Args); + checkOptions(Args); - // Traditional linkers can generate re-linkable object files instead - // of executables or DSOs. We don't support that since the feature - // does not seem to provide more value than the static archiver. - if (Args.hasArg(OPT_relocatable)) - error("-r option is not supported. Use 'ar' command instead."); - switch (Config->EKind) { case ELF32LEKind: link(Args); return; case ELF32BEKind: link(Args); return; case ELF64LEKind: link(Args); return; case ELF64BEKind: link(Args); return; default: error("-m or at least a .o file required"); } } -void LinkerDriver::createFiles(opt::InputArgList &Args) { +// Initializes Config members by the command line options. +void LinkerDriver::readConfigs(opt::InputArgList &Args) { for (auto *Arg : Args.filtered(OPT_L)) Config->SearchPaths.push_back(Arg->getValue()); std::vector RPaths; for (auto *Arg : Args.filtered(OPT_rpath)) RPaths.push_back(Arg->getValue()); if (!RPaths.empty()) Config->RPath = llvm::join(RPaths.begin(), RPaths.end(), ":"); if (auto *Arg = Args.getLastArg(OPT_m)) { + // Parse ELF{32,64}{LE,BE} and CPU type. StringRef S = Arg->getValue(); - std::pair P = parseEmulation(S); - Config->EKind = P.first; - Config->EMachine = P.second; + std::tie(Config->EKind, Config->EMachine) = parseEmulation(S); Config->Emulation = S; } Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition); Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic); Config->DiscardAll = Args.hasArg(OPT_discard_all); Config->DiscardLocals = Args.hasArg(OPT_discard_locals); Config->DiscardNone = Args.hasArg(OPT_discard_none); Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags); Config->ExportDynamic = Args.hasArg(OPT_export_dynamic); Config->GcSections = Args.hasArg(OPT_gc_sections); Config->NoInhibitExec = Args.hasArg(OPT_noinhibit_exec); Config->NoUndefined = Args.hasArg(OPT_no_undefined); Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections); Config->Shared = Args.hasArg(OPT_shared); Config->StripAll = Args.hasArg(OPT_strip_all); Config->Verbose = Args.hasArg(OPT_verbose); Config->DynamicLinker = getString(Args, OPT_dynamic_linker); Config->Entry = getString(Args, OPT_entry); Config->Fini = getString(Args, OPT_fini, "_fini"); Config->Init = getString(Args, OPT_init, "_init"); Config->OutputFile = getString(Args, OPT_o); Config->SoName = getString(Args, OPT_soname); Config->Sysroot = getString(Args, OPT_sysroot); Config->ZExecStack = hasZOption(Args, "execstack"); Config->ZNodelete = hasZOption(Args, "nodelete"); Config->ZNow = hasZOption(Args, "now"); Config->ZOrigin = hasZOption(Args, "origin"); Config->ZRelro = !hasZOption(Args, "norelro"); if (auto *Arg = Args.getLastArg(OPT_O)) { StringRef Val = Arg->getValue(); if (Val.getAsInteger(10, Config->Optimize)) error("Invalid optimization level"); } if (auto *Arg = Args.getLastArg(OPT_hash_style)) { StringRef S = Arg->getValue(); if (S == "gnu") { Config->GnuHash = true; Config->SysvHash = false; } else if (S == "both") { Config->GnuHash = true; } else if (S != "sysv") error("Unknown hash style: " + S); } for (auto *Arg : Args.filtered(OPT_undefined)) Config->Undefined.push_back(Arg->getValue()); +} +void LinkerDriver::createFiles(opt::InputArgList &Args) { for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_l: addFile(searchLibrary(Arg->getValue())); break; case OPT_INPUT: case OPT_script: addFile(Arg->getValue()); break; case OPT_as_needed: Config->AsNeeded = true; break; case OPT_no_as_needed: Config->AsNeeded = false; break; case OPT_Bstatic: Config->Static = true; break; case OPT_Bdynamic: Config->Static = false; break; case OPT_whole_archive: WholeArchive = true; break; case OPT_no_whole_archive: WholeArchive = false; break; } } if (Files.empty()) error("no input files."); - - if (Config->GnuHash && Config->EMachine == EM_MIPS) - error("The .gnu.hash section is not compatible with the MIPS target."); } template void LinkerDriver::link(opt::InputArgList &Args) { SymbolTable Symtab; Target.reset(createTarget()); if (!Config->Shared) { // Add entry symbol. - if (Config->Entry.empty()) + // + // There is no entry symbol for AMDGPU binaries, so skip adding one to avoid + // having and undefined symbol. + if (Config->Entry.empty() && Config->EMachine != EM_AMDGPU) Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start"; // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol // is magical and is used to produce a R_386_GOTPC relocation. // The R_386_GOTPC relocation value doesn't actually depend on the // symbol value, so it could use an index of STN_UNDEF which, according // to the spec, means the symbol value is 0. // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in // the object file. // The situation is even stranger on x86_64 where the assembly doesn't // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as // an undefined symbol in the .o files. // Given that the symbol is effectively unused, we just create a dummy // hidden one to avoid the undefined symbol error. Symtab.addIgnored("_GLOBAL_OFFSET_TABLE_"); } if (!Config->Entry.empty()) { // Set either EntryAddr (if S is a number) or EntrySym (otherwise). StringRef S = Config->Entry; if (S.getAsInteger(0, Config->EntryAddr)) Config->EntrySym = Symtab.addUndefined(S); } if (Config->EMachine == EM_MIPS) { // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between - // start of function and gp pointer into GOT. - Config->MipsGpDisp = Symtab.addIgnored("_gp_disp"); + // start of function and gp pointer into GOT. Use 'strong' variant of + // the addIgnored to prevent '_gp_disp' substitution. + Config->MipsGpDisp = Symtab.addIgnoredStrong("_gp_disp"); // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer // so that it points to an absolute address which is relative to GOT. // See "Global Data Symbols" in Chapter 6 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf Symtab.addAbsolute("_gp", ElfSym::MipsGp); } for (std::unique_ptr &F : Files) Symtab.addFile(std::move(F)); for (StringRef S : Config->Undefined) Symtab.addUndefinedOpt(S); + + for (auto *Arg : Args.filtered(OPT_wrap)) + Symtab.wrap(Arg->getValue()); if (Config->OutputFile.empty()) Config->OutputFile = "a.out"; // Write the result to the file. Symtab.scanShlibUndefined(); if (Config->GcSections) markLive(&Symtab); writeResult(&Symtab); } Index: vendor/lld/dist/ELF/Driver.h =================================================================== --- vendor/lld/dist/ELF/Driver.h (revision 293845) +++ vendor/lld/dist/ELF/Driver.h (revision 293846) @@ -1,66 +1,64 @@ //===- Driver.h -------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_ELF_DRIVER_H #define LLD_ELF_DRIVER_H #include "SymbolTable.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/StringRef.h" #include "llvm/Option/ArgList.h" namespace lld { namespace elf2 { extern class LinkerDriver *Driver; // Entry point of the ELF linker. void link(ArrayRef Args); class LinkerDriver { public: void main(ArrayRef Args); - void createFiles(llvm::opt::InputArgList &Args); - template void link(llvm::opt::InputArgList &Args); - void addFile(StringRef Path); private: - template