Index: vendor/lld/dist/CMakeLists.txt =================================================================== --- vendor/lld/dist/CMakeLists.txt (revision 317956) +++ vendor/lld/dist/CMakeLists.txt (revision 317957) @@ -1,223 +1,224 @@ # Check if lld is built as a standalone project. if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) project(lld) cmake_minimum_required(VERSION 3.4.3) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(LLD_BUILT_STANDALONE TRUE) find_program(LLVM_CONFIG_PATH "llvm-config" DOC "Path to llvm-config binary") if(NOT LLVM_CONFIG_PATH) message(FATAL_ERROR "llvm-config not found: specify LLVM_CONFIG_PATH") endif() execute_process(COMMAND "${LLVM_CONFIG_PATH}" "--obj-root" "--includedir" "--cmakedir" "--src-root" RESULT_VARIABLE HAD_ERROR OUTPUT_VARIABLE LLVM_CONFIG_OUTPUT OUTPUT_STRIP_TRAILING_WHITESPACE) if(HAD_ERROR) message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}") endif() string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" LLVM_CONFIG_OUTPUT "${LLVM_CONFIG_OUTPUT}") list(GET LLVM_CONFIG_OUTPUT 0 OBJ_ROOT) list(GET LLVM_CONFIG_OUTPUT 1 MAIN_INCLUDE_DIR) list(GET LLVM_CONFIG_OUTPUT 2 LLVM_CMAKE_PATH) list(GET LLVM_CONFIG_OUTPUT 3 MAIN_SRC_DIR) set(LLVM_OBJ_ROOT ${OBJ_ROOT} CACHE PATH "path to LLVM build tree") set(LLVM_MAIN_INCLUDE_DIR ${MAIN_INCLUDE_DIR} CACHE PATH "path to llvm/include") set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree") file(TO_CMAKE_PATH ${LLVM_OBJ_ROOT} LLVM_BINARY_DIR) if(NOT EXISTS "${LLVM_CMAKE_PATH}/LLVMConfig.cmake") message(FATAL_ERROR "LLVMConfig.cmake not found") endif() include("${LLVM_CMAKE_PATH}/LLVMConfig.cmake") list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}") set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}") include_directories("${LLVM_BINARY_DIR}/include" ${LLVM_INCLUDE_DIRS}) link_directories(${LLVM_LIBRARY_DIRS}) set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}) set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin) find_program(LLVM_TABLEGEN_EXE "llvm-tblgen" ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH) include(AddLLVM) include(TableGen) include(HandleLLVMOptions) if(LLVM_INCLUDE_TESTS) set(Python_ADDITIONAL_VERSIONS 2.7) include(FindPythonInterp) if(NOT PYTHONINTERP_FOUND) message(FATAL_ERROR "Unable to find Python interpreter, required for testing. Please install Python or specify the PYTHON_EXECUTABLE CMake variable.") endif() if(${PYTHON_VERSION_STRING} VERSION_LESS 2.7) message(FATAL_ERROR "Python 2.7 or newer is required") endif() # Check prebuilt llvm/utils. if(EXISTS ${LLVM_TOOLS_BINARY_DIR}/FileCheck${CMAKE_EXECUTABLE_SUFFIX} AND EXISTS ${LLVM_TOOLS_BINARY_DIR}/not${CMAKE_EXECUTABLE_SUFFIX}) set(LLVM_UTILS_PROVIDED ON) endif() if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py) # Note: path not really used, except for checking if lit was found set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py) if(NOT LLVM_UTILS_PROVIDED) add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/FileCheck utils/FileCheck) add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/not utils/not) set(LLVM_UTILS_PROVIDED ON) set(LLD_TEST_DEPS FileCheck not) endif() set(UNITTEST_DIR ${LLVM_MAIN_SRC_DIR}/utils/unittest) if(EXISTS ${UNITTEST_DIR}/googletest/include/gtest/gtest.h AND NOT EXISTS ${LLVM_LIBRARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX} AND EXISTS ${UNITTEST_DIR}/CMakeLists.txt) add_subdirectory(${UNITTEST_DIR} utils/unittest) endif() else() # Seek installed Lit. find_program(LLVM_LIT NAMES llvm-lit lit.py lit PATHS "${LLVM_MAIN_SRC_DIR}/utils/lit" DOC "Path to lit.py") endif() if(LLVM_LIT) # Define the default arguments to use with 'lit', and an option for the user # to override. set(LIT_ARGS_DEFAULT "-sv") if (MSVC OR XCODE) set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar") endif() set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit") # On Win32 hosts, provide an option to specify the path to the GnuWin32 tools. if(WIN32 AND NOT CYGWIN) set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools") endif() else() set(LLVM_INCLUDE_TESTS OFF) endif() endif() endif() 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") include(AddLLD) 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() option(LLD_BUILD_TOOLS "Build the lld tools. If OFF, just generate build targets." ON) 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() add_subdirectory(lib) add_subdirectory(tools/lld) 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/Chunks.h =================================================================== --- vendor/lld/dist/COFF/Chunks.h (revision 317956) +++ vendor/lld/dist/COFF/Chunks.h (revision 317957) @@ -1,331 +1,331 @@ //===- 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; 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; } ArrayRef getContents() const; 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; const coff_section *Header; // The file that this chunk was created from. ObjectFile *File; private: 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); - uint32_t Color[2] = {0, 0}; + uint32_t Class[2] = {0, 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(std::move(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; }; } // namespace coff } // namespace lld #endif Index: vendor/lld/dist/COFF/ICF.cpp =================================================================== --- vendor/lld/dist/COFF/ICF.cpp (revision 317956) +++ vendor/lld/dist/COFF/ICF.cpp (revision 317957) @@ -1,261 +1,261 @@ //===- ICF.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // ICF is short for Identical Code Folding. That is a size optimization to // identify and merge two or more read-only sections (typically functions) // that happened to have the same contents. It usually reduces output size // by a few percent. // // On Windows, ICF is enabled by default. // // See ELF/ICF.cpp for the details about the algortihm. // //===----------------------------------------------------------------------===// #include "Chunks.h" #include "Error.h" #include "Symbols.h" #include "lld/Core/Parallel.h" #include "llvm/ADT/Hashing.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include #include #include using namespace llvm; namespace lld { namespace coff { class ICF { public: void run(const std::vector &V); private: void segregate(size_t Begin, size_t End, bool Constant); bool equalsConstant(const SectionChunk *A, const SectionChunk *B); bool equalsVariable(const SectionChunk *A, const SectionChunk *B); uint32_t getHash(SectionChunk *C); bool isEligible(SectionChunk *C); size_t findBoundary(size_t Begin, size_t End); - void forEachColorRange(size_t Begin, size_t End, + void forEachClassRange(size_t Begin, size_t End, std::function Fn); - void forEachColor(std::function Fn); + void forEachClass(std::function Fn); std::vector Chunks; int Cnt = 0; std::atomic NextId = {1}; std::atomic Repeat = {false}; }; // Returns a hash value for S. uint32_t ICF::getHash(SectionChunk *C) { return hash_combine(C->getPermissions(), hash_value(C->SectionName), C->NumRelocs, C->getAlign(), uint32_t(C->Header->SizeOfRawData), C->Checksum); } // Returns true if section S is subject of ICF. // // Microsoft's documentation // (https://msdn.microsoft.com/en-us/library/bxwfs976.aspx; visited April // 2017) says that /opt:icf folds both functions and read-only data. // Despite that, the MSVC linker folds only functions. We found // a few instances of programs that are not safe for data merging. // Therefore, we merge only functions just like the MSVC tool. bool ICF::isEligible(SectionChunk *C) { bool Global = C->Sym && C->Sym->isExternal(); bool Executable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE; bool Writable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE; return C->isCOMDAT() && C->isLive() && Global && Executable && !Writable; } -// Split a range into smaller ranges by recoloring sections +// Split an equivalence class into smaller classes. void ICF::segregate(size_t Begin, size_t End, bool Constant) { while (Begin < End) { // Divide [Begin, End) into two. Let Mid be the start index of the // second group. auto Bound = std::stable_partition( Chunks.begin() + Begin + 1, Chunks.begin() + End, [&](SectionChunk *S) { if (Constant) return equalsConstant(Chunks[Begin], S); return equalsVariable(Chunks[Begin], S); }); size_t Mid = Bound - Chunks.begin(); // Split [Begin, End) into [Begin, Mid) and [Mid, End). uint32_t Id = NextId++; for (size_t I = Begin; I < Mid; ++I) - Chunks[I]->Color[(Cnt + 1) % 2] = Id; + Chunks[I]->Class[(Cnt + 1) % 2] = Id; // If we created a group, we need to iterate the main loop again. if (Mid != End) Repeat = true; Begin = Mid; } } // Compare "non-moving" part of two sections, namely everything // except relocation targets. bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) { if (A->NumRelocs != B->NumRelocs) return false; // Compare relocations. auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) { if (R1.Type != R2.Type || R1.VirtualAddress != R2.VirtualAddress) { return false; } SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex); SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex); if (B1 == B2) return true; if (auto *D1 = dyn_cast(B1)) if (auto *D2 = dyn_cast(B2)) return D1->getValue() == D2->getValue() && - D1->getChunk()->Color[Cnt % 2] == D2->getChunk()->Color[Cnt % 2]; + D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2]; return false; }; if (!std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq)) return false; // Compare section attributes and contents. return A->getPermissions() == B->getPermissions() && A->SectionName == B->SectionName && A->getAlign() == B->getAlign() && A->Header->SizeOfRawData == B->Header->SizeOfRawData && A->Checksum == B->Checksum && A->getContents() == B->getContents(); } // Compare "moving" part of two sections, namely relocation targets. bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) { // Compare relocations. auto Eq = [&](const coff_relocation &R1, const coff_relocation &R2) { SymbolBody *B1 = A->File->getSymbolBody(R1.SymbolTableIndex); SymbolBody *B2 = B->File->getSymbolBody(R2.SymbolTableIndex); if (B1 == B2) return true; if (auto *D1 = dyn_cast(B1)) if (auto *D2 = dyn_cast(B2)) - return D1->getChunk()->Color[Cnt % 2] == D2->getChunk()->Color[Cnt % 2]; + return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2]; return false; }; return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq); } size_t ICF::findBoundary(size_t Begin, size_t End) { for (size_t I = Begin + 1; I < End; ++I) - if (Chunks[Begin]->Color[Cnt % 2] != Chunks[I]->Color[Cnt % 2]) + if (Chunks[Begin]->Class[Cnt % 2] != Chunks[I]->Class[Cnt % 2]) return I; return End; } -void ICF::forEachColorRange(size_t Begin, size_t End, +void ICF::forEachClassRange(size_t Begin, size_t End, std::function Fn) { if (Begin > 0) Begin = findBoundary(Begin - 1, End); while (Begin < End) { size_t Mid = findBoundary(Begin, Chunks.size()); Fn(Begin, Mid); Begin = Mid; } } -// Call Fn on each color group. -void ICF::forEachColor(std::function Fn) { +// Call Fn on each class group. +void ICF::forEachClass(std::function Fn) { // If the number of sections are too small to use threading, // call Fn sequentially. if (Chunks.size() < 1024) { - forEachColorRange(0, Chunks.size(), Fn); + forEachClassRange(0, Chunks.size(), Fn); return; } // Split sections into 256 shards and call Fn in parallel. size_t NumShards = 256; size_t Step = Chunks.size() / NumShards; parallel_for(size_t(0), NumShards, [&](size_t I) { - forEachColorRange(I * Step, (I + 1) * Step, Fn); + forEachClassRange(I * Step, (I + 1) * Step, Fn); }); - forEachColorRange(Step * NumShards, Chunks.size(), Fn); + forEachClassRange(Step * NumShards, Chunks.size(), Fn); } // Merge identical COMDAT sections. // Two sections are considered the same if their section headers, // contents and relocations are all the same. void ICF::run(const std::vector &Vec) { // Collect only mergeable sections and group by hash value. for (Chunk *C : Vec) { auto *SC = dyn_cast(C); if (!SC) continue; if (isEligible(SC)) { - // Set MSB to 1 to avoid collisions with non-hash colors. - SC->Color[0] = getHash(SC) | (1 << 31); + // Set MSB to 1 to avoid collisions with non-hash classs. + SC->Class[0] = getHash(SC) | (1 << 31); Chunks.push_back(SC); } else { - SC->Color[0] = NextId++; + SC->Class[0] = NextId++; } } if (Chunks.empty()) return; // From now on, sections in Chunks are ordered so that sections in // the same group are consecutive in the vector. std::stable_sort(Chunks.begin(), Chunks.end(), [](SectionChunk *A, SectionChunk *B) { - return A->Color[0] < B->Color[0]; + return A->Class[0] < B->Class[0]; }); // Compare static contents and assign unique IDs for each static content. - forEachColor([&](size_t Begin, size_t End) { segregate(Begin, End, true); }); + forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); }); ++Cnt; // Split groups by comparing relocations until convergence is obtained. do { Repeat = false; - forEachColor( + forEachClass( [&](size_t Begin, size_t End) { segregate(Begin, End, false); }); ++Cnt; } while (Repeat); log("ICF needed " + Twine(Cnt) + " iterations"); - // Merge sections in the same colors. - forEachColor([&](size_t Begin, size_t End) { + // Merge sections in the same classs. + forEachClass([&](size_t Begin, size_t End) { if (End - Begin == 1) return; log("Selected " + Chunks[Begin]->getDebugName()); for (size_t I = Begin + 1; I < End; ++I) { log(" Removed " + Chunks[I]->getDebugName()); Chunks[Begin]->replace(Chunks[I]); } }); } // Entry point to ICF. void doICF(const std::vector &Chunks) { ICF().run(Chunks); } } // namespace coff } // namespace lld Index: vendor/lld/dist/COFF/PDB.cpp =================================================================== --- vendor/lld/dist/COFF/PDB.cpp (revision 317956) +++ vendor/lld/dist/COFF/PDB.cpp (revision 317957) @@ -1,230 +1,230 @@ //===- PDB.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "PDB.h" #include "Chunks.h" #include "Config.h" #include "Error.h" #include "SymbolTable.h" #include "Symbols.h" #include "llvm/DebugInfo/CodeView/CVDebugRecord.h" #include "llvm/DebugInfo/CodeView/CVTypeDumper.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" #include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" #include "llvm/Object/COFF.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/Endian.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" #include using namespace lld; using namespace lld::coff; using namespace llvm; using namespace llvm::codeview; using namespace llvm::support; using namespace llvm::support::endian; using llvm::object::coff_section; static ExitOnError ExitOnErr; // Returns a list of all SectionChunks. static std::vector getInputSections(SymbolTable *Symtab) { std::vector V; for (Chunk *C : Symtab->getChunks()) if (auto *SC = dyn_cast(C)) V.push_back(*SC->Header); return V; } static SectionChunk *findByName(std::vector &Sections, StringRef Name) { for (SectionChunk *C : Sections) if (C->getSectionName() == Name) return C; return nullptr; } static ArrayRef getDebugSection(ObjectFile *File, StringRef SecName) { SectionChunk *Sec = findByName(File->getDebugChunks(), SecName); if (!Sec) return {}; // First 4 bytes are section magic. ArrayRef Data = Sec->getContents(); if (Data.size() < 4) fatal(SecName + " too short"); if (read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC) fatal(SecName + " has an invalid magic"); return Data.slice(4); } static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder, codeview::TypeTableBuilder &TypeTable) { // Start the TPI or IPI stream header. TpiBuilder.setVersionHeader(pdb::PdbTpiV80); // Flatten the in memory type table. TypeTable.ForEachRecord([&](TypeIndex TI, ArrayRef Rec) { // FIXME: Hash types. TpiBuilder.addTypeRecord(Rec, None); }); } // Merge .debug$T sections into IpiData and TpiData. static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder, codeview::TypeTableBuilder &TypeTable, codeview::TypeTableBuilder &IDTable) { // Visit all .debug$T sections to add them to Builder. for (ObjectFile *File : Symtab->ObjectFiles) { ArrayRef Data = getDebugSection(File, ".debug$T"); if (Data.empty()) continue; BinaryByteStream Stream(Data, support::little); codeview::CVTypeArray Types; BinaryStreamReader Reader(Stream); // Follow type servers. If the same type server is encountered more than // once for this instance of `PDBTypeServerHandler` (for example if many // object files reference the same TypeServer), the types from the // TypeServer will only be visited once. pdb::PDBTypeServerHandler Handler; Handler.addSearchPath(llvm::sys::path::parent_path(File->getName())); if (auto EC = Reader.readArray(Types, Reader.getLength())) fatal(EC, "Reader::readArray failed"); if (auto Err = codeview::mergeTypeStreams(IDTable, TypeTable, &Handler, Types)) fatal(Err, "codeview::mergeTypeStreams failed"); } // Construct TPI stream contents. addTypeInfo(Builder.getTpiBuilder(), TypeTable); // Construct IPI stream contents. addTypeInfo(Builder.getIpiBuilder(), IDTable); } static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) { ListScope LS(W, "DebugT"); ArrayRef Data = getDebugSection(File, ".debug$T"); if (Data.empty()) return; - TypeDatabase TDB; + TypeDatabase TDB(0); TypeDumpVisitor TDV(TDB, &W, false); // Use a default implementation that does not follow type servers and instead // just dumps the contents of the TypeServer2 record. CVTypeDumper TypeDumper(TDB); if (auto EC = TypeDumper.dump(Data, TDV)) fatal(EC, "CVTypeDumper::dump failed"); } static void dumpDebugS(ScopedPrinter &W, ObjectFile *File) { ListScope LS(W, "DebugS"); ArrayRef Data = getDebugSection(File, ".debug$S"); if (Data.empty()) return; BinaryByteStream Stream(Data, llvm::support::little); CVSymbolArray Symbols; BinaryStreamReader Reader(Stream); if (auto EC = Reader.readArray(Symbols, Reader.getLength())) fatal(EC, "StreamReader.readArray failed"); - TypeDatabase TDB; + TypeDatabase TDB(0); CVSymbolDumper SymbolDumper(W, TDB, nullptr, false); if (auto EC = SymbolDumper.dump(Symbols)) fatal(EC, "CVSymbolDumper::dump failed"); } // Dump CodeView debug info. This is for debugging. static void dumpCodeView(SymbolTable *Symtab) { ScopedPrinter W(outs()); for (ObjectFile *File : Symtab->ObjectFiles) { dumpDebugT(W, File); dumpDebugS(W, File); } } // Creates a PDB file. void coff::createPDB(StringRef Path, SymbolTable *Symtab, ArrayRef SectionTable, const llvm::codeview::DebugInfo *DI) { if (Config->DumpPdb) dumpCodeView(Symtab); BumpPtrAllocator Alloc; pdb::PDBFileBuilder Builder(Alloc); ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize // Create streams in MSF for predefined streams, namely // PDB, TPI, DBI and IPI. for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I) ExitOnErr(Builder.getMsfBuilder().addStream(0)); // Add an Info stream. auto &InfoBuilder = Builder.getInfoBuilder(); InfoBuilder.setAge(DI ? DI->PDB70.Age : 0); pdb::PDB_UniqueId uuid{}; if (DI) memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid)); InfoBuilder.setGuid(uuid); // Should be the current time, but set 0 for reproducibilty. InfoBuilder.setSignature(0); InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70); // Add an empty DPI stream. auto &DbiBuilder = Builder.getDbiBuilder(); DbiBuilder.setVersionHeader(pdb::PdbDbiV110); codeview::TypeTableBuilder TypeTable(BAlloc); codeview::TypeTableBuilder IDTable(BAlloc); mergeDebugT(Symtab, Builder, TypeTable, IDTable); // Add Section Contributions. std::vector Contribs = pdb::DbiStreamBuilder::createSectionContribs(getInputSections(Symtab)); DbiBuilder.setSectionContribs(Contribs); // Add Section Map stream. ArrayRef Sections = { (const object::coff_section *)SectionTable.data(), SectionTable.size() / sizeof(object::coff_section)}; std::vector SectionMap = pdb::DbiStreamBuilder::createSectionMap(Sections); DbiBuilder.setSectionMap(SectionMap); ExitOnErr(DbiBuilder.addModuleInfo("* Linker *")); // Add COFF section header stream. ExitOnErr( DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable)); // Write to a file. ExitOnErr(Builder.commit(Path)); } Index: vendor/lld/dist/ELF/Config.h =================================================================== --- vendor/lld/dist/ELF/Config.h (revision 317956) +++ vendor/lld/dist/ELF/Config.h (revision 317957) @@ -1,229 +1,229 @@ //===- 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_ELF_CONFIG_H #define LLD_ELF_CONFIG_H #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/CachePruning.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" #include namespace lld { namespace elf { class InputFile; struct Symbol; enum ELFKind { ELFNoneKind, ELF32LEKind, ELF32BEKind, ELF64LEKind, ELF64BEKind }; // For --build-id. enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid }; // For --discard-{all,locals,none}. enum class DiscardPolicy { Default, All, Locals, None }; // For --strip-{all,debug}. enum class StripPolicy { None, All, Debug }; // For --unresolved-symbols. enum class UnresolvedPolicy { ReportError, Warn, WarnAll, Ignore, IgnoreAll }; // For --sort-section and linkerscript sorting rules. enum class SortSectionPolicy { Default, None, Alignment, Name, Priority }; // For --target2 enum class Target2Policy { Abs, Rel, GotRel }; struct SymbolVersion { llvm::StringRef Name; bool IsExternCpp; bool HasWildcard; }; // This struct contains symbols version definition that // can be found in version script if it is used for link. struct VersionDefinition { llvm::StringRef Name; uint16_t Id = 0; std::vector Globals; size_t NameOff = 0; // Offset in the string table }; // This struct contains the global configuration for the linker. // Most fields are direct mapping from the command line options // and such fields have the same name as the corresponding options. // Most fields are initialized by the driver. struct Configuration { InputFile *FirstElf = nullptr; + bool HasStaticTlsModel = false; uint8_t OSABI = 0; llvm::CachePruningPolicy ThinLTOCachePolicy; llvm::StringMap SectionStartMap; llvm::StringRef DynamicLinker; llvm::StringRef Entry; llvm::StringRef Emulation; llvm::StringRef Fini; llvm::StringRef Init; llvm::StringRef LTOAAPipeline; llvm::StringRef LTONewPmPasses; llvm::StringRef MapFile; llvm::StringRef OutputFile; llvm::StringRef OptRemarksFilename; llvm::StringRef SoName; llvm::StringRef Sysroot; llvm::StringRef ThinLTOCacheDir; std::string Rpath; std::vector VersionDefinitions; std::vector AuxiliaryList; std::vector SearchPaths; std::vector SymbolOrderingFile; std::vector Undefined; std::vector VersionScriptGlobals; std::vector VersionScriptLocals; std::vector BuildIdVector; bool AllowMultipleDefinition; - bool ArchiveWithoutSymbolsSeen = false; bool AsNeeded = false; bool Bsymbolic; bool BsymbolicFunctions; bool ColorDiagnostics = false; bool CompressDebugSections; bool DefineCommon; bool Demangle = true; bool DisableVerify; bool EhFrameHdr; bool EmitRelocs; bool EnableNewDtags; bool ExportDynamic; bool FatalWarnings; bool GcSections; bool GdbIndex; bool GnuHash; bool ICF; bool MipsN32Abi = false; bool NoGnuUnique; bool NoUndefinedVersion; bool Nostdlib; bool OFormatBinary; bool Omagic; bool OptRemarksWithHotness; bool Pie; bool PrintGcSections; bool Relocatable; bool SaveTemps; bool SingleRoRx; bool Shared; bool Static = false; bool SysvHash; bool Target1Rel; bool Threads; bool Trace; bool Verbose; bool WarnCommon; bool WarnMissingEntry; bool ZCombreloc; bool ZExecstack; bool ZNocopyreloc; bool ZNodelete; bool ZNodlopen; bool ZNow; bool ZOrigin; bool ZRelro; bool ZText; bool ExitEarly; bool ZWxneeded; DiscardPolicy Discard; SortSectionPolicy SortSection; StripPolicy Strip; UnresolvedPolicy UnresolvedSymbols; Target2Policy Target2; BuildIdKind BuildId = BuildIdKind::None; ELFKind EKind = ELFNoneKind; uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL; uint16_t EMachine = llvm::ELF::EM_NONE; uint64_t ErrorLimit = 20; uint64_t ImageBase; uint64_t MaxPageSize; uint64_t ZStackSize; unsigned LTOPartitions; unsigned LTOO; unsigned Optimize; unsigned ThinLTOJobs; // The following config options do not directly correspond to any // particualr command line options. // True if we need to pass through relocations in input files to the // output file. Usually false because we consume relocations. bool CopyRelocs; // True if the target is ELF64. False if ELF32. bool Is64; // True if the target is little-endian. False if big-endian. bool IsLE; // endianness::little if IsLE is true. endianness::big otherwise. llvm::support::endianness Endianness; // True if the target is the little-endian MIPS64. // // The reason why we have this variable only for the MIPS is because // we use this often. Some ELF headers for MIPS64EL are in a // mixed-endian (which is horrible and I'd say that's a serious spec // bug), and we need to know whether we are reading MIPS ELF files or // not in various places. // // (Note that MIPS64EL is not a typo for MIPS64LE. This is the official // name whatever that means. A fun hypothesis is that "EL" is short for // little-endian written in the little-endian order, but I don't know // if that's true.) bool IsMips64EL; // The ELF spec defines two types of relocation table entries, RELA and // REL. RELA is a triplet of (offset, info, addend) while REL is a // tuple of (offset, info). Addends for REL are implicit and read from // the location where the relocations are applied. So, REL is more // compact than RELA but requires a bit of more work to process. // // (From the linker writer's view, this distinction is not necessary. // If the ELF had chosen whichever and sticked with it, it would have // been easier to write code to process relocations, but it's too late // to change the spec.) // // Each ABI defines its relocation type. IsRela is true if target // uses RELA. As far as we know, all 64-bit ABIs are using RELA. A // few 32-bit ABIs are using RELA too. bool IsRela; // True if we are creating position-independent code. bool Pic; // 4 for ELF32, 8 for ELF64. int Wordsize; }; // The only instance of Configuration struct. extern Configuration *Config; } // namespace elf } // namespace lld #endif Index: vendor/lld/dist/ELF/Driver.cpp =================================================================== --- vendor/lld/dist/ELF/Driver.cpp (revision 317956) +++ vendor/lld/dist/ELF/Driver.cpp (revision 317957) @@ -1,999 +1,1015 @@ //===- Driver.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // The driver drives the entire linking process. It is responsible for // parsing command line options and doing whatever it is instructed to do. // // One notable thing in the LLD's driver when compared to other linkers is // that the LLD's driver is agnostic on the host operating system. // Other linkers usually have implicit default values (such as a dynamic // linker path or library paths) for each host OS. // // I don't think implicit default values are useful because they are // usually explicitly specified by the compiler driver. They can even // be harmful when you are doing cross-linking. Therefore, in LLD, we // simply trust the compiler driver to pass all required options and // don't try to make effort on our side. // //===----------------------------------------------------------------------===// #include "Driver.h" #include "Config.h" #include "Error.h" #include "Filesystem.h" #include "ICF.h" #include "InputFiles.h" #include "InputSection.h" #include "LinkerScript.h" #include "Memory.h" #include "OutputSections.h" #include "ScriptParser.h" #include "Strings.h" #include "SymbolTable.h" #include "Target.h" #include "Threads.h" #include "Writer.h" #include "lld/Config/Version.h" #include "lld/Driver/Driver.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Object/Decompressor.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" #include #include using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::sys; using namespace lld; using namespace lld::elf; Configuration *elf::Config; LinkerDriver *elf::Driver; BumpPtrAllocator elf::BAlloc; StringSaver elf::Saver{BAlloc}; std::vector elf::SpecificAllocBase::Instances; static void setConfigs(); bool elf::link(ArrayRef Args, bool CanExitEarly, raw_ostream &Error) { ErrorCount = 0; ErrorOS = &Error; Argv0 = Args[0]; InputSections.clear(); Tar = nullptr; Config = make(); Driver = make(); Script = make(); Driver->main(Args, CanExitEarly); freeArena(); return !ErrorCount; } // Parses a linker -m option. static std::tuple parseEmulation(StringRef Emul) { uint8_t OSABI = 0; StringRef S = Emul; if (S.endswith("_fbsd")) { S = S.drop_back(5); OSABI = ELFOSABI_FREEBSD; } std::pair Ret = StringSwitch>(S) .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64}) .Case("armelf_linux_eabi", {ELF32LEKind, EM_ARM}) .Case("elf32_x86_64", {ELF32LEKind, EM_X86_64}) .Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS}) .Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS}) .Case("elf32ppc", {ELF32BEKind, EM_PPC}) .Case("elf64btsmip", {ELF64BEKind, EM_MIPS}) .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS}) .Case("elf64ppc", {ELF64BEKind, EM_PPC64}) .Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64}) .Case("elf_i386", {ELF32LEKind, EM_386}) .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU}) .Default({ELFNoneKind, EM_NONE}); if (Ret.first == ELFNoneKind) { if (S == "i386pe" || S == "i386pep" || S == "thumb2pe") error("Windows targets are not supported on the ELF frontend: " + Emul); else error("unknown emulation: " + Emul); } return std::make_tuple(Ret.first, Ret.second, OSABI); } // Returns slices of MB by parsing MB as an archive file. // Each slice consists of a member file in the archive. -std::vector -static getArchiveMembers(MemoryBufferRef MB) { +std::vector> static getArchiveMembers( + MemoryBufferRef MB) { std::unique_ptr File = check(Archive::create(MB), MB.getBufferIdentifier() + ": failed to parse archive"); - std::vector V; + std::vector> V; Error Err = Error::success(); for (const ErrorOr &COrErr : File->children(Err)) { Archive::Child C = check(COrErr, MB.getBufferIdentifier() + ": could not get the child of the archive"); MemoryBufferRef MBRef = check(C.getMemoryBufferRef(), MB.getBufferIdentifier() + ": could not get the buffer for a child of the archive"); - V.push_back(MBRef); + V.push_back(std::make_pair(MBRef, C.getChildOffset())); } if (Err) fatal(MB.getBufferIdentifier() + ": Archive::children failed: " + toString(std::move(Err))); // Take ownership of memory buffers created for members of thin archives. for (std::unique_ptr &MB : File->takeThinBuffers()) make>(std::move(MB)); return V; } -// Opens and parses a file. Path has to be resolved already. -// Newly created memory buffers are owned by this driver. +// Opens a file and create a file object. Path has to be resolved already. void LinkerDriver::addFile(StringRef Path, bool WithLOption) { using namespace sys::fs; Optional Buffer = readFile(Path); if (!Buffer.hasValue()) return; MemoryBufferRef MBRef = *Buffer; if (InBinary) { Files.push_back(make(MBRef)); return; } switch (identify_magic(MBRef.getBuffer())) { case file_magic::unknown: readLinkerScript(MBRef); return; - case file_magic::archive: + case file_magic::archive: { + // Handle -whole-archive. if (InWholeArchive) { - for (MemoryBufferRef MB : getArchiveMembers(MBRef)) - Files.push_back(createObjectFile(MB, Path)); + for (const auto &P : getArchiveMembers(MBRef)) + Files.push_back(createObjectFile(P.first, Path, P.second)); return; } - Files.push_back(make(MBRef)); + + std::unique_ptr File = + check(Archive::create(MBRef), Path + ": failed to parse archive"); + + // If an archive file has no symbol table, it is likely that a user + // is attempting LTO and using a default ar command that doesn't + // understand the LLVM bitcode file. It is a pretty common error, so + // we'll handle it as if it had a symbol table. + if (!File->hasSymbolTable()) { + for (const auto &P : getArchiveMembers(MBRef)) + Files.push_back(make(P.first, Path, P.second)); + return; + } + + // Handle the regular case. + Files.push_back(make(std::move(File))); return; + } case file_magic::elf_shared_object: if (Config->Relocatable) { error("attempted static link of dynamic object " + Path); return; } // DSOs usually have DT_SONAME tags in their ELF headers, and the // sonames are used to identify DSOs. But if they are missing, // they are identified by filenames. We don't know whether the new // file has a DT_SONAME or not because we haven't parsed it yet. // Here, we set the default soname for the file because we might // need it later. // // If a file was specified by -lfoo, the directory part is not // significant, as a user did not specify it. This behavior is // compatible with GNU. Files.push_back(createSharedFile( MBRef, WithLOption ? sys::path::filename(Path) : Path)); return; default: if (InLib) - Files.push_back(make(MBRef)); + Files.push_back(make(MBRef, "", 0)); else Files.push_back(createObjectFile(MBRef)); } } // Add a given library by searching it from input search paths. void LinkerDriver::addLibrary(StringRef Name) { if (Optional Path = searchLibrary(Name)) addFile(*Path, /*WithLOption=*/true); else error("unable to find library -l" + Name); } // This function is called on startup. We need this for LTO since // LTO calls LLVM functions to compile bitcode files to native code. // Technically this can be delayed until we read bitcode files, but // we don't bother to do lazily because the initialization is fast. static void initLLVM(opt::InputArgList &Args) { InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmPrinters(); InitializeAllAsmParsers(); // Parse and evaluate -mllvm options. std::vector V; V.push_back("lld (LLVM option parsing)"); for (auto *Arg : Args.filtered(OPT_mllvm)) V.push_back(Arg->getValue()); cl::ParseCommandLineOptions(V.size(), V.data()); } // Some command line options or some combinations of them are not allowed. // This function checks for such errors. static void checkOptions(opt::InputArgList &Args) { // 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->Pie && Config->Shared) error("-shared and -pie may not be used together"); if (!Config->Shared && !Config->AuxiliaryList.empty()) error("-f may not be used without -shared"); if (Config->Relocatable) { if (Config->Shared) error("-r and -shared may not be used together"); if (Config->GcSections) error("-r and --gc-sections may not be used together"); if (Config->ICF) error("-r and --icf may not be used together"); if (Config->Pie) error("-r and -pie may not be used together"); } } static StringRef getString(opt::InputArgList &Args, unsigned Key, StringRef Default = "") { if (auto *Arg = Args.getLastArg(Key)) return Arg->getValue(); return Default; } static int getInteger(opt::InputArgList &Args, unsigned Key, int Default) { int V = Default; if (auto *Arg = Args.getLastArg(Key)) { StringRef S = Arg->getValue(); if (S.getAsInteger(10, V)) error(Arg->getSpelling() + ": number expected, but got " + S); } return V; } static const char *getReproduceOption(opt::InputArgList &Args) { if (auto *Arg = Args.getLastArg(OPT_reproduce)) return Arg->getValue(); return getenv("LLD_REPRODUCE"); } static bool hasZOption(opt::InputArgList &Args, StringRef Key) { for (auto *Arg : Args.filtered(OPT_z)) if (Key == Arg->getValue()) return true; return false; } static uint64_t getZOptionValue(opt::InputArgList &Args, StringRef Key, uint64_t Default) { for (auto *Arg : Args.filtered(OPT_z)) { StringRef Value = Arg->getValue(); size_t Pos = Value.find("="); if (Pos != StringRef::npos && Key == Value.substr(0, Pos)) { Value = Value.substr(Pos + 1); uint64_t Result; if (Value.getAsInteger(0, Result)) error("invalid " + Key + ": " + Value); return Result; } } return Default; } void LinkerDriver::main(ArrayRef ArgsArr, bool CanExitEarly) { ELFOptTable Parser; opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); // Interpret this flag early because error() depends on them. Config->ErrorLimit = getInteger(Args, OPT_error_limit, 20); // Handle -help if (Args.hasArg(OPT_help)) { printHelp(ArgsArr[0]); return; } // Handle -v or -version. // // A note about "compatible with GNU linkers" message: this is a hack for // scripts generated by GNU Libtool 2.4.6 (released in February 2014 and // still the newest version in March 2017) or earlier to recognize LLD as // a GNU compatible linker. As long as an output for the -v option // contains "GNU" or "with BFD", they recognize us as GNU-compatible. // // This is somewhat ugly hack, but in reality, we had no choice other // than doing this. Considering the very long release cycle of Libtool, // it is not easy to improve it to recognize LLD as a GNU compatible // linker in a timely manner. Even if we can make it, there are still a // lot of "configure" scripts out there that are generated by old version // of Libtool. We cannot convince every software developer to migrate to // the latest version and re-generate scripts. So we have this hack. if (Args.hasArg(OPT_v) || Args.hasArg(OPT_version)) message(getLLDVersion() + " (compatible with GNU linkers)"); // ld.bfd always exits after printing out the version string. // ld.gold proceeds if a given option is -v. Because gold's behavior // is more permissive than ld.bfd, we chose what gold does here. if (Args.hasArg(OPT_version)) return; Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown); if (const char *Path = getReproduceOption(Args)) { // Note that --reproduce is a debug option so you can ignore it // if you are trying to understand the whole picture of the code. Expected> ErrOrWriter = TarWriter::create(Path, path::stem(Path)); if (ErrOrWriter) { Tar = ErrOrWriter->get(); Tar->append("response.txt", createResponseFile(Args)); Tar->append("version.txt", getLLDVersion() + "\n"); make>(std::move(*ErrOrWriter)); } else { error(Twine("--reproduce: failed to open ") + Path + ": " + toString(ErrOrWriter.takeError())); } } readConfigs(Args); initLLVM(Args); createFiles(Args); inferMachineType(); setConfigs(); checkOptions(Args); if (ErrorCount) return; switch (Config->EKind) { case ELF32LEKind: link(Args); return; case ELF32BEKind: link(Args); return; case ELF64LEKind: link(Args); return; case ELF64BEKind: link(Args); return; default: llvm_unreachable("unknown Config->EKind"); } } static bool getArg(opt::InputArgList &Args, unsigned K1, unsigned K2, bool Default) { if (auto *Arg = Args.getLastArg(K1, K2)) return Arg->getOption().getID() == K1; return Default; } static std::vector getArgs(opt::InputArgList &Args, int Id) { std::vector V; for (auto *Arg : Args.filtered(Id)) V.push_back(Arg->getValue()); return V; } static std::string getRpath(opt::InputArgList &Args) { std::vector V = getArgs(Args, OPT_rpath); return llvm::join(V.begin(), V.end(), ":"); } // Determines what we should do if there are remaining unresolved // symbols after the name resolution. static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) { // -noinhibit-exec or -r imply some default values. if (Args.hasArg(OPT_noinhibit_exec)) return UnresolvedPolicy::WarnAll; if (Args.hasArg(OPT_relocatable)) return UnresolvedPolicy::IgnoreAll; UnresolvedPolicy ErrorOrWarn = getArg(Args, OPT_error_unresolved_symbols, OPT_warn_unresolved_symbols, true) ? UnresolvedPolicy::ReportError : UnresolvedPolicy::Warn; // Process the last of -unresolved-symbols, -no-undefined or -z defs. for (auto *Arg : llvm::reverse(Args)) { switch (Arg->getOption().getID()) { case OPT_unresolved_symbols: { StringRef S = Arg->getValue(); if (S == "ignore-all" || S == "ignore-in-object-files") return UnresolvedPolicy::Ignore; if (S == "ignore-in-shared-libs" || S == "report-all") return ErrorOrWarn; error("unknown --unresolved-symbols value: " + S); continue; } case OPT_no_undefined: return ErrorOrWarn; case OPT_z: if (StringRef(Arg->getValue()) == "defs") return ErrorOrWarn; continue; } } // -shared implies -unresolved-symbols=ignore-all because missing // symbols are likely to be resolved at runtime using other DSOs. if (Config->Shared) return UnresolvedPolicy::Ignore; return ErrorOrWarn; } static Target2Policy getTarget2(opt::InputArgList &Args) { StringRef S = getString(Args, OPT_target2, "got-rel"); if (S == "rel") return Target2Policy::Rel; if (S == "abs") return Target2Policy::Abs; if (S == "got-rel") return Target2Policy::GotRel; error("unknown --target2 option: " + S); return Target2Policy::GotRel; } static bool isOutputFormatBinary(opt::InputArgList &Args) { if (auto *Arg = Args.getLastArg(OPT_oformat)) { StringRef S = Arg->getValue(); if (S == "binary") return true; error("unknown --oformat value: " + S); } return false; } static DiscardPolicy getDiscard(opt::InputArgList &Args) { if (Args.hasArg(OPT_relocatable)) return DiscardPolicy::None; auto *Arg = Args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none); if (!Arg) return DiscardPolicy::Default; if (Arg->getOption().getID() == OPT_discard_all) return DiscardPolicy::All; if (Arg->getOption().getID() == OPT_discard_locals) return DiscardPolicy::Locals; return DiscardPolicy::None; } static StringRef getDynamicLinker(opt::InputArgList &Args) { auto *Arg = Args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker); if (!Arg || Arg->getOption().getID() == OPT_no_dynamic_linker) return ""; return Arg->getValue(); } static StripPolicy getStrip(opt::InputArgList &Args) { if (Args.hasArg(OPT_relocatable)) return StripPolicy::None; auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug); if (!Arg) return StripPolicy::None; if (Arg->getOption().getID() == OPT_strip_all) return StripPolicy::All; return StripPolicy::Debug; } static uint64_t parseSectionAddress(StringRef S, opt::Arg *Arg) { uint64_t VA = 0; if (S.startswith("0x")) S = S.drop_front(2); if (S.getAsInteger(16, VA)) error("invalid argument: " + toString(Arg)); return VA; } static StringMap getSectionStartMap(opt::InputArgList &Args) { StringMap Ret; for (auto *Arg : Args.filtered(OPT_section_start)) { StringRef Name; StringRef Addr; std::tie(Name, Addr) = StringRef(Arg->getValue()).split('='); Ret[Name] = parseSectionAddress(Addr, Arg); } if (auto *Arg = Args.getLastArg(OPT_Ttext)) Ret[".text"] = parseSectionAddress(Arg->getValue(), Arg); if (auto *Arg = Args.getLastArg(OPT_Tdata)) Ret[".data"] = parseSectionAddress(Arg->getValue(), Arg); if (auto *Arg = Args.getLastArg(OPT_Tbss)) Ret[".bss"] = parseSectionAddress(Arg->getValue(), Arg); return Ret; } static SortSectionPolicy getSortSection(opt::InputArgList &Args) { StringRef S = getString(Args, OPT_sort_section); if (S == "alignment") return SortSectionPolicy::Alignment; if (S == "name") return SortSectionPolicy::Name; if (!S.empty()) error("unknown --sort-section rule: " + S); return SortSectionPolicy::Default; } static std::pair getHashStyle(opt::InputArgList &Args) { StringRef S = getString(Args, OPT_hash_style, "sysv"); if (S == "sysv") return {true, false}; if (S == "gnu") return {false, true}; if (S != "both") error("unknown -hash-style: " + S); return {true, true}; } // Parse --build-id or --build-id=