Index: projects/clang700-import/contrib/llvm/tools/lld/CMakeLists.txt =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/CMakeLists.txt (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/CMakeLists.txt (revision 336982) Property changes on: projects/clang700-import/contrib/llvm/tools/lld/CMakeLists.txt ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/CODE_OWNERS.TXT =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/CODE_OWNERS.TXT (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/CODE_OWNERS.TXT (revision 336982) Property changes on: projects/clang700-import/contrib/llvm/tools/lld/CODE_OWNERS.TXT ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/Strings.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/Strings.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/Strings.cpp (nonexistent) @@ -1,35 +0,0 @@ -//===- Strings.cpp -------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Strings.h" -#include - -#if defined(_MSC_VER) -#include -#include -#pragma comment(lib, "dbghelp.lib") -#endif - -using namespace lld; -using namespace lld::coff; -using namespace llvm; - -Optional coff::demangleMSVC(StringRef S) { -#if defined(_MSC_VER) - // UnDecorateSymbolName is not thread-safe, so we need a mutex. - static std::mutex Mu; - std::lock_guard Lock(Mu); - - char Buf[4096]; - if (S.startswith("?")) - if (size_t Len = UnDecorateSymbolName(S.str().c_str(), Buf, sizeof(Buf), 0)) - return std::string(Buf, Len); -#endif - return None; -} Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/Strings.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/Strings.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/Strings.h (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/Strings.h (nonexistent) @@ -1,23 +0,0 @@ -//===- Strings.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_STRINGS_H -#define LLD_COFF_STRINGS_H - -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringRef.h" -#include - -namespace lld { -namespace coff { -llvm::Optional demangleMSVC(llvm::StringRef S); -} -} - -#endif Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/Strings.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/CMakeLists.txt =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/CMakeLists.txt (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/CMakeLists.txt (revision 336982) @@ -1,48 +1,47 @@ set(LLVM_TARGET_DEFINITIONS Options.td) tablegen(LLVM Options.inc -gen-opt-parser-defs) add_public_tablegen_target(COFFOptionsTableGen) if(NOT LLD_BUILT_STANDALONE) set(tablegen_deps intrinsics_gen) endif() add_lld_library(lldCOFF Chunks.cpp DLL.cpp Driver.cpp DriverUtils.cpp ICF.cpp InputFiles.cpp LTO.cpp MapFile.cpp MarkLive.cpp MinGW.cpp PDB.cpp - Strings.cpp SymbolTable.cpp Symbols.cpp Writer.cpp LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} BinaryFormat Core DebugInfoCodeView DebugInfoMSF DebugInfoPDB LibDriver LTO MC Object Option Support WindowsManifest LINK_LIBS lldCommon ${LLVM_PTHREAD_LIB} DEPENDS COFFOptionsTableGen ${tablegen_deps} ) Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/CMakeLists.txt ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/Chunks.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/Chunks.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/Chunks.cpp (revision 336982) @@ -1,535 +1,644 @@ //===- 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 "InputFiles.h" #include "Symbols.h" #include "Writer.h" #include "lld/Common/ErrorHandler.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/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(ObjFile *F, const coff_section *H) : Chunk(SectionKind), Repl(this), Header(H), File(F), - Relocs(File->getCOFFObj()->getRelocations(Header)), - NumRelocs(std::distance(Relocs.begin(), Relocs.end())) { + Relocs(File->getCOFFObj()->getRelocations(Header)) { // Initialize SectionName. File->getCOFFObj()->getSectionName(Header, SectionName); Alignment = Header->getAlignment(); // If linker GC is disabled, every chunk starts out alive. If linker GC is // enabled, treat non-comdat sections as roots. Generally optimized object // files will be built with -ffunction-sections or /Gy, so most things worth // stripping will be in a comdat. Live = !Config->DoGC || !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); } static void or32(uint8_t *P, uint32_t V) { write32le(P, read32le(P) | V); } +// Verify that given sections are appropriate targets for SECREL +// relocations. This check is relaxed because unfortunately debug +// sections have section-relative relocations against absolute symbols. +static bool checkSecRel(const SectionChunk *Sec, OutputSection *OS) { + if (OS) + return true; + if (Sec->isCodeView()) + return false; + fatal("SECREL relocation cannot be applied to absolute symbols"); +} + static void applySecRel(const SectionChunk *Sec, uint8_t *Off, OutputSection *OS, uint64_t S) { - if (!OS) { - if (Sec->isCodeView()) - return; - fatal("SECREL relocation cannot be applied to absolute symbols"); - } + if (!checkSecRel(Sec, OS)) + return; uint64_t SecRel = S - OS->getRVA(); if (SecRel > UINT32_MAX) { error("overflow in SECREL relocation in section: " + Sec->getSectionName()); return; } add32(Off, SecRel); } static void applySecIdx(uint8_t *Off, OutputSection *OS) { - // If we have no output section, this must be an absolute symbol. Use the - // sentinel absolute symbol section index. - uint16_t SecIdx = OS ? OS->SectionIndex : DefinedAbsolute::OutputSectionIndex; - add16(Off, SecIdx); + // Absolute symbol doesn't have section index, but section index relocation + // against absolute symbol should be resolved to one plus the last output + // section index. This is required for compatibility with MSVC. + if (OS) + add16(Off, OS->SectionIndex); + else + add16(Off, DefinedAbsolute::NumOutputSections + 1); } void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, uint64_t P) const { 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: applySecIdx(Off, OS); break; case IMAGE_REL_AMD64_SECREL: applySecRel(this, Off, OS, S); break; default: - fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); + fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + + toString(File)); } } void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, uint64_t P) const { 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: applySecIdx(Off, OS); break; case IMAGE_REL_I386_SECREL: applySecRel(this, Off, OS, S); break; default: - fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); + fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + + toString(File)); } } static void applyMOV(uint8_t *Off, uint16_t V) { write16le(Off, (read16le(Off) & 0xfbf0) | ((V & 0x800) >> 1) | ((V >> 12) & 0xf)); write16le(Off + 2, (read16le(Off + 2) & 0x8f00) | ((V & 0x700) << 4) | (V & 0xff)); } static uint16_t readMOV(uint8_t *Off) { - uint16_t Opcode1 = read16le(Off); - uint16_t Opcode2 = read16le(Off + 2); - uint16_t Imm = (Opcode2 & 0x00ff) | ((Opcode2 >> 4) & 0x0700); - Imm |= ((Opcode1 << 1) & 0x0800) | ((Opcode1 & 0x000f) << 12); - return Imm; + uint16_t Op1 = read16le(Off); + uint16_t Op2 = read16le(Off + 2); + return (Op2 & 0x00ff) | ((Op2 >> 4) & 0x0700) | ((Op1 << 1) & 0x0800) | + ((Op1 & 0x000f) << 12); } void applyMOV32T(uint8_t *Off, uint32_t V) { uint16_t ImmW = readMOV(Off); // read MOVW operand uint16_t ImmT = readMOV(Off + 4); // read MOVT operand uint32_t Imm = ImmW | (ImmT << 16); V += Imm; // add the immediate offset applyMOV(Off, V); // set MOVW operand applyMOV(Off + 4, V >> 16); // set MOVT operand } static void applyBranch20T(uint8_t *Off, int32_t V) { if (!isInt<21>(V)) fatal("relocation out of range"); 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)); } void applyBranch24T(uint8_t *Off, int32_t V) { if (!isInt<25>(V)) fatal("relocation out of range"); 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)); // Clear out the J1 and J2 bits which may be set. write16le(Off + 2, (read16le(Off + 2) & 0xd000) | (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); } void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, uint64_t P) const { // Pointer to thumb code must have the LSB set. uint64_t SX = S; - if (OS && (OS->getPermissions() & IMAGE_SCN_MEM_EXECUTE)) + if (OS && (OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)) SX |= 1; switch (Type) { case IMAGE_REL_ARM_ADDR32: add32(Off, SX + Config->ImageBase); break; case IMAGE_REL_ARM_ADDR32NB: add32(Off, SX); break; case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, SX + Config->ImageBase); break; case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, SX - P - 4); break; case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, SX - P - 4); break; case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, SX - P - 4); break; case IMAGE_REL_ARM_SECTION: applySecIdx(Off, OS); break; case IMAGE_REL_ARM_SECREL: applySecRel(this, Off, OS, S); break; default: - fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); + fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + + toString(File)); } } // Interpret the existing immediate value as a byte offset to the // target symbol, then update the instruction with the immediate as // the page offset from the current instruction to the target. -static void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P) { +static void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift) { uint32_t Orig = read32le(Off); uint64_t Imm = ((Orig >> 29) & 0x3) | ((Orig >> 3) & 0x1FFFFC); S += Imm; - Imm = (S >> 12) - (P >> 12); + Imm = (S >> Shift) - (P >> Shift); uint32_t ImmLo = (Imm & 0x3) << 29; uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); write32le(Off, (Orig & ~Mask) | ImmLo | ImmHi); } // Update the immediate field in a AARCH64 ldr, str, and add instruction. // Optionally limit the range of the written immediate by one or more bits // (RangeLimit). static void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit) { uint32_t Orig = read32le(Off); Imm += (Orig >> 10) & 0xFFF; Orig &= ~(0xFFF << 10); write32le(Off, Orig | ((Imm & (0xFFF >> RangeLimit)) << 10)); } // Add the 12 bit page offset to the existing immediate. // Ldr/str instructions store the opcode immediate scaled // by the load/store size (giving a larger range for larger // loads/stores). The immediate is always (both before and after // fixing up the relocation) stored scaled similarly. // Even if larger loads/stores have a larger range, limit the // effective offset to 12 bit, since it is intended to be a // page offset. static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) { uint32_t Orig = read32le(Off); uint32_t Size = Orig >> 30; // 0x04000000 indicates SIMD/FP registers // 0x00800000 indicates 128 bit if ((Orig & 0x4800000) == 0x4800000) Size += 4; if ((Imm & ((1 << Size) - 1)) != 0) fatal("misaligned ldr/str offset"); applyArm64Imm(Off, Imm >> Size, Size); } +static void applySecRelLow12A(const SectionChunk *Sec, uint8_t *Off, + OutputSection *OS, uint64_t S) { + if (checkSecRel(Sec, OS)) + applyArm64Imm(Off, (S - OS->getRVA()) & 0xfff, 0); +} + +static void applySecRelHigh12A(const SectionChunk *Sec, uint8_t *Off, + OutputSection *OS, uint64_t S) { + if (!checkSecRel(Sec, OS)) + return; + uint64_t SecRel = (S - OS->getRVA()) >> 12; + if (0xfff < SecRel) { + error("overflow in SECREL_HIGH12A relocation in section: " + + Sec->getSectionName()); + return; + } + applyArm64Imm(Off, SecRel & 0xfff, 0); +} + +static void applySecRelLdr(const SectionChunk *Sec, uint8_t *Off, + OutputSection *OS, uint64_t S) { + if (checkSecRel(Sec, OS)) + applyArm64Ldr(Off, (S - OS->getRVA()) & 0xfff); +} + +static void applyArm64Branch26(uint8_t *Off, int64_t V) { + if (!isInt<28>(V)) + fatal("relocation out of range"); + or32(Off, (V & 0x0FFFFFFC) >> 2); +} + +static void applyArm64Branch19(uint8_t *Off, int64_t V) { + if (!isInt<21>(V)) + fatal("relocation out of range"); + or32(Off, (V & 0x001FFFFC) << 3); +} + +static void applyArm64Branch14(uint8_t *Off, int64_t V) { + if (!isInt<16>(V)) + fatal("relocation out of range"); + or32(Off, (V & 0x0000FFFC) << 3); +} + void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, uint64_t P) const { switch (Type) { - case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P); break; + case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P, 12); break; + case IMAGE_REL_ARM64_REL21: applyArm64Addr(Off, S, P, 0); break; case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff, 0); break; case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break; - case IMAGE_REL_ARM64_BRANCH26: or32(Off, ((S - P) & 0x0FFFFFFC) >> 2); break; + case IMAGE_REL_ARM64_BRANCH26: applyArm64Branch26(Off, S - P); break; + case IMAGE_REL_ARM64_BRANCH19: applyArm64Branch19(Off, S - P); break; + case IMAGE_REL_ARM64_BRANCH14: applyArm64Branch14(Off, S - P); break; case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break; case IMAGE_REL_ARM64_ADDR32NB: add32(Off, S); break; case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break; case IMAGE_REL_ARM64_SECREL: applySecRel(this, Off, OS, S); break; + case IMAGE_REL_ARM64_SECREL_LOW12A: applySecRelLow12A(this, Off, OS, S); break; + case IMAGE_REL_ARM64_SECREL_HIGH12A: applySecRelHigh12A(this, Off, OS, S); break; + case IMAGE_REL_ARM64_SECREL_LOW12L: applySecRelLdr(this, Off, OS, S); break; + case IMAGE_REL_ARM64_SECTION: applySecIdx(Off, OS); break; default: - fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); + fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + + toString(File)); } } 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()); + if (!A.empty()) + memcpy(Buf + OutputSectionOff, A.data(), A.size()); // Apply relocations. size_t InputSize = getSize(); for (const coff_relocation &Rel : Relocs) { // Check for an invalid relocation offset. This check isn't perfect, because // we don't have the relocation size, which is only known after checking the // machine and relocation type. As a result, a relocation may overwrite the // beginning of the following input section. if (Rel.VirtualAddress >= InputSize) fatal("relocation points beyond the end of its parent section"); uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress; // Get the output section of the symbol for this relocation. The output // section is needed to compute SECREL and SECTION relocations used in debug // info. auto *Sym = dyn_cast_or_null(File->getSymbol(Rel.SymbolTableIndex)); if (!Sym) { if (isCodeView() || isDWARF()) continue; // Symbols in early discarded sections are represented using null pointers, // so we need to retrieve the name from the object file. COFFSymbolRef Sym = check(File->getCOFFObj()->getSymbol(Rel.SymbolTableIndex)); StringRef Name; File->getCOFFObj()->getSymbolName(Sym, Name); fatal("relocation against symbol in discarded section: " + Name); } Chunk *C = Sym->getChunk(); OutputSection *OS = C ? C->getOutputSection() : nullptr; // Only absolute and __ImageBase symbols lack an output section. For any // other symbol, this indicates that the chunk was discarded. Normally // relocations against discarded sections are an error. However, debug info // sections are not GC roots and can end up with these kinds of relocations. // Skip these relocations. if (!OS && !isa(Sym) && !isa(Sym)) { if (isCodeView() || isDWARF()) continue; fatal("relocation against symbol in discarded section: " + Sym->getName()); } uint64_t S = Sym->getRVA(); // Compute the RVA of the relocation for relative relocations. uint64_t P = RVA + Rel.VirtualAddress; switch (Config->Machine) { case AMD64: applyRelX64(Off, Rel.Type, OS, S, P); break; case I386: applyRelX86(Off, Rel.Type, OS, S, P); break; case ARMNT: applyRelARM(Off, Rel.Type, OS, S, P); break; case ARM64: applyRelARM64(Off, Rel.Type, OS, S, 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; case ARM64: if (Rel.Type == IMAGE_REL_ARM64_ADDR64) return IMAGE_REL_BASED_DIR64; 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; Symbol *Target = File->getSymbol(Rel.SymbolTableIndex); if (!Target || isa(Target)) 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; +uint32_t SectionChunk::getOutputCharacteristics() const { + return Header->Characteristics & (PermMask | TypeMask); } 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) message("Discarded " + Sym->getName()); } 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) { + Alignment = std::max(Alignment, Other->Alignment); 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. Alignment = std::min(uint64_t(32), PowerOf2Ceil(Sym.getValue())); } -uint32_t CommonChunk::getPermissions() const { +uint32_t CommonChunk::getOutputCharacteristics() 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. Alignment = 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 ImportThunkChunkARM64::writeTo(uint8_t *Buf) const { int64_t Off = ImpSymbol->getRVA() & 0xfff; memcpy(Buf + OutputSectionOff, ImportThunkARM64, sizeof(ImportThunkARM64)); - applyArm64Addr(Buf + OutputSectionOff, ImpSymbol->getRVA(), RVA); + applyArm64Addr(Buf + OutputSectionOff, ImpSymbol->getRVA(), RVA, 12); applyArm64Ldr(Buf + OutputSectionOff + 4, Off); } 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 { +void RVATableChunk::writeTo(uint8_t *Buf) const { ulittle32_t *Begin = reinterpret_cast(Buf + OutputSectionOff); size_t Cnt = 0; - for (Defined *D : Syms) - Begin[Cnt++] = D->getRVA(); + for (const ChunkAndOffset &CO : Syms) + Begin[Cnt++] = CO.InputChunk->getRVA() + CO.Offset; std::sort(Begin, Begin + Cnt); + assert(std::unique(Begin, Begin + Cnt) == Begin + Cnt && + "RVA tables should be de-duplicated"); } // Windows-specific. This class represents a block in .reloc section. // The format is described here. // // On Windows, each DLL is linked against a fixed base address and // usually loaded to that address. However, if there's already another // DLL that overlaps, the loader has to relocate it. To do that, DLLs // contain .reloc sections which contain offsets that need to be fixed // up at runtime. If the loader finds that a DLL cannot be loaded to its // desired base address, it loads it to somewhere else, and add - to each offset that is // specified by the .reloc section. In ELF terms, .reloc sections // contain relative relocations in REL format (as opposed to RELA.) // // This already significantly reduces the size of relocations compared // to ELF .rel.dyn, but Windows does more to reduce it (probably because // it was invented for PCs in the late '80s or early '90s.) Offsets in // .reloc are grouped by page where the page size is 12 bits, and // offsets sharing the same page address are stored consecutively to // represent them with less space. This is very similar to the page // table which is grouped by (multiple stages of) pages. // // For example, let's say we have 0x00030, 0x00500, 0x00700, 0x00A00, // 0x20004, and 0x20008 in a .reloc section for x64. The uppermost 4 // bits have a type IMAGE_REL_BASED_DIR64 or 0xA. In the section, they // are represented like this: // // 0x00000 -- page address (4 bytes) // 16 -- size of this block (4 bytes) // 0xA030 -- entries (2 bytes each) // 0xA500 // 0xA700 // 0xAA00 // 0x20000 -- page address (4 bytes) // 12 -- size of this block (4 bytes) // 0xA004 -- entries (2 bytes each) // 0xA008 // // Usually we have a lot of relocations for each page, so the number of // bytes for one .reloc entry is close to 2 bytes on average. 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(alignTo((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: case ARM64: return IMAGE_REL_BASED_DIR64; case I386: case ARMNT: return IMAGE_REL_BASED_HIGHLOW; default: llvm_unreachable("unknown machine type"); } +} + +std::map MergeChunk::Instances; + +MergeChunk::MergeChunk(uint32_t Alignment) + : Builder(StringTableBuilder::RAW, Alignment) { + this->Alignment = Alignment; +} + +void MergeChunk::addSection(SectionChunk *C) { + auto *&MC = Instances[C->Alignment]; + if (!MC) + MC = make(C->Alignment); + MC->Sections.push_back(C); +} + +void MergeChunk::finalizeContents() { + for (SectionChunk *C : Sections) + if (C->isLive()) + Builder.add(toStringRef(C->getContents())); + Builder.finalize(); + + for (SectionChunk *C : Sections) { + if (!C->isLive()) + continue; + size_t Off = Builder.getOffset(toStringRef(C->getContents())); + C->setOutputSection(Out); + C->setRVA(RVA + Off); + C->OutputSectionOff = OutputSectionOff + Off; + } +} + +uint32_t MergeChunk::getOutputCharacteristics() const { + return IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA; +} + +size_t MergeChunk::getSize() const { + return Builder.getSize(); +} + +void MergeChunk::writeTo(uint8_t *Buf) const { + Builder.write(Buf + OutputSectionOff); } } // namespace coff } // namespace lld Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/Chunks.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/Chunks.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/Chunks.h (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/Chunks.h (revision 336982) @@ -1,365 +1,429 @@ //===- 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/Common/LLVM.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/MC/StringTableBuilder.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 ObjFile; class OutputSection; class Symbol; -// Mask for section types (code, data, bss, disacardable, etc.) -// and permissions (writable, readable or executable). -const uint32_t PermMask = 0xFF0000F0; +// Mask for permissions (discardable, writable, readable, executable, etc). +const uint32_t PermMask = 0xFE000000; +// Mask for section types (code, data, bss). +const uint32_t TypeMask = 0x000000E0; + // 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 {} + // Called by the writer after an RVA is assigned, but before calling + // getSize(). + virtual void finalizeContents() {} + // The writer sets and uses the addresses. uint64_t getRVA() const { return RVA; } void setRVA(uint64_t V) { RVA = 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; } + virtual uint32_t getOutputCharacteristics() 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() const { 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 ""; } // The alignment of this chunk. The writer uses the value. uint32_t Alignment = 1; 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 output section for this chunk. OutputSection *Out = nullptr; public: // The offset from beginning of the output section. The writer sets a value. uint64_t OutputSectionOff = 0; }; // A chunk corresponding a section of an input file. class SectionChunk final : 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, Symbol *> { friend SectionChunk; ObjFile *File; symbol_iterator(ObjFile *File, const coff_relocation *I) : symbol_iterator::iterator_adaptor_base(I), File(File) {} public: symbol_iterator() = default; Symbol *operator*() const { return File->getSymbol(I->SymbolTableIndex); } }; SectionChunk(ObjFile *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; + uint32_t getOutputCharacteristics() 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, OutputSection *OS, uint64_t S, uint64_t P) const; void applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, uint64_t P) const; void applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, uint64_t P) const; void applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, 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; // Returns true if the chunk was not dropped by GC. bool isLive() { return Live; } // Used by the garbage collector. void markLive() { assert(Config->DoGC && "should only mark things live from GC"); assert(!isLive() && "Cannot mark an already live section!"); Live = true; } // True if this is a codeview debug info chunk. These will not be laid out in // the image. Instead they will end up in the PDB, if one is requested. bool isCodeView() const { return SectionName == ".debug" || SectionName.startswith(".debug$"); } // True if this is a DWARF debug info or exception handling chunk. bool isDWARF() const { return SectionName.startswith(".debug_") || SectionName == ".eh_frame"; } // 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. ObjFile *File; // The COMDAT leader symbol if this is a COMDAT chunk. DefinedRegular *Sym = nullptr; + ArrayRef Relocs; + 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 Class[2] = {0, 0}; }; +// This class is used to implement an lld-specific feature (not implemented in +// MSVC) that minimizes the output size by finding string literals sharing tail +// parts and merging them. +// +// If string tail merging is enabled and a section is identified as containing a +// string literal, it is added to a MergeChunk with an appropriate alignment. +// The MergeChunk then tail merges the strings using the StringTableBuilder +// class and assigns RVAs and section offsets to each of the member chunks based +// on the offsets assigned by the StringTableBuilder. +class MergeChunk : public Chunk { +public: + MergeChunk(uint32_t Alignment); + static void addSection(SectionChunk *C); + void finalizeContents() override; + + uint32_t getOutputCharacteristics() const override; + StringRef getSectionName() const override { return ".rdata"; } + size_t getSize() const override; + void writeTo(uint8_t *Buf) const override; + + static std::map Instances; + std::vector Sections; + +private: + llvm::StringTableBuilder Builder; +}; + // 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; + uint32_t getOutputCharacteristics() 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] }; static const uint8_t ImportThunkARM64[] = { 0x10, 0x00, 0x00, 0x90, // adrp x16, #0 0x10, 0x02, 0x40, 0xf9, // ldr x16, [x16] 0x00, 0x02, 0x1f, 0xd6, // br x16 }; // 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; }; class ImportThunkChunkARM64 : public Chunk { public: explicit ImportThunkChunkARM64(Defined *S) : ImpSymbol(S) {} size_t getSize() const override { return sizeof(ImportThunkARM64); } 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 { +// Duplicate RVAs are not allowed in RVA tables, so unique symbols by chunk and +// offset into the chunk. Order does not matter as the RVA table will be sorted +// later. +struct ChunkAndOffset { + Chunk *InputChunk; + uint32_t Offset; + + struct DenseMapInfo { + static ChunkAndOffset getEmptyKey() { + return {llvm::DenseMapInfo::getEmptyKey(), 0}; + } + static ChunkAndOffset getTombstoneKey() { + return {llvm::DenseMapInfo::getTombstoneKey(), 0}; + } + static unsigned getHashValue(const ChunkAndOffset &CO) { + return llvm::DenseMapInfo>::getHashValue( + {CO.InputChunk, CO.Offset}); + } + static bool isEqual(const ChunkAndOffset &LHS, const ChunkAndOffset &RHS) { + return LHS.InputChunk == RHS.InputChunk && LHS.Offset == RHS.Offset; + } + }; +}; + +using SymbolRVASet = llvm::DenseSet; + +// Table which contains symbol RVAs. Used for /safeseh and /guard:cf. +class RVATableChunk : public Chunk { public: - explicit SEHTableChunk(std::set S) : Syms(std::move(S)) {} + explicit RVATableChunk(SymbolRVASet 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; + SymbolRVASet 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; }; void applyMOV32T(uint8_t *Off, uint32_t V); void applyBranch24T(uint8_t *Off, int32_t V); } // namespace coff } // namespace lld + +namespace llvm { +template <> +struct DenseMapInfo + : lld::coff::ChunkAndOffset::DenseMapInfo {}; +} #endif Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/Chunks.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/Config.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/Config.h (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/Config.h (revision 336982) @@ -1,186 +1,209 @@ //===- 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/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/COFF.h" #include "llvm/Support/CachePruning.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 Symbol; // Short aliases. static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64; static const auto ARM64 = llvm::COFF::IMAGE_FILE_MACHINE_ARM64; 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 Symbol *Sym = nullptr; uint16_t Ordinal = 0; bool Noname = false; bool Data = false; bool Private = false; bool Constant = 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); } }; enum class DebugType { None = 0x0, CV = 0x1, /// CodeView PData = 0x2, /// Procedure Data Fixup = 0x4, /// Relocation Table }; +enum class GuardCFLevel { + Off, + NoLongJmp, // Emit gfids but no longjmp tables + Full, // Enable all protections. +}; + // Global configuration. struct Configuration { enum ManifestKind { SideBySide, Embed, No }; bool is64() { return Machine == AMD64 || Machine == ARM64; } llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN; bool Verbose = false; WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN; Symbol *Entry = nullptr; bool NoEntry = false; std::string OutputFile; std::string ImportName; bool DoGC = true; bool DoICF = true; + bool TailMerge; bool Relocatable = true; bool Force = false; bool Debug = false; bool DebugDwarf = false; bool DebugGHashes = false; + bool DebugSymtab = false; + bool ShowTiming = false; unsigned DebugTypes = static_cast(DebugType::None); + std::vector NatvisFiles; + llvm::SmallString<128> PDBAltPath; llvm::SmallString<128> PDBPath; + llvm::SmallString<128> PDBSourcePath; std::vector Argv; // Symbols in this set are considered as live by the garbage collector. std::vector 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; Symbol *DelayLoadHelper = nullptr; bool SaveTemps = false; + // /guard:cf + GuardCFLevel GuardCF = GuardCFLevel::Off; + // Used for SafeSEH. Symbol *SEHTable = nullptr; Symbol *SEHCount = nullptr; // Used for /opt:lldlto=N - unsigned LTOOptLevel = 2; + unsigned LTOO = 2; // Used for /opt:lldltojobs=N - unsigned LTOJobs = 0; + unsigned ThinLTOJobs = 0; // Used for /opt:lldltopartitions=N unsigned LTOPartitions = 1; // Used for /opt:lldltocache=path StringRef LTOCache; // Used for /opt:lldltocachepolicy=policy llvm::CachePruningPolicy LTOCachePolicy; // Used for /merge:from=to (e.g. /merge:.rdata=.text) std::map Merge; // Used for /section=.name,{DEKPRSW} to set section attributes. std::map Section; // Options for manifest files. ManifestKind Manifest = No; int ManifestID = 1; StringRef ManifestDependency; bool ManifestUAC = true; std::vector ManifestInput; StringRef ManifestLevel = "'asInvoker'"; StringRef ManifestUIAccess = "'false'"; StringRef ManifestFile; // Used for /aligncomm. std::map AlignComm; // Used for /failifmismatch. std::map MustMatch; // Used for /alternatename. std::map AlternateNames; + // Used for /order. + llvm::StringMap Order; + // Used for /lldmap. std::string MapFile; 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 CanExitEarly = false; + uint32_t Timestamp = 0; bool DynamicBase = true; bool AllowBind = true; bool NxCompat = true; bool AllowIsolation = true; bool TerminalServerAware = true; bool LargeAddressAware = false; bool HighEntropyVA = false; bool AppContainer = false; bool MinGW = false; + bool WarnMissingOrderSymbol = true; bool WarnLocallyDefinedImported = true; + bool Incremental = true; + bool IntegrityCheck = false; bool KillAt = false; + bool Repro = false; }; extern Configuration *Config; } // namespace coff } // namespace lld #endif Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/Config.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/DLL.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/DLL.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/DLL.cpp (revision 336982) @@ -1,597 +1,597 @@ //===- 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 "Chunks.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 alignTo(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) { Alignment = ptrSize(); } 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) { Alignment = ptrSize(); } 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; } 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 &KV : M) { // Sort symbols by name for each group. std::vector &Syms = KV.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 }; static const uint8_t ThunkARM[] = { 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 __imp_ 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 __imp_ 0x2d, 0xe9, 0x0f, 0x48, // push.w {r0, r1, r2, r3, r11, lr} 0x0d, 0xf2, 0x10, 0x0b, // addw r11, sp, #16 0x2d, 0xed, 0x10, 0x0b, // vpush {d0, d1, d2, d3, d4, d5, d6, d7} 0x61, 0x46, // mov r1, ip 0x40, 0xf2, 0x00, 0x00, // mov.w r0, #0 DELAY_IMPORT_DESCRIPTOR 0xc0, 0xf2, 0x00, 0x00, // mov.t r0, #0 DELAY_IMPORT_DESCRIPTOR 0x00, 0xf0, 0x00, 0xd0, // bl #0 __delayLoadHelper2 0x84, 0x46, // mov ip, r0 0xbd, 0xec, 0x10, 0x0b, // vpop {d0, d1, d2, d3, d4, d5, d6, d7} 0xbd, 0xe8, 0x0f, 0x48, // pop.w {r0, r1, r2, r3, r11, lr} 0x60, 0x47, // bx ip }; // 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; }; class ThunkChunkARM : public Chunk { public: ThunkChunkARM(Defined *I, Chunk *D, Defined *H) : Imp(I), Desc(D), Helper(H) {} size_t getSize() const override { return sizeof(ThunkARM); } void writeTo(uint8_t *Buf) const override { memcpy(Buf + OutputSectionOff, ThunkARM, sizeof(ThunkARM)); applyMOV32T(Buf + OutputSectionOff + 0, Imp->getRVA() + Config->ImageBase); applyMOV32T(Buf + OutputSectionOff + 22, Desc->getRVA() + Config->ImageBase); applyBranch24T(Buf + OutputSectionOff + 30, Helper->getRVA() - RVA - 34); } void getBaserels(std::vector *Res) override { Res->emplace_back(RVA + 0, IMAGE_REL_BASED_ARM_MOV32T); Res->emplace_back(RVA + 22, IMAGE_REL_BASED_ARM_MOV32T); } 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) { Alignment = ptrSize(); } 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 { uint32_t Bit = 0; // Pointer to thumb code must have the LSB set, so adjust it. if (Config->Machine == ARMNT) Bit = 1; write32le(Buf + OutputSectionOff, (Thunk->getRVA() + Config->ImageBase) | Bit); } } 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 (const Export &E : Config->Exports) { uint8_t *P = Buf + OutputSectionOff + E.Ordinal * 4; uint32_t Bit = 0; // Pointer to thumb code must have the LSB set, so adjust it. if (Config->Machine == ARMNT && !E.Data) Bit = 1; if (E.ForwardChunk) { write32le(P, E.ForwardChunk->getRVA() | Bit); } else { write32le(P, cast(E.Sym)->getRVA() | Bit); } } } 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(); // The loader assumes a specific order of data. // Add each type in the correct order. std::vector V; V.insert(V.end(), Dirs.begin(), Dirs.end()); V.insert(V.end(), Lookups.begin(), Lookups.end()); V.insert(V.end(), Addresses.begin(), Addresses.end()); V.insert(V.end(), Hints.begin(), Hints.end()); V.insert(V.end(), DLLNames.begin(), DLLNames.end()); return V; } void IdataContents::create() { std::vector> V = binImports(Imports); // Create .idata contents for each DLL. for (std::vector &Syms : V) { // 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(Ord)); Addresses.push_back(make(Ord)); continue; } auto *C = make(S->getExternalName(), Ord); Lookups.push_back(make(C)); Addresses.push_back(make(C)); Hints.push_back(C); } // Terminate with null values. Lookups.push_back(make(ptrSize())); Addresses.push_back(make(ptrSize())); for (int I = 0, E = Syms.size(); I < E; ++I) Syms[I]->setLocation(Addresses[Base + I]); // Create the import table header. DLLNames.push_back(make(Syms[0]->getDLLName())); auto *Dir = make(DLLNames.back()); Dir->LookupTab = Lookups[Base]; Dir->AddressTab = Addresses[Base]; Dirs.push_back(Dir); } // Add null terminator. Dirs.push_back(make(sizeof(ImportDirectoryTableEntry))); } std::vector DelayLoadContents::getChunks() { std::vector V; V.insert(V.end(), Dirs.begin(), Dirs.end()); V.insert(V.end(), Names.begin(), Names.end()); V.insert(V.end(), HintNames.begin(), HintNames.end()); V.insert(V.end(), DLLNames.begin(), DLLNames.end()); return V; } std::vector DelayLoadContents::getDataChunks() { std::vector V; V.insert(V.end(), ModuleHandles.begin(), ModuleHandles.end()); V.insert(V.end(), Addresses.begin(), Addresses.end()); 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) { // Create the delay import table header. DLLNames.push_back(make(Syms[0]->getDLLName())); auto *Dir = make(DLLNames.back()); size_t Base = Addresses.size(); for (DefinedImportData *S : Syms) { Chunk *T = newThunkChunk(S, Dir); auto *A = make(T); Addresses.push_back(A); Thunks.push_back(T); StringRef ExtName = S->getExternalName(); if (ExtName.empty()) { Names.push_back(make(S->getOrdinal())); } else { auto *C = make(ExtName, 0); Names.push_back(make(C)); HintNames.push_back(C); } } // Terminate with null values. Addresses.push_back(make(8)); Names.push_back(make(8)); for (int I = 0, E = Syms.size(); I < E; ++I) Syms[I]->setLocation(Addresses[Base + I]); auto *MH = make(8); MH->Alignment = 8; ModuleHandles.push_back(MH); // Fill the delay import table header fields. Dir->ModuleHandle = MH; Dir->AddressTab = Addresses[Base]; Dir->NameTab = Names[Base]; Dirs.push_back(Dir); } // Add null terminator. Dirs.push_back(make(sizeof(delay_import_directory_table_entry))); } Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) { switch (Config->Machine) { case AMD64: return make(S, Dir, Helper); case I386: return make(S, Dir, Helper); case ARMNT: return make(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 = make(sys::path::filename(Config->OutputFile)); auto *AddressTab = make(MaxOrdinal); std::vector Names; for (Export &E : Config->Exports) if (!E.Noname) Names.push_back(make(E.ExportName)); std::vector Forwards; for (Export &E : Config->Exports) { if (E.ForwardTo.empty()) continue; E.ForwardChunk = make(E.ForwardTo); Forwards.push_back(E.ForwardChunk); } auto *NameTab = make(Names); auto *OrdinalTab = make(Names.size()); auto *Dir = make(MaxOrdinal, Names.size(), DLLName, AddressTab, NameTab, OrdinalTab); Chunks.push_back(Dir); Chunks.push_back(DLLName); Chunks.push_back(AddressTab); Chunks.push_back(NameTab); Chunks.push_back(OrdinalTab); Chunks.insert(Chunks.end(), Names.begin(), Names.end()); Chunks.insert(Chunks.end(), Forwards.begin(), Forwards.end()); } } // namespace coff } // namespace lld Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/DLL.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/DLL.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/DLL.h (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/DLL.h (revision 336982) @@ -1,84 +1,89 @@ //===- DLL.h ----------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_COFF_DLL_H #define LLD_COFF_DLL_H #include "Chunks.h" #include "Symbols.h" namespace lld { namespace coff { // Windows-specific. // IdataContents creates all chunks for the DLL import table. // You are supposed to call add() to add symbols and then // call getChunks() to get a list of chunks. class IdataContents { public: void add(DefinedImportData *Sym) { Imports.push_back(Sym); } bool empty() { return Imports.empty(); } std::vector getChunks(); uint64_t getDirRVA() { return Dirs[0]->getRVA(); } uint64_t getDirSize(); uint64_t getIATRVA() { return Addresses[0]->getRVA(); } uint64_t getIATSize(); private: void create(); std::vector Imports; std::vector Dirs; std::vector Lookups; std::vector Addresses; std::vector Hints; std::vector DLLNames; }; // Windows-specific. // DelayLoadContents creates all chunks for the delay-load DLL import table. class DelayLoadContents { public: void add(DefinedImportData *Sym) { Imports.push_back(Sym); } bool empty() { return Imports.empty(); } void create(Defined *Helper); std::vector getChunks(); std::vector getDataChunks(); ArrayRef getCodeChunks() { return Thunks; } uint64_t getDirRVA() { return Dirs[0]->getRVA(); } uint64_t getDirSize(); private: Chunk *newThunkChunk(DefinedImportData *S, Chunk *Dir); Defined *Helper; std::vector Imports; std::vector Dirs; std::vector ModuleHandles; std::vector Addresses; std::vector Names; std::vector HintNames; std::vector Thunks; std::vector DLLNames; }; // Windows-specific. // EdataContents creates all chunks for the DLL export table. class EdataContents { public: EdataContents(); std::vector Chunks; + + uint64_t getRVA() { return Chunks[0]->getRVA(); } + uint64_t getSize() { + return Chunks.back()->getRVA() + Chunks.back()->getSize() - getRVA(); + } }; } // namespace coff } // namespace lld #endif Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/DLL.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/Driver.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/Driver.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/Driver.cpp (revision 336982) @@ -1,1339 +1,1592 @@ //===- 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 "ICF.h" #include "InputFiles.h" +#include "MarkLive.h" #include "MinGW.h" #include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" +#include "lld/Common/Args.h" #include "lld/Common/Driver.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "lld/Common/Timer.h" #include "lld/Common/Version.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/BinaryFormat/Magic.h" #include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/COFFImportFile.h" #include "llvm/Object/COFFModuleDefinition.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/TarWriter.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ToolDrivers/llvm-lib/LibDriver.h" #include +#include #include -#include - using namespace llvm; using namespace llvm::object; using namespace llvm::COFF; using llvm::sys::Process; namespace lld { namespace coff { +static Timer InputFileTimer("Input File Reading", Timer::root()); + Configuration *Config; LinkerDriver *Driver; bool link(ArrayRef Args, bool CanExitEarly, raw_ostream &Diag) { - errorHandler().LogName = Args[0]; + errorHandler().LogName = sys::path::filename(Args[0]); errorHandler().ErrorOS = &Diag; errorHandler().ColorDiagnostics = Diag.has_colors(); errorHandler().ErrorLimitExceededMsg = "too many errors emitted, stopping now" - " (use /ERRORLIMIT:0 to see all errors)"; + " (use /errorlimit:0 to see all errors)"; errorHandler().ExitEarly = CanExitEarly; Config = make(); - Config->Argv = {Args.begin(), Args.end()}; - Config->CanExitEarly = CanExitEarly; Symtab = make(); Driver = make(); Driver->link(Args); // Call exit() if we can to avoid calling destructors. if (CanExitEarly) exitLld(errorCount() ? 1 : 0); freeArena(); + ObjFile::Instances.clear(); + ImportFile::Instances.clear(); + BitcodeFile::Instances.clear(); return !errorCount(); } // Drop directory components and replace extension with ".exe" or ".dll". static std::string getOutputPath(StringRef Path) { auto P = Path.find_last_of("\\/"); StringRef S = (P == StringRef::npos) ? Path : Path.substr(P + 1); const char* E = Config->DLL ? ".dll" : ".exe"; return (S.substr(0, S.rfind('.')) + E).str(); } // ErrorOr is not default constructible, so it cannot be used as the type // parameter of a future. // FIXME: We could open the file in createFutureForFile and avoid needing to // return an error here, but for the moment that would cost us a file descriptor // (a limited resource on Windows) for the duration that the future is pending. typedef std::pair, std::error_code> MBErrPair; // Create a std::future that opens and maps a file using the best strategy for // the host platform. static std::future createFutureForFile(std::string Path) { -#if LLVM_ON_WIN32 +#if _WIN32 // On Windows, file I/O is relatively slow so it is best to do this // asynchronously. auto Strategy = std::launch::async; #else auto Strategy = std::launch::deferred; #endif return std::async(Strategy, [=]() { - auto MBOrErr = MemoryBuffer::getFile(Path); + auto MBOrErr = MemoryBuffer::getFile(Path, + /*FileSize*/ -1, + /*RequiresNullTerminator*/ false); if (!MBOrErr) return MBErrPair{nullptr, MBOrErr.getError()}; return MBErrPair{std::move(*MBOrErr), std::error_code()}; }); } MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr MB) { MemoryBufferRef MBRef = *MB; make>(std::move(MB)); // take ownership if (Driver->Tar) Driver->Tar->append(relativeToRoot(MBRef.getBufferIdentifier()), MBRef.getBuffer()); return MBRef; } void LinkerDriver::addBuffer(std::unique_ptr MB, bool WholeArchive) { + StringRef Filename = MB->getBufferIdentifier(); + MemoryBufferRef MBRef = takeBuffer(std::move(MB)); - FilePaths.push_back(MBRef.getBufferIdentifier()); + FilePaths.push_back(Filename); // File type is detected by contents, not by file extension. switch (identify_magic(MBRef.getBuffer())) { case file_magic::windows_resource: Resources.push_back(MBRef); break; - case file_magic::archive: if (WholeArchive) { std::unique_ptr File = - CHECK(Archive::create(MBRef), - MBRef.getBufferIdentifier() + ": failed to parse archive"); + CHECK(Archive::create(MBRef), Filename + ": failed to parse archive"); for (MemoryBufferRef M : getArchiveMembers(File.get())) - addArchiveBuffer(M, "", MBRef.getBufferIdentifier()); + addArchiveBuffer(M, "", Filename); return; } Symtab->addFile(make(MBRef)); break; - case file_magic::bitcode: Symtab->addFile(make(MBRef)); break; - + case file_magic::coff_object: + case file_magic::coff_import_library: + Symtab->addFile(make(MBRef)); + break; case file_magic::coff_cl_gl_object: - error(MBRef.getBufferIdentifier() + ": is not a native COFF file. " - "Recompile without /GL"); + error(Filename + ": is not a native COFF file. Recompile without /GL"); break; - + case file_magic::pecoff_executable: + if (Filename.endswith_lower(".dll")) { + error(Filename + ": bad file type. Did you specify a DLL instead of an " + "import library?"); + break; + } + LLVM_FALLTHROUGH; default: - Symtab->addFile(make(MBRef)); + error(MBRef.getBufferIdentifier() + ": unknown file type"); break; } } void LinkerDriver::enqueuePath(StringRef Path, bool WholeArchive) { auto Future = std::make_shared>(createFutureForFile(Path)); std::string PathStr = Path; enqueueTask([=]() { auto MBOrErr = Future->get(); if (MBOrErr.second) error("could not open " + PathStr + ": " + MBOrErr.second.message()); else Driver->addBuffer(std::move(MBOrErr.first), WholeArchive); }); } void LinkerDriver::addArchiveBuffer(MemoryBufferRef MB, StringRef SymName, StringRef ParentName) { file_magic Magic = identify_magic(MB.getBuffer()); if (Magic == file_magic::coff_import_library) { Symtab->addFile(make(MB)); return; } InputFile *Obj; if (Magic == file_magic::coff_object) { Obj = make(MB); } else if (Magic == file_magic::bitcode) { Obj = make(MB); } else { error("unknown file type: " + MB.getBufferIdentifier()); return; } Obj->ParentName = ParentName; Symtab->addFile(Obj); log("Loaded " + toString(Obj) + " for " + SymName); } void LinkerDriver::enqueueArchiveMember(const Archive::Child &C, StringRef SymName, StringRef ParentName) { if (!C.getParent()->isThin()) { MemoryBufferRef MB = CHECK( C.getMemoryBufferRef(), "could not get the buffer for the member defining symbol " + SymName); enqueueTask([=]() { Driver->addArchiveBuffer(MB, SymName, ParentName); }); return; } auto Future = std::make_shared>(createFutureForFile( CHECK(C.getFullName(), "could not get the filename for the member defining symbol " + SymName))); enqueueTask([=]() { auto MBOrErr = Future->get(); if (MBOrErr.second) fatal("could not get the buffer for the member defining " + SymName + ": " + MBOrErr.second.message()); Driver->addArchiveBuffer(takeBuffer(std::move(MBOrErr.first)), SymName, ParentName); }); } static bool isDecorated(StringRef Sym) { return Sym.startswith("@") || Sym.contains("@@") || Sym.startswith("?") || (!Config->MinGW && Sym.contains('@')); } // Parses .drectve section contents and returns a list of files // specified by /defaultlib. void LinkerDriver::parseDirectives(StringRef S) { ArgParser Parser; // .drectve is always tokenized using Windows shell rules. - opt::InputArgList Args = Parser.parseDirectives(S); + // /EXPORT: option can appear too many times, processing in fastpath. + opt::InputArgList Args; + std::vector Exports; + std::tie(Args, Exports) = Parser.parseDirectives(S); + for (StringRef E : Exports) { + // If a common header file contains dllexported function + // declarations, many object files may end up with having the + // same /EXPORT options. In order to save cost of parsing them, + // we dedup them first. + if (!DirectivesExports.insert(E).second) + continue; + + Export Exp = parseExport(E); + if (Config->Machine == I386 && Config->MinGW) { + if (!isDecorated(Exp.Name)) + Exp.Name = Saver.save("_" + Exp.Name); + if (!Exp.ExtName.empty() && !isDecorated(Exp.ExtName)) + Exp.ExtName = Saver.save("_" + Exp.ExtName); + } + Exp.Directives = true; + Config->Exports.push_back(Exp); + } + for (auto *Arg : Args) { switch (Arg->getOption().getUnaliasedOption().getID()) { case OPT_aligncomm: parseAligncomm(Arg->getValue()); break; case OPT_alternatename: parseAlternateName(Arg->getValue()); break; case OPT_defaultlib: if (Optional Path = findLib(Arg->getValue())) enqueuePath(*Path, false); break; case OPT_entry: Config->Entry = addUndefined(mangle(Arg->getValue())); break; - case OPT_export: { - // If a common header file contains dllexported function - // declarations, many object files may end up with having the - // same /EXPORT options. In order to save cost of parsing them, - // we dedup them first. - if (!DirectivesExports.insert(Arg->getValue()).second) - break; - - Export E = parseExport(Arg->getValue()); - if (Config->Machine == I386 && Config->MinGW) { - if (!isDecorated(E.Name)) - E.Name = Saver.save("_" + E.Name); - if (!E.ExtName.empty() && !isDecorated(E.ExtName)) - E.ExtName = Saver.save("_" + E.ExtName); - } - 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_section: parseSection(Arg->getValue()); break; case OPT_subsystem: parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion, &Config->MinorOSVersion); break; case OPT_editandcontinue: case OPT_fastfail: case OPT_guardsym: case OPT_natvis: case OPT_throwingnew: break; default: error(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.contains('.'); for (StringRef Dir : SearchPaths) { SmallString<128> Path = Dir; sys::path::append(Path, Filename); if (sys::fs::exists(Path.str())) return Saver.save(Path.str()); if (!HasExt) { Path.append(".obj"); if (sys::fs::exists(Path.str())) return Saver.save(Path.str()); } } return Filename; } +static Optional getUniqueID(StringRef Path) { + sys::fs::UniqueID Ret; + if (sys::fs::getUniqueID(Path, Ret)) + return None; + return Ret; +} + // 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; + + if (Optional ID = getUniqueID(Path)) { + bool Seen = !VisitedFiles.insert(*ID).second; + if (Seen) + return None; + } + if (Path.endswith_lower(".lib")) VisitedLibs.insert(sys::path::filename(Path)); 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.contains('.'); if (!HasExt) Filename = Saver.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; if (!VisitedLibs.insert(Filename.lower()).second) return None; + StringRef Path = doFindLib(Filename); if (Config->NoDefaultLibs.count(Path)) return None; - if (!VisitedFiles.insert(Path.lower()).second) - return None; + + if (Optional ID = getUniqueID(Path)) + if (!VisitedFiles.insert(*ID).second) + 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 = Saver.save(*EnvOpt); while (!Env.empty()) { StringRef Path; std::tie(Path, Env) = Env.split(';'); SearchPaths.push_back(Path); } } Symbol *LinkerDriver::addUndefined(StringRef Name) { Symbol *B = Symtab->addUndefined(Name); if (!B->IsGCRoot) { B->IsGCRoot = true; Config->GCRoot.push_back(B); } return B; } // 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 Saver.save("_" + Sym); return Sym; } // Windows specific -- find default entry point name. +// +// There are four different entry point functions for Windows executables, +// each of which corresponds to a user-defined "main" function. This function +// infers an entry point from a user-defined "main" function. StringRef LinkerDriver::findDefaultEntry() { + // As a special case, if /nodefaultlib is given, we directly look for an + // entry point. This is because, if no default library is linked, users + // need to define an entry point instead of a "main". + if (Config->NoDefaultLibAll) { + for (StringRef S : {"mainCRTStartup", "wmainCRTStartup", + "WinMainCRTStartup", "wWinMainCRTStartup"}) { + StringRef Entry = Symtab->findMangle(S); + if (!Entry.empty() && !isa(Symtab->find(Entry))) + return mangle(S); + } + return ""; + } + // 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))) 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; } static std::string createResponseFile(const opt::InputArgList &Args, ArrayRef FilePaths, ArrayRef SearchPaths) { SmallString<0> Data; raw_svector_ostream OS(Data); for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_linkrepro: case OPT_INPUT: case OPT_defaultlib: case OPT_libpath: case OPT_manifest: case OPT_manifest_colon: case OPT_manifestdependency: case OPT_manifestfile: case OPT_manifestinput: case OPT_manifestuac: break; default: OS << toString(*Arg) << "\n"; } } for (StringRef Path : SearchPaths) { std::string RelPath = relativeToRoot(Path); OS << "/libpath:" << quote(RelPath) << "\n"; } for (StringRef Path : FilePaths) OS << quote(relativeToRoot(Path)) << "\n"; return Data.str(); } static unsigned getDefaultDebugType(const opt::InputArgList &Args) { unsigned DebugTypes = static_cast(DebugType::CV); if (Args.hasArg(OPT_driver)) DebugTypes |= static_cast(DebugType::PData); if (Args.hasArg(OPT_profile)) DebugTypes |= static_cast(DebugType::Fixup); return DebugTypes; } static unsigned parseDebugType(StringRef Arg) { SmallVector Types; Arg.split(Types, ',', /*KeepEmpty=*/false); unsigned DebugTypes = static_cast(DebugType::None); for (StringRef Type : Types) DebugTypes |= StringSwitch(Type.lower()) .Case("cv", static_cast(DebugType::CV)) .Case("pdata", static_cast(DebugType::PData)) .Case("fixup", static_cast(DebugType::Fixup)) .Default(0); return DebugTypes; } static std::string getMapFile(const opt::InputArgList &Args) { auto *Arg = Args.getLastArg(OPT_lldmap, OPT_lldmap_file); if (!Arg) return ""; if (Arg->getOption().getID() == OPT_lldmap_file) return Arg->getValue(); assert(Arg->getOption().getID() == OPT_lldmap); StringRef OutFile = Config->OutputFile; return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str(); } 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(); } // // The import name is caculated as the following: // // | LIBRARY w/ ext | LIBRARY w/o ext | no LIBRARY // -----+----------------+---------------------+------------------ // LINK | {value} | {value}.{.dll/.exe} | {output name} // LIB | {value} | {value}.dll | {output name}.dll // static std::string getImportName(bool AsLib) { SmallString<128> Out; if (Config->ImportName.empty()) { Out.assign(sys::path::filename(Config->OutputFile)); if (AsLib) sys::path::replace_extension(Out, ".dll"); } else { Out.assign(Config->ImportName); if (!sys::path::has_extension(Out)) sys::path::replace_extension(Out, (Config->DLL || AsLib) ? ".dll" : ".exe"); } return Out.str(); } static void createImportLibrary(bool AsLib) { std::vector Exports; for (Export &E1 : Config->Exports) { COFFShortExport E2; E2.Name = E1.Name; E2.SymbolName = E1.SymbolName; E2.ExtName = E1.ExtName; E2.Ordinal = E1.Ordinal; E2.Noname = E1.Noname; E2.Data = E1.Data; E2.Private = E1.Private; E2.Constant = E1.Constant; Exports.push_back(E2); } - auto E = writeImportLibrary(getImportName(AsLib), getImplibPath(), Exports, - Config->Machine, false); - handleAllErrors(std::move(E), - [&](ErrorInfoBase &EIB) { error(EIB.message()); }); + auto HandleError = [](Error &&E) { + handleAllErrors(std::move(E), + [](ErrorInfoBase &EIB) { error(EIB.message()); }); + }; + std::string LibName = getImportName(AsLib); + std::string Path = getImplibPath(); + + if (!Config->Incremental) { + HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine, + Config->MinGW)); + return; + } + + // If the import library already exists, replace it only if the contents + // have changed. + ErrorOr> OldBuf = MemoryBuffer::getFile( + Path, /*FileSize*/ -1, /*RequiresNullTerminator*/ false); + if (!OldBuf) { + HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine, + Config->MinGW)); + return; + } + + SmallString<128> TmpName; + if (std::error_code EC = + sys::fs::createUniqueFile(Path + ".tmp-%%%%%%%%.lib", TmpName)) + fatal("cannot create temporary file for import library " + Path + ": " + + EC.message()); + + if (Error E = writeImportLibrary(LibName, TmpName, Exports, Config->Machine, + Config->MinGW)) { + HandleError(std::move(E)); + return; + } + + std::unique_ptr NewBuf = check(MemoryBuffer::getFile( + TmpName, /*FileSize*/ -1, /*RequiresNullTerminator*/ false)); + if ((*OldBuf)->getBuffer() != NewBuf->getBuffer()) { + OldBuf->reset(); + HandleError(errorCodeToError(sys::fs::rename(TmpName, Path))); + } else { + sys::fs::remove(TmpName); + } } static void parseModuleDefs(StringRef Path) { std::unique_ptr MB = CHECK( MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); COFFModuleDefinition M = check(parseCOFFModuleDefinition( MB->getMemBufferRef(), Config->Machine, Config->MinGW)); if (Config->OutputFile.empty()) Config->OutputFile = Saver.save(M.OutputFile); Config->ImportName = Saver.save(M.ImportName); if (M.ImageBase) Config->ImageBase = M.ImageBase; if (M.StackReserve) Config->StackReserve = M.StackReserve; if (M.StackCommit) Config->StackCommit = M.StackCommit; if (M.HeapReserve) Config->HeapReserve = M.HeapReserve; if (M.HeapCommit) Config->HeapCommit = M.HeapCommit; if (M.MajorImageVersion) Config->MajorImageVersion = M.MajorImageVersion; if (M.MinorImageVersion) Config->MinorImageVersion = M.MinorImageVersion; if (M.MajorOSVersion) Config->MajorOSVersion = M.MajorOSVersion; if (M.MinorOSVersion) Config->MinorOSVersion = M.MinorOSVersion; for (COFFShortExport E1 : M.Exports) { Export E2; + // In simple cases, only Name is set. Renamed exports are parsed + // and set as "ExtName = Name". If Name has the form "OtherDll.Func", + // it shouldn't be a normal exported function but a forward to another + // DLL instead. This is supported by both MS and GNU linkers. + if (E1.ExtName != E1.Name && StringRef(E1.Name).contains('.')) { + E2.Name = Saver.save(E1.ExtName); + E2.ForwardTo = Saver.save(E1.Name); + Config->Exports.push_back(E2); + continue; + } E2.Name = Saver.save(E1.Name); - if (E1.isWeak()) - E2.ExtName = Saver.save(E1.ExtName); + E2.ExtName = Saver.save(E1.ExtName); E2.Ordinal = E1.Ordinal; E2.Noname = E1.Noname; E2.Data = E1.Data; E2.Private = E1.Private; E2.Constant = E1.Constant; Config->Exports.push_back(E2); } } // A helper function for filterBitcodeFiles. static bool needsRebuilding(MemoryBufferRef MB) { // The MSVC linker doesn't support thin archives, so if it's a thin // archive, we always need to rebuild it. std::unique_ptr File = CHECK(Archive::create(MB), "Failed to read " + MB.getBufferIdentifier()); if (File->isThin()) return true; // Returns true if the archive contains at least one bitcode file. for (MemoryBufferRef Member : getArchiveMembers(File.get())) if (identify_magic(Member.getBuffer()) == file_magic::bitcode) return true; return false; } // Opens a given path as an archive file and removes bitcode files // from them if exists. This function is to appease the MSVC linker as // their linker doesn't like archive files containing non-native // object files. // // If a given archive doesn't contain bitcode files, the archive path // is returned as-is. Otherwise, a new temporary file is created and // its path is returned. static Optional filterBitcodeFiles(StringRef Path, std::vector &TemporaryFiles) { std::unique_ptr MB = CHECK( MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); MemoryBufferRef MBRef = MB->getMemBufferRef(); file_magic Magic = identify_magic(MBRef.getBuffer()); if (Magic == file_magic::bitcode) return None; if (Magic != file_magic::archive) return Path.str(); if (!needsRebuilding(MBRef)) return Path.str(); std::unique_ptr File = CHECK(Archive::create(MBRef), MBRef.getBufferIdentifier() + ": failed to parse archive"); std::vector New; for (MemoryBufferRef Member : getArchiveMembers(File.get())) if (identify_magic(Member.getBuffer()) != file_magic::bitcode) New.emplace_back(Member); if (New.empty()) return None; log("Creating a temporary archive for " + Path + " to remove bitcode files"); SmallString<128> S; - if (auto EC = sys::fs::createTemporaryFile("lld-" + sys::path::stem(Path), - ".lib", S)) + if (std::error_code EC = sys::fs::createTemporaryFile( + "lld-" + sys::path::stem(Path), ".lib", S)) fatal("cannot create a temporary file: " + EC.message()); std::string Temp = S.str(); TemporaryFiles.push_back(Temp); Error E = llvm::writeArchive(Temp, New, /*WriteSymtab=*/true, Archive::Kind::K_GNU, /*Deterministics=*/true, /*Thin=*/false); handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) { error("failed to create a new archive " + S.str() + ": " + EI.message()); }); return Temp; } // Create response file contents and invoke the MSVC linker. void LinkerDriver::invokeMSVC(opt::InputArgList &Args) { std::string Rsp = "/nologo\n"; std::vector Temps; // Write out archive members that we used in symbol resolution and pass these // to MSVC before any archives, so that MSVC uses the same objects to satisfy // references. for (ObjFile *Obj : ObjFile::Instances) { if (Obj->ParentName.empty()) continue; SmallString<128> S; int Fd; if (auto EC = sys::fs::createTemporaryFile( "lld-" + sys::path::filename(Obj->ParentName), ".obj", Fd, S)) fatal("cannot create a temporary file: " + EC.message()); raw_fd_ostream OS(Fd, /*shouldClose*/ true); OS << Obj->MB.getBuffer(); Temps.push_back(S.str()); Rsp += quote(S) + "\n"; } for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_linkrepro: case OPT_lldmap: case OPT_lldmap_file: case OPT_lldsavetemps: case OPT_msvclto: // LLD-specific options are stripped. break; case OPT_opt: if (!StringRef(Arg->getValue()).startswith("lld")) Rsp += toString(*Arg) + " "; break; case OPT_INPUT: { if (Optional Path = doFindFile(Arg->getValue())) { if (Optional S = filterBitcodeFiles(*Path, Temps)) Rsp += quote(*S) + "\n"; continue; } Rsp += quote(Arg->getValue()) + "\n"; break; } default: Rsp += toString(*Arg) + "\n"; } } std::vector ObjFiles = Symtab->compileBitcodeFiles(); runMSVCLinker(Rsp, ObjFiles); for (StringRef Path : Temps) sys::fs::remove(Path); } void LinkerDriver::enqueueTask(std::function Task) { TaskQueue.push_back(std::move(Task)); } bool LinkerDriver::run() { + ScopedTimer T(InputFileTimer); + bool DidWork = !TaskQueue.empty(); while (!TaskQueue.empty()) { TaskQueue.front()(); TaskQueue.pop_front(); } return DidWork; } +// Parse an /order file. If an option is given, the linker places +// COMDAT sections in the same order as their names appear in the +// given file. +static void parseOrderFile(StringRef Arg) { + // For some reason, the MSVC linker requires a filename to be + // preceded by "@". + if (!Arg.startswith("@")) { + error("malformed /order option: '@' missing"); + return; + } + + // Get a list of all comdat sections for error checking. + DenseSet Set; + for (Chunk *C : Symtab->getChunks()) + if (auto *Sec = dyn_cast(C)) + if (Sec->Sym) + Set.insert(Sec->Sym->getName()); + + // Open a file. + StringRef Path = Arg.substr(1); + std::unique_ptr MB = CHECK( + MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); + + // Parse a file. An order file contains one symbol per line. + // All symbols that were not present in a given order file are + // considered to have the lowest priority 0 and are placed at + // end of an output section. + for (std::string S : args::getLines(MB->getMemBufferRef())) { + if (Config->Machine == I386 && !isDecorated(S)) + S = "_" + S; + + if (Set.count(S) == 0) { + if (Config->WarnMissingOrderSymbol) + warn("/order:" + Arg + ": missing symbol: " + S + " [LNK4037]"); + } + else + Config->Order[S] = INT_MIN + Config->Order.size(); + } +} + void LinkerDriver::link(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) fatal("lib failed"); return; } // Needed for LTO. InitializeAllTargetInfos(); InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmParsers(); InitializeAllAsmPrinters(); - InitializeAllDisassemblers(); // Parse command line options. ArgParser Parser; - opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1)); + opt::InputArgList Args = Parser.parseLINK(ArgsArr); // Parse and evaluate -mllvm options. std::vector V; V.push_back("lld-link (LLVM option parsing)"); for (auto *Arg : Args.filtered(OPT_mllvm)) V.push_back(Arg->getValue()); cl::ParseCommandLineOptions(V.size(), V.data()); // Handle /errorlimit early, because error() depends on it. if (auto *Arg = Args.getLastArg(OPT_errorlimit)) { int N = 20; StringRef S = Arg->getValue(); if (S.getAsInteger(10, N)) error(Arg->getSpelling() + " number expected, but got " + S); errorHandler().ErrorLimit = N; } // Handle /help if (Args.hasArg(OPT_help)) { printHelp(ArgsArr[0]); return; } + if (Args.hasArg(OPT_show_timing)) + Config->ShowTiming = true; + + ScopedTimer T(Timer::root()); // Handle --version, which is an lld extension. This option is a bit odd // because it doesn't start with "/", but we deliberately chose "--" to // avoid conflict with /version and for compatibility with clang-cl. if (Args.hasArg(OPT_dash_dash_version)) { outs() << getLLDVersion() << "\n"; return; } // Handle /lldmingw early, since it can potentially affect how other // options are handled. Config->MinGW = Args.hasArg(OPT_lldmingw); if (auto *Arg = Args.getLastArg(OPT_linkrepro)) { SmallString<64> Path = StringRef(Arg->getValue()); sys::path::append(Path, "repro.tar"); Expected> ErrOrWriter = TarWriter::create(Path, "repro"); if (ErrOrWriter) { Tar = std::move(*ErrOrWriter); } else { error("/linkrepro: failed to open " + Path + ": " + toString(ErrOrWriter.takeError())); } } if (!Args.hasArg(OPT_INPUT)) { if (Args.hasArg(OPT_deffile)) Config->NoEntry = true; else fatal("no input files"); } // Construct search path list. SearchPaths.push_back(""); for (auto *Arg : Args.filtered(OPT_libpath)) SearchPaths.push_back(Arg->getValue()); addLibSearchPaths(); // Handle /ignore for (auto *Arg : Args.filtered(OPT_ignore)) { - if (StringRef(Arg->getValue()) == "4217") + if (StringRef(Arg->getValue()) == "4037") + Config->WarnMissingOrderSymbol = false; + else if (StringRef(Arg->getValue()) == "4217") Config->WarnLocallyDefinedImported = false; // Other warning numbers are ignored. } // Handle /out if (auto *Arg = Args.getLastArg(OPT_out)) Config->OutputFile = Arg->getValue(); // Handle /verbose if (Args.hasArg(OPT_verbose)) Config->Verbose = true; errorHandler().Verbose = Config->Verbose; // Handle /force or /force:unresolved if (Args.hasArg(OPT_force, OPT_force_unresolved)) Config->Force = true; // Handle /debug if (Args.hasArg(OPT_debug, OPT_debug_dwarf, OPT_debug_ghash)) { Config->Debug = true; + Config->Incremental = true; if (auto *Arg = Args.getLastArg(OPT_debugtype)) Config->DebugTypes = parseDebugType(Arg->getValue()); else Config->DebugTypes = getDefaultDebugType(Args); } // Handle /pdb bool ShouldCreatePDB = Args.hasArg(OPT_debug, OPT_debug_ghash); - if (ShouldCreatePDB) + if (ShouldCreatePDB) { if (auto *Arg = Args.getLastArg(OPT_pdb)) Config->PDBPath = Arg->getValue(); + if (auto *Arg = Args.getLastArg(OPT_pdbaltpath)) + Config->PDBAltPath = Arg->getValue(); + if (Args.hasArg(OPT_natvis)) + Config->NatvisFiles = Args.getAllArgValues(OPT_natvis); + if (auto *Arg = Args.getLastArg(OPT_pdb_source_path)) + Config->PDBSourcePath = Arg->getValue(); + } + // Handle /noentry if (Args.hasArg(OPT_noentry)) { if (Args.hasArg(OPT_dll)) Config->NoEntry = true; else error("/noentry must be specified with /dll"); } // Handle /dll if (Args.hasArg(OPT_dll)) { Config->DLL = true; Config->ManifestID = 2; } // Handle /dynamicbase and /fixed. We can't use hasFlag for /dynamicbase // because we need to explicitly check whether that option or its inverse was // present in the argument list in order to handle /fixed. auto *DynamicBaseArg = Args.getLastArg(OPT_dynamicbase, OPT_dynamicbase_no); if (DynamicBaseArg && DynamicBaseArg->getOption().getID() == OPT_dynamicbase_no) Config->DynamicBase = false; + // MSDN claims "/FIXED:NO is the default setting for a DLL, and /FIXED is the + // default setting for any other project type.", but link.exe defaults to + // /FIXED:NO for exe outputs as well. Match behavior, not docs. bool Fixed = Args.hasFlag(OPT_fixed, OPT_fixed_no, false); if (Fixed) { if (DynamicBaseArg && DynamicBaseArg->getOption().getID() == OPT_dynamicbase) { error("/fixed must not be specified with /dynamicbase"); } else { Config->Relocatable = false; Config->DynamicBase = false; } } // Handle /appcontainer Config->AppContainer = Args.hasFlag(OPT_appcontainer, OPT_appcontainer_no, 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 /guard:cf + if (auto *Arg = Args.getLastArg(OPT_guard)) + parseGuard(Arg->getValue()); + // 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 /timestamp + if (llvm::opt::Arg *Arg = Args.getLastArg(OPT_timestamp, OPT_repro)) { + if (Arg->getOption().getID() == OPT_repro) { + Config->Timestamp = 0; + Config->Repro = true; + } else { + Config->Repro = false; + StringRef Value(Arg->getValue()); + if (Value.getAsInteger(0, Config->Timestamp)) + fatal(Twine("invalid timestamp: ") + Value + + ". Expected 32-bit integer"); + } + } else { + Config->Repro = false; + Config->Timestamp = time(nullptr); + } + // 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. - bool DoGC = !Args.hasArg(OPT_debug); - unsigned ICFLevel = 1; // 0: off, 1: limited, 2: on + bool DoGC = !Args.hasArg(OPT_debug) || Args.hasArg(OPT_profile); + unsigned ICFLevel = + Args.hasArg(OPT_profile) ? 0 : 1; // 0: off, 1: limited, 2: on + unsigned TailMerge = 1; 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 == "ref") { DoGC = true; } else if (S == "noref") { DoGC = false; } else if (S == "icf" || S.startswith("icf=")) { ICFLevel = 2; } else if (S == "noicf") { ICFLevel = 0; + } else if (S == "lldtailmerge") { + TailMerge = 2; + } else if (S == "nolldtailmerge") { + TailMerge = 0; } else if (S.startswith("lldlto=")) { StringRef OptLevel = S.substr(7); - if (OptLevel.getAsInteger(10, Config->LTOOptLevel) || - Config->LTOOptLevel > 3) + if (OptLevel.getAsInteger(10, Config->LTOO) || Config->LTOO > 3) error("/opt:lldlto: invalid optimization level: " + OptLevel); } else if (S.startswith("lldltojobs=")) { StringRef Jobs = S.substr(11); - if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0) + if (Jobs.getAsInteger(10, Config->ThinLTOJobs) || + Config->ThinLTOJobs == 0) error("/opt:lldltojobs: invalid job count: " + Jobs); } else if (S.startswith("lldltopartitions=")) { StringRef N = S.substr(17); if (N.getAsInteger(10, Config->LTOPartitions) || Config->LTOPartitions == 0) error("/opt:lldltopartitions: invalid partition count: " + N); } else if (S != "lbr" && S != "nolbr") error("/opt: unknown option: " + S); } } // Limited ICF is enabled if GC is enabled and ICF was never mentioned // explicitly. // FIXME: LLD only implements "limited" ICF, i.e. it only merges identical // code. If the user passes /OPT:ICF explicitly, LLD should merge identical // comdat readonly data. if (ICFLevel == 1 && !DoGC) ICFLevel = 0; Config->DoGC = DoGC; Config->DoICF = ICFLevel > 0; + Config->TailMerge = (TailMerge == 1 && Config->DoICF) || TailMerge == 2; // Handle /lldsavetemps if (Args.hasArg(OPT_lldsavetemps)) Config->SaveTemps = true; // Handle /kill-at if (Args.hasArg(OPT_kill_at)) Config->KillAt = true; // Handle /lldltocache if (auto *Arg = Args.getLastArg(OPT_lldltocache)) Config->LTOCache = Arg->getValue(); // Handle /lldsavecachepolicy if (auto *Arg = Args.getLastArg(OPT_lldltocachepolicy)) Config->LTOCachePolicy = CHECK( parseCachePruningPolicy(Arg->getValue()), Twine("/lldltocachepolicy: invalid cache policy: ") + Arg->getValue()); // Handle /failifmismatch for (auto *Arg : Args.filtered(OPT_failifmismatch)) checkFailIfMismatch(Arg->getValue()); // Handle /merge for (auto *Arg : Args.filtered(OPT_merge)) parseMerge(Arg->getValue()); + // Add default section merging rules after user rules. User rules take + // precedence, but we will emit a warning if there is a conflict. + parseMerge(".idata=.rdata"); + parseMerge(".didat=.rdata"); + parseMerge(".edata=.rdata"); + parseMerge(".xdata=.rdata"); + parseMerge(".bss=.data"); + // Handle /section for (auto *Arg : Args.filtered(OPT_section)) parseSection(Arg->getValue()); // Handle /aligncomm for (auto *Arg : Args.filtered(OPT_aligncomm)) parseAligncomm(Arg->getValue()); // Handle /manifestdependency. This enables /manifest unless /manifest:no is // also passed. if (auto *Arg = Args.getLastArg(OPT_manifestdependency)) { Config->ManifestDependency = Arg->getValue(); Config->Manifest = Configuration::SideBySide; } // Handle /manifest and /manifest: if (auto *Arg = Args.getLastArg(OPT_manifest, OPT_manifest_colon)) { if (Arg->getOption().getID() == OPT_manifest) Config->Manifest = Configuration::SideBySide; else parseManifest(Arg->getValue()); } // Handle /manifestuac if (auto *Arg = Args.getLastArg(OPT_manifestuac)) parseManifestUAC(Arg->getValue()); // Handle /manifestfile if (auto *Arg = Args.getLastArg(OPT_manifestfile)) Config->ManifestFile = Arg->getValue(); // Handle /manifestinput for (auto *Arg : Args.filtered(OPT_manifestinput)) Config->ManifestInput.push_back(Arg->getValue()); if (!Config->ManifestInput.empty() && Config->Manifest != Configuration::Embed) { - fatal("/MANIFESTINPUT: requires /MANIFEST:EMBED"); + fatal("/manifestinput: requires /manifest:embed"); } // Handle miscellaneous boolean flags. Config->AllowBind = Args.hasFlag(OPT_allowbind, OPT_allowbind_no, true); Config->AllowIsolation = Args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true); + Config->Incremental = + Args.hasFlag(OPT_incremental, OPT_incremental_no, + !Config->DoGC && !Config->DoICF && !Args.hasArg(OPT_order) && + !Args.hasArg(OPT_profile)); + Config->IntegrityCheck = + Args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false); Config->NxCompat = Args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true); - Config->TerminalServerAware = Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true); + Config->TerminalServerAware = + !Config->DLL && Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true); Config->DebugDwarf = Args.hasArg(OPT_debug_dwarf); Config->DebugGHashes = Args.hasArg(OPT_debug_ghash); + Config->DebugSymtab = Args.hasArg(OPT_debug_symtab); Config->MapFile = getMapFile(Args); + if (Config->Incremental && Args.hasArg(OPT_profile)) { + warn("ignoring '/incremental' due to '/profile' specification"); + Config->Incremental = false; + } + + if (Config->Incremental && Args.hasArg(OPT_order)) { + warn("ignoring '/incremental' due to '/order' specification"); + Config->Incremental = false; + } + + if (Config->Incremental && Config->DoGC) { + warn("ignoring '/incremental' because REF is enabled; use '/opt:noref' to " + "disable"); + Config->Incremental = false; + } + + if (Config->Incremental && Config->DoICF) { + warn("ignoring '/incremental' because ICF is enabled; use '/opt:noicf' to " + "disable"); + Config->Incremental = false; + } + if (errorCount()) return; - bool WholeArchiveFlag = Args.hasArg(OPT_wholearchive_flag); + std::set WholeArchives; + for (auto *Arg : Args.filtered(OPT_wholearchive_file)) + if (Optional Path = doFindFile(Arg->getValue())) + if (Optional ID = getUniqueID(*Path)) + WholeArchives.insert(*ID); + + // A predicate returning true if a given path is an argument for + // /wholearchive:, or /wholearchive is enabled globally. + // This function is a bit tricky because "foo.obj /wholearchive:././foo.obj" + // needs to be handled as "/wholearchive:foo.obj foo.obj". + auto IsWholeArchive = [&](StringRef Path) -> bool { + if (Args.hasArg(OPT_wholearchive_flag)) + return true; + if (Optional ID = getUniqueID(Path)) + return WholeArchives.count(*ID); + return false; + }; + // Create a list of input files. Files can be given as arguments // for /defaultlib option. - std::vector MBs; - for (auto *Arg : Args.filtered(OPT_INPUT, OPT_wholearchive_file)) { - switch (Arg->getOption().getID()) { - case OPT_INPUT: - if (Optional Path = findFile(Arg->getValue())) - enqueuePath(*Path, WholeArchiveFlag); - break; - case OPT_wholearchive_file: - if (Optional Path = findFile(Arg->getValue())) - enqueuePath(*Path, true); - break; - } - } + for (auto *Arg : Args.filtered(OPT_INPUT, OPT_wholearchive_file)) + if (Optional Path = findFile(Arg->getValue())) + enqueuePath(*Path, IsWholeArchive(*Path)); + for (auto *Arg : Args.filtered(OPT_defaultlib)) if (Optional Path = findLib(Arg->getValue())) enqueuePath(*Path, false); // Windows specific -- Create a resource file containing a manifest file. if (Config->Manifest == Configuration::Embed) addBuffer(createManifestRes(), false); // Read all input files given via the command line. run(); // We should have inferred a machine type by now from the input files, but if // not we assume x64. if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { warn("/machine is not specified. x64 is assumed"); Config->Machine = AMD64; } // Input files can be Windows resource files (.res files). We use // WindowsResource to convert resource files to a regular COFF file, // then link the resulting file normally. if (!Resources.empty()) Symtab->addFile(make(convertResToCOFF(Resources))); if (Tar) Tar->append("response.txt", createResponseFile(Args, FilePaths, ArrayRef(SearchPaths).slice(1))); // Handle /largeaddressaware Config->LargeAddressAware = Args.hasFlag( OPT_largeaddressaware, OPT_largeaddressaware_no, Config->is64()); // Handle /highentropyva Config->HighEntropyVA = Config->is64() && Args.hasFlag(OPT_highentropyva, OPT_highentropyva_no, true); if (!Config->DynamicBase && (Config->Machine == ARMNT || Config->Machine == ARM64)) error("/dynamicbase:no is not compatible with " + machineToStr(Config->Machine)); // Handle /entry and /dll if (auto *Arg = Args.getLastArg(OPT_entry)) { Config->Entry = addUndefined(mangle(Arg->getValue())); } else if (!Config->Entry && !Config->NoEntry) { if (Args.hasArg(OPT_dll)) { StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12" : "_DllMainCRTStartup"; Config->Entry = addUndefined(S); } else { // 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()) fatal("entry point must be defined"); Config->Entry = addUndefined(S); log("Entry name inferred: " + S); } } // Handle /export for (auto *Arg : Args.filtered(OPT_export)) { Export E = parseExport(Arg->getValue()); if (Config->Machine == I386) { if (!isDecorated(E.Name)) E.Name = Saver.save("_" + E.Name); if (!E.ExtName.empty() && !isDecorated(E.ExtName)) E.ExtName = Saver.save("_" + E.ExtName); } Config->Exports.push_back(E); } // Handle /def if (auto *Arg = Args.getLastArg(OPT_deffile)) { // parseModuleDefs mutates Config object. parseModuleDefs(Arg->getValue()); } // Handle generation of import library from a def file. if (!Args.hasArg(OPT_INPUT)) { fixupExports(); createImportLibrary(/*AsLib=*/true); return; } // 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 name if neither /out or /def set it. if (Config->OutputFile.empty()) { Config->OutputFile = getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue()); } - // Put the PDB next to the image if no /pdb flag was passed. - if (ShouldCreatePDB && Config->PDBPath.empty()) { - Config->PDBPath = Config->OutputFile; - sys::path::replace_extension(Config->PDBPath, ".pdb"); + if (ShouldCreatePDB) { + // Put the PDB next to the image if no /pdb flag was passed. + if (Config->PDBPath.empty()) { + Config->PDBPath = Config->OutputFile; + sys::path::replace_extension(Config->PDBPath, ".pdb"); + } + + // The embedded PDB path should be the absolute path to the PDB if no + // /pdbaltpath flag was passed. + if (Config->PDBAltPath.empty()) { + Config->PDBAltPath = Config->PDBPath; + + // It's important to make the path absolute and remove dots. This path + // will eventually be written into the PE header, and certain Microsoft + // tools won't work correctly if these assumptions are not held. + sys::fs::make_absolute(Config->PDBAltPath); + sys::path::remove_dots(Config->PDBAltPath); + } } // Set default image base if /base is not given. if (Config->ImageBase == uint64_t(-1)) Config->ImageBase = getDefaultImageBase(); Symtab->addSynthetic(mangle("__ImageBase"), nullptr); if (Config->Machine == I386) { Symtab->addAbsolute("___safe_se_handler_table", 0); 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_count"), 0); Symtab->addAbsolute(mangle("__guard_fids_table"), 0); - Symtab->addAbsolute(mangle("__guard_flags"), 0x100); + Symtab->addAbsolute(mangle("__guard_flags"), 0); Symtab->addAbsolute(mangle("__guard_iat_count"), 0); Symtab->addAbsolute(mangle("__guard_iat_table"), 0); Symtab->addAbsolute(mangle("__guard_longjmp_count"), 0); Symtab->addAbsolute(mangle("__guard_longjmp_table"), 0); // Needed for MSVC 2017 15.5 CRT. Symtab->addAbsolute(mangle("__enclave_config"), 0); // This code may add new undefined symbols to the link, which may enqueue more // symbol resolution tasks, so we need to continue executing tasks until we // converge. do { // 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)) 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")); } while (run()); if (errorCount()) return; // If /msvclto is given, we use the MSVC linker to link LTO output files. // This is useful because MSVC link.exe can generate complete PDBs. if (Args.hasArg(OPT_msvclto)) { invokeMSVC(Args); return; } // Do LTO by compiling bitcode input files to a set of native COFF files then // link those files. Symtab->addCombinedLTOObjects(); run(); // Make sure we have resolved all symbols. Symtab->reportRemainingUndefines(); if (errorCount()) return; // 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) fatal("subsystem must be defined"); } // Handle /safeseh. if (Args.hasFlag(OPT_safeseh, OPT_safeseh_no, false)) { for (ObjFile *File : ObjFile::Instances) - if (!File->SEHCompat) + if (!File->hasSafeSEH()) error("/safeseh: " + File->getName() + " is not compatible with SEH"); if (errorCount()) return; } // In MinGW, all symbols are automatically exported if no symbols // are chosen to be exported. if (Config->DLL && ((Config->MinGW && Config->Exports.empty()) || Args.hasArg(OPT_export_all_symbols))) { AutoExporter Exporter; Symtab->forEachSymbol([=](Symbol *S) { auto *Def = dyn_cast(S); if (!Exporter.shouldExport(Def)) return; Export E; E.Name = Def->getName(); E.Sym = Def; if (Def->getChunk() && - !(Def->getChunk()->getPermissions() & IMAGE_SCN_MEM_EXECUTE)) + !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) E.Data = true; Config->Exports.push_back(E); }); } // Windows specific -- when we are creating a .dll file, we also // need to create a .lib file. if (!Config->Exports.empty() || Config->DLL) { fixupExports(); createImportLibrary(/*AsLib=*/false); assignExportOrdinals(); } // Handle /output-def (MinGW specific). if (auto *Arg = Args.getLastArg(OPT_output_def)) writeDefFile(Arg->getValue()); // Set extra alignment for .comm symbols for (auto Pair : Config->AlignComm) { StringRef Name = Pair.first; uint32_t Alignment = Pair.second; Symbol *Sym = Symtab->find(Name); if (!Sym) { warn("/aligncomm symbol " + Name + " not found"); continue; } auto *DC = dyn_cast(Sym); if (!DC) { warn("/aligncomm symbol " + Name + " of wrong kind"); continue; } CommonChunk *C = DC->getChunk(); C->Alignment = std::max(C->Alignment, Alignment); } // Windows specific -- Create a side-by-side manifest file. if (Config->Manifest == Configuration::SideBySide) createSideBySideManifest(); + // Handle /order. We want to do this at this moment because we + // need a complete list of comdat sections to warn on nonexistent + // functions. + if (auto *Arg = Args.getLastArg(OPT_order)) + parseOrderFile(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(); + + // Stop early so we can print the results. + Timer::root().stop(); + if (Config->ShowTiming) + Timer::root().print(); } } // namespace coff } // namespace lld Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/Driver.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/Driver.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/Driver.h (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/Driver.h (revision 336982) @@ -1,196 +1,199 @@ //===- Driver.h -------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_COFF_DRIVER_H #define LLD_COFF_DRIVER_H #include "Config.h" #include "SymbolTable.h" #include "lld/Common/LLVM.h" #include "lld/Common/Reproduce.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFF.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/TarWriter.h" #include #include #include namespace lld { namespace coff { class LinkerDriver; extern LinkerDriver *Driver; using llvm::COFF::MachineTypes; using llvm::COFF::WindowsSubsystem; using llvm::Optional; -// Implemented in MarkLive.cpp. -void markLive(ArrayRef Chunks); - -// Implemented in ICF.cpp. -void doICF(ArrayRef Chunks); - class COFFOptTable : public llvm::opt::OptTable { public: COFFOptTable(); }; class ArgParser { public: // Concatenate LINK environment variable and given arguments and parse them. llvm::opt::InputArgList parseLINK(std::vector Args); // Tokenizes a given string and then parses as command line options. llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); } // Tokenizes a given string and then parses as command line options in - // .drectve section. - llvm::opt::InputArgList parseDirectives(StringRef S); + // .drectve section. /EXPORT options are returned in second element + // to be processed in fastpath. + std::pair> + parseDirectives(StringRef S); private: // Parses command line options. llvm::opt::InputArgList parse(llvm::ArrayRef Args); std::vector tokenize(StringRef S); COFFOptTable Table; }; class LinkerDriver { public: void link(llvm::ArrayRef Args); // Used by the resolver to parse .drectve section contents. void parseDirectives(StringRef S); // Used by ArchiveFile to enqueue members. void enqueueArchiveMember(const Archive::Child &C, StringRef SymName, StringRef ParentName); MemoryBufferRef takeBuffer(std::unique_ptr MB); private: std::unique_ptr Tar; // for /linkrepro // Opens a file. Path has to be resolved already. MemoryBufferRef openFile(StringRef Path); // Searches a file from search paths. Optional findFile(StringRef Filename); Optional findLib(StringRef Filename); StringRef doFindFile(StringRef Filename); StringRef doFindLib(StringRef Filename); // Parses LIB environment which contains a list of search paths. void addLibSearchPaths(); // Library search path. The first element is always "" (current directory). std::vector SearchPaths; - std::set VisitedFiles; + + // We don't want to add the same file more than once. + // Files are uniquified by their filesystem and file number. + std::set VisitedFiles; + std::set VisitedLibs; Symbol *addUndefined(StringRef Sym); StringRef mangle(StringRef Sym); // Windows specific -- "main" is not the only main function in Windows. // You can choose one from these four -- {w,}{WinMain,main}. // There are four different entry point functions for them, // {w,}{WinMain,main}CRTStartup, respectively. The linker needs to // choose the right one depending on which "main" function is defined. // This function looks up the symbol table and resolve corresponding // entry point name. StringRef findDefaultEntry(); WindowsSubsystem inferSubsystem(); void invokeMSVC(llvm::opt::InputArgList &Args); void addBuffer(std::unique_ptr MB, bool WholeArchive); void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName, StringRef ParentName); void enqueuePath(StringRef Path, bool WholeArchive); void enqueueTask(std::function Task); bool run(); std::list> TaskQueue; std::vector FilePaths; std::vector Resources; llvm::StringSet<> DirectivesExports; }; // Functions below this line are defined in DriverUtils.cpp. void printHelp(const char *Argv0); // For /machine option. MachineTypes getMachineType(StringRef Arg); StringRef machineToStr(MachineTypes MT); // Parses a string in the form of "[,]". void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr); + +void parseGuard(StringRef Arg); // Parses a string in the form of "[.]". // Minor's default value is 0. void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor); // Parses a string in the form of "[,[.]]". void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, uint32_t *Minor); void parseAlternateName(StringRef); void parseMerge(StringRef); void parseSection(StringRef); void parseAligncomm(StringRef); // Parses a string in the form of "EMBED[,=]|NO". void parseManifest(StringRef Arg); // Parses a string in the form of "level=|uiAccess=" void parseManifestUAC(StringRef Arg); // Create a resource file containing a manifest XML. std::unique_ptr createManifestRes(); void createSideBySideManifest(); // Used for dllexported symbols. Export parseExport(StringRef Arg); void fixupExports(); void assignExportOrdinals(); // Parses a string in the form of "key=value" and check // if value matches previous values for the key. // This feature used in the directive section to reject // incompatible objects. void checkFailIfMismatch(StringRef Arg); // Convert Windows resource files (.res files) to a .obj file. MemoryBufferRef convertResToCOFF(ArrayRef MBs); void runMSVCLinker(std::string Rsp, ArrayRef Objects); // Create enum with OPT_xxx values for each option in Options.td enum { OPT_INVALID = 0, #define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, #include "Options.inc" #undef OPTION }; } // namespace coff } // namespace lld #endif Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/Driver.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/DriverUtils.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/DriverUtils.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/DriverUtils.cpp (revision 336982) @@ -1,825 +1,890 @@ //===- 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 "Symbols.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/COFF.h" #include "llvm/Object/WindowsResource.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/MathExtras.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" #include "llvm/WindowsManifest/WindowsManifestMerger.h" #include using namespace llvm::COFF; using namespace llvm; using llvm::sys::Process; namespace lld { namespace coff { namespace { const uint16_t SUBLANG_ENGLISH_US = 0x0409; const uint16_t RT_MANIFEST = 24; class Executor { public: explicit Executor(StringRef S) : 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 = sys::findProgramByName(Prog); if (auto EC = ExeOrErr.getError()) fatal("unable to find " + Prog + " in PATH: " + EC.message()); StringRef Exe = Saver.save(*ExeOrErr); Args.insert(Args.begin(), Exe); - std::vector Vec; - for (StringRef S : Args) - Vec.push_back(S.data()); - Vec.push_back(nullptr); - - if (sys::ExecuteAndWait(Args[0], Vec.data()) != 0) + if (sys::ExecuteAndWait(Args[0], Args) != 0) fatal("ExecuteAndWait failed: " + llvm::join(Args.begin(), Args.end(), " ")); } private: StringRef Prog; std::vector Args; }; } // anonymous namespace // Returns /machine's value. MachineTypes getMachineType(StringRef S) { MachineTypes MT = StringSwitch(S.lower()) .Cases("x64", "amd64", AMD64) .Cases("x86", "i386", I386) .Case("arm", ARMNT) .Case("arm64", ARM64) .Default(IMAGE_FILE_MACHINE_UNKNOWN); if (MT != IMAGE_FILE_MACHINE_UNKNOWN) return MT; fatal("unknown /machine argument: " + S); } StringRef machineToStr(MachineTypes MT) { switch (MT) { case ARMNT: return "arm"; case ARM64: return "arm64"; 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)) fatal("invalid number: " + S1); if (Size && !S2.empty() && S2.getAsInteger(0, *Size)) fatal("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)) fatal("invalid number: " + S1); *Minor = 0; if (!S2.empty() && S2.getAsInteger(0, *Minor)) fatal("invalid number: " + S2); } +void parseGuard(StringRef FullArg) { + SmallVector SplitArgs; + FullArg.split(SplitArgs, ","); + for (StringRef Arg : SplitArgs) { + if (Arg.equals_lower("no")) + Config->GuardCF = GuardCFLevel::Off; + else if (Arg.equals_lower("nolongjmp")) + Config->GuardCF = GuardCFLevel::NoLongJmp; + else if (Arg.equals_lower("cf") || Arg.equals_lower("longjmp")) + Config->GuardCF = GuardCFLevel::Full; + else + fatal("invalid argument to /guard: " + Arg); + } +} + // 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) fatal("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()) fatal("/alternatename: invalid argument: " + S); auto It = Config->AlternateNames.find(From); if (It != Config->AlternateNames.end() && It->second != To) fatal("/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()) fatal("/merge: invalid argument: " + S); + if (From == ".rsrc" || To == ".rsrc") + fatal("/merge: cannot merge '.rsrc' with any section"); + if (From == ".reloc" || To == ".reloc") + fatal("/merge: cannot merge '.reloc' with any section"); auto Pair = Config->Merge.insert(std::make_pair(From, To)); bool Inserted = Pair.second; if (!Inserted) { StringRef Existing = Pair.first->second; if (Existing != To) warn(S + ": already merged into " + Existing); } } static uint32_t parseSectionAttributes(StringRef S) { uint32_t Ret = 0; for (char C : S.lower()) { switch (C) { case 'd': Ret |= IMAGE_SCN_MEM_DISCARDABLE; break; case 'e': Ret |= IMAGE_SCN_MEM_EXECUTE; break; case 'k': Ret |= IMAGE_SCN_MEM_NOT_CACHED; break; case 'p': Ret |= IMAGE_SCN_MEM_NOT_PAGED; break; case 'r': Ret |= IMAGE_SCN_MEM_READ; break; case 's': Ret |= IMAGE_SCN_MEM_SHARED; break; case 'w': Ret |= IMAGE_SCN_MEM_WRITE; break; default: fatal("/section: invalid argument: " + S); } } return Ret; } // Parses /section option argument. void parseSection(StringRef S) { StringRef Name, Attrs; std::tie(Name, Attrs) = S.split(','); if (Name.empty() || Attrs.empty()) fatal("/section: invalid argument: " + S); Config->Section[Name] = parseSectionAttributes(Attrs); } // Parses /aligncomm option argument. void parseAligncomm(StringRef S) { StringRef Name, Align; std::tie(Name, Align) = S.split(','); if (Name.empty() || Align.empty()) { error("/aligncomm: invalid argument: " + S); return; } int V; if (Align.getAsInteger(0, V)) { error("/aligncomm: invalid argument: " + S); return; } Config->AlignComm[Name] = std::max(Config->AlignComm[Name], 1 << V); } // 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")) fatal("invalid option " + Arg); Config->Manifest = Configuration::Embed; Arg = Arg.substr(strlen("embed")); if (Arg.empty()) return; if (!Arg.startswith_lower(",id=")) fatal("invalid option " + Arg); Arg = Arg.substr(strlen(",id=")); if (Arg.getAsInteger(0, Config->ManifestID)) fatal("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; } fatal("invalid option " + Arg); } } // An RAII temporary file class that automatically removes a temporary file. namespace { class TemporaryFile { public: TemporaryFile(StringRef Prefix, StringRef Extn, StringRef Contents = "") { SmallString<128> S; if (auto EC = sys::fs::createTemporaryFile("lld-" + Prefix, Extn, S)) fatal("cannot create a temporary file: " + EC.message()); Path = S.str(); if (!Contents.empty()) { std::error_code EC; raw_fd_ostream OS(Path, EC, sys::fs::F_None); if (EC) fatal("failed to open " + Path + ": " + EC.message()); OS << Contents; } } TemporaryFile(TemporaryFile &&Obj) { std::swap(Path, Obj.Path); } ~TemporaryFile() { if (Path.empty()) return; if (sys::fs::remove(Path)) fatal("failed to remove " + Path); } // Returns a memory buffer of this temporary file. // Note that this function does not leave the file open, // so it is safe to remove the file immediately after this function // is called (you cannot remove an opened file on Windows.) std::unique_ptr getMemoryBuffer() { // IsVolatileSize=true forces MemoryBuffer to not use mmap(). return CHECK(MemoryBuffer::getFile(Path, /*FileSize=*/-1, /*RequiresNullTerminator=*/false, /*IsVolatileSize=*/true), "could not open " + Path); } std::string Path; }; } static std::string createDefaultXml() { std::string Ret; raw_string_ostream OS(Ret); // 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"; return OS.str(); } static std::string createManifestXmlWithInternalMt(StringRef DefaultXml) { std::unique_ptr DefaultXmlCopy = MemoryBuffer::getMemBufferCopy(DefaultXml); windows_manifest::WindowsManifestMerger Merger; if (auto E = Merger.merge(*DefaultXmlCopy.get())) fatal("internal manifest tool failed on default xml: " + toString(std::move(E))); for (StringRef Filename : Config->ManifestInput) { std::unique_ptr Manifest = check(MemoryBuffer::getFile(Filename)); if (auto E = Merger.merge(*Manifest.get())) fatal("internal manifest tool failed on file " + Filename + ": " + toString(std::move(E))); } return Merger.getMergedManifest().get()->getBuffer(); } static std::string createManifestXmlWithExternalMt(StringRef DefaultXml) { // Create the default manifest file as a temporary file. TemporaryFile Default("defaultxml", "manifest"); std::error_code EC; raw_fd_ostream OS(Default.Path, EC, sys::fs::F_Text); if (EC) fatal("failed to open " + Default.Path + ": " + EC.message()); OS << DefaultXml; OS.close(); // Merge user-supplied manifests if they are given. Since libxml2 is not // enabled, we must shell out to Microsoft's mt.exe tool. TemporaryFile User("user", "manifest"); Executor E("mt.exe"); E.add("/manifest"); E.add(Default.Path); for (StringRef Filename : Config->ManifestInput) { E.add("/manifest"); E.add(Filename); } E.add("/nologo"); E.add("/out:" + StringRef(User.Path)); E.run(); return CHECK(MemoryBuffer::getFile(User.Path), "could not open " + User.Path) .get() ->getBuffer(); } static std::string createManifestXml() { std::string DefaultXml = createDefaultXml(); if (Config->ManifestInput.empty()) return DefaultXml; if (windows_manifest::isAvailable()) return createManifestXmlWithInternalMt(DefaultXml); return createManifestXmlWithExternalMt(DefaultXml); } -static std::unique_ptr +static std::unique_ptr createMemoryBufferForManifestRes(size_t ManifestSize) { size_t ResSize = alignTo( object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE + sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) + sizeof(object::WinResHeaderSuffix) + ManifestSize, object::WIN_RES_DATA_ALIGNMENT); - return MemoryBuffer::getNewMemBuffer(ResSize, - Config->OutputFile + ".manifest.res"); + return WritableMemoryBuffer::getNewMemBuffer(ResSize, Config->OutputFile + + ".manifest.res"); } static void writeResFileHeader(char *&Buf) { memcpy(Buf, COFF::WinResMagic, sizeof(COFF::WinResMagic)); Buf += sizeof(COFF::WinResMagic); memset(Buf, 0, object::WIN_RES_NULL_ENTRY_SIZE); Buf += object::WIN_RES_NULL_ENTRY_SIZE; } static void writeResEntryHeader(char *&Buf, size_t ManifestSize) { // Write the prefix. auto *Prefix = reinterpret_cast(Buf); Prefix->DataSize = ManifestSize; Prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) + sizeof(object::WinResHeaderSuffix); Buf += sizeof(object::WinResHeaderPrefix); // Write the Type/Name IDs. auto *IDs = reinterpret_cast(Buf); IDs->setType(RT_MANIFEST); IDs->setName(Config->ManifestID); Buf += sizeof(object::WinResIDs); // Write the suffix. auto *Suffix = reinterpret_cast(Buf); Suffix->DataVersion = 0; Suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE; Suffix->Language = SUBLANG_ENGLISH_US; Suffix->Version = 0; Suffix->Characteristics = 0; Buf += sizeof(object::WinResHeaderSuffix); } // Create a resource file containing a manifest XML. std::unique_ptr createManifestRes() { std::string Manifest = createManifestXml(); - std::unique_ptr Res = + std::unique_ptr Res = createMemoryBufferForManifestRes(Manifest.size()); - char *Buf = const_cast(Res->getBufferStart()); + char *Buf = Res->getBufferStart(); writeResFileHeader(Buf); writeResEntryHeader(Buf, Manifest.size()); // Copy the manifest data into the .res file. std::copy(Manifest.begin(), Manifest.end(), Buf); - return Res; + return std::move(Res); } void createSideBySideManifest() { std::string Path = Config->ManifestFile; if (Path == "") Path = Config->OutputFile + ".manifest"; std::error_code EC; raw_fd_ostream Out(Path, EC, sys::fs::F_Text); if (EC) fatal("failed to create manifest: " + EC.message()); Out << createManifestXml(); } // Parse a string in the form of // "[=][,@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.contains('=')) { StringRef X, Y; std::tie(X, Y) = E.Name.split("="); // If "=.". if (Y.contains(".")) { 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("constant")) { E.Constant = 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: fatal("invalid /export: " + Arg); } static StringRef undecorate(StringRef Sym) { if (Config->Machine != I386) return Sym; + // In MSVC mode, a fully decorated stdcall function is exported + // as-is with the leading underscore (with type IMPORT_NAME). + // In MinGW mode, a decorated stdcall function gets the underscore + // removed, just like normal cdecl functions. + if (Sym.startswith("_") && Sym.contains('@') && !Config->MinGW) + return Sym; return Sym.startswith("_") ? Sym.substr(1) : Sym; } // Convert stdcall/fastcall style symbols into unsuffixed symbols, // with or without a leading underscore. (MinGW specific.) static StringRef killAt(StringRef Sym, bool Prefix) { if (Sym.empty()) return Sym; // Strip any trailing stdcall suffix Sym = Sym.substr(0, Sym.find('@', 1)); if (!Sym.startswith("@")) { if (Prefix && !Sym.startswith("_")) return Saver.save("_" + Sym); return Sym; } // For fastcall, remove the leading @ and replace it with an // underscore, if prefixes are used. Sym = Sym.substr(1); if (Prefix) Sym = Saver.save("_" + Sym); return 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) fatal("duplicate export ordinal: " + E.Name); } for (Export &E : Config->Exports) { Symbol *Sym = E.Sym; if (!E.ForwardTo.empty() || !Sym) { E.SymbolName = E.Name; } else { if (auto *U = dyn_cast(Sym)) if (U->WeakAlias) Sym = U->WeakAlias; E.SymbolName = Sym->getName(); } } 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); } } if (Config->KillAt && Config->Machine == I386) { for (Export &E : Config->Exports) { E.Name = killAt(E.Name, true); E.ExportName = killAt(E.ExportName, false); E.ExtName = killAt(E.ExtName, true); E.SymbolName = killAt(E.SymbolName, true); } } // Uniquefy by name. DenseMap Map(Config->Exports.size()); 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; warn("duplicate /export option: " + E.Name); } 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()) fatal("/failifmismatch: invalid argument: " + Arg); StringRef Existing = Config->MustMatch[K]; if (!Existing.empty() && V != Existing) fatal("/failifmismatch: mismatch detected: " + Existing + " and " + V + " for key " + K); Config->MustMatch[K] = V; } // Convert Windows resource files (.res files) to a .obj file. MemoryBufferRef convertResToCOFF(ArrayRef MBs) { object::WindowsResourceParser Parser; for (MemoryBufferRef MB : MBs) { std::unique_ptr Bin = check(object::createBinary(MB)); object::WindowsResource *RF = dyn_cast(Bin.get()); if (!RF) fatal("cannot compile non-resource file as resource"); if (auto EC = Parser.parse(RF)) fatal("failed to parse .res file: " + toString(std::move(EC))); } Expected> E = llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser); if (!E) fatal("failed to write .res to COFF: " + toString(E.takeError())); MemoryBufferRef MBRef = **E; make>(std::move(*E)); // take ownership return MBRef; } // Run MSVC link.exe for given in-memory object files. // Command line options are copied from those given to LLD. // This is for the /msvclto option. void runMSVCLinker(std::string Rsp, ArrayRef Objects) { // Write the in-memory object files to disk. std::vector Temps; for (StringRef S : Objects) { Temps.emplace_back("lto", "obj", S); Rsp += quote(Temps.back().Path) + "\n"; } log("link.exe " + Rsp); // Run MSVC link.exe. Temps.emplace_back("lto", "rsp", Rsp); Executor E("link.exe"); E.add(Twine("@" + Temps.back().Path)); E.run(); } // 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, X7, X8, X9, X10, X11, X12) \ {X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, \ X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, #include "Options.inc" #undef OPTION }; COFFOptTable::COFFOptTable() : OptTable(InfoTable, true) {} +// Set color diagnostics according to --color-diagnostics={auto,always,never} +// or --no-color-diagnostics flags. +static void handleColorDiagnostics(opt::InputArgList &Args) { + auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, + OPT_no_color_diagnostics); + if (!Arg) + return; + if (Arg->getOption().getID() == OPT_color_diagnostics) { + errorHandler().ColorDiagnostics = true; + } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) { + errorHandler().ColorDiagnostics = false; + } else { + StringRef S = Arg->getValue(); + if (S == "always") + errorHandler().ColorDiagnostics = true; + else if (S == "never") + errorHandler().ColorDiagnostics = false; + else if (S != "auto") + error("unknown option: --color-diagnostics=" + S); + } +} + static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) { if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) { StringRef S = Arg->getValue(); if (S != "windows" && S != "posix") error("invalid response file quoting: " + S); if (S == "windows") return cl::TokenizeWindowsCommandLine; return cl::TokenizeGNUCommandLine; } // The COFF linker always defaults to Windows quoting. return cl::TokenizeWindowsCommandLine; } // Parses a given list of options. opt::InputArgList ArgParser::parse(ArrayRef Argv) { // Make InputArgList from string vectors. unsigned MissingIndex; unsigned MissingCount; - SmallVector Vec(Argv.data(), Argv.data() + Argv.size()); // We need to get the quoting style for response files before parsing all // options so we parse here before and ignore all the options but // --rsp-quoting. - opt::InputArgList Args = Table.ParseArgs(Vec, MissingIndex, MissingCount); + opt::InputArgList Args = Table.ParseArgs(Argv, MissingIndex, MissingCount); // Expand response files (arguments in the form of @) // and then parse the argument again. - cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec); - Args = Table.ParseArgs(Vec, MissingIndex, MissingCount); + SmallVector ExpandedArgv(Argv.data(), Argv.data() + Argv.size()); + cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), ExpandedArgv); + Args = Table.ParseArgs(makeArrayRef(ExpandedArgv).drop_front(), MissingIndex, + MissingCount); // Print the real command line if response files are expanded. - if (Args.hasArg(OPT_verbose) && Argv.size() != Vec.size()) { + if (Args.hasArg(OPT_verbose) && Argv.size() != ExpandedArgv.size()) { std::string Msg = "Command line:"; - for (const char *S : Vec) + for (const char *S : ExpandedArgv) Msg += " " + std::string(S); message(Msg); } + // Save the command line after response file expansion so we can write it to + // the PDB if necessary. + Config->Argv = {ExpandedArgv.begin(), ExpandedArgv.end()}; + // Handle /WX early since it converts missing argument warnings to errors. errorHandler().FatalWarnings = Args.hasFlag(OPT_WX, OPT_WX_no, false); if (MissingCount) fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); + + handleColorDiagnostics(Args); + for (auto *Arg : Args.filtered(OPT_UNKNOWN)) warn("ignoring unknown argument: " + Arg->getSpelling()); + + if (Args.hasArg(OPT_lib)) + warn("ignoring /lib since it's not the first argument"); + return Args; } // Tokenizes and parses a given string as command line in .drective section. -opt::InputArgList ArgParser::parseDirectives(StringRef S) { - // Make InputArgList from string vectors. +// /EXPORT options are processed in fastpath. +std::pair> +ArgParser::parseDirectives(StringRef S) { + std::vector Exports; + SmallVector Rest; + + for (StringRef Tok : tokenize(S)) { + if (Tok.startswith_lower("/export:") || Tok.startswith_lower("-export:")) + Exports.push_back(Tok.substr(strlen("/export:"))); + else + Rest.push_back(Tok.data()); + } + + // Make InputArgList from unparsed string vectors. unsigned MissingIndex; unsigned MissingCount; - opt::InputArgList Args = - Table.ParseArgs(tokenize(S), MissingIndex, MissingCount); + opt::InputArgList Args = Table.ParseArgs(Rest, MissingIndex, MissingCount); if (MissingCount) fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); for (auto *Arg : Args.filtered(OPT_UNKNOWN)) warn("ignoring unknown argument: " + Arg->getSpelling()); - return Args; + return {std::move(Args), std::move(Exports)}; } // link.exe has an interesting feature. If LINK or _LINK_ environment // variables exist, their contents are handled as command line strings. // So you can pass extra arguments using them. opt::InputArgList ArgParser::parseLINK(std::vector Argv) { // Concatenate LINK env and command line arguments, and then parse them. if (Optional S = Process::GetEnv("LINK")) { std::vector V = tokenize(*S); - Argv.insert(Argv.begin(), V.begin(), V.end()); + Argv.insert(std::next(Argv.begin()), V.begin(), V.end()); } if (Optional S = Process::GetEnv("_LINK_")) { std::vector V = tokenize(*S); - Argv.insert(Argv.begin(), V.begin(), V.end()); + Argv.insert(std::next(Argv.begin()), V.begin(), V.end()); } return parse(Argv); } std::vector ArgParser::tokenize(StringRef S) { SmallVector Tokens; cl::TokenizeWindowsCommandLine(S, Saver, Tokens); return std::vector(Tokens.begin(), Tokens.end()); } void printHelp(const char *Argv0) { COFFOptTable().PrintHelp(outs(), Argv0, "LLVM Linker", false); } } // namespace coff } // namespace lld Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/DriverUtils.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/ICF.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/ICF.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/ICF.cpp (revision 336982) @@ -1,263 +1,307 @@ //===- 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 "ICF.h" #include "Chunks.h" #include "Symbols.h" #include "lld/Common/ErrorHandler.h" +#include "lld/Common/Timer.h" #include "llvm/ADT/Hashing.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Parallel.h" #include "llvm/Support/raw_ostream.h" #include #include #include using namespace llvm; namespace lld { namespace coff { +static Timer ICFTimer("ICF", Timer::root()); + class ICF { public: void run(ArrayRef V); private: void segregate(size_t Begin, size_t End, bool Constant); + bool assocEquals(const SectionChunk *A, const SectionChunk *B); + 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 forEachClassRange(size_t Begin, size_t End, std::function Fn); void forEachClass(std::function Fn); std::vector Chunks; int Cnt = 0; std::atomic Repeat = {false}; }; // Returns a hash value for S. uint32_t ICF::getHash(SectionChunk *C) { - return hash_combine(C->getPermissions(), C->SectionName, C->NumRelocs, - C->Alignment, uint32_t(C->Header->SizeOfRawData), + return hash_combine(C->getOutputCharacteristics(), C->SectionName, + C->Relocs.size(), uint32_t(C->Header->SizeOfRawData), C->Checksum, C->getContents()); } // 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. However, we merge -// identical .xdata sections, because the address of unwind information is -// insignificant to the user program and the Visual C++ linker does this. +// Therefore, we merge only functions just like the MSVC tool. However, we also +// merge read-only sections in a couple of cases where the address of the +// section is insignificant to the user program and the behaviour matches that +// of the Visual C++ linker. bool ICF::isEligible(SectionChunk *C) { // Non-comdat chunks, dead chunks, and writable chunks are not elegible. - bool Writable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE; + bool Writable = C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE; if (!C->isCOMDAT() || !C->isLive() || Writable) return false; // Code sections are eligible. - if (C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE) + if (C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE) return true; - // .xdata unwind info sections are eligble. - return C->getSectionName().split('$').first == ".xdata"; + // .pdata and .xdata unwind info sections are eligible. + StringRef OutSecName = C->getSectionName().split('$').first; + if (OutSecName == ".pdata" || OutSecName == ".xdata") + return true; + + // So are vtables. + return C->Sym && C->Sym->getName().startswith("??_7"); } // 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). We use Mid as an // equivalence class ID because every group ends with a unique index. for (size_t I = Begin; I < Mid; ++I) Chunks[I]->Class[(Cnt + 1) % 2] = Mid; // If we created a group, we need to iterate the main loop again. if (Mid != End) Repeat = true; Begin = Mid; } } +// Returns true if two sections' associative children are equal. +bool ICF::assocEquals(const SectionChunk *A, const SectionChunk *B) { + auto ChildClasses = [&](const SectionChunk *SC) { + std::vector Classes; + for (const SectionChunk *C : SC->children()) + if (!C->SectionName.startswith(".debug") && + C->SectionName != ".gfids$y" && C->SectionName != ".gljmp$y") + Classes.push_back(C->Class[Cnt % 2]); + return Classes; + }; + return ChildClasses(A) == ChildClasses(B); +} + // 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) + if (A->Relocs.size() != B->Relocs.size()) 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; } Symbol *B1 = A->File->getSymbol(R1.SymbolTableIndex); Symbol *B2 = B->File->getSymbol(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()->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->Alignment == B->Alignment && + return A->getOutputCharacteristics() == B->getOutputCharacteristics() && + A->SectionName == B->SectionName && A->Header->SizeOfRawData == B->Header->SizeOfRawData && - A->Checksum == B->Checksum && A->getContents() == B->getContents(); + A->Checksum == B->Checksum && A->getContents() == B->getContents() && + assocEquals(A, B); } // 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) { Symbol *B1 = A->File->getSymbol(R1.SymbolTableIndex); Symbol *B2 = B->File->getSymbol(R2.SymbolTableIndex); if (B1 == B2) return true; if (auto *D1 = dyn_cast(B1)) if (auto *D2 = dyn_cast(B2)) 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); + return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), + Eq) && + assocEquals(A, B); } +// Find the first Chunk after Begin that has a different class from Begin. size_t ICF::findBoundary(size_t Begin, size_t End) { for (size_t I = Begin + 1; I < End; ++I) if (Chunks[Begin]->Class[Cnt % 2] != Chunks[I]->Class[Cnt % 2]) return I; return 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()); + size_t Mid = findBoundary(Begin, End); Fn(Begin, Mid); Begin = Mid; } } // 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) { forEachClassRange(0, Chunks.size(), Fn); ++Cnt; return; } - // Split sections into 256 shards and call Fn in parallel. - size_t NumShards = 256; + // Shard into non-overlapping intervals, and call Fn in parallel. + // The sharding must be completed before any calls to Fn are made + // so that Fn can modify the Chunks in its shard without causing data + // races. + const size_t NumShards = 256; size_t Step = Chunks.size() / NumShards; - for_each_n(parallel::par, size_t(0), NumShards, [&](size_t I) { - size_t End = (I == NumShards - 1) ? Chunks.size() : (I + 1) * Step; - forEachClassRange(I * Step, End, Fn); + size_t Boundaries[NumShards + 1]; + Boundaries[0] = 0; + Boundaries[NumShards] = Chunks.size(); + for_each_n(parallel::par, size_t(1), NumShards, [&](size_t I) { + Boundaries[I] = findBoundary((I - 1) * Step, Chunks.size()); }); + for_each_n(parallel::par, size_t(1), NumShards + 1, [&](size_t I) { + if (Boundaries[I - 1] < Boundaries[I]) { + forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn); + } + }); ++Cnt; } // Merge identical COMDAT sections. // Two sections are considered the same if their section headers, // contents and relocations are all the same. void ICF::run(ArrayRef Vec) { + ScopedTimer T(ICFTimer); + // Collect only mergeable sections and group by hash value. uint32_t NextId = 1; for (Chunk *C : Vec) { if (auto *SC = dyn_cast(C)) { if (isEligible(SC)) Chunks.push_back(SC); else SC->Class[0] = NextId++; } } + + // Make sure that ICF doesn't merge sections that are being handled by string + // tail merging. + for (auto &P : MergeChunk::Instances) + for (SectionChunk *SC : P.second->Sections) + SC->Class[0] = NextId++; // Initially, we use hash values to partition sections. for_each(parallel::par, Chunks.begin(), Chunks.end(), [&](SectionChunk *SC) { // Set MSB to 1 to avoid collisions with non-hash classs. SC->Class[0] = getHash(SC) | (1 << 31); }); // 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->Class[0] < B->Class[0]; }); // Compare static contents and assign unique IDs for each static content. forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); }); // Split groups by comparing relocations until convergence is obtained. do { Repeat = false; forEachClass( [&](size_t Begin, size_t End) { segregate(Begin, End, false); }); } while (Repeat); log("ICF needed " + Twine(Cnt) + " iterations"); // 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(ArrayRef Chunks) { ICF().run(Chunks); } } // namespace coff } // namespace lld Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/ICF.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/ICF.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/ICF.h (nonexistent) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/ICF.h (revision 336982) @@ -0,0 +1,26 @@ +//===- ICF.h --------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_ICF_H +#define LLD_COFF_ICF_H + +#include "lld/Common/LLVM.h" +#include "llvm/ADT/ArrayRef.h" + +namespace lld { +namespace coff { + +class Chunk; + +void doICF(ArrayRef Chunks); + +} // namespace coff +} // namespace lld + +#endif Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/ICF.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/InputFiles.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/InputFiles.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/InputFiles.cpp (revision 336982) @@ -1,505 +1,519 @@ //===- InputFiles.cpp -----------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "InputFiles.h" #include "Chunks.h" #include "Config.h" #include "Driver.h" #include "SymbolTable.h" #include "Symbols.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" #include "llvm-c/lto.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/Binary.h" #include "llvm/Object/COFF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" #include "llvm/Target/TargetOptions.h" #include #include #include using namespace llvm; using namespace llvm::COFF; using namespace llvm::object; using namespace llvm::support::endian; using llvm::Triple; using llvm::support::ulittle32_t; namespace lld { namespace coff { std::vector ObjFile::Instances; std::vector ImportFile::Instances; std::vector BitcodeFile::Instances; /// Checks that Source is compatible with being a weak alias to Target. /// If Source is Undefined and has no weak alias set, makes it a weak /// alias to Target. static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F, Symbol *Source, Symbol *Target) { if (auto *U = dyn_cast(Source)) { if (U->WeakAlias && U->WeakAlias != Target) Symtab->reportDuplicate(Source, F); U->WeakAlias = Target; } } ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} void ArchiveFile::parse() { // Parse a MemoryBufferRef as an archive file. File = CHECK(Archive::create(MB), this); // Read the symbol table to construct Lazy objects. for (const Archive::Symbol &Sym : File->symbols()) Symtab->addLazy(this, Sym); } // Returns a buffer pointing to a member file containing a given symbol. void ArchiveFile::addMember(const Archive::Symbol *Sym) { const Archive::Child &C = CHECK(Sym->getMember(), "could not get the member for symbol " + Sym->getName()); // Return an empty buffer if we have already returned the same buffer. if (!Seen.insert(C.getChildOffset()).second) return; Driver->enqueueArchiveMember(C, Sym->getName(), getName()); } std::vector getArchiveMembers(Archive *File) { std::vector V; Error Err = Error::success(); for (const ErrorOr &COrErr : File->children(Err)) { Archive::Child C = CHECK(COrErr, File->getFileName() + ": could not get the child of the archive"); MemoryBufferRef MBRef = CHECK(C.getMemoryBufferRef(), File->getFileName() + ": could not get the buffer for a child of the archive"); V.push_back(MBRef); } if (Err) fatal(File->getFileName() + ": Archive::children failed: " + toString(std::move(Err))); return V; } void ObjFile::parse() { // Parse a memory buffer as a COFF file. std::unique_ptr Bin = CHECK(createBinary(MB), this); if (auto *Obj = dyn_cast(Bin.get())) { Bin.release(); COFFObj.reset(Obj); } else { fatal(toString(this) + " is not a COFF file"); } // Read section and symbol tables. initializeChunks(); initializeSymbols(); } // We set SectionChunk pointers in the SparseChunks vector to this value // temporarily to mark comdat sections as having an unknown resolution. As we // walk the object file's symbol table, once we visit either a leader symbol or // an associative section definition together with the parent comdat's leader, // we set the pointer to either nullptr (to mark the section as discarded) or a // valid SectionChunk for that section. static SectionChunk *const PendingComdat = reinterpret_cast(1); void ObjFile::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; if (auto EC = COFFObj->getSection(I, Sec)) fatal("getSection failed: #" + Twine(I) + ": " + EC.message()); if (Sec->Characteristics & IMAGE_SCN_LNK_COMDAT) SparseChunks[I] = PendingComdat; else - SparseChunks[I] = readSection(I, nullptr); + SparseChunks[I] = readSection(I, nullptr, ""); } } SectionChunk *ObjFile::readSection(uint32_t SectionNumber, - const coff_aux_section_definition *Def) { + const coff_aux_section_definition *Def, + StringRef LeaderName) { const coff_section *Sec; StringRef Name; if (auto EC = COFFObj->getSection(SectionNumber, Sec)) fatal("getSection failed: #" + Twine(SectionNumber) + ": " + EC.message()); if (auto EC = COFFObj->getSectionName(Sec, Name)) fatal("getSectionName failed: #" + Twine(SectionNumber) + ": " + EC.message()); - if (Name == ".sxdata") { - ArrayRef Data; - COFFObj->getSectionContents(Sec, Data); - if (Data.size() % 4 != 0) - fatal(".sxdata must be an array of symbol table indices"); - SXData = {reinterpret_cast(Data.data()), - Data.size() / 4}; - return nullptr; - } + if (Name == ".drectve") { ArrayRef Data; COFFObj->getSectionContents(Sec, Data); Directives = std::string((const char *)Data.data(), Data.size()); return nullptr; } // Object files may have DWARF debug info or MS CodeView debug info // (or both). // // DWARF sections don't need any special handling from the perspective // of the linker; they are just a data section containing relocations. // We can just link them to complete debug info. // // CodeView needs a linker support. We need to interpret and debug // info, and then write it to a separate .pdb file. - // Ignore debug info unless /debug is given. - if (!Config->Debug && Name.startswith(".debug")) + // Ignore DWARF debug info unless /debug is given. + if (!Config->Debug && Name.startswith(".debug_")) return nullptr; if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) return nullptr; auto *C = make(this, Sec); if (Def) C->Checksum = Def->CheckSum; // CodeView sections are stored to a different vector because they are not // linked in the regular manner. if (C->isCodeView()) DebugChunks.push_back(C); + else if (Config->GuardCF != GuardCFLevel::Off && Name == ".gfids$y") + GuardFidChunks.push_back(C); + else if (Config->GuardCF != GuardCFLevel::Off && Name == ".gljmp$y") + GuardLJmpChunks.push_back(C); + else if (Name == ".sxdata") + SXDataChunks.push_back(C); + else if (Config->TailMerge && Sec->NumberOfRelocations == 0 && + Name == ".rdata" && LeaderName.startswith("??_C@")) + // COFF sections that look like string literal sections (i.e. no + // relocations, in .rdata, leader symbol name matches the MSVC name mangling + // for string literals) are subject to string tail merging. + MergeChunk::addSection(C); else Chunks.push_back(C); return C; } void ObjFile::readAssociativeDefinition( COFFSymbolRef Sym, const coff_aux_section_definition *Def) { SectionChunk *Parent = SparseChunks[Def->getNumber(Sym.isBigObj())]; // If the parent is pending, it probably means that its section definition // appears after us in the symbol table. Leave the associated section as // pending; we will handle it during the second pass in initializeSymbols(). if (Parent == PendingComdat) return; // Check whether the parent is prevailing. If it is, so are we, and we read // the section; otherwise mark it as discarded. int32_t SectionNumber = Sym.getSectionNumber(); if (Parent) { - SparseChunks[SectionNumber] = readSection(SectionNumber, Def); + SparseChunks[SectionNumber] = readSection(SectionNumber, Def, ""); if (SparseChunks[SectionNumber]) Parent->addAssociative(SparseChunks[SectionNumber]); } else { SparseChunks[SectionNumber] = nullptr; } } Symbol *ObjFile::createRegular(COFFSymbolRef Sym) { SectionChunk *SC = SparseChunks[Sym.getSectionNumber()]; if (Sym.isExternal()) { StringRef Name; COFFObj->getSymbolName(Sym, Name); if (SC) return Symtab->addRegular(this, Name, Sym.getGeneric(), SC); return Symtab->addUndefined(Name, this, false); } if (SC) return make(this, /*Name*/ "", false, /*IsExternal*/ false, Sym.getGeneric(), SC); return nullptr; } void ObjFile::initializeSymbols() { uint32_t NumSymbols = COFFObj->getNumberOfSymbols(); Symbols.resize(NumSymbols); SmallVector, 8> WeakAliases; std::vector PendingIndexes; PendingIndexes.reserve(NumSymbols); std::vector ComdatDefs( COFFObj->getNumberOfSections() + 1); for (uint32_t I = 0; I < NumSymbols; ++I) { COFFSymbolRef COFFSym = check(COFFObj->getSymbol(I)); if (COFFSym.isUndefined()) { Symbols[I] = createUndefined(COFFSym); } else if (COFFSym.isWeakExternal()) { Symbols[I] = createUndefined(COFFSym); uint32_t TagIndex = COFFSym.getAux()->TagIndex; WeakAliases.emplace_back(Symbols[I], TagIndex); } else if (Optional OptSym = createDefined(COFFSym, ComdatDefs)) { Symbols[I] = *OptSym; } else { // createDefined() returns None if a symbol belongs to a section that // was pending at the point when the symbol was read. This can happen in // two cases: // 1) section definition symbol for a comdat leader; // 2) symbol belongs to a comdat section associated with a section whose // section definition symbol appears later in the symbol table. // In both of these cases, we can expect the section to be resolved by // the time we finish visiting the remaining symbols in the symbol // table. So we postpone the handling of this symbol until that time. PendingIndexes.push_back(I); } I += COFFSym.getNumberOfAuxSymbols(); } for (uint32_t I : PendingIndexes) { COFFSymbolRef Sym = check(COFFObj->getSymbol(I)); if (auto *Def = Sym.getSectionDefinition()) if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) readAssociativeDefinition(Sym, Def); + if (SparseChunks[Sym.getSectionNumber()] == PendingComdat) { + StringRef Name; + COFFObj->getSymbolName(Sym, Name); + log("comdat section " + Name + + " without leader and unassociated, discarding"); + continue; + } Symbols[I] = createRegular(Sym); } for (auto &KV : WeakAliases) { Symbol *Sym = KV.first; uint32_t Idx = KV.second; checkAndSetWeakAlias(Symtab, this, Sym, Symbols[Idx]); } } Symbol *ObjFile::createUndefined(COFFSymbolRef Sym) { StringRef Name; COFFObj->getSymbolName(Sym, Name); return Symtab->addUndefined(Name, this, Sym.isWeakExternal()); } Optional ObjFile::createDefined( COFFSymbolRef Sym, std::vector &ComdatDefs) { - StringRef Name; + auto GetName = [&]() { + StringRef S; + COFFObj->getSymbolName(Sym, S); + return S; + }; + if (Sym.isCommon()) { auto *C = make(Sym); Chunks.push_back(C); - COFFObj->getSymbolName(Sym, Name); - Symbol *S = - Symtab->addCommon(this, Name, Sym.getValue(), Sym.getGeneric(), C); - return S; + return Symtab->addCommon(this, GetName(), Sym.getValue(), Sym.getGeneric(), + C); } + if (Sym.isAbsolute()) { - COFFObj->getSymbolName(Sym, Name); + StringRef Name = GetName(); + // 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; + Feat00Flags = Sym.getValue(); return nullptr; } + if (Sym.isExternal()) return Symtab->addAbsolute(Name, Sym); - else - return make(Name, Sym); + return make(Name, Sym); } + int32_t SectionNumber = Sym.getSectionNumber(); if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG) return nullptr; - // Reserved sections numbers don't have contents. if (llvm::COFF::isReservedSectionNumber(SectionNumber)) - fatal("broken object file: " + toString(this)); + fatal(toString(this) + ": " + GetName() + + " should not refer to special section " + Twine(SectionNumber)); - // This symbol references a section which is not present in the section - // header. if ((uint32_t)SectionNumber >= SparseChunks.size()) - fatal("broken object file: " + toString(this)); + fatal(toString(this) + ": " + GetName() + + " should not refer to non-existent section " + Twine(SectionNumber)); // Handle comdat leader symbols. if (const coff_aux_section_definition *Def = ComdatDefs[SectionNumber]) { ComdatDefs[SectionNumber] = nullptr; Symbol *Leader; bool Prevailing; if (Sym.isExternal()) { - COFFObj->getSymbolName(Sym, Name); std::tie(Leader, Prevailing) = - Symtab->addComdat(this, Name, Sym.getGeneric()); + Symtab->addComdat(this, GetName(), Sym.getGeneric()); } else { Leader = make(this, /*Name*/ "", false, /*IsExternal*/ false, Sym.getGeneric()); Prevailing = true; } + if (Prevailing) { - SectionChunk *C = readSection(SectionNumber, Def); + SectionChunk *C = readSection(SectionNumber, Def, GetName()); SparseChunks[SectionNumber] = C; C->Sym = cast(Leader); cast(Leader)->Data = &C->Repl; } else { SparseChunks[SectionNumber] = nullptr; } return Leader; } // Read associative section definitions and prepare to handle the comdat // leader symbol by setting the section's ComdatDefs pointer if we encounter a // non-associative comdat. if (SparseChunks[SectionNumber] == PendingComdat) { if (auto *Def = Sym.getSectionDefinition()) { if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) readAssociativeDefinition(Sym, Def); else ComdatDefs[SectionNumber] = Def; } } if (SparseChunks[SectionNumber] == PendingComdat) return None; return createRegular(Sym); } MachineTypes ObjFile::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)) fatal("broken import library"); // Read names and create an __imp_ symbol. StringRef Name = Saver.save(StringRef(Buf + sizeof(*Hdr))); StringRef ImpName = Saver.save("__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; } this->Hdr = Hdr; ExternalName = ExtName; ImpSym = Symtab->addImportData(ImpName, this); if (Hdr->getType() == llvm::COFF::IMPORT_CONST) static_cast(Symtab->addImportData(Name, this)); // 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) - ThunkSym = Symtab->addImportThunk(Name, ImpSym, Hdr->Machine); + ThunkSym = Symtab->addImportThunk( + Name, cast_or_null(ImpSym), Hdr->Machine); } void BitcodeFile::parse() { Obj = check(lto::InputFile::create(MemoryBufferRef( MB.getBuffer(), Saver.save(ParentName + MB.getBufferIdentifier())))); std::vector> Comdat(Obj->getComdatTable().size()); for (size_t I = 0; I != Obj->getComdatTable().size(); ++I) Comdat[I] = Symtab->addComdat(this, Saver.save(Obj->getComdatTable()[I])); for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) { StringRef SymName = Saver.save(ObjSym.getName()); int ComdatIndex = ObjSym.getComdatIndex(); Symbol *Sym; if (ObjSym.isUndefined()) { Sym = Symtab->addUndefined(SymName, this, false); } else if (ObjSym.isCommon()) { Sym = Symtab->addCommon(this, SymName, ObjSym.getCommonSize()); } else if (ObjSym.isWeak() && ObjSym.isIndirect()) { // Weak external. Sym = Symtab->addUndefined(SymName, this, true); std::string Fallback = ObjSym.getCOFFWeakExternalFallback(); Symbol *Alias = Symtab->addUndefined(Saver.save(Fallback)); checkAndSetWeakAlias(Symtab, this, Sym, Alias); } else if (ComdatIndex != -1) { if (SymName == Obj->getComdatTable()[ComdatIndex]) Sym = Comdat[ComdatIndex].first; else if (Comdat[ComdatIndex].second) Sym = Symtab->addRegular(this, SymName); else Sym = Symtab->addUndefined(SymName, this, false); } else { Sym = Symtab->addRegular(this, SymName); } - SymbolBodies.push_back(Sym); + Symbols.push_back(Sym); } Directives = Obj->getCOFFLinkerOpts(); } MachineTypes BitcodeFile::getMachineType() { switch (Triple(Obj->getTargetTriple()).getArch()) { case Triple::x86_64: return AMD64; case Triple::x86: return I386; case Triple::arm: return ARMNT; case Triple::aarch64: return ARM64; default: return IMAGE_FILE_MACHINE_UNKNOWN; } } } // namespace coff } // namespace lld // 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); + return sys::path::filename(Path, sys::path::Style::windows); } // Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)". std::string lld::toString(const coff::InputFile *File) { if (!File) return ""; if (File->ParentName.empty()) return File->getName(); return (getBasename(File->ParentName) + "(" + getBasename(File->getName()) + ")") .str(); } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/InputFiles.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/InputFiles.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/InputFiles.h (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/InputFiles.h (revision 336982) @@ -1,235 +1,254 @@ //===- InputFiles.h ---------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_COFF_INPUT_FILES_H #define LLD_COFF_INPUT_FILES_H #include "Config.h" #include "lld/Common/LLVM.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" #include "llvm/LTO/LTO.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFF.h" #include "llvm/Support/StringSaver.h" #include #include #include namespace llvm { namespace pdb { class DbiModuleDescriptorBuilder; } } namespace lld { namespace coff { std::vector getArchiveMembers(llvm::object::Archive *File); using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN; using llvm::COFF::MachineTypes; using llvm::object::Archive; using llvm::object::COFFObjectFile; using llvm::object::COFFSymbolRef; using llvm::object::coff_import_header; using llvm::object::coff_section; class Chunk; class Defined; class DefinedImportData; class DefinedImportThunk; class Lazy; class SectionChunk; class Symbol; class Undefined; // The root class of input files. class InputFile { public: enum Kind { ArchiveKind, ObjectKind, ImportKind, BitcodeKind }; Kind kind() const { return FileKind; } virtual ~InputFile() {} // Returns the filename. StringRef getName() const { return MB.getBufferIdentifier(); } // Reads a file (the constructor doesn't do that). virtual void parse() = 0; // Returns the CPU type this file was compiled to. virtual MachineTypes getMachineType() { return IMAGE_FILE_MACHINE_UNKNOWN; } MemoryBufferRef MB; // An archive file name if this file is created from an archive. StringRef ParentName; // Returns .drectve section contents if exist. StringRef getDirectives() { return StringRef(Directives).trim(); } protected: InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} std::string Directives; private: const Kind FileKind; }; // .lib or .a file. class ArchiveFile : public InputFile { public: explicit ArchiveFile(MemoryBufferRef M); static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } void parse() override; // Enqueues an archive member load for the given symbol. If we've already // enqueued a load for the same archive member, this function does nothing, // which ensures that we don't load the same member more than once. void addMember(const Archive::Symbol *Sym); private: std::unique_ptr File; std::string Filename; llvm::DenseSet Seen; }; // .obj or .o file. This may be a member of an archive file. class ObjFile : public InputFile { public: explicit ObjFile(MemoryBufferRef M) : InputFile(ObjectKind, M) {} static bool classof(const InputFile *F) { return F->kind() == ObjectKind; } void parse() override; MachineTypes getMachineType() override; ArrayRef getChunks() { return Chunks; } ArrayRef getDebugChunks() { return DebugChunks; } + ArrayRef getSXDataChunks() { return SXDataChunks; } + ArrayRef getGuardFidChunks() { return GuardFidChunks; } + ArrayRef getGuardLJmpChunks() { return GuardLJmpChunks; } ArrayRef getSymbols() { return Symbols; } // Returns a Symbol object for the SymbolIndex'th symbol in the // underlying object file. Symbol *getSymbol(uint32_t SymbolIndex) { return Symbols[SymbolIndex]; } // Returns the underying COFF file. COFFObjectFile *getCOFFObj() { return COFFObj.get(); } static std::vector Instances; - // True if this object file is compatible with SEH. - // COFF-specific and x86-only. - bool SEHCompat = false; + // Flags in the absolute @feat.00 symbol if it is present. These usually + // indicate if an object was compiled with certain security features enabled + // like stack guard, safeseh, /guard:cf, or other things. + uint32_t Feat00Flags = 0; - // The symbol table indexes of the safe exception handlers. - // COFF-specific and x86-only. - ArrayRef SXData; + // True if this object file is compatible with SEH. COFF-specific and + // x86-only. COFF spec 5.10.1. The .sxdata section. + bool hasSafeSEH() { return Feat00Flags & 0x1; } + // True if this file was compiled with /guard:cf. + bool hasGuardCF() { return Feat00Flags & 0x800; } + // Pointer to the PDB module descriptor builder. Various debug info records // will reference object files by "module index", which is here. Things like // source files and section contributions are also recorded here. Will be null // if we are not producing a PDB. llvm::pdb::DbiModuleDescriptorBuilder *ModuleDBI = nullptr; private: void initializeChunks(); void initializeSymbols(); SectionChunk * readSection(uint32_t SectionNumber, - const llvm::object::coff_aux_section_definition *Def); + const llvm::object::coff_aux_section_definition *Def, + StringRef LeaderName); void readAssociativeDefinition( COFFSymbolRef COFFSym, const llvm::object::coff_aux_section_definition *Def); llvm::Optional createDefined(COFFSymbolRef Sym, std::vector &ComdatDefs); Symbol *createRegular(COFFSymbolRef Sym); Symbol *createUndefined(COFFSymbolRef Sym); std::unique_ptr COFFObj; // List of all chunks defined by this file. This includes both section // chunks and non-section chunks for common symbols. std::vector Chunks; // CodeView debug info sections. std::vector DebugChunks; + // Chunks containing symbol table indices of exception handlers. Only used for + // 32-bit x86. + std::vector SXDataChunks; + + // Chunks containing symbol table indices of address taken symbols and longjmp + // targets. These are not linked into the final binary when /guard:cf is set. + std::vector GuardFidChunks; + std::vector GuardLJmpChunks; + // This vector contains the same chunks as Chunks, but they are // indexed such that you can get a SectionChunk by section index. // Nonexistent section indices are filled with null pointers. // (Because section number is 1-based, the first slot is always a // null pointer.) std::vector SparseChunks; // This vector contains a list of all symbols defined or referenced by this // file. They are indexed such that you can get a Symbol by symbol // index. Nonexistent indices (which are occupied by auxiliary // symbols in the real symbol table) are filled with null pointers. std::vector Symbols; }; // This type represents import library members that contain DLL names // and symbols exported from the DLLs. See Microsoft PE/COFF spec. 7 // for details about the format. class ImportFile : public InputFile { public: - explicit ImportFile(MemoryBufferRef M) - : InputFile(ImportKind, M), Live(!Config->DoGC) {} + explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M) {} static bool classof(const InputFile *F) { return F->kind() == ImportKind; } static std::vector Instances; - DefinedImportData *ImpSym = nullptr; - DefinedImportThunk *ThunkSym = nullptr; + Symbol *ImpSym = nullptr; + Symbol *ThunkSym = nullptr; std::string DLLName; private: void parse() override; public: StringRef ExternalName; const coff_import_header *Hdr; Chunk *Location = nullptr; // We want to eliminate dllimported symbols if no one actually refers them. - // This "Live" bit is used to keep track of which import library members + // These "Live" bits are used to keep track of which import library members // are actually in use. // // If the Live bit is turned off by MarkLive, Writer will ignore dllimported - // symbols provided by this import library member. - bool Live; + // symbols provided by this import library member. We also track whether the + // imported symbol is used separately from whether the thunk is used in order + // to avoid creating unnecessary thunks. + bool Live = !Config->DoGC; + bool ThunkLive = !Config->DoGC; }; // Used for LTO. class BitcodeFile : public InputFile { public: explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {} static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } - ArrayRef getSymbols() { return SymbolBodies; } + ArrayRef getSymbols() { return Symbols; } MachineTypes getMachineType() override; static std::vector Instances; std::unique_ptr Obj; private: void parse() override; - std::vector SymbolBodies; + std::vector Symbols; }; } // namespace coff std::string toString(const coff::InputFile *File); } // namespace lld #endif Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/InputFiles.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/LTO.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/LTO.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/LTO.cpp (revision 336982) @@ -1,163 +1,149 @@ //===- LTO.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "LTO.h" #include "Config.h" #include "InputFiles.h" #include "Symbols.h" #include "lld/Common/ErrorHandler.h" +#include "lld/Common/Strings.h" #include "lld/Common/TargetOptionsCommandFlags.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/LTO/Caching.h" #include "llvm/LTO/Config.h" #include "llvm/LTO/LTO.h" #include "llvm/Object/SymbolicFile.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include #include using namespace llvm; using namespace llvm::object; using namespace lld; using namespace lld::coff; -static void diagnosticHandler(const DiagnosticInfo &DI) { - SmallString<128> ErrStorage; - raw_svector_ostream OS(ErrStorage); - DiagnosticPrinterRawOStream DP(OS); - DI.print(DP); - warn(ErrStorage); -} +static std::unique_ptr createLTO() { + lto::Config C; + C.Options = InitTargetOptionsFromCodeGenFlags(); -static void checkError(Error E) { - handleAllErrors(std::move(E), - [&](ErrorInfoBase &EIB) { error(EIB.message()); }); -} + // Always emit a section per function/datum with LTO. LLVM LTO should get most + // of the benefit of linker GC, but there are still opportunities for ICF. + C.Options.FunctionSections = true; + C.Options.DataSections = true; -static void saveBuffer(StringRef Buffer, const Twine &Path) { - std::error_code EC; - raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None); - if (EC) - error("cannot create " + Path + ": " + EC.message()); - OS << Buffer; -} - -static std::unique_ptr createLTO() { - lto::Config Conf; - Conf.Options = InitTargetOptionsFromCodeGenFlags(); // Use static reloc model on 32-bit x86 because it usually results in more // compact code, and because there are also known code generation bugs when // using the PIC model (see PR34306). if (Config->Machine == COFF::IMAGE_FILE_MACHINE_I386) - Conf.RelocModel = Reloc::Static; + C.RelocModel = Reloc::Static; else - Conf.RelocModel = Reloc::PIC_; - Conf.DisableVerify = true; - Conf.DiagHandler = diagnosticHandler; - Conf.OptLevel = Config->LTOOptLevel; + C.RelocModel = Reloc::PIC_; + C.DisableVerify = true; + C.DiagHandler = diagnosticHandler; + C.OptLevel = Config->LTOO; if (Config->SaveTemps) - checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".", - /*UseInputModulePath*/ true)); + checkError(C.addSaveTemps(std::string(Config->OutputFile) + ".", + /*UseInputModulePath*/ true)); lto::ThinBackend Backend; - if (Config->LTOJobs != 0) - Backend = lto::createInProcessThinBackend(Config->LTOJobs); - return llvm::make_unique(std::move(Conf), Backend, + if (Config->ThinLTOJobs != 0) + Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs); + return llvm::make_unique(std::move(C), Backend, Config->LTOPartitions); } BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {} BitcodeCompiler::~BitcodeCompiler() = default; static void undefine(Symbol *S) { replaceSymbol(S, S->getName()); } void BitcodeCompiler::add(BitcodeFile &F) { lto::InputFile &Obj = *F.Obj; unsigned SymNum = 0; std::vector SymBodies = F.getSymbols(); std::vector Resols(SymBodies.size()); // Provide a resolution to the LTO API for each symbol. for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) { Symbol *Sym = SymBodies[SymNum]; lto::SymbolResolution &R = Resols[SymNum]; ++SymNum; // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile // reports two symbols for module ASM defined. Without this check, lld // flags an undefined in IR with a definition in ASM as prevailing. // Once IRObjectFile is fixed to report only one symbol this hack can // be removed. R.Prevailing = !ObjSym.isUndefined() && Sym->getFile() == &F; R.VisibleToRegularObj = Sym->IsUsedInRegularObj; if (R.Prevailing) undefine(Sym); } checkError(LTOObj->add(std::move(F.Obj), Resols)); } // Merge all the bitcode files we have seen, codegen the result // and return the resulting objects. std::vector BitcodeCompiler::compile() { unsigned MaxTasks = LTOObj->getMaxTasks(); - Buff.resize(MaxTasks); + Buf.resize(MaxTasks); Files.resize(MaxTasks); // The /lldltocache option specifies the path to a directory in which to cache // native object files for ThinLTO incremental builds. If a path was // specified, configure LTO to use it as the cache directory. lto::NativeObjectCache Cache; if (!Config->LTOCache.empty()) - Cache = check( - lto::localCache(Config->LTOCache, - [&](size_t Task, std::unique_ptr MB, - StringRef Path) { Files[Task] = std::move(MB); })); + Cache = check(lto::localCache( + Config->LTOCache, [&](size_t Task, std::unique_ptr MB) { + Files[Task] = std::move(MB); + })); checkError(LTOObj->run( [&](size_t Task) { return llvm::make_unique( - llvm::make_unique(Buff[Task])); + llvm::make_unique(Buf[Task])); }, Cache)); if (!Config->LTOCache.empty()) pruneCache(Config->LTOCache, Config->LTOCachePolicy); std::vector Ret; for (unsigned I = 0; I != MaxTasks; ++I) { - if (Buff[I].empty()) + if (Buf[I].empty()) continue; if (Config->SaveTemps) { if (I == 0) - saveBuffer(Buff[I], Config->OutputFile + ".lto.obj"); + saveBuffer(Buf[I], Config->OutputFile + ".lto.obj"); else - saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.obj"); + saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.obj"); } - Ret.emplace_back(Buff[I].data(), Buff[I].size()); + Ret.emplace_back(Buf[I].data(), Buf[I].size()); } for (std::unique_ptr &File : Files) if (File) Ret.push_back(File->getBuffer()); return Ret; } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/LTO.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/LTO.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/LTO.h (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/LTO.h (revision 336982) @@ -1,57 +1,57 @@ //===- LTO.h ----------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file provides a way to combine bitcode files into one COFF // file by compiling them using LLVM. // // If LTO is in use, your input files are not in regular COFF files // but instead LLVM bitcode files. In that case, the linker has to // convert bitcode files into the native format so that we can create // a COFF file that contains native code. This file provides that // functionality. // //===----------------------------------------------------------------------===// #ifndef LLD_COFF_LTO_H #define LLD_COFF_LTO_H #include "lld/Common/LLVM.h" #include "llvm/ADT/SmallString.h" #include #include namespace llvm { namespace lto { class LTO; } } namespace lld { namespace coff { class BitcodeFile; class InputFile; class BitcodeCompiler { public: BitcodeCompiler(); ~BitcodeCompiler(); void add(BitcodeFile &F); std::vector compile(); private: std::unique_ptr LTOObj; - std::vector> Buff; + std::vector> Buf; std::vector> Files; }; } } #endif Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/LTO.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/MapFile.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/MapFile.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/MapFile.cpp (revision 336982) @@ -1,125 +1,125 @@ //===- MapFile.cpp --------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the /lldmap option. It shows lists in order and // hierarchically the output sections, input sections, input files and // symbol: // // Address Size Align Out File Symbol // 00201000 00000015 4 .text // 00201000 0000000e 4 test.o:(.text) // 0020100e 00000000 0 local // 00201005 00000000 0 f(int) // //===----------------------------------------------------------------------===// #include "MapFile.h" #include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" - #include "lld/Common/ErrorHandler.h" #include "llvm/Support/Parallel.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace llvm::object; using namespace lld; using namespace lld::coff; typedef DenseMap> SymbolMapTy; +static const std::string Indent8 = " "; // 8 spaces +static const std::string Indent16 = " "; // 16 spaces + // Print out the first three columns of a line. static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size, uint64_t Align) { OS << format("%08llx %08llx %5lld ", Addr, Size, Align); } -static std::string indent(int Depth) { return std::string(Depth * 8, ' '); } - // Returns a list of all symbols that we want to print out. static std::vector getSymbols() { std::vector V; for (ObjFile *File : ObjFile::Instances) for (Symbol *B : File->getSymbols()) if (auto *Sym = dyn_cast_or_null(B)) if (Sym && !Sym->getCOFFSymbol().isSectionDefinition()) V.push_back(Sym); return V; } // Returns a map from sections to their symbols. static SymbolMapTy getSectionSyms(ArrayRef Syms) { SymbolMapTy Ret; for (DefinedRegular *S : Syms) Ret[S->getChunk()].push_back(S); // Sort symbols by address. for (auto &It : Ret) { SmallVectorImpl &V = It.second; std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) { return A->getRVA() < B->getRVA(); }); } return Ret; } // Construct a map from symbols to their stringified representations. static DenseMap getSymbolStrings(ArrayRef Syms) { std::vector Str(Syms.size()); for_each_n(parallel::par, (size_t)0, Syms.size(), [&](size_t I) { raw_string_ostream OS(Str[I]); writeHeader(OS, Syms[I]->getRVA(), 0, 0); - OS << indent(2) << toString(*Syms[I]); + OS << Indent16 << toString(*Syms[I]); }); DenseMap Ret; for (size_t I = 0, E = Syms.size(); I < E; ++I) Ret[Syms[I]] = std::move(Str[I]); return Ret; } void coff::writeMapFile(ArrayRef OutputSections) { if (Config->MapFile.empty()) return; std::error_code EC; raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None); if (EC) fatal("cannot open " + Config->MapFile + ": " + EC.message()); // Collect symbol info that we want to print out. std::vector Syms = getSymbols(); SymbolMapTy SectionSyms = getSectionSyms(Syms); DenseMap SymStr = getSymbolStrings(Syms); // Print out the header line. OS << "Address Size Align Out In Symbol\n"; // Print out file contents. for (OutputSection *Sec : OutputSections) { writeHeader(OS, Sec->getRVA(), Sec->getVirtualSize(), /*Align=*/PageSize); - OS << Sec->getName() << '\n'; + OS << Sec->Name << '\n'; for (Chunk *C : Sec->getChunks()) { auto *SC = dyn_cast(C); if (!SC) continue; writeHeader(OS, SC->getRVA(), SC->getSize(), SC->Alignment); - OS << indent(1) << SC->File->getName() << ":(" << SC->getSectionName() + OS << Indent8 << SC->File->getName() << ":(" << SC->getSectionName() << ")\n"; for (DefinedRegular *Sym : SectionSyms[SC]) OS << SymStr[Sym] << '\n'; } } } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/MapFile.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/MapFile.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/MapFile.h (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/MapFile.h (revision 336982) Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/MapFile.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/MarkLive.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/MarkLive.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/MarkLive.cpp (revision 336982) @@ -1,69 +1,74 @@ //===- MarkLive.cpp -------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Chunks.h" #include "Symbols.h" +#include "lld/Common/Timer.h" #include "llvm/ADT/STLExtras.h" #include namespace lld { namespace coff { +static Timer GCTimer("GC", Timer::root()); + // Set live bit on for each reachable chunk. Unmarked (unreachable) // COMDAT chunks will be ignored by Writer, so they will be excluded // from the final output. void markLive(ArrayRef Chunks) { + ScopedTimer T(GCTimer); + // We build up a worklist of sections which have been marked as live. We only // push into the worklist when we discover an unmarked section, and we mark // as we push, so sections never appear twice in the list. SmallVector Worklist; // COMDAT section chunks are dead by default. Add non-COMDAT chunks. for (Chunk *C : Chunks) if (auto *SC = dyn_cast(C)) if (SC->isLive()) Worklist.push_back(SC); auto Enqueue = [&](SectionChunk *C) { if (C->isLive()) return; C->markLive(); Worklist.push_back(C); }; auto AddSym = [&](Symbol *B) { if (auto *Sym = dyn_cast(B)) Enqueue(Sym->getChunk()); else if (auto *Sym = dyn_cast(B)) Sym->File->Live = true; else if (auto *Sym = dyn_cast(B)) - Sym->WrappedSym->File->Live = true; + Sym->WrappedSym->File->Live = Sym->WrappedSym->File->ThunkLive = true; }; // Add GC root chunks. for (Symbol *B : Config->GCRoot) AddSym(B); while (!Worklist.empty()) { SectionChunk *SC = Worklist.pop_back_val(); assert(SC->isLive() && "We mark as live when pushing onto the worklist!"); // Mark all symbols listed in the relocation table for this section. for (Symbol *B : SC->symbols()) if (B) AddSym(B); // Mark associative sections if any. for (SectionChunk *C : SC->children()) Enqueue(C); } } } } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/MarkLive.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/MarkLive.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/MarkLive.h (nonexistent) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/MarkLive.h (revision 336982) @@ -0,0 +1,24 @@ +//===- MarkLive.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_MARKLIVE_H +#define LLD_COFF_MARKLIVE_H + +#include "lld/Common/LLVM.h" +#include "llvm/ADT/ArrayRef.h" + +namespace lld { +namespace coff { + +void markLive(ArrayRef Chunks); + +} // namespace coff +} // namespace lld + +#endif // LLD_COFF_MARKLIVE_H Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/MarkLive.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/MinGW.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/MinGW.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/MinGW.cpp (revision 336982) @@ -1,146 +1,146 @@ //===- MinGW.cpp ----------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "MinGW.h" #include "SymbolTable.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Object/COFF.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" using namespace lld; using namespace lld::coff; using namespace llvm; using namespace llvm::COFF; AutoExporter::AutoExporter() { if (Config->Machine == I386) { ExcludeSymbols = { "__NULL_IMPORT_DESCRIPTOR", "__pei386_runtime_relocator", "_do_pseudo_reloc", "_impure_ptr", "__impure_ptr", "__fmode", "_environ", "___dso_handle", // These are the MinGW names that differ from the standard // ones (lacking an extra underscore). "_DllMain@12", "_DllEntryPoint@12", "_DllMainCRTStartup@12", }; } else { ExcludeSymbols = { "_NULL_IMPORT_DESCRIPTOR", "_pei386_runtime_relocator", "do_pseudo_reloc", "impure_ptr", "_impure_ptr", "_fmode", "environ", "__dso_handle", // These are the MinGW names that differ from the standard // ones (lacking an extra underscore). "DllMain", "DllEntryPoint", "DllMainCRTStartup", }; } ExcludeLibs = { "libgcc", "libgcc_s", "libstdc++", "libmingw32", "libmingwex", "libg2c", "libsupc++", "libobjc", "libgcj", "libclang_rt.builtins-aarch64", "libclang_rt.builtins-arm", "libclang_rt.builtins-i386", "libclang_rt.builtins-x86_64", "libc++", "libc++abi", "libunwind", "libmsvcrt", "libucrtbase", }; ExcludeObjects = { "crt0.o", "crt1.o", "crt1u.o", "crt2.o", "crt2u.o", "dllcrt1.o", "dllcrt2.o", "gcrt0.o", "gcrt1.o", "gcrt2.o", "crtbegin.o", "crtend.o", }; } bool AutoExporter::shouldExport(Defined *Sym) const { if (!Sym || !Sym->isLive() || !Sym->getChunk()) return false; // Only allow the symbol kinds that make sense to export; in particular, // disallow import symbols. if (!isa(Sym) && !isa(Sym)) return false; if (ExcludeSymbols.count(Sym->getName())) return false; // Don't export anything that looks like an import symbol (which also can be // a manually defined data symbol with such a name). if (Sym->getName().startswith("__imp_")) return false; // If a corresponding __imp_ symbol exists and is defined, don't export it. if (Symtab->find(("__imp_" + Sym->getName()).str())) return false; // Check that file is non-null before dereferencing it, symbols not // originating in regular object files probably shouldn't be exported. if (!Sym->getFile()) return false; StringRef LibName = sys::path::filename(Sym->getFile()->ParentName); // Drop the file extension. LibName = LibName.substr(0, LibName.rfind('.')); if (!LibName.empty()) return !ExcludeLibs.count(LibName); StringRef FileName = sys::path::filename(Sym->getFile()->getName()); return !ExcludeObjects.count(FileName); } void coff::writeDefFile(StringRef Name) { std::error_code EC; raw_fd_ostream OS(Name, EC, sys::fs::F_None); if (EC) fatal("cannot open " + Name + ": " + EC.message()); OS << "EXPORTS\n"; for (Export &E : Config->Exports) { OS << " " << E.ExportName << " " << "@" << E.Ordinal; if (auto *Def = dyn_cast_or_null(E.Sym)) { if (Def && Def->getChunk() && - !(Def->getChunk()->getPermissions() & IMAGE_SCN_MEM_EXECUTE)) + !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) OS << " DATA"; } OS << "\n"; } } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/MinGW.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/MinGW.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/MinGW.h (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/MinGW.h (revision 336982) Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/MinGW.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/Options.td =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/Options.td (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/Options.td (revision 336982) @@ -1,166 +1,187 @@ include "llvm/Option/OptParser.td" // link.exe accepts options starting with either a dash or a slash. // Flag that takes no arguments. class F : Flag<["/", "-", "-?"], name>; // Flag that takes one argument after ":". class P : Joined<["/", "-", "-?"], name#":">, HelpText; // Boolean flag which can be suffixed by ":no". Using it unsuffixed turns the // flag on and using it suffixed by ":no" turns it off. multiclass B { def "" : F, HelpText; def _no : F, HelpText; } def align : P<"align", "Section alignment">; def aligncomm : P<"aligncomm", "Set common symbol alignment">; def alternatename : P<"alternatename", "Define weak alias">; def base : P<"base", "Base address of the program">; +def color_diagnostics: Flag<["--"], "color-diagnostics">, + HelpText<"Use colors in diagnostics">; +def color_diagnostics_eq: Joined<["--"], "color-diagnostics=">, + HelpText<"Use colors in diagnostics; one of 'always', 'never', 'auto'">; def defaultlib : P<"defaultlib", "Add the library to the list of input files">; def delayload : P<"delayload", "Delay loaded DLL name">; def entry : P<"entry", "Name of entry point symbol">; def errorlimit : P<"errorlimit", "Maximum number of errors to emit before stopping (0 = no limit)">; def export : P<"export", "Export a function">; // No help text because /failifmismatch is not intended to be used by the user. def failifmismatch : P<"failifmismatch", "">; +def guard : P<"guard", "Control flow guard">; def heap : P<"heap", "Size of the heap">; def ignore : P<"ignore", "Specify warning codes to ignore">; def implib : P<"implib", "Import library name">; +def lib : F<"lib">, + HelpText<"Act like lib.exe; must be first argument if present">; def libpath : P<"libpath", "Additional library search path">; def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">; def lldltocache : P<"lldltocache", "Path to ThinLTO cached object file directory">; def lldltocachepolicy : P<"lldltocachepolicy", "Pruning policy for the ThinLTO cache">; def lldsavetemps : F<"lldsavetemps">, HelpText<"Save temporary files instead of deleting them">; def machine : P<"machine", "Specify target platform">; def merge : P<"merge", "Combine sections">; def mllvm : P<"mllvm", "Options to pass to LLVM">; def nodefaultlib : P<"nodefaultlib", "Remove a default library">; def opt : P<"opt", "Control optimizations">; +def order : P<"order", "Put functions in order">; def out : P<"out", "Path to file to write output">; +def natvis : P<"natvis", "Path to natvis file to embed in the PDB">; +def no_color_diagnostics: F<"no-color-diagnostics">, + HelpText<"Do not use colors in diagnostics">; def pdb : P<"pdb", "PDB file path">; +def pdbaltpath : P<"pdbaltpath", "PDB file path to embed in the image">; def section : P<"section", "Specify section attributes">; def stack : P<"stack", "Size of the stack">; def stub : P<"stub", "Specify DOS stub file">; def subsystem : P<"subsystem", "Specify subsystem">; +def timestamp : P<"timestamp", "Specify the PE header timestamp">; def version : P<"version", "Specify a version number in the PE header">; def wholearchive_file : P<"wholearchive", "Include all object files from this archive">; def disallowlib : Joined<["/", "-", "-?"], "disallowlib:">, Alias; def manifest : F<"manifest">; def manifest_colon : P<"manifest", "Create manifest file">; def manifestuac : P<"manifestuac", "User access control">; def manifestfile : P<"manifestfile", "Manifest file path">; def manifestdependency : P<"manifestdependency", "Attributes for in manifest file">; def manifestinput : P<"manifestinput", "Specify manifest file">; // We cannot use multiclass P because class name "incl" is different // from its command line option name. We do this because "include" is // a reserved keyword in tablegen. def incl : Joined<["/", "-"], "include:">, HelpText<"Force symbol to be added to symbol table as undefined one">; // "def" is also a keyword. def deffile : Joined<["/", "-"], "def:">, HelpText<"Use module-definition file">; def debug : F<"debug">, HelpText<"Embed a symbol table in the image">; +def debug_full : F<"debug:full">, Alias; def debugtype : P<"debugtype", "Debug Info Options">; def dll : F<"dll">, HelpText<"Create a DLL">; def driver : P<"driver", "Generate a Windows NT Kernel Mode Driver">; def nodefaultlib_all : F<"nodefaultlib">; def noentry : F<"noentry">; def profile : F<"profile">; +def repro : F<"Brepro">, HelpText<"Use a hash of the executable as the PE header timestamp">; def swaprun_cd : F<"swaprun:cd">; def swaprun_net : F<"swaprun:net">; def verbose : F<"verbose">; def wholearchive_flag : F<"wholearchive">; def force : F<"force">, HelpText<"Allow undefined symbols when creating executables">; def force_unresolved : F<"force:unresolved">; defm WX : B<"WX", "Treat warnings as errors", "Don't treat warnings as errors">; defm allowbind : B<"allowbind", "Enable DLL binding (default)", "Disable DLL binding">; defm allowisolation : B<"allowisolation", "Enable DLL isolation (default)", "Disable DLL isolation">; defm appcontainer : B<"appcontainer", "Image can only be run in an app container", "Image can run outside an app container (default)">; defm dynamicbase : B<"dynamicbase", "Enable ASLR (default unless /fixed)", "Disable ASLR (default when /fixed)">; defm fixed : B<"fixed", "Disable base relocations", "Enable base relocations (default)">; defm highentropyva : B<"highentropyva", "Enable 64-bit ASLR (default on 64-bit)", "Disable 64-bit ASLR">; +defm incremental : B<"incremental", + "Keep original import library if contents are unchanged", + "Overwrite import library even if contents are unchanged">; +defm integritycheck : B<"integritycheck", + "Set FORCE_INTEGRITY bit in PE header", + "No effect (default)">; defm largeaddressaware : B<"largeaddressaware", "Enable large addresses (default on 64-bit)", "Disable large addresses (default on 32-bit)">; defm nxcompat : B<"nxcompat", "Enable data execution prevention (default)", "Disable data execution provention">; defm safeseh : B<"safeseh", "Produce an image with Safe Exception Handler (only for x86)", "Don't produce an image with Safe Exception Handler">; defm tsaware : B<"tsaware", "Create Terminal Server aware executable (default)", "Create non-Terminal Server aware executable">; def help : F<"help">; def help_q : Flag<["/?", "-?"], "">, Alias; // LLD extensions def debug_ghash : F<"debug:ghash">; def debug_dwarf : F<"debug:dwarf">; +def debug_symtab : F<"debug:symtab">; def export_all_symbols : F<"export-all-symbols">; def kill_at : F<"kill-at">; def lldmingw : F<"lldmingw">; def msvclto : F<"msvclto">; def output_def : Joined<["/", "-"], "output-def:">; +def pdb_source_path : P<"pdbsourcepath", + "Base path used to make relative source file path absolute in PDB">; def rsp_quoting : Joined<["--"], "rsp-quoting=">, HelpText<"Quoting style for response files, 'windows' (default) or 'posix'">; def dash_dash_version : Flag<["--"], "version">, HelpText<"Print version information">; // Flags for debugging def lldmap : F<"lldmap">; def lldmap_file : Joined<["/", "-"], "lldmap:">; +def show_timing : F<"time">; //============================================================================== // The flags below do nothing. They are defined only for link.exe compatibility. //============================================================================== class QF : Joined<["/", "-", "-?"], name#":">; multiclass QB { def "" : F; def _no : F; } def functionpadmin : F<"functionpadmin">; def ignoreidl : F<"ignoreidl">; -def incremental : F<"incremental">; -def no_incremental : F<"incremental:no">; def nologo : F<"nologo">; def throwingnew : F<"throwingnew">; def editandcontinue : F<"editandcontinue">; def fastfail : F<"fastfail">; def delay : QF<"delay">; def errorreport : QF<"errorreport">; def idlout : QF<"idlout">; def maxilksize : QF<"maxilksize">; -def natvis : QF<"natvis">; -def pdbaltpath : QF<"pdbaltpath">; def tlbid : QF<"tlbid">; def tlbout : QF<"tlbout">; def verbose_all : QF<"verbose">; def guardsym : QF<"guardsym">; Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/PDB.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/PDB.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/PDB.cpp (revision 336982) @@ -1,1022 +1,1334 @@ //===- 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 "Driver.h" #include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" #include "lld/Common/ErrorHandler.h" -#include "llvm/DebugInfo/CodeView/CVDebugRecord.h" +#include "lld/Common/Timer.h" #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" #include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h" #include "llvm/DebugInfo/CodeView/RecordName.h" #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" #include "llvm/DebugInfo/CodeView/SymbolSerializer.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/NativeSession.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/TpiHashing.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" #include "llvm/DebugInfo/PDB/PDB.h" #include "llvm/Object/COFF.h" +#include "llvm/Object/CVDebugRecord.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/JamCRC.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 llvm::object::coff_section; static ExitOnError ExitOnErr; +static Timer TotalPdbLinkTimer("PDB Emission (Cumulative)", Timer::root()); + +static Timer AddObjectsTimer("Add Objects", TotalPdbLinkTimer); +static Timer TypeMergingTimer("Type Merging", AddObjectsTimer); +static Timer SymbolMergingTimer("Symbol Merging", AddObjectsTimer); +static Timer GlobalsLayoutTimer("Globals Stream Layout", TotalPdbLinkTimer); +static Timer TpiStreamLayoutTimer("TPI Stream Layout", TotalPdbLinkTimer); +static Timer DiskCommitTimer("Commit to Disk", TotalPdbLinkTimer); + namespace { /// Map from type index and item index in a type server PDB to the /// corresponding index in the destination PDB. struct CVIndexMap { SmallVector TPIMap; SmallVector IPIMap; bool IsTypeServerMap = false; }; class PDBLinker { public: PDBLinker(SymbolTable *Symtab) : Alloc(), Symtab(Symtab), Builder(Alloc), TypeTable(Alloc), - IDTable(Alloc), GlobalTypeTable(Alloc), GlobalIDTable(Alloc) {} + IDTable(Alloc), GlobalTypeTable(Alloc), GlobalIDTable(Alloc) { + // This isn't strictly necessary, but link.exe usually puts an empty string + // as the first "valid" string in the string table, so we do the same in + // order to maintain as much byte-for-byte compatibility as possible. + PDBStrTab.insert(""); + } /// Emit the basic PDB structure: initial streams, headers, etc. void initialize(const llvm::codeview::DebugInfo &BuildId); + /// Add natvis files specified on the command line. + void addNatvisFiles(); + /// Link CodeView from each object file in the symbol table into the PDB. void addObjectsToPDB(); /// Link CodeView from a single object file into the PDB. void addObjFile(ObjFile *File); /// Produce a mapping from the type and item indices used in the object /// file to those in the destination PDB. /// /// If the object file uses a type server PDB (compiled with /Zi), merge TPI /// and IPI from the type server PDB and return a map for it. Each unique type /// server PDB is merged at most once, so this may return an existing index /// mapping. /// /// If the object does not use a type server PDB (compiled with /Z7), we merge /// all the type and item records from the .debug$S stream and fill in the /// caller-provided ObjectIndexMap. Expected mergeDebugT(ObjFile *File, CVIndexMap &ObjectIndexMap); Expected maybeMergeTypeServerPDB(ObjFile *File, TypeServer2Record &TS); /// Add the section map and section contributions to the PDB. void addSections(ArrayRef OutputSections, ArrayRef SectionTable); - void addSectionContrib(pdb::DbiModuleDescriptorBuilder &LinkerModule, - OutputSection *OS, Chunk *C); - /// Write the PDB to disk. void commit(); private: BumpPtrAllocator Alloc; SymbolTable *Symtab; pdb::PDBFileBuilder Builder; /// Type records that will go into the PDB TPI stream. MergingTypeTableBuilder TypeTable; /// Item records that will go into the PDB IPI stream. MergingTypeTableBuilder IDTable; /// Type records that will go into the PDB TPI stream (for /DEBUG:GHASH) GlobalTypeTableBuilder GlobalTypeTable; /// Item records that will go into the PDB IPI stream (for /DEBUG:GHASH) GlobalTypeTableBuilder GlobalIDTable; /// PDBs use a single global string table for filenames in the file checksum /// table. DebugStringTableSubsection PDBStrTab; llvm::SmallString<128> NativePath; + /// A list of other PDBs which are loaded during the linking process and which + /// we need to keep around since the linking operation may reference pointers + /// inside of these PDBs. + llvm::SmallVector, 2> LoadedPDBs; + std::vector SectionMap; /// Type index mappings of type server PDBs that we've loaded so far. std::map TypeServerIndexMappings; /// List of TypeServer PDBs which cannot be loaded. /// Cached to prevent repeated load attempts. std::set MissingTypeServerPDBs; }; } static SectionChunk *findByName(ArrayRef Sections, StringRef Name) { for (SectionChunk *C : Sections) if (C->getSectionName() == Name) return C; return nullptr; } static ArrayRef consumeDebugMagic(ArrayRef Data, StringRef SecName) { // First 4 bytes are section magic. if (Data.size() < 4) fatal(SecName + " too short"); if (support::endian::read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC) fatal(SecName + " has an invalid magic"); return Data.slice(4); } static ArrayRef getDebugSection(ObjFile *File, StringRef SecName) { if (SectionChunk *Sec = findByName(File->getDebugChunks(), SecName)) return consumeDebugMagic(Sec->getContents(), SecName); return {}; } // A COFF .debug$H section is currently a clang extension. This function checks // if a .debug$H section is in a format that we expect / understand, so that we // can ignore any sections which are coincidentally also named .debug$H but do // not contain a format we recognize. static bool canUseDebugH(ArrayRef DebugH) { if (DebugH.size() < sizeof(object::debug_h_header)) return false; auto *Header = reinterpret_cast(DebugH.data()); DebugH = DebugH.drop_front(sizeof(object::debug_h_header)); return Header->Magic == COFF::DEBUG_HASHES_SECTION_MAGIC && Header->Version == 0 && - Header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1) && - (DebugH.size() % 20 == 0); + Header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1_8) && + (DebugH.size() % 8 == 0); } static Optional> getDebugH(ObjFile *File) { SectionChunk *Sec = findByName(File->getDebugChunks(), ".debug$H"); if (!Sec) return llvm::None; ArrayRef Contents = Sec->getContents(); if (!canUseDebugH(Contents)) return None; return Contents; } static ArrayRef getHashesFromDebugH(ArrayRef DebugH) { assert(canUseDebugH(DebugH)); DebugH = DebugH.drop_front(sizeof(object::debug_h_header)); uint32_t Count = DebugH.size() / sizeof(GloballyHashedType); return {reinterpret_cast(DebugH.data()), Count}; } static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder, TypeCollection &TypeTable) { // Start the TPI or IPI stream header. TpiBuilder.setVersionHeader(pdb::PdbTpiV80); // Flatten the in memory type table and hash each type. TypeTable.ForEachRecord([&](TypeIndex TI, const CVType &Type) { auto Hash = pdb::hashTypeRecord(Type); if (auto E = Hash.takeError()) fatal("type hashing error"); TpiBuilder.addTypeRecord(Type.RecordData, *Hash); }); } static Optional maybeReadTypeServerRecord(CVTypeArray &Types) { auto I = Types.begin(); if (I == Types.end()) return None; const CVType &Type = *I; if (Type.kind() != LF_TYPESERVER2) return None; TypeServer2Record TS; if (auto EC = TypeDeserializer::deserializeAs(const_cast(Type), TS)) fatal("error reading type server record: " + toString(std::move(EC))); return std::move(TS); } Expected PDBLinker::mergeDebugT(ObjFile *File, CVIndexMap &ObjectIndexMap) { + ScopedTimer T(TypeMergingTimer); + ArrayRef Data = getDebugSection(File, ".debug$T"); if (Data.empty()) return ObjectIndexMap; BinaryByteStream Stream(Data, support::little); CVTypeArray Types; BinaryStreamReader Reader(Stream); if (auto EC = Reader.readArray(Types, Reader.getLength())) fatal("Reader::readArray failed: " + toString(std::move(EC))); // Look through type servers. If we've already seen this type server, don't // merge any type information. if (Optional TS = maybeReadTypeServerRecord(Types)) return maybeMergeTypeServerPDB(File, *TS); // This is a /Z7 object. Fill in the temporary, caller-provided // ObjectIndexMap. if (Config->DebugGHashes) { ArrayRef Hashes; std::vector OwnedHashes; if (Optional> DebugH = getDebugH(File)) Hashes = getHashesFromDebugH(*DebugH); else { OwnedHashes = GloballyHashedType::hashTypes(Types); Hashes = OwnedHashes; } if (auto Err = mergeTypeAndIdRecords(GlobalIDTable, GlobalTypeTable, ObjectIndexMap.TPIMap, Types, Hashes)) fatal("codeview::mergeTypeAndIdRecords failed: " + toString(std::move(Err))); } else { if (auto Err = mergeTypeAndIdRecords(IDTable, TypeTable, ObjectIndexMap.TPIMap, Types)) fatal("codeview::mergeTypeAndIdRecords failed: " + toString(std::move(Err))); } return ObjectIndexMap; } static Expected> tryToLoadPDB(const GUID &GuidFromObj, StringRef TSPath) { ErrorOr> MBOrErr = MemoryBuffer::getFile( TSPath, /*FileSize=*/-1, /*RequiresNullTerminator=*/false); if (!MBOrErr) return errorCodeToError(MBOrErr.getError()); std::unique_ptr ThisSession; if (auto EC = pdb::NativeSession::createFromPdb( MemoryBuffer::getMemBuffer(Driver->takeBuffer(std::move(*MBOrErr)), /*RequiresNullTerminator=*/false), ThisSession)) return std::move(EC); std::unique_ptr NS( static_cast(ThisSession.release())); pdb::PDBFile &File = NS->getPDBFile(); auto ExpectedInfo = File.getPDBInfoStream(); // All PDB Files should have an Info stream. if (!ExpectedInfo) return ExpectedInfo.takeError(); // Just because a file with a matching name was found and it was an actual // PDB file doesn't mean it matches. For it to match the InfoStream's GUID // must match the GUID specified in the TypeServer2 record. if (ExpectedInfo->getGuid() != GuidFromObj) return make_error( pdb::generic_error_code::type_server_not_found, TSPath); return std::move(NS); } Expected PDBLinker::maybeMergeTypeServerPDB(ObjFile *File, TypeServer2Record &TS) { const GUID& TSId = TS.getGuid(); StringRef TSPath = TS.getName(); // First, check if the PDB has previously failed to load. if (MissingTypeServerPDBs.count(TSId)) return make_error( pdb::generic_error_code::type_server_not_found, TSPath); // Second, check if we already loaded a PDB with this GUID. Return the type // index mapping if we have it. auto Insertion = TypeServerIndexMappings.insert({TSId, CVIndexMap()}); CVIndexMap &IndexMap = Insertion.first->second; if (!Insertion.second) return IndexMap; // Mark this map as a type server map. IndexMap.IsTypeServerMap = true; // Check for a PDB at: // 1. The given file path // 2. Next to the object file or archive file auto ExpectedSession = tryToLoadPDB(TSId, TSPath); if (!ExpectedSession) { consumeError(ExpectedSession.takeError()); StringRef LocalPath = !File->ParentName.empty() ? File->ParentName : File->getName(); SmallString<128> Path = sys::path::parent_path(LocalPath); sys::path::append( Path, sys::path::filename(TSPath, sys::path::Style::windows)); ExpectedSession = tryToLoadPDB(TSId, Path); } if (auto E = ExpectedSession.takeError()) { TypeServerIndexMappings.erase(TSId); MissingTypeServerPDBs.emplace(TSId); return std::move(E); } - auto ExpectedTpi = (*ExpectedSession)->getPDBFile().getPDBTpiStream(); + pdb::NativeSession *Session = ExpectedSession->get(); + + // Keep a strong reference to this PDB, so that it's safe to hold pointers + // into the file. + LoadedPDBs.push_back(std::move(*ExpectedSession)); + + auto ExpectedTpi = Session->getPDBFile().getPDBTpiStream(); if (auto E = ExpectedTpi.takeError()) fatal("Type server does not have TPI stream: " + toString(std::move(E))); - auto ExpectedIpi = (*ExpectedSession)->getPDBFile().getPDBIpiStream(); + auto ExpectedIpi = Session->getPDBFile().getPDBIpiStream(); if (auto E = ExpectedIpi.takeError()) fatal("Type server does not have TPI stream: " + toString(std::move(E))); if (Config->DebugGHashes) { // PDBs do not actually store global hashes, so when merging a type server // PDB we have to synthesize global hashes. To do this, we first synthesize // global hashes for the TPI stream, since it is independent, then we // synthesize hashes for the IPI stream, using the hashes for the TPI stream // as inputs. auto TpiHashes = GloballyHashedType::hashTypes(ExpectedTpi->typeArray()); auto IpiHashes = GloballyHashedType::hashIds(ExpectedIpi->typeArray(), TpiHashes); // Merge TPI first, because the IPI stream will reference type indices. if (auto Err = mergeTypeRecords(GlobalTypeTable, IndexMap.TPIMap, ExpectedTpi->typeArray(), TpiHashes)) fatal("codeview::mergeTypeRecords failed: " + toString(std::move(Err))); // Merge IPI. if (auto Err = mergeIdRecords(GlobalIDTable, IndexMap.TPIMap, IndexMap.IPIMap, ExpectedIpi->typeArray(), IpiHashes)) fatal("codeview::mergeIdRecords failed: " + toString(std::move(Err))); } else { // Merge TPI first, because the IPI stream will reference type indices. if (auto Err = mergeTypeRecords(TypeTable, IndexMap.TPIMap, ExpectedTpi->typeArray())) fatal("codeview::mergeTypeRecords failed: " + toString(std::move(Err))); // Merge IPI. if (auto Err = mergeIdRecords(IDTable, IndexMap.TPIMap, IndexMap.IPIMap, ExpectedIpi->typeArray())) fatal("codeview::mergeIdRecords failed: " + toString(std::move(Err))); } return IndexMap; } static bool remapTypeIndex(TypeIndex &TI, ArrayRef TypeIndexMap) { if (TI.isSimple()) return true; if (TI.toArrayIndex() >= TypeIndexMap.size()) return false; TI = TypeIndexMap[TI.toArrayIndex()]; return true; } static void remapTypesInSymbolRecord(ObjFile *File, SymbolKind SymKind, MutableArrayRef Contents, const CVIndexMap &IndexMap, ArrayRef TypeRefs) { for (const TiReference &Ref : TypeRefs) { unsigned ByteSize = Ref.Count * sizeof(TypeIndex); if (Contents.size() < Ref.Offset + ByteSize) fatal("symbol record too short"); // This can be an item index or a type index. Choose the appropriate map. ArrayRef TypeOrItemMap = IndexMap.TPIMap; bool IsItemIndex = Ref.Kind == TiRefKind::IndexRef; if (IsItemIndex && IndexMap.IsTypeServerMap) TypeOrItemMap = IndexMap.IPIMap; MutableArrayRef TIs( reinterpret_cast(Contents.data() + Ref.Offset), Ref.Count); for (TypeIndex &TI : TIs) { if (!remapTypeIndex(TI, TypeOrItemMap)) { log("ignoring symbol record of kind 0x" + utohexstr(SymKind) + " in " + File->getName() + " with bad " + (IsItemIndex ? "item" : "type") + " index 0x" + utohexstr(TI.getIndex())); TI = TypeIndex(SimpleTypeKind::NotTranslated); continue; } } } } +static void +recordStringTableReferenceAtOffset(MutableArrayRef Contents, + uint32_t Offset, + std::vector &StrTableRefs) { + Contents = + Contents.drop_front(Offset).take_front(sizeof(support::ulittle32_t)); + ulittle32_t *Index = reinterpret_cast(Contents.data()); + StrTableRefs.push_back(Index); +} + +static void +recordStringTableReferences(SymbolKind Kind, MutableArrayRef Contents, + std::vector &StrTableRefs) { + // For now we only handle S_FILESTATIC, but we may need the same logic for + // S_DEFRANGE and S_DEFRANGE_SUBFIELD. However, I cannot seem to generate any + // PDBs that contain these types of records, so because of the uncertainty + // they are omitted here until we can prove that it's necessary. + switch (Kind) { + case SymbolKind::S_FILESTATIC: + // FileStaticSym::ModFileOffset + recordStringTableReferenceAtOffset(Contents, 4, StrTableRefs); + break; + case SymbolKind::S_DEFRANGE: + case SymbolKind::S_DEFRANGE_SUBFIELD: + log("Not fixing up string table reference in S_DEFRANGE / " + "S_DEFRANGE_SUBFIELD record"); + break; + default: + break; + } +} + static SymbolKind symbolKind(ArrayRef RecordData) { const RecordPrefix *Prefix = reinterpret_cast(RecordData.data()); return static_cast(uint16_t(Prefix->RecordKind)); } /// MSVC translates S_PROC_ID_END to S_END, and S_[LG]PROC32_ID to S_[LG]PROC32 static void translateIdSymbols(MutableArrayRef &RecordData, TypeCollection &IDTable) { RecordPrefix *Prefix = reinterpret_cast(RecordData.data()); SymbolKind Kind = symbolKind(RecordData); if (Kind == SymbolKind::S_PROC_ID_END) { Prefix->RecordKind = SymbolKind::S_END; return; } // In an object file, GPROC32_ID has an embedded reference which refers to the // single object file type index namespace. This has already been translated // to the PDB file's ID stream index space, but we need to convert this to a // symbol that refers to the type stream index space. So we remap again from // ID index space to type index space. if (Kind == SymbolKind::S_GPROC32_ID || Kind == SymbolKind::S_LPROC32_ID) { SmallVector Refs; auto Content = RecordData.drop_front(sizeof(RecordPrefix)); CVSymbol Sym(Kind, RecordData); discoverTypeIndicesInSymbol(Sym, Refs); assert(Refs.size() == 1); assert(Refs.front().Count == 1); TypeIndex *TI = reinterpret_cast(Content.data() + Refs[0].Offset); // `TI` is the index of a FuncIdRecord or MemberFuncIdRecord which lives in // the IPI stream, whose `FunctionType` member refers to the TPI stream. // Note that LF_FUNC_ID and LF_MEMFUNC_ID have the same record layout, and // in both cases we just need the second type index. if (!TI->isSimple() && !TI->isNoneType()) { CVType FuncIdData = IDTable.getType(*TI); SmallVector Indices; discoverTypeIndices(FuncIdData, Indices); assert(Indices.size() == 2); *TI = Indices[1]; } Kind = (Kind == SymbolKind::S_GPROC32_ID) ? SymbolKind::S_GPROC32 : SymbolKind::S_LPROC32; Prefix->RecordKind = uint16_t(Kind); } } /// Copy the symbol record. In a PDB, symbol records must be 4 byte aligned. /// The object file may not be aligned. static MutableArrayRef copySymbolForPdb(const CVSymbol &Sym, BumpPtrAllocator &Alloc) { size_t Size = alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb)); assert(Size >= 4 && "record too short"); assert(Size <= MaxRecordLength && "record too long"); void *Mem = Alloc.Allocate(Size, 4); // Copy the symbol record and zero out any padding bytes. MutableArrayRef NewData(reinterpret_cast(Mem), Size); memcpy(NewData.data(), Sym.data().data(), Sym.length()); memset(NewData.data() + Sym.length(), 0, Size - Sym.length()); // Update the record prefix length. It should point to the beginning of the // next record. auto *Prefix = reinterpret_cast(Mem); Prefix->RecordLen = Size - 2; return NewData; } /// Return true if this symbol opens a scope. This implies that the symbol has /// "parent" and "end" fields, which contain the offset of the S_END or /// S_INLINESITE_END record. static bool symbolOpensScope(SymbolKind Kind) { switch (Kind) { case SymbolKind::S_GPROC32: case SymbolKind::S_LPROC32: case SymbolKind::S_LPROC32_ID: case SymbolKind::S_GPROC32_ID: case SymbolKind::S_BLOCK32: case SymbolKind::S_SEPCODE: case SymbolKind::S_THUNK32: case SymbolKind::S_INLINESITE: case SymbolKind::S_INLINESITE2: return true; default: break; } return false; } static bool symbolEndsScope(SymbolKind Kind) { switch (Kind) { case SymbolKind::S_END: case SymbolKind::S_PROC_ID_END: case SymbolKind::S_INLINESITE_END: return true; default: break; } return false; } struct ScopeRecord { ulittle32_t PtrParent; ulittle32_t PtrEnd; }; struct SymbolScope { ScopeRecord *OpeningRecord; uint32_t ScopeOffset; }; static void scopeStackOpen(SmallVectorImpl &Stack, uint32_t CurOffset, CVSymbol &Sym) { assert(symbolOpensScope(Sym.kind())); SymbolScope S; S.ScopeOffset = CurOffset; S.OpeningRecord = const_cast( reinterpret_cast(Sym.content().data())); S.OpeningRecord->PtrParent = Stack.empty() ? 0 : Stack.back().ScopeOffset; Stack.push_back(S); } static void scopeStackClose(SmallVectorImpl &Stack, uint32_t CurOffset, ObjFile *File) { if (Stack.empty()) { warn("symbol scopes are not balanced in " + File->getName()); return; } SymbolScope S = Stack.pop_back_val(); S.OpeningRecord->PtrEnd = CurOffset; } static bool symbolGoesInModuleStream(const CVSymbol &Sym) { switch (Sym.kind()) { case SymbolKind::S_GDATA32: case SymbolKind::S_CONSTANT: case SymbolKind::S_UDT: // We really should not be seeing S_PROCREF and S_LPROCREF in the first place // since they are synthesized by the linker in response to S_GPROC32 and // S_LPROC32, but if we do see them, don't put them in the module stream I // guess. case SymbolKind::S_PROCREF: case SymbolKind::S_LPROCREF: return false; // S_GDATA32 does not go in the module stream, but S_LDATA32 does. case SymbolKind::S_LDATA32: default: return true; } } static bool symbolGoesInGlobalsStream(const CVSymbol &Sym) { switch (Sym.kind()) { case SymbolKind::S_CONSTANT: case SymbolKind::S_GDATA32: // S_LDATA32 goes in both the module stream and the globals stream. case SymbolKind::S_LDATA32: case SymbolKind::S_GPROC32: case SymbolKind::S_LPROC32: // We really should not be seeing S_PROCREF and S_LPROCREF in the first place // since they are synthesized by the linker in response to S_GPROC32 and // S_LPROC32, but if we do see them, copy them straight through. case SymbolKind::S_PROCREF: case SymbolKind::S_LPROCREF: return true; // FIXME: For now, we drop all S_UDT symbols (i.e. they don't go in the // globals stream or the modules stream). These have special handling which // needs more investigation before we can get right, but by putting them all // into the globals stream WinDbg fails to display local variables of class // types saying that it cannot find the type Foo *. So as a stopgap just to // keep things working, we drop them. case SymbolKind::S_UDT: default: return false; } } static void addGlobalSymbol(pdb::GSIStreamBuilder &Builder, ObjFile &File, const CVSymbol &Sym) { switch (Sym.kind()) { case SymbolKind::S_CONSTANT: case SymbolKind::S_UDT: case SymbolKind::S_GDATA32: case SymbolKind::S_LDATA32: case SymbolKind::S_PROCREF: case SymbolKind::S_LPROCREF: Builder.addGlobalSymbol(Sym); break; case SymbolKind::S_GPROC32: case SymbolKind::S_LPROC32: { SymbolRecordKind K = SymbolRecordKind::ProcRefSym; if (Sym.kind() == SymbolKind::S_LPROC32) K = SymbolRecordKind::LocalProcRef; ProcRefSym PS(K); PS.Module = static_cast(File.ModuleDBI->getModuleIndex()); // For some reason, MSVC seems to add one to this value. ++PS.Module; PS.Name = getSymbolName(Sym); PS.SumName = 0; PS.SymOffset = File.ModuleDBI->getNextSymbolOffset(); Builder.addGlobalSymbol(PS); break; } default: llvm_unreachable("Invalid symbol kind!"); } } static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjFile *File, pdb::GSIStreamBuilder &GsiBuilder, const CVIndexMap &IndexMap, TypeCollection &IDTable, + std::vector &StringTableRefs, BinaryStreamRef SymData) { // FIXME: Improve error recovery by warning and skipping records when // possible. - CVSymbolArray Syms; - BinaryStreamReader Reader(SymData); - ExitOnErr(Reader.readArray(Syms, Reader.getLength())); + ArrayRef SymsBuffer; + cantFail(SymData.readBytes(0, SymData.getLength(), SymsBuffer)); SmallVector Scopes; - for (CVSymbol Sym : Syms) { - // Discover type index references in the record. Skip it if we don't know - // where they are. - SmallVector TypeRefs; - if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) { - log("ignoring unknown symbol record with kind 0x" + utohexstr(Sym.kind())); - continue; - } - // Copy the symbol record so we can mutate it. - MutableArrayRef NewData = copySymbolForPdb(Sym, Alloc); + auto EC = forEachCodeViewRecord( + SymsBuffer, [&](const CVSymbol &Sym) -> llvm::Error { + // Discover type index references in the record. Skip it if we don't + // know where they are. + SmallVector TypeRefs; + if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) { + log("ignoring unknown symbol record with kind 0x" + + utohexstr(Sym.kind())); + return Error::success(); + } - // Re-map all the type index references. - MutableArrayRef Contents = - NewData.drop_front(sizeof(RecordPrefix)); - remapTypesInSymbolRecord(File, Sym.kind(), Contents, IndexMap, TypeRefs); + // Copy the symbol record so we can mutate it. + MutableArrayRef NewData = copySymbolForPdb(Sym, Alloc); - // An object file may have S_xxx_ID symbols, but these get converted to - // "real" symbols in a PDB. - translateIdSymbols(NewData, IDTable); + // Re-map all the type index references. + MutableArrayRef Contents = + NewData.drop_front(sizeof(RecordPrefix)); + remapTypesInSymbolRecord(File, Sym.kind(), Contents, IndexMap, + TypeRefs); - SymbolKind NewKind = symbolKind(NewData); + // An object file may have S_xxx_ID symbols, but these get converted to + // "real" symbols in a PDB. + translateIdSymbols(NewData, IDTable); - // Fill in "Parent" and "End" fields by maintaining a stack of scopes. - CVSymbol NewSym(NewKind, NewData); - if (symbolOpensScope(NewKind)) - scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), NewSym); - else if (symbolEndsScope(NewKind)) - scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File); + // If this record refers to an offset in the object file's string table, + // add that item to the global PDB string table and re-write the index. + recordStringTableReferences(Sym.kind(), Contents, StringTableRefs); - // Add the symbol to the globals stream if necessary. Do this before adding - // the symbol to the module since we may need to get the next symbol offset, - // and writing to the module's symbol stream will update that offset. - if (symbolGoesInGlobalsStream(NewSym)) - addGlobalSymbol(GsiBuilder, *File, NewSym); + SymbolKind NewKind = symbolKind(NewData); - // Add the symbol to the module. - if (symbolGoesInModuleStream(NewSym)) - File->ModuleDBI->addSymbol(NewSym); - } + // Fill in "Parent" and "End" fields by maintaining a stack of scopes. + CVSymbol NewSym(NewKind, NewData); + if (symbolOpensScope(NewKind)) + scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), + NewSym); + else if (symbolEndsScope(NewKind)) + scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File); + + // Add the symbol to the globals stream if necessary. Do this before + // adding the symbol to the module since we may need to get the next + // symbol offset, and writing to the module's symbol stream will update + // that offset. + if (symbolGoesInGlobalsStream(NewSym)) + addGlobalSymbol(GsiBuilder, *File, NewSym); + + // Add the symbol to the module. + if (symbolGoesInModuleStream(NewSym)) + File->ModuleDBI->addSymbol(NewSym); + return Error::success(); + }); + cantFail(std::move(EC)); } // Allocate memory for a .debug$S section and relocate it. static ArrayRef relocateDebugChunk(BumpPtrAllocator &Alloc, SectionChunk *DebugChunk) { uint8_t *Buffer = Alloc.Allocate(DebugChunk->getSize()); assert(DebugChunk->OutputSectionOff == 0 && "debug sections should not be in output sections"); DebugChunk->writeTo(Buffer); return consumeDebugMagic(makeArrayRef(Buffer, DebugChunk->getSize()), ".debug$S"); } +static pdb::SectionContrib createSectionContrib(const Chunk *C, uint32_t Modi) { + OutputSection *OS = C->getOutputSection(); + pdb::SectionContrib SC; + memset(&SC, 0, sizeof(SC)); + SC.ISect = OS->SectionIndex; + SC.Off = C->getRVA() - OS->getRVA(); + SC.Size = C->getSize(); + if (auto *SecChunk = dyn_cast(C)) { + SC.Characteristics = SecChunk->Header->Characteristics; + SC.Imod = SecChunk->File->ModuleDBI->getModuleIndex(); + ArrayRef Contents = SecChunk->getContents(); + JamCRC CRC(0); + ArrayRef CharContents = makeArrayRef( + reinterpret_cast(Contents.data()), Contents.size()); + CRC.update(CharContents); + SC.DataCrc = CRC.getCRC(); + } else { + SC.Characteristics = OS->Header.Characteristics; + // FIXME: When we start creating DBI for import libraries, use those here. + SC.Imod = Modi; + } + SC.RelocCrc = 0; // FIXME + + return SC; +} + void PDBLinker::addObjFile(ObjFile *File) { // Add a module descriptor for every object file. We need to put an absolute // path to the object into the PDB. If this is a plain object, we make its // path absolute. If it's an object in an archive, we make the archive path // absolute. bool InArchive = !File->ParentName.empty(); SmallString<128> Path = InArchive ? File->ParentName : File->getName(); sys::fs::make_absolute(Path); sys::path::native(Path, sys::path::Style::windows); StringRef Name = InArchive ? File->getName() : StringRef(Path); File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name)); File->ModuleDBI->setObjFileName(Path); + auto Chunks = File->getChunks(); + uint32_t Modi = File->ModuleDBI->getModuleIndex(); + for (Chunk *C : Chunks) { + auto *SecChunk = dyn_cast(C); + if (!SecChunk || !SecChunk->isLive()) + continue; + pdb::SectionContrib SC = createSectionContrib(SecChunk, Modi); + File->ModuleDBI->setFirstSectionContrib(SC); + break; + } + // Before we can process symbol substreams from .debug$S, we need to process // type information, file checksums, and the string table. Add type info to // the PDB first, so that we can get the map from object file type and item // indices to PDB type and item indices. CVIndexMap ObjectIndexMap; auto IndexMapResult = mergeDebugT(File, ObjectIndexMap); // If the .debug$T sections fail to merge, assume there is no debug info. if (!IndexMapResult) { warn("Type server PDB for " + Name + " is invalid, ignoring debug info. " + toString(IndexMapResult.takeError())); return; } const CVIndexMap &IndexMap = *IndexMapResult; + ScopedTimer T(SymbolMergingTimer); + // Now do all live .debug$S sections. + DebugStringTableSubsectionRef CVStrTab; + DebugChecksumsSubsectionRef Checksums; + std::vector StringTableReferences; for (SectionChunk *DebugChunk : File->getDebugChunks()) { if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S") continue; ArrayRef RelocatedDebugContents = relocateDebugChunk(Alloc, DebugChunk); if (RelocatedDebugContents.empty()) continue; DebugSubsectionArray Subsections; BinaryStreamReader Reader(RelocatedDebugContents, support::little); ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size())); - DebugStringTableSubsectionRef CVStrTab; - DebugChecksumsSubsectionRef Checksums; for (const DebugSubsectionRecord &SS : Subsections) { switch (SS.kind()) { - case DebugSubsectionKind::StringTable: + case DebugSubsectionKind::StringTable: { + assert(!CVStrTab.valid() && + "Encountered multiple string table subsections!"); ExitOnErr(CVStrTab.initialize(SS.getRecordData())); break; + } case DebugSubsectionKind::FileChecksums: + assert(!Checksums.valid() && + "Encountered multiple checksum subsections!"); ExitOnErr(Checksums.initialize(SS.getRecordData())); break; case DebugSubsectionKind::Lines: // We can add the relocated line table directly to the PDB without // modification because the file checksum offsets will stay the same. File->ModuleDBI->addDebugSubsection(SS); break; case DebugSubsectionKind::Symbols: if (Config->DebugGHashes) { mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap, - GlobalIDTable, SS.getRecordData()); + GlobalIDTable, StringTableReferences, + SS.getRecordData()); } else { mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap, - IDTable, SS.getRecordData()); + IDTable, StringTableReferences, + SS.getRecordData()); } break; default: // FIXME: Process the rest of the subsections. break; } } + } - if (Checksums.valid()) { - // Make a new file checksum table that refers to offsets in the PDB-wide - // string table. Generally the string table subsection appears after the - // checksum table, so we have to do this after looping over all the - // subsections. - if (!CVStrTab.valid()) - fatal(".debug$S sections must have both a string table subsection " - "and a checksum subsection table or neither"); - auto NewChecksums = make_unique(PDBStrTab); - for (FileChecksumEntry &FC : Checksums) { - StringRef FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); - ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile(*File->ModuleDBI, - FileName)); - NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum); - } - File->ModuleDBI->addDebugSubsection(std::move(NewChecksums)); + // We should have seen all debug subsections across the entire object file now + // which means that if a StringTable subsection and Checksums subsection were + // present, now is the time to handle them. + if (!CVStrTab.valid()) { + if (Checksums.valid()) + fatal(".debug$S sections with a checksums subsection must also contain a " + "string table subsection"); + + if (!StringTableReferences.empty()) + warn("No StringTable subsection was encountered, but there are string " + "table references"); + return; + } + + // Rewrite each string table reference based on the value that the string + // assumes in the final PDB. + for (ulittle32_t *Ref : StringTableReferences) { + auto ExpectedString = CVStrTab.getString(*Ref); + if (!ExpectedString) { + warn("Invalid string table reference"); + consumeError(ExpectedString.takeError()); + continue; } + + *Ref = PDBStrTab.insert(*ExpectedString); } + + // Make a new file checksum table that refers to offsets in the PDB-wide + // string table. Generally the string table subsection appears after the + // checksum table, so we have to do this after looping over all the + // subsections. + auto NewChecksums = make_unique(PDBStrTab); + for (FileChecksumEntry &FC : Checksums) { + SmallString<128> FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); + if (!sys::path::is_absolute(FileName) && + !Config->PDBSourcePath.empty()) { + SmallString<128> AbsoluteFileName = Config->PDBSourcePath; + sys::path::append(AbsoluteFileName, FileName); + sys::path::native(AbsoluteFileName); + sys::path::remove_dots(AbsoluteFileName, /*remove_dot_dots=*/true); + FileName = std::move(AbsoluteFileName); + } + ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile(*File->ModuleDBI, + FileName)); + NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum); + } + File->ModuleDBI->addDebugSubsection(std::move(NewChecksums)); } static PublicSym32 createPublic(Defined *Def) { PublicSym32 Pub(SymbolKind::S_PUB32); Pub.Name = Def->getName(); if (auto *D = dyn_cast(Def)) { if (D->getCOFFSymbol().isFunctionDefinition()) Pub.Flags = PublicSymFlags::Function; } else if (isa(Def)) { Pub.Flags = PublicSymFlags::Function; } OutputSection *OS = Def->getChunk()->getOutputSection(); assert(OS && "all publics should be in final image"); Pub.Offset = Def->getRVA() - OS->getRVA(); Pub.Segment = OS->SectionIndex; return Pub; } // Add all object files to the PDB. Merge .debug$T sections into IpiData and // TpiData. void PDBLinker::addObjectsToPDB() { + ScopedTimer T1(AddObjectsTimer); for (ObjFile *File : ObjFile::Instances) addObjFile(File); Builder.getStringTableBuilder().setStrings(PDBStrTab); + T1.stop(); // Construct TPI and IPI stream contents. + ScopedTimer T2(TpiStreamLayoutTimer); if (Config->DebugGHashes) { addTypeInfo(Builder.getTpiBuilder(), GlobalTypeTable); addTypeInfo(Builder.getIpiBuilder(), GlobalIDTable); } else { addTypeInfo(Builder.getTpiBuilder(), TypeTable); addTypeInfo(Builder.getIpiBuilder(), IDTable); } + T2.stop(); + ScopedTimer T3(GlobalsLayoutTimer); // Compute the public and global symbols. auto &GsiBuilder = Builder.getGsiBuilder(); std::vector Publics; Symtab->forEachSymbol([&Publics](Symbol *S) { // Only emit defined, live symbols that have a chunk. auto *Def = dyn_cast(S); if (Def && Def->isLive() && Def->getChunk()) Publics.push_back(createPublic(Def)); }); if (!Publics.empty()) { // Sort the public symbols and add them to the stream. std::sort(Publics.begin(), Publics.end(), [](const PublicSym32 &L, const PublicSym32 &R) { return L.Name < R.Name; }); for (const PublicSym32 &Pub : Publics) GsiBuilder.addPublicSymbol(Pub); } } +void PDBLinker::addNatvisFiles() { + for (StringRef File : Config->NatvisFiles) { + ErrorOr> DataOrErr = + MemoryBuffer::getFile(File); + if (!DataOrErr) { + warn("Cannot open input file: " + File); + continue; + } + Builder.addInjectedSource(File, std::move(*DataOrErr)); + } +} + +static codeview::CPUType toCodeViewMachine(COFF::MachineTypes Machine) { + switch (Machine) { + case COFF::IMAGE_FILE_MACHINE_AMD64: + return codeview::CPUType::X64; + case COFF::IMAGE_FILE_MACHINE_ARM: + return codeview::CPUType::ARM7; + case COFF::IMAGE_FILE_MACHINE_ARM64: + return codeview::CPUType::ARM64; + case COFF::IMAGE_FILE_MACHINE_ARMNT: + return codeview::CPUType::ARMNT; + case COFF::IMAGE_FILE_MACHINE_I386: + return codeview::CPUType::Intel80386; + default: + llvm_unreachable("Unsupported CPU Type"); + } +} + static void addCommonLinkerModuleSymbols(StringRef Path, pdb::DbiModuleDescriptorBuilder &Mod, BumpPtrAllocator &Allocator) { ObjNameSym ONS(SymbolRecordKind::ObjNameSym); Compile3Sym CS(SymbolRecordKind::Compile3Sym); EnvBlockSym EBS(SymbolRecordKind::EnvBlockSym); ONS.Name = "* Linker *"; ONS.Signature = 0; - CS.Machine = Config->is64() ? CPUType::X64 : CPUType::Intel80386; + CS.Machine = toCodeViewMachine(Config->Machine); // Interestingly, if we set the string to 0.0.0.0, then when trying to view // local variables WinDbg emits an error that private symbols are not present. // By setting this to a valid MSVC linker version string, local variables are // displayed properly. As such, even though it is not representative of // LLVM's version information, we need this for compatibility. CS.Flags = CompileSym3Flags::None; CS.VersionBackendBuild = 25019; CS.VersionBackendMajor = 14; CS.VersionBackendMinor = 10; CS.VersionBackendQFE = 0; // MSVC also sets the frontend to 0.0.0.0 since this is specifically for the // linker module (which is by definition a backend), so we don't need to do // anything here. Also, it seems we can use "LLVM Linker" for the linker name // without any problems. Only the backend version has to be hardcoded to a // magic number. CS.VersionFrontendBuild = 0; CS.VersionFrontendMajor = 0; CS.VersionFrontendMinor = 0; CS.VersionFrontendQFE = 0; CS.Version = "LLVM Linker"; CS.setLanguage(SourceLanguage::Link); ArrayRef Args = makeArrayRef(Config->Argv).drop_front(); std::string ArgStr = llvm::join(Args, " "); EBS.Fields.push_back("cwd"); SmallString<64> cwd; sys::fs::current_path(cwd); EBS.Fields.push_back(cwd); EBS.Fields.push_back("exe"); SmallString<64> exe = Config->Argv[0]; llvm::sys::fs::make_absolute(exe); EBS.Fields.push_back(exe); EBS.Fields.push_back("pdb"); EBS.Fields.push_back(Path); EBS.Fields.push_back("cmd"); EBS.Fields.push_back(ArgStr); Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( ONS, Allocator, CodeViewContainer::Pdb)); Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( CS, Allocator, CodeViewContainer::Pdb)); Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( EBS, Allocator, CodeViewContainer::Pdb)); } static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &Mod, OutputSection &OS, BumpPtrAllocator &Allocator) { SectionSym Sym(SymbolRecordKind::SectionSym); Sym.Alignment = 12; // 2^12 = 4KB - Sym.Characteristics = OS.getCharacteristics(); + Sym.Characteristics = OS.Header.Characteristics; Sym.Length = OS.getVirtualSize(); - Sym.Name = OS.getName(); + Sym.Name = OS.Name; Sym.Rva = OS.getRVA(); Sym.SectionNumber = OS.SectionIndex; Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( Sym, Allocator, CodeViewContainer::Pdb)); } // Creates a PDB file. void coff::createPDB(SymbolTable *Symtab, ArrayRef OutputSections, ArrayRef SectionTable, const llvm::codeview::DebugInfo &BuildId) { + ScopedTimer T1(TotalPdbLinkTimer); PDBLinker PDB(Symtab); + PDB.initialize(BuildId); PDB.addObjectsToPDB(); PDB.addSections(OutputSections, SectionTable); + PDB.addNatvisFiles(); + + ScopedTimer T2(DiskCommitTimer); PDB.commit(); } void PDBLinker::initialize(const llvm::codeview::DebugInfo &BuildId) { 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(BuildId.PDB70.Age); - GUID uuid; memcpy(&uuid, &BuildId.PDB70.Signature, sizeof(uuid)); + InfoBuilder.setAge(BuildId.PDB70.Age); InfoBuilder.setGuid(uuid); - InfoBuilder.setSignature(time(nullptr)); InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70); // Add an empty DBI stream. pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); DbiBuilder.setAge(BuildId.PDB70.Age); DbiBuilder.setVersionHeader(pdb::PdbDbiV70); - ExitOnErr(DbiBuilder.addDbgStream(pdb::DbgHeaderType::NewFPO, {})); + DbiBuilder.setMachineType(Config->Machine); + // Technically we are not link.exe 14.11, but there are known cases where + // debugging tools on Windows expect Microsoft-specific version numbers or + // they fail to work at all. Since we know we produce PDBs that are + // compatible with LINK 14.11, we set that version number here. + DbiBuilder.setBuildNumber(14, 11); } -void PDBLinker::addSectionContrib(pdb::DbiModuleDescriptorBuilder &LinkerModule, - OutputSection *OS, Chunk *C) { - pdb::SectionContrib SC; - memset(&SC, 0, sizeof(SC)); - SC.ISect = OS->SectionIndex; - SC.Off = C->getRVA() - OS->getRVA(); - SC.Size = C->getSize(); - if (auto *SecChunk = dyn_cast(C)) { - SC.Characteristics = SecChunk->Header->Characteristics; - SC.Imod = SecChunk->File->ModuleDBI->getModuleIndex(); - ArrayRef Contents = SecChunk->getContents(); - JamCRC CRC(0); - ArrayRef CharContents = makeArrayRef( - reinterpret_cast(Contents.data()), Contents.size()); - CRC.update(CharContents); - SC.DataCrc = CRC.getCRC(); - } else { - SC.Characteristics = OS->getCharacteristics(); - // FIXME: When we start creating DBI for import libraries, use those here. - SC.Imod = LinkerModule.getModuleIndex(); - } - SC.RelocCrc = 0; // FIXME - Builder.getDbiBuilder().addSectionContrib(SC); -} - void PDBLinker::addSections(ArrayRef OutputSections, ArrayRef SectionTable) { // It's not entirely clear what this is, but the * Linker * module uses it. pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); NativePath = Config->PDBPath; sys::fs::make_absolute(NativePath); sys::path::native(NativePath, sys::path::Style::windows); uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath); auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *")); LinkerModule.setPdbFilePathNI(PdbFilePathNI); addCommonLinkerModuleSymbols(NativePath, LinkerModule, Alloc); // Add section contributions. They must be ordered by ascending RVA. for (OutputSection *OS : OutputSections) { addLinkerModuleSectionSymbol(LinkerModule, *OS, Alloc); - for (Chunk *C : OS->getChunks()) - addSectionContrib(LinkerModule, OS, C); + for (Chunk *C : OS->getChunks()) { + pdb::SectionContrib SC = + createSectionContrib(C, LinkerModule.getModuleIndex()); + Builder.getDbiBuilder().addSectionContrib(SC); + } } // Add Section Map stream. ArrayRef Sections = { (const object::coff_section *)SectionTable.data(), SectionTable.size() / sizeof(object::coff_section)}; SectionMap = pdb::DbiStreamBuilder::createSectionMap(Sections); DbiBuilder.setSectionMap(SectionMap); // Add COFF section header stream. ExitOnErr( DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable)); } void PDBLinker::commit() { // Write to a file. ExitOnErr(Builder.commit(Config->PDBPath)); +} + +static Expected +getFileName(const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID) { + auto Iter = Checksums.getArray().at(FileID); + if (Iter == Checksums.getArray().end()) + return make_error(cv_error_code::no_records); + uint32_t Offset = Iter->FileNameOffset; + return Strings.getString(Offset); +} + +static uint32_t getSecrelReloc() { + switch (Config->Machine) { + case AMD64: + return COFF::IMAGE_REL_AMD64_SECREL; + case I386: + return COFF::IMAGE_REL_I386_SECREL; + case ARMNT: + return COFF::IMAGE_REL_ARM_SECREL; + case ARM64: + return COFF::IMAGE_REL_ARM64_SECREL; + default: + llvm_unreachable("unknown machine type"); + } +} + +// Try to find a line table for the given offset Addr into the given chunk C. +// If a line table was found, the line table, the string and checksum tables +// that are used to interpret the line table, and the offset of Addr in the line +// table are stored in the output arguments. Returns whether a line table was +// found. +static bool findLineTable(const SectionChunk *C, uint32_t Addr, + DebugStringTableSubsectionRef &CVStrTab, + DebugChecksumsSubsectionRef &Checksums, + DebugLinesSubsectionRef &Lines, + uint32_t &OffsetInLinetable) { + ExitOnError ExitOnErr; + uint32_t SecrelReloc = getSecrelReloc(); + + for (SectionChunk *DbgC : C->File->getDebugChunks()) { + if (DbgC->getSectionName() != ".debug$S") + continue; + + // Build a mapping of SECREL relocations in DbgC that refer to C. + DenseMap Secrels; + for (const coff_relocation &R : DbgC->Relocs) { + if (R.Type != SecrelReloc) + continue; + + if (auto *S = dyn_cast_or_null( + C->File->getSymbols()[R.SymbolTableIndex])) + if (S->getChunk() == C) + Secrels[R.VirtualAddress] = S->getValue(); + } + + ArrayRef Contents = + consumeDebugMagic(DbgC->getContents(), ".debug$S"); + DebugSubsectionArray Subsections; + BinaryStreamReader Reader(Contents, support::little); + ExitOnErr(Reader.readArray(Subsections, Contents.size())); + + for (const DebugSubsectionRecord &SS : Subsections) { + switch (SS.kind()) { + case DebugSubsectionKind::StringTable: { + assert(!CVStrTab.valid() && + "Encountered multiple string table subsections!"); + ExitOnErr(CVStrTab.initialize(SS.getRecordData())); + break; + } + case DebugSubsectionKind::FileChecksums: + assert(!Checksums.valid() && + "Encountered multiple checksum subsections!"); + ExitOnErr(Checksums.initialize(SS.getRecordData())); + break; + case DebugSubsectionKind::Lines: { + ArrayRef Bytes; + auto Ref = SS.getRecordData(); + ExitOnErr(Ref.readLongestContiguousChunk(0, Bytes)); + size_t OffsetInDbgC = Bytes.data() - DbgC->getContents().data(); + + // Check whether this line table refers to C. + auto I = Secrels.find(OffsetInDbgC); + if (I == Secrels.end()) + break; + + // Check whether this line table covers Addr in C. + DebugLinesSubsectionRef LinesTmp; + ExitOnErr(LinesTmp.initialize(BinaryStreamReader(Ref))); + uint32_t OffsetInC = I->second + LinesTmp.header()->RelocOffset; + if (Addr < OffsetInC || Addr >= OffsetInC + LinesTmp.header()->CodeSize) + break; + + assert(!Lines.header() && + "Encountered multiple line tables for function!"); + ExitOnErr(Lines.initialize(BinaryStreamReader(Ref))); + OffsetInLinetable = Addr - OffsetInC; + break; + } + default: + break; + } + + if (CVStrTab.valid() && Checksums.valid() && Lines.header()) + return true; + } + } + + return false; +} + +// Use CodeView line tables to resolve a file and line number for the given +// offset into the given chunk and return them, or {"", 0} if a line table was +// not found. +std::pair coff::getFileLine(const SectionChunk *C, + uint32_t Addr) { + ExitOnError ExitOnErr; + + DebugStringTableSubsectionRef CVStrTab; + DebugChecksumsSubsectionRef Checksums; + DebugLinesSubsectionRef Lines; + uint32_t OffsetInLinetable; + + if (!findLineTable(C, Addr, CVStrTab, Checksums, Lines, OffsetInLinetable)) + return {"", 0}; + + uint32_t NameIndex; + uint32_t LineNumber; + for (LineColumnEntry &Entry : Lines) { + for (const LineNumberEntry &LN : Entry.LineNumbers) { + if (LN.Offset > OffsetInLinetable) { + StringRef Filename = + ExitOnErr(getFileName(CVStrTab, Checksums, NameIndex)); + return {Filename, LineNumber}; + } + LineInfo LI(LN.Flags); + NameIndex = Entry.NameIndex; + LineNumber = LI.getStartLine(); + } + } + StringRef Filename = ExitOnErr(getFileName(CVStrTab, Checksums, NameIndex)); + return {Filename, LineNumber}; } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/PDB.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/PDB.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/PDB.h (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/PDB.h (revision 336982) @@ -1,34 +1,38 @@ //===- PDB.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_PDB_H #define LLD_COFF_PDB_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" namespace llvm { namespace codeview { union DebugInfo; } } namespace lld { namespace coff { class OutputSection; +class SectionChunk; class SymbolTable; void createPDB(SymbolTable *Symtab, llvm::ArrayRef OutputSections, llvm::ArrayRef SectionTable, const llvm::codeview::DebugInfo &BuildId); + +std::pair getFileLine(const SectionChunk *C, + uint32_t Addr); } } #endif Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/PDB.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/SymbolTable.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/SymbolTable.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/SymbolTable.cpp (revision 336982) @@ -1,395 +1,461 @@ //===- SymbolTable.cpp ----------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "SymbolTable.h" #include "Config.h" #include "Driver.h" #include "LTO.h" +#include "PDB.h" #include "Symbols.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "lld/Common/Timer.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include using namespace llvm; namespace lld { namespace coff { +static Timer LTOTimer("LTO", Timer::root()); + SymbolTable *Symtab; void SymbolTable::addFile(InputFile *File) { log("Reading " + toString(File)); File->parse(); MachineTypes MT = File->getMachineType(); if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { Config->Machine = MT; } else if (MT != IMAGE_FILE_MACHINE_UNKNOWN && Config->Machine != MT) { - fatal(toString(File) + ": machine type " + machineToStr(MT) + + error(toString(File) + ": machine type " + machineToStr(MT) + " conflicts with " + machineToStr(Config->Machine)); + return; } if (auto *F = dyn_cast(File)) { ObjFile::Instances.push_back(F); } else if (auto *F = dyn_cast(File)) { BitcodeFile::Instances.push_back(F); } else if (auto *F = dyn_cast(File)) { ImportFile::Instances.push_back(F); } StringRef S = File->getDirectives(); if (S.empty()) return; log("Directives: " + toString(File) + ": " + S); Driver->parseDirectives(S); } static void errorOrWarn(const Twine &S) { if (Config->Force) warn(S); else error(S); } +// Returns the name of the symbol in SC whose value is <= Addr that is closest +// to Addr. This is generally the name of the global variable or function whose +// definition contains Addr. +static StringRef getSymbolName(SectionChunk *SC, uint32_t Addr) { + DefinedRegular *Candidate = nullptr; + + for (Symbol *S : SC->File->getSymbols()) { + auto *D = dyn_cast_or_null(S); + if (!D || D->getChunk() != SC || D->getValue() > Addr || + (Candidate && D->getValue() < Candidate->getValue())) + continue; + + Candidate = D; + } + + if (!Candidate) + return ""; + return Candidate->getName(); +} + +static std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) { + struct Location { + StringRef SymName; + std::pair FileLine; + }; + std::vector Locations; + + for (Chunk *C : File->getChunks()) { + auto *SC = dyn_cast(C); + if (!SC) + continue; + for (const coff_relocation &R : SC->Relocs) { + if (R.SymbolTableIndex != SymIndex) + continue; + std::pair FileLine = + getFileLine(SC, R.VirtualAddress); + StringRef SymName = getSymbolName(SC, R.VirtualAddress); + if (!FileLine.first.empty() || !SymName.empty()) + Locations.push_back({SymName, FileLine}); + } + } + + if (Locations.empty()) + return "\n>>> referenced by " + toString(File) + "\n"; + + std::string Out; + llvm::raw_string_ostream OS(Out); + for (Location Loc : Locations) { + OS << "\n>>> referenced by "; + if (!Loc.FileLine.first.empty()) + OS << Loc.FileLine.first << ":" << Loc.FileLine.second + << "\n>>> "; + OS << toString(File); + if (!Loc.SymName.empty()) + OS << ":(" << Loc.SymName << ')'; + } + OS << '\n'; + return OS.str(); +} + void SymbolTable::reportRemainingUndefines() { SmallPtrSet Undefs; DenseMap LocalImports; for (auto &I : SymMap) { Symbol *Sym = I.second; auto *Undef = dyn_cast(Sym); if (!Undef) continue; if (!Sym->IsUsedInRegularObj) continue; StringRef Name = Undef->getName(); // A weak alias may have been resolved, so check for that. if (Defined *D = Undef->getWeakAlias()) { // We want to replace Sym with D. However, we can't just blindly // copy sizeof(SymbolUnion) bytes from D to Sym because D may be an // internal symbol, and internal symbols are stored as "unparented" // Symbols. For that reason we need to check which type of symbol we // are dealing with and copy the correct number of bytes. if (isa(D)) memcpy(Sym, D, sizeof(DefinedRegular)); else if (isa(D)) memcpy(Sym, D, sizeof(DefinedAbsolute)); else memcpy(Sym, D, sizeof(SymbolUnion)); continue; } // If we can resolve a symbol by removing __imp_ prefix, do that. // This odd rule is for compatibility with MSVC linker. if (Name.startswith("__imp_")) { Symbol *Imp = find(Name.substr(strlen("__imp_"))); if (Imp && isa(Imp)) { auto *D = cast(Imp); replaceSymbol(Sym, Name, D); LocalImportChunks.push_back(cast(Sym)->getChunk()); LocalImports[Sym] = D; continue; } } // Remaining undefined symbols are not fatal if /force is specified. // They are replaced with dummy defined symbols. if (Config->Force) replaceSymbol(Sym, Name, 0); Undefs.insert(Sym); } if (Undefs.empty() && LocalImports.empty()) return; for (Symbol *B : Config->GCRoot) { if (Undefs.count(B)) errorOrWarn(": undefined symbol: " + B->getName()); if (Config->WarnLocallyDefinedImported) if (Symbol *Imp = LocalImports.lookup(B)) warn(": locally defined symbol imported: " + Imp->getName() + - " (defined in " + toString(Imp->getFile()) + ")"); + " (defined in " + toString(Imp->getFile()) + ") [LNK4217]"); } for (ObjFile *File : ObjFile::Instances) { + size_t SymIndex = (size_t)-1; for (Symbol *Sym : File->getSymbols()) { + ++SymIndex; if (!Sym) continue; if (Undefs.count(Sym)) - errorOrWarn(toString(File) + ": undefined symbol: " + Sym->getName()); + errorOrWarn("undefined symbol: " + Sym->getName() + + getSymbolLocations(File, SymIndex)); if (Config->WarnLocallyDefinedImported) if (Symbol *Imp = LocalImports.lookup(Sym)) warn(toString(File) + ": locally defined symbol imported: " + Imp->getName() + " (defined in " + toString(Imp->getFile()) + - ")"); + ") [LNK4217]"); } } } std::pair SymbolTable::insert(StringRef Name) { Symbol *&Sym = SymMap[CachedHashStringRef(Name)]; if (Sym) return {Sym, false}; - Sym = (Symbol *)make(); + Sym = reinterpret_cast(make()); Sym->IsUsedInRegularObj = false; Sym->PendingArchiveLoad = false; return {Sym, true}; } Symbol *SymbolTable::addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); if (!F || !isa(F)) S->IsUsedInRegularObj = true; if (WasInserted || (isa(S) && IsWeakAlias)) { replaceSymbol(S, Name); return S; } if (auto *L = dyn_cast(S)) { if (!S->PendingArchiveLoad) { S->PendingArchiveLoad = true; L->File->addMember(&L->Sym); } } return S; } void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol Sym) { StringRef Name = Sym.getName(); Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); if (WasInserted) { replaceSymbol(S, F, Sym); return; } auto *U = dyn_cast(S); if (!U || U->WeakAlias || S->PendingArchiveLoad) return; S->PendingArchiveLoad = true; F->addMember(&Sym); } void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) { error("duplicate symbol: " + toString(*Existing) + " in " + toString(Existing->getFile()) + " and in " + toString(NewFile)); } Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N); S->IsUsedInRegularObj = true; if (WasInserted || isa(S) || isa(S)) replaceSymbol(S, N, Sym); else if (!isa(S)) reportDuplicate(S, nullptr); return S; } Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N); S->IsUsedInRegularObj = true; if (WasInserted || isa(S) || isa(S)) replaceSymbol(S, N, VA); else if (!isa(S)) reportDuplicate(S, nullptr); return S; } Symbol *SymbolTable::addSynthetic(StringRef N, Chunk *C) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N); S->IsUsedInRegularObj = true; if (WasInserted || isa(S) || isa(S)) replaceSymbol(S, N, C); else if (!isa(S)) reportDuplicate(S, nullptr); return S; } Symbol *SymbolTable::addRegular(InputFile *F, StringRef N, const coff_symbol_generic *Sym, SectionChunk *C) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N); if (!isa(F)) S->IsUsedInRegularObj = true; if (WasInserted || !isa(S)) replaceSymbol(S, F, N, /*IsCOMDAT*/ false, /*IsExternal*/ true, Sym, C); else reportDuplicate(S, F); return S; } std::pair SymbolTable::addComdat(InputFile *F, StringRef N, const coff_symbol_generic *Sym) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N); if (!isa(F)) S->IsUsedInRegularObj = true; if (WasInserted || !isa(S)) { replaceSymbol(S, F, N, /*IsCOMDAT*/ true, /*IsExternal*/ true, Sym, nullptr); return {S, true}; } if (!cast(S)->isCOMDAT()) reportDuplicate(S, F); return {S, false}; } Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size, const coff_symbol_generic *Sym, CommonChunk *C) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N); if (!isa(F)) S->IsUsedInRegularObj = true; if (WasInserted || !isa(S)) replaceSymbol(S, F, N, Size, Sym, C); else if (auto *DC = dyn_cast(S)) if (Size > DC->getSize()) replaceSymbol(S, F, N, Size, Sym, C); return S; } -DefinedImportData *SymbolTable::addImportData(StringRef N, ImportFile *F) { +Symbol *SymbolTable::addImportData(StringRef N, ImportFile *F) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N); S->IsUsedInRegularObj = true; if (WasInserted || isa(S) || isa(S)) { replaceSymbol(S, N, F); - return cast(S); + return S; } reportDuplicate(S, F); return nullptr; } -DefinedImportThunk *SymbolTable::addImportThunk(StringRef Name, - DefinedImportData *ID, - uint16_t Machine) { +Symbol *SymbolTable::addImportThunk(StringRef Name, DefinedImportData *ID, + uint16_t Machine) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); S->IsUsedInRegularObj = true; if (WasInserted || isa(S) || isa(S)) { replaceSymbol(S, Name, ID, Machine); - return cast(S); + return S; } reportDuplicate(S, ID->File); return nullptr; } std::vector SymbolTable::getChunks() { std::vector Res; for (ObjFile *File : ObjFile::Instances) { ArrayRef V = File->getChunks(); Res.insert(Res.end(), V.begin(), V.end()); } return Res; } Symbol *SymbolTable::find(StringRef Name) { - auto It = SymMap.find(CachedHashStringRef(Name)); - if (It == SymMap.end()) - return nullptr; - return It->second; + return SymMap.lookup(CachedHashStringRef(Name)); } Symbol *SymbolTable::findUnderscore(StringRef Name) { if (Config->Machine == I386) return find(("_" + Name).str()); return find(Name); } StringRef SymbolTable::findByPrefix(StringRef Prefix) { for (auto Pair : SymMap) { StringRef Name = Pair.first.val(); if (Name.startswith(Prefix)) return Name; } return ""; } StringRef SymbolTable::findMangle(StringRef Name) { if (Symbol *Sym = find(Name)) if (!isa(Sym)) return Name; if (Config->Machine != I386) return findByPrefix(("?" + Name + "@@Y").str()); if (!Name.startswith("_")) return ""; // Search for x86 stdcall function. StringRef S = findByPrefix((Name + "@").str()); if (!S.empty()) return S; // Search for x86 fastcall function. S = findByPrefix(("@" + Name.substr(1) + "@").str()); if (!S.empty()) return S; // Search for x86 vectorcall function. S = findByPrefix((Name.substr(1) + "@@").str()); if (!S.empty()) return S; // Search for x86 C++ non-member function. return findByPrefix(("?" + Name.substr(1) + "@@Y").str()); } void SymbolTable::mangleMaybe(Symbol *B) { auto *U = dyn_cast(B); if (!U || U->WeakAlias) return; StringRef Alias = findMangle(U->getName()); if (!Alias.empty()) { log(U->getName() + " aliased to " + Alias); U->WeakAlias = addUndefined(Alias); } } Symbol *SymbolTable::addUndefined(StringRef Name) { return addUndefined(Name, nullptr, false); } std::vector SymbolTable::compileBitcodeFiles() { LTO.reset(new BitcodeCompiler); for (BitcodeFile *F : BitcodeFile::Instances) LTO->add(*F); return LTO->compile(); } void SymbolTable::addCombinedLTOObjects() { if (BitcodeFile::Instances.empty()) return; + + ScopedTimer T(LTOTimer); for (StringRef Object : compileBitcodeFiles()) { auto *Obj = make(MemoryBufferRef(Object, "lto.tmp")); Obj->parse(); ObjFile::Instances.push_back(Obj); } } } // namespace coff } // namespace lld Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/SymbolTable.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/SymbolTable.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/SymbolTable.h (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/SymbolTable.h (revision 336982) @@ -1,123 +1,123 @@ //===- SymbolTable.h --------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_COFF_SYMBOL_TABLE_H #define LLD_COFF_SYMBOL_TABLE_H #include "InputFiles.h" #include "LTO.h" #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMapInfo.h" #include "llvm/Support/raw_ostream.h" namespace llvm { struct LTOCodeGenerator; } namespace lld { namespace coff { class Chunk; class CommonChunk; class Defined; class DefinedAbsolute; class DefinedRelative; class Lazy; class SectionChunk; class Symbol; // SymbolTable is a bucket of all known symbols, including defined, // undefined, or lazy symbols (the last one is symbols in archive // files whose archive members are not yet loaded). // // We put all symbols of all files to a SymbolTable, and the // SymbolTable selects the "best" symbols if there are name // conflicts. For example, obviously, a defined symbol is better than // an undefined symbol. Or, if there's a conflict between a lazy and a // undefined, it'll read an archive member to read a real definition // to replace the lazy symbol. The logic is implemented in the // add*() functions, which are called by input files as they are parsed. // There is one add* function per symbol type. class SymbolTable { public: void addFile(InputFile *File); // Try to resolve any undefined symbols and update the symbol table // accordingly, then print an error message for any remaining undefined // symbols. void reportRemainingUndefines(); // Returns a list of chunks of selected symbols. std::vector getChunks(); // Returns a symbol for a given name. Returns a nullptr if not found. Symbol *find(StringRef Name); Symbol *findUnderscore(StringRef Name); // Occasionally we have to resolve an undefined symbol to its // mangled symbol. This function tries to find a mangled name // for U from the symbol table, and if found, set the symbol as // a weak alias for U. void mangleMaybe(Symbol *B); StringRef findMangle(StringRef Name); // Build a set of COFF objects representing the combined contents of // BitcodeFiles and add them to the symbol table. Called after all files are // added and before the writer writes results to a file. void addCombinedLTOObjects(); std::vector compileBitcodeFiles(); // Creates an Undefined symbol for a given name. Symbol *addUndefined(StringRef Name); Symbol *addSynthetic(StringRef N, Chunk *C); Symbol *addAbsolute(StringRef N, uint64_t VA); Symbol *addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias); void addLazy(ArchiveFile *F, const Archive::Symbol Sym); Symbol *addAbsolute(StringRef N, COFFSymbolRef S); Symbol *addRegular(InputFile *F, StringRef N, const llvm::object::coff_symbol_generic *S = nullptr, SectionChunk *C = nullptr); std::pair addComdat(InputFile *F, StringRef N, const llvm::object::coff_symbol_generic *S = nullptr); Symbol *addCommon(InputFile *F, StringRef N, uint64_t Size, const llvm::object::coff_symbol_generic *S = nullptr, CommonChunk *C = nullptr); - DefinedImportData *addImportData(StringRef N, ImportFile *F); - DefinedImportThunk *addImportThunk(StringRef Name, DefinedImportData *S, - uint16_t Machine); + Symbol *addImportData(StringRef N, ImportFile *F); + Symbol *addImportThunk(StringRef Name, DefinedImportData *S, + uint16_t Machine); void reportDuplicate(Symbol *Existing, InputFile *NewFile); // A list of chunks which to be added to .rdata. std::vector LocalImportChunks; // Iterates symbols in non-determinstic hash table order. template void forEachSymbol(T Callback) { for (auto &Pair : SymMap) Callback(Pair.second); } private: std::pair insert(StringRef Name); StringRef findByPrefix(StringRef Prefix); llvm::DenseMap SymMap; std::unique_ptr LTO; }; extern SymbolTable *Symtab; } // namespace coff } // namespace lld #endif Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/SymbolTable.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/Symbols.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/Symbols.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/Symbols.cpp (revision 336982) @@ -1,100 +1,100 @@ //===- Symbols.cpp --------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Symbols.h" #include "InputFiles.h" -#include "Strings.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace llvm::object; // Returns a symbol name for an error message. std::string lld::toString(coff::Symbol &B) { - if (Optional S = coff::demangleMSVC(B.getName())) + if (Optional S = lld::demangleMSVC(B.getName())) return ("\"" + *S + "\" (" + B.getName() + ")").str(); return B.getName(); } namespace lld { namespace coff { StringRef Symbol::getName() { // COFF symbol names are read lazily for a performance reason. // Non-external symbol names are never used by the linker except for logging // or debugging. Their internal references are resolved not by name but by // symbol index. And because they are not external, no one can refer them by // name. Object files contain lots of non-external symbols, and creating // StringRefs for them (which involves lots of strlen() on the string table) // is a waste of time. if (Name.empty()) { auto *D = cast(this); cast(D->File)->getCOFFObj()->getSymbolName(D->Sym, Name); } return Name; } InputFile *Symbol::getFile() { if (auto *Sym = dyn_cast(this)) return Sym->File; if (auto *Sym = dyn_cast(this)) return Sym->File; return nullptr; } bool Symbol::isLive() const { if (auto *R = dyn_cast(this)) return R->getChunk()->isLive(); if (auto *Imp = dyn_cast(this)) return Imp->File->Live; if (auto *Imp = dyn_cast(this)) - return Imp->WrappedSym->File->Live; + return Imp->WrappedSym->File->ThunkLive; // Assume any other kind of symbol is live. return true; } COFFSymbolRef DefinedCOFF::getCOFFSymbol() { size_t SymSize = cast(File)->getCOFFObj()->getSymbolTableEntrySize(); if (SymSize == sizeof(coff_symbol16)) return COFFSymbolRef(reinterpret_cast(Sym)); assert(SymSize == sizeof(coff_symbol32)); return COFFSymbolRef(reinterpret_cast(Sym)); } -uint16_t DefinedAbsolute::OutputSectionIndex = 0; +uint16_t DefinedAbsolute::NumOutputSections; static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) { if (Machine == AMD64) return make(S); if (Machine == I386) return make(S); if (Machine == ARM64) return make(S); assert(Machine == ARMNT); return make(S); } DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S, uint16_t Machine) : Defined(DefinedImportThunkKind, Name), WrappedSym(S), Data(makeImportThunk(S, Machine)) {} Defined *Undefined::getWeakAlias() { // A weak alias may be a weak alias to another symbol, so check recursively. for (Symbol *A = WeakAlias; A; A = cast(A)->WeakAlias) if (auto *D = dyn_cast(A)) return D; return nullptr; } } // namespace coff } // namespace lld Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/Symbols.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/Symbols.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/Symbols.h (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/Symbols.h (revision 336982) @@ -1,431 +1,432 @@ //===- Symbols.h ------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_COFF_SYMBOLS_H #define LLD_COFF_SYMBOLS_H #include "Chunks.h" #include "Config.h" #include "lld/Common/LLVM.h" #include "lld/Common/Memory.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFF.h" #include #include #include namespace lld { namespace coff { using llvm::object::Archive; using llvm::object::COFFSymbolRef; using llvm::object::coff_import_header; using llvm::object::coff_symbol_generic; class ArchiveFile; class InputFile; class ObjFile; class SymbolTable; // The base class for real symbol classes. class Symbol { public: enum Kind { // The order of these is significant. We start with the regular defined // symbols as those are the most prevelant and the zero tag is the cheapest // to set. Among the defined kinds, the lower the kind is preferred over // the higher kind when testing wether one symbol should take precedence // over another. DefinedRegularKind = 0, DefinedCommonKind, DefinedLocalImportKind, DefinedImportThunkKind, DefinedImportDataKind, DefinedAbsoluteKind, DefinedSyntheticKind, UndefinedKind, LazyKind, LastDefinedCOFFKind = DefinedCommonKind, LastDefinedKind = DefinedSyntheticKind, }; Kind kind() const { return static_cast(SymbolKind); } // Returns true if this is an external symbol. bool isExternal() { return IsExternal; } // Returns the symbol name. StringRef getName(); // Returns the file from which this symbol was created. InputFile *getFile(); // Indicates that this symbol will be included in the final image. Only valid // after calling markLive. bool isLive() const; protected: friend SymbolTable; explicit Symbol(Kind K, StringRef N = "") : SymbolKind(K), IsExternal(true), IsCOMDAT(false), WrittenToSymtab(false), PendingArchiveLoad(false), IsGCRoot(false), Name(N) {} const unsigned SymbolKind : 8; unsigned IsExternal : 1; // This bit is used by the \c DefinedRegular subclass. unsigned IsCOMDAT : 1; public: // This bit is used by Writer::createSymbolAndStringTable() to prevent // symbols from being written to the symbol table more than once. unsigned WrittenToSymtab : 1; // True if this symbol was referenced by a regular (non-bitcode) object. unsigned IsUsedInRegularObj : 1; // True if we've seen both a lazy and an undefined symbol with this symbol // name, which means that we have enqueued an archive member load and should // not load any more archive members to resolve the same symbol. unsigned PendingArchiveLoad : 1; /// True if we've already added this symbol to the list of GC roots. unsigned IsGCRoot : 1; protected: StringRef Name; }; // The base class for any defined symbols, including absolute symbols, // etc. class Defined : public Symbol { public: Defined(Kind K, StringRef N) : Symbol(K, N) {} static bool classof(const Symbol *S) { return S->kind() <= LastDefinedKind; } // Returns the RVA (relative virtual address) of this symbol. The // writer sets and uses RVAs. uint64_t getRVA(); // Returns the chunk containing this symbol. Absolute symbols and __ImageBase // do not have chunks, so this may return null. Chunk *getChunk(); }; // Symbols defined via a COFF object file or bitcode file. For COFF files, this // stores a coff_symbol_generic*, and names of internal symbols are lazily // loaded through that. For bitcode files, Sym is nullptr and the name is stored // as a StringRef. class DefinedCOFF : public Defined { friend Symbol; public: DefinedCOFF(Kind K, InputFile *F, StringRef N, const coff_symbol_generic *S) : Defined(K, N), File(F), Sym(S) {} static bool classof(const Symbol *S) { return S->kind() <= LastDefinedCOFFKind; } InputFile *getFile() { return File; } COFFSymbolRef getCOFFSymbol(); InputFile *File; protected: const coff_symbol_generic *Sym; }; // Regular defined symbols read from object file symbol tables. class DefinedRegular : public DefinedCOFF { public: DefinedRegular(InputFile *F, StringRef N, bool IsCOMDAT, bool IsExternal = false, const coff_symbol_generic *S = nullptr, SectionChunk *C = nullptr) : DefinedCOFF(DefinedRegularKind, F, N, S), Data(C ? &C->Repl : nullptr) { this->IsExternal = IsExternal; this->IsCOMDAT = IsCOMDAT; } static bool classof(const Symbol *S) { return S->kind() == DefinedRegularKind; } uint64_t getRVA() const { return (*Data)->getRVA() + Sym->Value; } bool isCOMDAT() const { return IsCOMDAT; } SectionChunk *getChunk() const { return *Data; } uint32_t getValue() const { return Sym->Value; } SectionChunk **Data; }; class DefinedCommon : public DefinedCOFF { public: DefinedCommon(InputFile *F, StringRef N, uint64_t Size, const coff_symbol_generic *S = nullptr, CommonChunk *C = nullptr) : DefinedCOFF(DefinedCommonKind, F, N, S), Data(C), Size(Size) { this->IsExternal = true; } static bool classof(const Symbol *S) { return S->kind() == DefinedCommonKind; } uint64_t getRVA() { return Data->getRVA(); } CommonChunk *getChunk() { return Data; } private: friend SymbolTable; uint64_t getSize() const { return Size; } CommonChunk *Data; uint64_t Size; }; // Absolute symbols. class DefinedAbsolute : public Defined { public: DefinedAbsolute(StringRef N, COFFSymbolRef S) : Defined(DefinedAbsoluteKind, N), VA(S.getValue()) { IsExternal = S.isExternal(); } DefinedAbsolute(StringRef N, uint64_t V) : Defined(DefinedAbsoluteKind, N), VA(V) {} static bool classof(const Symbol *S) { return S->kind() == DefinedAbsoluteKind; } uint64_t getRVA() { return VA - Config->ImageBase; } void setVA(uint64_t V) { VA = V; } - // The sentinel absolute symbol section index. Section index relocations - // against absolute symbols resolve to this 16 bit number, and it is the - // largest valid section index plus one. This is written by the Writer. - static uint16_t OutputSectionIndex; - uint16_t getSecIdx() { return OutputSectionIndex; } + // Section index relocations against absolute symbols resolve to + // this 16 bit number, and it is the largest valid section index + // plus one. This variable keeps it. + static uint16_t NumOutputSections; private: uint64_t VA; }; // This symbol is used for linker-synthesized symbols like __ImageBase and // __safe_se_handler_table. class DefinedSynthetic : public Defined { public: explicit DefinedSynthetic(StringRef Name, Chunk *C) : Defined(DefinedSyntheticKind, Name), C(C) {} static bool classof(const Symbol *S) { return S->kind() == DefinedSyntheticKind; } // A null chunk indicates that this is __ImageBase. Otherwise, this is some // other synthesized chunk, like SEHTableChunk. uint32_t getRVA() { return C ? C->getRVA() : 0; } Chunk *getChunk() { return C; } private: Chunk *C; }; // This class represents a symbol defined in an archive file. It is // created from an archive file header, and it knows how to load an // object file from an archive to replace itself with a defined // symbol. If the resolver finds both Undefined and Lazy for // the same name, it will ask the Lazy to load a file. class Lazy : public Symbol { public: Lazy(ArchiveFile *F, const Archive::Symbol S) : Symbol(LazyKind, S.getName()), File(F), Sym(S) {} static bool classof(const Symbol *S) { return S->kind() == LazyKind; } ArchiveFile *File; private: friend SymbolTable; private: const Archive::Symbol Sym; }; // Undefined symbols. class Undefined : public Symbol { public: explicit Undefined(StringRef N) : Symbol(UndefinedKind, N) {} static bool classof(const Symbol *S) { return S->kind() == UndefinedKind; } // An undefined symbol can have a fallback symbol which gives an // undefined symbol a second chance if it would remain undefined. // If it remains undefined, it'll be replaced with whatever the // Alias pointer points to. Symbol *WeakAlias = nullptr; // If this symbol is external weak, try to resolve it to a defined // symbol by searching the chain of fallback symbols. Returns the symbol if // successful, otherwise returns null. Defined *getWeakAlias(); }; // Windows-specific classes. // This class represents a symbol imported from a DLL. This has two // names for internal use and external use. The former is used for // name resolution, and the latter is used for the import descriptor // table in an output. The former has "__imp_" prefix. class DefinedImportData : public Defined { public: DefinedImportData(StringRef N, ImportFile *F) : Defined(DefinedImportDataKind, N), File(F) { } static bool classof(const Symbol *S) { return S->kind() == DefinedImportDataKind; } uint64_t getRVA() { return File->Location->getRVA(); } Chunk *getChunk() { return File->Location; } void setLocation(Chunk *AddressTable) { File->Location = AddressTable; } StringRef getDLLName() { return File->DLLName; } StringRef getExternalName() { return File->ExternalName; } uint16_t getOrdinal() { return File->Hdr->OrdinalHint; } ImportFile *File; }; // This class represents a symbol for a jump table entry which jumps // to a function in a DLL. Linker are supposed to create such symbols // without "__imp_" prefix for all function symbols exported from // DLLs, so that you can call DLL functions as regular functions with // a regular name. A function pointer is given as a DefinedImportData. class DefinedImportThunk : public Defined { public: DefinedImportThunk(StringRef Name, DefinedImportData *S, uint16_t Machine); static bool classof(const Symbol *S) { return S->kind() == DefinedImportThunkKind; } uint64_t getRVA() { return Data->getRVA(); } Chunk *getChunk() { return Data; } DefinedImportData *WrappedSym; private: Chunk *Data; }; // If you have a symbol "__imp_foo" in your object file, a symbol name // "foo" becomes automatically available as a pointer to "__imp_foo". // This class is for such automatically-created symbols. // Yes, this is an odd feature. We didn't intend to implement that. // This is here just for compatibility with MSVC. class DefinedLocalImport : public Defined { public: DefinedLocalImport(StringRef N, Defined *S) : Defined(DefinedLocalImportKind, N), Data(make(S)) {} static bool classof(const Symbol *S) { return S->kind() == DefinedLocalImportKind; } uint64_t getRVA() { return Data->getRVA(); } Chunk *getChunk() { return Data; } private: LocalImportChunk *Data; }; inline uint64_t Defined::getRVA() { switch (kind()) { case DefinedAbsoluteKind: return cast(this)->getRVA(); case DefinedSyntheticKind: return cast(this)->getRVA(); case DefinedImportDataKind: return cast(this)->getRVA(); case DefinedImportThunkKind: return cast(this)->getRVA(); case DefinedLocalImportKind: return cast(this)->getRVA(); case DefinedCommonKind: return cast(this)->getRVA(); case DefinedRegularKind: return cast(this)->getRVA(); case LazyKind: case UndefinedKind: llvm_unreachable("Cannot get the address for an undefined symbol."); } llvm_unreachable("unknown symbol kind"); } inline Chunk *Defined::getChunk() { switch (kind()) { case DefinedRegularKind: return cast(this)->getChunk(); case DefinedAbsoluteKind: return nullptr; case DefinedSyntheticKind: return cast(this)->getChunk(); case DefinedImportDataKind: return cast(this)->getChunk(); case DefinedImportThunkKind: return cast(this)->getChunk(); case DefinedLocalImportKind: return cast(this)->getChunk(); case DefinedCommonKind: return cast(this)->getChunk(); case LazyKind: case UndefinedKind: llvm_unreachable("Cannot get the chunk of an undefined symbol."); } llvm_unreachable("unknown symbol kind"); } // A buffer class that is large enough to hold any Symbol-derived // object. We allocate memory using this class and instantiate a symbol // using the placement new. union SymbolUnion { alignas(DefinedRegular) char A[sizeof(DefinedRegular)]; alignas(DefinedCommon) char B[sizeof(DefinedCommon)]; alignas(DefinedAbsolute) char C[sizeof(DefinedAbsolute)]; alignas(DefinedSynthetic) char D[sizeof(DefinedSynthetic)]; alignas(Lazy) char E[sizeof(Lazy)]; alignas(Undefined) char F[sizeof(Undefined)]; alignas(DefinedImportData) char G[sizeof(DefinedImportData)]; alignas(DefinedImportThunk) char H[sizeof(DefinedImportThunk)]; alignas(DefinedLocalImport) char I[sizeof(DefinedLocalImport)]; }; template void replaceSymbol(Symbol *S, ArgT &&... Arg) { + static_assert(std::is_trivially_destructible(), + "Symbol types must be trivially destructible"); static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small"); static_assert(alignof(T) <= alignof(SymbolUnion), "SymbolUnion not aligned enough"); assert(static_cast(static_cast(nullptr)) == nullptr && "Not a Symbol"); new (S) T(std::forward(Arg)...); } } // namespace coff std::string toString(coff::Symbol &B); } // namespace lld #endif Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/Symbols.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/Writer.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/Writer.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/Writer.cpp (revision 336982) @@ -1,971 +1,1292 @@ //===- Writer.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Writer.h" #include "Config.h" #include "DLL.h" #include "InputFiles.h" #include "MapFile.h" #include "PDB.h" #include "SymbolTable.h" #include "Symbols.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "lld/Common/Timer.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Parallel.h" +#include "llvm/Support/Path.h" #include "llvm/Support/RandomNumberGenerator.h" +#include "llvm/Support/xxhash.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; +/* To re-generate DOSProgram: +$ cat > /tmp/DOSProgram.asm +org 0 + ; Copy cs to ds. + push cs + pop ds + ; Point ds:dx at the $-terminated string. + mov dx, str + ; Int 21/AH=09h: Write string to standard output. + mov ah, 0x9 + int 0x21 + ; Int 21/AH=4Ch: Exit with return code (in AL). + mov ax, 0x4C01 + int 0x21 +str: + db 'This program cannot be run in DOS mode.$' +align 8, db 0 +$ nasm -fbin /tmp/DOSProgram.asm -o /tmp/DOSProgram.bin +$ xxd -i /tmp/DOSProgram.bin +*/ +static unsigned char DOSProgram[] = { + 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, + 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, + 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, + 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, + 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x24, 0x00, 0x00 +}; +static_assert(sizeof(DOSProgram) % 8 == 0, + "DOSProgram size must be multiple of 8"); + static const int SectorSize = 512; -static const int DOSStubSize = 64; +static const int DOSStubSize = sizeof(dos_header) + sizeof(DOSProgram); +static_assert(DOSStubSize % 8 == 0, "DOSStub size must be multiple of 8"); + static const int NumberfOfDataDirectory = 16; namespace { class DebugDirectoryChunk : public Chunk { public: DebugDirectoryChunk(const std::vector &R) : Records(R) {} size_t getSize() const override { return Records.size() * sizeof(debug_directory); } void writeTo(uint8_t *B) const override { auto *D = reinterpret_cast(B + OutputSectionOff); for (const Chunk *Record : Records) { D->Characteristics = 0; D->TimeDateStamp = 0; D->MajorVersion = 0; D->MinorVersion = 0; D->Type = COFF::IMAGE_DEBUG_TYPE_CODEVIEW; D->SizeOfData = Record->getSize(); D->AddressOfRawData = Record->getRVA(); OutputSection *OS = Record->getOutputSection(); uint64_t Offs = OS->getFileOff() + (Record->getRVA() - OS->getRVA()); D->PointerToRawData = Offs; + TimeDateStamps.push_back(&D->TimeDateStamp); ++D; } } + void setTimeDateStamp(uint32_t TimeDateStamp) { + for (support::ulittle32_t *TDS : TimeDateStamps) + *TDS = TimeDateStamp; + } + private: + mutable std::vector TimeDateStamps; const std::vector &Records; }; class CVDebugRecordChunk : public Chunk { public: - CVDebugRecordChunk() { - PDBAbsPath = Config->PDBPath; - if (!PDBAbsPath.empty()) - llvm::sys::fs::make_absolute(PDBAbsPath); - } - size_t getSize() const override { - return sizeof(codeview::DebugInfo) + PDBAbsPath.size() + 1; + return sizeof(codeview::DebugInfo) + Config->PDBAltPath.size() + 1; } void writeTo(uint8_t *B) const override { // Save off the DebugInfo entry to backfill the file signature (build id) // in Writer::writeBuildId BuildId = reinterpret_cast(B + OutputSectionOff); // variable sized field (PDB Path) char *P = reinterpret_cast(B + OutputSectionOff + sizeof(*BuildId)); - if (!PDBAbsPath.empty()) - memcpy(P, PDBAbsPath.data(), PDBAbsPath.size()); - P[PDBAbsPath.size()] = '\0'; + if (!Config->PDBAltPath.empty()) + memcpy(P, Config->PDBAltPath.data(), Config->PDBAltPath.size()); + P[Config->PDBAltPath.size()] = '\0'; } - SmallString<128> PDBAbsPath; mutable codeview::DebugInfo *BuildId = nullptr; }; // The writer writes a SymbolTable result to a file. class Writer { public: Writer() : Buffer(errorHandler().OutputBuffer) {} void run(); private: void createSections(); void createMiscChunks(); void createImportTables(); void createExportTable(); + void mergeSections(); void assignAddresses(); void removeEmptySections(); void createSymbolAndStringTable(); void openFile(StringRef OutputPath); template void writeHeader(); - void createSEHTable(OutputSection *RData); + void createSEHTable(); + void createGuardCFTables(); + void markSymbolsForRVATable(ObjFile *File, + ArrayRef SymIdxChunks, + SymbolRVASet &TableSymbols); + void maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym, + StringRef CountSym); void setSectionPermissions(); void writeSections(); void writeBuildId(); void sortExceptionTable(); 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); + void addBaserels(); + void addBaserelBlocks(std::vector &V); uint32_t getSizeOfInitializedData(); std::map> binImports(); std::unique_ptr &Buffer; std::vector OutputSections; std::vector Strtab; std::vector OutputSymtab; IdataContents Idata; DelayLoadContents DelayIdata; EdataContents Edata; - SEHTableChunk *SEHTable = nullptr; + bool SetNoSEHCharacteristic = false; - Chunk *DebugDirectory = nullptr; + DebugDirectoryChunk *DebugDirectory = nullptr; std::vector DebugRecords; CVDebugRecordChunk *BuildId = nullptr; Optional PreviousBuildId; ArrayRef SectionTable; uint64_t FileSize; uint32_t PointerToSymbolTable = 0; uint64_t SizeOfImage; uint64_t SizeOfHeaders; + + OutputSection *TextSec; + OutputSection *RdataSec; + OutputSection *BuildidSec; + OutputSection *DataSec; + OutputSection *PdataSec; + OutputSection *IdataSec; + OutputSection *EdataSec; + OutputSection *DidatSec; + OutputSection *RsrcSec; + OutputSection *RelocSec; + + // The first and last .pdata sections in the output file. + // + // We need to keep track of the location of .pdata in whichever section it + // gets merged into so that we can sort its contents and emit a correct data + // directory entry for the exception table. This is also the case for some + // other sections (such as .edata) but because the contents of those sections + // are entirely linker-generated we can keep track of their locations using + // the chunks that the linker creates. All .pdata chunks come from input + // files, so we need to keep track of them separately. + Chunk *FirstPdata = nullptr; + Chunk *LastPdata; }; } // anonymous namespace namespace lld { namespace coff { +static Timer CodeLayoutTimer("Code Layout", Timer::root()); +static Timer DiskCommitTimer("Commit Output File", Timer::root()); + void writeResult() { Writer().run(); } -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 = alignTo(Off, C->Alignment); - C->setRVA(Off); - C->OutputSectionOff = Off; - Off += C->getSize(); - if (Off > UINT32_MAX) - error("section larger than 4 GiB: " + Name); - Header.VirtualSize = Off; - if (C->hasData()) - Header.SizeOfRawData = alignTo(Off, SectorSize); } -void OutputSection::addPermissions(uint32_t C) { - Header.Characteristics |= C & PermMask; +void OutputSection::setPermissions(uint32_t C) { + Header.Characteristics &= ~PermMask; + Header.Characteristics |= C; } -void OutputSection::setPermissions(uint32_t C) { - Header.Characteristics = C & PermMask; +void OutputSection::merge(OutputSection *Other) { + for (Chunk *C : Other->Chunks) + C->setOutputSection(this); + Chunks.insert(Chunks.end(), Other->Chunks.begin(), Other->Chunks.end()); + Other->Chunks.clear(); } // 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 || (Hdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0); strncpy(Hdr->Name, Name.data(), std::min(Name.size(), (size_t)COFF::NameSize)); } } } // namespace coff } // namespace lld // PDBs are matched against executables using a build id which consists of three // components: // 1. A 16-bit GUID // 2. An age // 3. A time stamp. // // Debuggers and symbol servers match executables against debug info by checking // each of these components of the EXE/DLL against the corresponding value in // the PDB and failing a match if any of the components differ. In the case of // symbol servers, symbols are cached in a folder that is a function of the // GUID. As a result, in order to avoid symbol cache pollution where every // incremental build copies a new PDB to the symbol cache, we must try to re-use // the existing GUID if one exists, but bump the age. This way the match will // fail, so the symbol cache knows to use the new PDB, but the GUID matches, so // it overwrites the existing item in the symbol cache rather than making a new // one. static Optional loadExistingBuildId(StringRef Path) { // We don't need to incrementally update a previous build id if we're not // writing codeview debug info. if (!Config->Debug) return None; auto ExpectedBinary = llvm::object::createBinary(Path); if (!ExpectedBinary) { consumeError(ExpectedBinary.takeError()); return None; } auto Binary = std::move(*ExpectedBinary); if (!Binary.getBinary()->isCOFF()) return None; std::error_code EC; COFFObjectFile File(Binary.getBinary()->getMemoryBufferRef(), EC); if (EC) return None; // If the machine of the binary we're outputting doesn't match the machine // of the existing binary, don't try to re-use the build id. if (File.is64() != Config->is64() || File.getMachine() != Config->Machine) return None; for (const auto &DebugDir : File.debug_directories()) { if (DebugDir.Type != IMAGE_DEBUG_TYPE_CODEVIEW) continue; const codeview::DebugInfo *ExistingDI = nullptr; StringRef PDBFileName; if (auto EC = File.getDebugPDBInfo(ExistingDI, PDBFileName)) { (void)EC; return None; } // We only support writing PDBs in v70 format. So if this is not a build // id that we recognize / support, ignore it. if (ExistingDI->Signature.CVSignature != OMF::Signature::PDB70) return None; return *ExistingDI; } return None; } // The main function of the writer. void Writer::run() { + ScopedTimer T1(CodeLayoutTimer); + createSections(); createMiscChunks(); createImportTables(); createExportTable(); - if (Config->Relocatable) - createSection(".reloc"); + mergeSections(); assignAddresses(); removeEmptySections(); setSectionPermissions(); createSymbolAndStringTable(); + if (FileSize > UINT32_MAX) + fatal("image size (" + Twine(FileSize) + ") " + + "exceeds maximum allowable size (" + Twine(UINT32_MAX) + ")"); + // We must do this before opening the output file, as it depends on being able // to read the contents of the existing output file. PreviousBuildId = loadExistingBuildId(Config->OutputFile); openFile(Config->OutputFile); if (Config->is64()) { writeHeader(); } else { writeHeader(); } writeSections(); sortExceptionTable(); writeBuildId(); - if (!Config->PDBPath.empty() && Config->Debug) { + T1.stop(); + if (!Config->PDBPath.empty() && Config->Debug) { assert(BuildId); createPDB(Symtab, OutputSections, SectionTable, *BuildId->BuildId); } writeMapFile(OutputSections); + ScopedTimer T2(DiskCommitTimer); if (auto E = Buffer->commit()) fatal("failed to write the output file: " + toString(std::move(E))); } -static StringRef getOutputSection(StringRef Name) { +static StringRef getOutputSectionName(StringRef Name) { StringRef S = Name.split('$').first; // Treat a later period as a separator for MinGW, for sections like // ".ctors.01234". - S = S.substr(0, S.find('.', 1)); + return S.substr(0, S.find('.', 1)); +} - auto It = Config->Merge.find(S); - if (It == Config->Merge.end()) - return S; - return It->second; +// For /order. +static void sortBySectionOrder(std::vector &Chunks) { + auto GetPriority = [](const Chunk *C) { + if (auto *Sec = dyn_cast(C)) + if (Sec->Sym) + return Config->Order.lookup(Sec->Sym->getName()); + return 0; + }; + + std::stable_sort(Chunks.begin(), Chunks.end(), + [=](const Chunk *A, const Chunk *B) { + return GetPriority(A) < GetPriority(B); + }); } // Create output section objects and add them to OutputSections. void Writer::createSections() { - // First, bin chunks by name. - std::map> Map; + // First, create the builtin sections. + const uint32_t DATA = IMAGE_SCN_CNT_INITIALIZED_DATA; + const uint32_t BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA; + const uint32_t CODE = IMAGE_SCN_CNT_CODE; + const uint32_t DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE; + const uint32_t R = IMAGE_SCN_MEM_READ; + const uint32_t W = IMAGE_SCN_MEM_WRITE; + const uint32_t X = IMAGE_SCN_MEM_EXECUTE; + + SmallDenseMap, OutputSection *> Sections; + auto CreateSection = [&](StringRef Name, uint32_t OutChars) { + OutputSection *&Sec = Sections[{Name, OutChars}]; + if (!Sec) { + Sec = make(Name, OutChars); + OutputSections.push_back(Sec); + } + return Sec; + }; + + // Try to match the section order used by link.exe. + TextSec = CreateSection(".text", CODE | R | X); + CreateSection(".bss", BSS | R | W); + RdataSec = CreateSection(".rdata", DATA | R); + BuildidSec = CreateSection(".buildid", DATA | R); + DataSec = CreateSection(".data", DATA | R | W); + PdataSec = CreateSection(".pdata", DATA | R); + IdataSec = CreateSection(".idata", DATA | R); + EdataSec = CreateSection(".edata", DATA | R); + DidatSec = CreateSection(".didat", DATA | R); + RsrcSec = CreateSection(".rsrc", DATA | R); + RelocSec = CreateSection(".reloc", DATA | DISCARDABLE | R); + + // Then bin chunks by name and output characteristics. + std::map, std::vector> 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); + Map[{C->getSectionName(), C->getOutputCharacteristics()}].push_back(C); } + // Process an /order option. + if (!Config->Order.empty()) + for (auto &Pair : Map) + sortBySectionOrder(Pair.second); + // 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 = make(Name); - OutputSections.push_back(Sec); - } + StringRef Name = getOutputSectionName(Pair.first.first); + uint32_t OutChars = Pair.first.second; + + // In link.exe, there is a special case for the I386 target where .CRT + // sections are treated as if they have output characteristics DATA | R if + // their characteristics are DATA | R | W. This implements the same special + // case for all architectures. + if (Name == ".CRT") + OutChars = DATA | R; + + OutputSection *Sec = CreateSection(Name, OutChars); std::vector &Chunks = Pair.second; - for (Chunk *C : Chunks) { + for (Chunk *C : Chunks) Sec->addChunk(C); - Sec->addPermissions(C->getPermissions()); - } } + + // Finally, move some output sections to the end. + auto SectionOrder = [&](OutputSection *S) { + // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because + // the loader cannot handle holes. Stripping can remove other discardable ones + // than .reloc, which is first of them (created early). + if (S->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) + return 2; + // .rsrc should come at the end of the non-discardable sections because its + // size may change by the Win32 UpdateResources() function, causing + // subsequent sections to move (see https://crbug.com/827082). + if (S == RsrcSec) + return 1; + return 0; + }; + std::stable_sort(OutputSections.begin(), OutputSections.end(), + [&](OutputSection *S, OutputSection *T) { + return SectionOrder(S) < SectionOrder(T); + }); } void Writer::createMiscChunks() { - OutputSection *RData = createSection(".rdata"); + for (auto &P : MergeChunk::Instances) + RdataSec->addChunk(P.second); // Create thunks for locally-dllimported symbols. if (!Symtab->LocalImportChunks.empty()) { for (Chunk *C : Symtab->LocalImportChunks) - RData->addChunk(C); + RdataSec->addChunk(C); } // Create Debug Information Chunks if (Config->Debug) { DebugDirectory = make(DebugRecords); + OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec; + // Make a CVDebugRecordChunk even when /DEBUG:CV is not specified. We // output a PDB no matter what, and this chunk provides the only means of // allowing a debugger to match a PDB and an executable. So we need it even // if we're ultimately not going to write CodeView data to the PDB. auto *CVChunk = make(); BuildId = CVChunk; DebugRecords.push_back(CVChunk); - RData->addChunk(DebugDirectory); + DebugInfoSec->addChunk(DebugDirectory); for (Chunk *C : DebugRecords) - RData->addChunk(C); + DebugInfoSec->addChunk(C); } - createSEHTable(RData); + // Create SEH table. x86-only. + if (Config->Machine == I386) + createSEHTable(); + + // Create /guard:cf tables if requested. + if (Config->GuardCF != GuardCFLevel::Off) + createGuardCFTables(); } // 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 (ImportFile::Instances.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 : ImportFile::Instances) { if (!File->Live) continue; 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 : ImportFile::Instances) { - if (!File->Live) - continue; + if (File->ThunkSym) { + if (!isa(File->ThunkSym)) + fatal(toString(*File->ThunkSym) + " was replaced"); + DefinedImportThunk *Thunk = cast(File->ThunkSym); + if (File->ThunkLive) + TextSec->addChunk(Thunk->getChunk()); + } - if (DefinedImportThunk *Thunk = File->ThunkSym) - Text->addChunk(Thunk->getChunk()); - + if (File->ImpSym && !isa(File->ImpSym)) + fatal(toString(*File->ImpSym) + " was replaced"); + DefinedImportData *ImpSym = cast_or_null(File->ImpSym); if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) { if (!File->ThunkSym) fatal("cannot delay-load " + toString(File) + - " due to import of data: " + toString(*File->ImpSym)); - DelayIdata.add(File->ImpSym); + " due to import of data: " + toString(*ImpSym)); + DelayIdata.add(ImpSym); } else { - Idata.add(File->ImpSym); + Idata.add(ImpSym); } } - if (!Idata.empty()) { - OutputSection *Sec = createSection(".idata"); + if (!Idata.empty()) for (Chunk *C : Idata.getChunks()) - Sec->addChunk(C); - } + IdataSec->addChunk(C); if (!DelayIdata.empty()) { Defined *Helper = cast(Config->DelayLoadHelper); DelayIdata.create(Helper); - OutputSection *Sec = createSection(".didat"); for (Chunk *C : DelayIdata.getChunks()) - Sec->addChunk(C); - Sec = createSection(".data"); + DidatSec->addChunk(C); for (Chunk *C : DelayIdata.getDataChunks()) - Sec->addChunk(C); - Sec = createSection(".text"); + DataSec->addChunk(C); for (Chunk *C : DelayIdata.getCodeChunks()) - Sec->addChunk(C); + TextSec->addChunk(C); } } void Writer::createExportTable() { if (Config->Exports.empty()) return; - OutputSection *Sec = createSection(".edata"); for (Chunk *C : Edata.Chunks) - Sec->addChunk(C); + EdataSec->addChunk(C); } // 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) { - // Relative symbols are unrepresentable in a COFF symbol table. - if (isa(Def)) + coff_symbol16 Sym; + switch (Def->kind()) { + case Symbol::DefinedAbsoluteKind: + Sym.Value = Def->getRVA(); + Sym.SectionNumber = IMAGE_SYM_ABSOLUTE; + break; + case Symbol::DefinedSyntheticKind: + // Relative symbols are unrepresentable in a COFF symbol table. return None; - - // Don't write dead symbols or symbols in codeview sections to the symbol - // table. - if (!Def->isLive()) - return None; - if (auto *D = dyn_cast(Def)) - if (D->getChunk()->isCodeView()) + default: { + // Don't write symbols that won't be written to the output to the symbol + // table. + Chunk *C = Def->getChunk(); + if (!C) return None; + OutputSection *OS = C->getOutputSection(); + if (!OS) + return None; - coff_symbol16 Sym; + Sym.Value = Def->getRVA() - OS->getRVA(); + Sym.SectionNumber = OS->SectionIndex; + break; + } + } + 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 Symbol::DefinedAbsoluteKind: - 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() { - // Name field in the section table is 8 byte long. Longer names need - // to be written to the string table. First, construct string table. + // PE/COFF images are limited to 8 byte section names. Longer names can be + // supported by writing a non-standard string table, but this string table is + // not mapped at runtime and the long names will therefore be inaccessible. + // link.exe always truncates section names to 8 bytes, whereas binutils always + // preserves long section names via the string table. LLD adopts a hybrid + // solution where discardable sections have long names preserved and + // non-discardable sections have their names truncated, to ensure that any + // section which is mapped at runtime also has its name mapped at runtime. for (OutputSection *Sec : OutputSections) { - StringRef Name = Sec->getName(); - if (Name.size() <= COFF::NameSize) + if (Sec->Name.size() <= COFF::NameSize) continue; - // If a section isn't discardable (i.e. will be mapped at runtime), - // prefer a truncated section name over a long section name in - // the string table that is unavailable at runtime. This is different from - // what link.exe does, but finding ".eh_fram" instead of "/4" is useful - // to libunwind. - if ((Sec->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0) + if ((Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) continue; - Sec->setStringTableOff(addEntryToStringTable(Name)); + Sec->setStringTableOff(addEntryToStringTable(Sec->Name)); } - if (Config->DebugDwarf) { + if (Config->DebugDwarf || Config->DebugSymtab) { for (ObjFile *File : ObjFile::Instances) { for (Symbol *B : File->getSymbols()) { auto *D = dyn_cast_or_null(B); if (!D || D->WrittenToSymtab) continue; D->WrittenToSymtab = true; if (Optional Sym = createSymbol(D)) OutputSymtab.push_back(*Sym); } } } if (OutputSymtab.empty() && Strtab.empty()) return; - OutputSection *LastSection = OutputSections.back(); // We position the symbol table to be adjacent to the end of the last section. - uint64_t FileOff = LastSection->getFileOff() + - alignTo(LastSection->getRawSize(), SectorSize); + uint64_t FileOff = FileSize; PointerToSymbolTable = FileOff; FileOff += OutputSymtab.size() * sizeof(coff_symbol16); FileOff += 4 + Strtab.size(); FileSize = alignTo(FileOff, SectorSize); } +void Writer::mergeSections() { + if (!PdataSec->getChunks().empty()) { + FirstPdata = PdataSec->getChunks().front(); + LastPdata = PdataSec->getChunks().back(); + } + + for (auto &P : Config->Merge) { + StringRef ToName = P.second; + if (P.first == ToName) + continue; + StringSet<> Names; + while (1) { + if (!Names.insert(ToName).second) + fatal("/merge: cycle found for section '" + P.first + "'"); + auto I = Config->Merge.find(ToName); + if (I == Config->Merge.end()) + break; + ToName = I->second; + } + OutputSection *From = findSection(P.first); + OutputSection *To = findSection(ToName); + if (!From) + continue; + if (!To) { + From->Name = ToName; + continue; + } + To->merge(From); + } +} + // 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 = alignTo(SizeOfHeaders, SectorSize); - uint64_t RVA = 0x1000; // The first page is kept unmapped. + uint64_t RVA = PageSize; // 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 += alignTo(Sec->getVirtualSize(), PageSize); - FileSize += alignTo(Sec->getRawSize(), SectorSize); + if (Sec == RelocSec) + addBaserels(); + uint64_t RawSize = 0, VirtualSize = 0; + Sec->Header.VirtualAddress = RVA; + for (Chunk *C : Sec->getChunks()) { + VirtualSize = alignTo(VirtualSize, C->Alignment); + C->setRVA(RVA + VirtualSize); + C->OutputSectionOff = VirtualSize; + C->finalizeContents(); + VirtualSize += C->getSize(); + if (C->hasData()) + RawSize = alignTo(VirtualSize, SectorSize); + } + if (VirtualSize > UINT32_MAX) + error("section larger than 4 GiB: " + Sec->Name); + Sec->Header.VirtualSize = VirtualSize; + Sec->Header.SizeOfRawData = RawSize; + if (RawSize != 0) + Sec->Header.PointerToRawData = FileSize; + RVA += alignTo(VirtualSize, PageSize); + FileSize += alignTo(RawSize, SectorSize); } SizeOfImage = alignTo(RVA, PageSize); } template void Writer::writeHeader() { - // Write DOS stub + // Write DOS header. For backwards compatibility, the first part of a PE/COFF + // executable consists of an MS-DOS MZ executable. If the executable is run + // under DOS, that program gets run (usually to just print an error message). + // When run under Windows, the loader looks at AddressOfNewExeHeader and uses + // the PE header instead. uint8_t *Buf = Buffer->getBufferStart(); auto *DOS = reinterpret_cast(Buf); - Buf += DOSStubSize; + Buf += sizeof(dos_header); DOS->Magic[0] = 'M'; DOS->Magic[1] = 'Z'; + DOS->UsedBytesInTheLastPage = DOSStubSize % 512; + DOS->FileSizeInPages = divideCeil(DOSStubSize, 512); + DOS->HeaderSizeInParagraphs = sizeof(dos_header) / 16; + DOS->AddressOfRelocationTable = sizeof(dos_header); DOS->AddressOfNewExeHeader = DOSStubSize; + // Write DOS program. + memcpy(Buf, DOSProgram, sizeof(DOSProgram)); + Buf += sizeof(DOSProgram); + // 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; // If {Major,Minor}LinkerVersion is left at 0.0, then for some // reason signing the resulting PE file with Authenticode produces a // signature that fails to validate on Windows 7 (but is OK on 10). // Set it to 14.0, which is what VS2015 outputs, and which avoids // that problem. PE->MajorLinkerVersion = 14; PE->MinorLinkerVersion = 0; 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); 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->AppContainer) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER; 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->Machine == I386 && !SEHTable && - !Symtab->findUnderscore("_load_config_used")) + if (Config->GuardCF != GuardCFLevel::Off) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF; + if (Config->IntegrityCheck) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY; + if (SetNoSEHCharacteristic) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH; 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(); + if (TextSec->getVirtualSize()) { + PE->BaseOfCode = TextSec->getRVA(); + PE->SizeOfCode = TextSec->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 (!Config->Exports.empty()) { + Dir[EXPORT_TABLE].RelativeVirtualAddress = Edata.getRVA(); + Dir[EXPORT_TABLE].Size = Edata.getSize(); } 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 (OutputSection *Sec = findSection(".rsrc")) { - Dir[RESOURCE_TABLE].RelativeVirtualAddress = Sec->getRVA(); - Dir[RESOURCE_TABLE].Size = Sec->getVirtualSize(); + if (RsrcSec->getVirtualSize()) { + Dir[RESOURCE_TABLE].RelativeVirtualAddress = RsrcSec->getRVA(); + Dir[RESOURCE_TABLE].Size = RsrcSec->getVirtualSize(); } - if (OutputSection *Sec = findSection(".pdata")) { - Dir[EXCEPTION_TABLE].RelativeVirtualAddress = Sec->getRVA(); - Dir[EXCEPTION_TABLE].Size = Sec->getVirtualSize(); + if (FirstPdata) { + Dir[EXCEPTION_TABLE].RelativeVirtualAddress = FirstPdata->getRVA(); + Dir[EXCEPTION_TABLE].Size = + LastPdata->getRVA() + LastPdata->getSize() - FirstPdata->getRVA(); } - if (OutputSection *Sec = findSection(".reloc")) { - Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = Sec->getRVA(); - Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize(); + if (RelocSec->getVirtualSize()) { + Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = RelocSec->getRVA(); + Dir[BASE_RELOCATION_TABLE].Size = RelocSec->getVirtualSize(); } if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) { if (Defined *B = dyn_cast(Sym)) { Dir[TLS_TABLE].RelativeVirtualAddress = B->getRVA(); Dir[TLS_TABLE].Size = Config->is64() ? sizeof(object::coff_tls_directory64) : sizeof(object::coff_tls_directory32); } } if (Config->Debug) { Dir[DEBUG_DIRECTORY].RelativeVirtualAddress = DebugDirectory->getRVA(); Dir[DEBUG_DIRECTORY].Size = DebugDirectory->getSize(); } if (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) { if (auto *B = dyn_cast(Sym)) { SectionChunk *SC = B->getChunk(); assert(B->getRVA() >= SC->getRVA()); uint64_t OffsetInChunk = B->getRVA() - SC->getRVA(); if (!SC->hasData() || OffsetInChunk + 4 > SC->getSize()) fatal("_load_config_used is malformed"); ArrayRef SecContents = SC->getContents(); uint32_t LoadConfigSize = *reinterpret_cast(&SecContents[OffsetInChunk]); if (OffsetInChunk + LoadConfigSize > SC->getSize()) fatal("_load_config_used is too large"); Dir[LOAD_CONFIG_TABLE].RelativeVirtualAddress = B->getRVA(); Dir[LOAD_CONFIG_TABLE].Size = LoadConfigSize; } } if (!DelayIdata.empty()) { Dir[DELAY_IMPORT_DESCRIPTOR].RelativeVirtualAddress = DelayIdata.getDirRVA(); Dir[DELAY_IMPORT_DESCRIPTOR].Size = DelayIdata.getDirSize(); } // Write section table for (OutputSection *Sec : OutputSections) { Sec->writeHeaderTo(Buf); Buf += sizeof(coff_section); } SectionTable = ArrayRef( Buf - OutputSections.size() * sizeof(coff_section), Buf); if (OutputSymtab.empty() && Strtab.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); if (!Strtab.empty()) memcpy(Buf + 4, Strtab.data(), Strtab.size()); } void Writer::openFile(StringRef Path) { Buffer = CHECK( FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable), "failed to open " + Path); } -void Writer::createSEHTable(OutputSection *RData) { - // Create SEH table. x86-only. - if (Config->Machine != I386) - return; +void Writer::createSEHTable() { + // Set the no SEH characteristic on x86 binaries unless we find exception + // handlers. + SetNoSEHCharacteristic = true; - std::set Handlers; - + SymbolRVASet Handlers; for (ObjFile *File : ObjFile::Instances) { - if (!File->SEHCompat) + // FIXME: We should error here instead of earlier unless /safeseh:no was + // passed. + if (!File->hasSafeSEH()) return; - for (uint32_t I : File->SXData) - if (Symbol *B = File->getSymbol(I)) - if (B->isLive()) - Handlers.insert(cast(B)); + + markSymbolsForRVATable(File, File->getSXDataChunks(), Handlers); } - if (Handlers.empty()) + // Remove the "no SEH" characteristic if all object files were built with + // safeseh, we found some exception handlers, and there is a load config in + // the object. + SetNoSEHCharacteristic = + Handlers.empty() || !Symtab->findUnderscore("_load_config_used"); + + maybeAddRVATable(std::move(Handlers), "__safe_se_handler_table", + "__safe_se_handler_count"); +} + +// Add a symbol to an RVA set. Two symbols may have the same RVA, but an RVA set +// cannot contain duplicates. Therefore, the set is uniqued by Chunk and the +// symbol's offset into that Chunk. +static void addSymbolToRVASet(SymbolRVASet &RVASet, Defined *S) { + Chunk *C = S->getChunk(); + if (auto *SC = dyn_cast(C)) + C = SC->Repl; // Look through ICF replacement. + uint32_t Off = S->getRVA() - (C ? C->getRVA() : 0); + RVASet.insert({C, Off}); +} + +// Visit all relocations from all section contributions of this object file and +// mark the relocation target as address-taken. +static void markSymbolsWithRelocations(ObjFile *File, + SymbolRVASet &UsedSymbols) { + for (Chunk *C : File->getChunks()) { + // We only care about live section chunks. Common chunks and other chunks + // don't generally contain relocations. + SectionChunk *SC = dyn_cast(C); + if (!SC || !SC->isLive()) + continue; + + // Look for relocations in this section against symbols in executable output + // sections. + for (Symbol *Ref : SC->symbols()) { + // FIXME: Do further testing to see if the relocation type matters, + // especially for 32-bit where taking the address of something usually + // uses an absolute relocation instead of a relative one. + if (auto *D = dyn_cast_or_null(Ref)) { + Chunk *RefChunk = D->getChunk(); + OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr; + if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE) + addSymbolToRVASet(UsedSymbols, D); + } + } + } +} + +// Create the guard function id table. This is a table of RVAs of all +// address-taken functions. It is sorted and uniqued, just like the safe SEH +// table. +void Writer::createGuardCFTables() { + SymbolRVASet AddressTakenSyms; + SymbolRVASet LongJmpTargets; + for (ObjFile *File : ObjFile::Instances) { + // If the object was compiled with /guard:cf, the address taken symbols + // are in .gfids$y sections, and the longjmp targets are in .gljmp$y + // sections. If the object was not compiled with /guard:cf, we assume there + // were no setjmp targets, and that all code symbols with relocations are + // possibly address-taken. + if (File->hasGuardCF()) { + markSymbolsForRVATable(File, File->getGuardFidChunks(), AddressTakenSyms); + markSymbolsForRVATable(File, File->getGuardLJmpChunks(), LongJmpTargets); + } else { + markSymbolsWithRelocations(File, AddressTakenSyms); + } + } + + // Mark the image entry as address-taken. + if (Config->Entry) + addSymbolToRVASet(AddressTakenSyms, cast(Config->Entry)); + + // Ensure sections referenced in the gfid table are 16-byte aligned. + for (const ChunkAndOffset &C : AddressTakenSyms) + if (C.InputChunk->Alignment < 16) + C.InputChunk->Alignment = 16; + + maybeAddRVATable(std::move(AddressTakenSyms), "__guard_fids_table", + "__guard_fids_count"); + + // Add the longjmp target table unless the user told us not to. + if (Config->GuardCF == GuardCFLevel::Full) + maybeAddRVATable(std::move(LongJmpTargets), "__guard_longjmp_table", + "__guard_longjmp_count"); + + // Set __guard_flags, which will be used in the load config to indicate that + // /guard:cf was enabled. + uint32_t GuardFlags = uint32_t(coff_guard_flags::CFInstrumented) | + uint32_t(coff_guard_flags::HasFidTable); + if (Config->GuardCF == GuardCFLevel::Full) + GuardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable); + Symbol *FlagSym = Symtab->findUnderscore("__guard_flags"); + cast(FlagSym)->setVA(GuardFlags); +} + +// Take a list of input sections containing symbol table indices and add those +// symbols to an RVA table. The challenge is that symbol RVAs are not known and +// depend on the table size, so we can't directly build a set of integers. +void Writer::markSymbolsForRVATable(ObjFile *File, + ArrayRef SymIdxChunks, + SymbolRVASet &TableSymbols) { + for (SectionChunk *C : SymIdxChunks) { + // Skip sections discarded by linker GC. This comes up when a .gfids section + // is associated with something like a vtable and the vtable is discarded. + // In this case, the associated gfids section is discarded, and we don't + // mark the virtual member functions as address-taken by the vtable. + if (!C->isLive()) + continue; + + // Validate that the contents look like symbol table indices. + ArrayRef Data = C->getContents(); + if (Data.size() % 4 != 0) { + warn("ignoring " + C->getSectionName() + + " symbol table index section in object " + toString(File)); + continue; + } + + // Read each symbol table index and check if that symbol was included in the + // final link. If so, add it to the table symbol set. + ArrayRef SymIndices( + reinterpret_cast(Data.data()), Data.size() / 4); + ArrayRef ObjSymbols = File->getSymbols(); + for (uint32_t SymIndex : SymIndices) { + if (SymIndex >= ObjSymbols.size()) { + warn("ignoring invalid symbol table index in section " + + C->getSectionName() + " in object " + toString(File)); + continue; + } + if (Symbol *S = ObjSymbols[SymIndex]) { + if (S->isLive()) + addSymbolToRVASet(TableSymbols, cast(S)); + } + } + } +} + +// Replace the absolute table symbol with a synthetic symbol pointing to +// TableChunk so that we can emit base relocations for it and resolve section +// relative relocations. +void Writer::maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym, + StringRef CountSym) { + if (TableSymbols.empty()) return; - SEHTable = make(Handlers); - RData->addChunk(SEHTable); + RVATableChunk *TableChunk = make(std::move(TableSymbols)); + RdataSec->addChunk(TableChunk); - // Replace the absolute table symbol with a synthetic symbol pointing to the - // SEHTable chunk so that we can emit base relocations for it and resolve - // section relative relocations. - Symbol *T = Symtab->find("___safe_se_handler_table"); - Symbol *C = Symtab->find("___safe_se_handler_count"); - replaceSymbol(T, T->getName(), SEHTable); - cast(C)->setVA(SEHTable->getSize() / 4); + Symbol *T = Symtab->findUnderscore(TableSym); + Symbol *C = Symtab->findUnderscore(CountSym); + replaceSymbol(T, T->getName(), TableChunk); + cast(C)->setVA(TableChunk->getSize() / 4); } // Handles /section options to allow users to overwrite // section attributes. void Writer::setSectionPermissions() { for (auto &P : Config->Section) { StringRef Name = P.first; uint32_t Perm = P.second; - if (auto *Sec = findSection(Name)) - Sec->setPermissions(Perm); + for (OutputSection *Sec : OutputSections) + if (Sec->Name == Name) + Sec->setPermissions(Perm); } } // Write section contents to a mmap'ed file. void Writer::writeSections() { - // Record the section index that should be used when resolving a section - // relocation against an absolute symbol. - DefinedAbsolute::OutputSectionIndex = OutputSections.size() + 1; + // Record the number of sections to apply section index relocations + // against absolute symbols. See applySecIdx in Chunks.cpp.. + DefinedAbsolute::NumOutputSections = OutputSections.size(); 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) + if (Sec->Header.Characteristics & IMAGE_SCN_CNT_CODE) memset(SecBuf, 0xCC, Sec->getRawSize()); for_each(parallel::par, Sec->getChunks().begin(), Sec->getChunks().end(), [&](Chunk *C) { C->writeTo(SecBuf); }); } } void Writer::writeBuildId() { - // If we're not writing a build id (e.g. because /debug is not specified), - // then just return; - if (!Config->Debug) - return; + // There are two important parts to the build ID. + // 1) If building with debug info, the COFF debug directory contains a + // timestamp as well as a Guid and Age of the PDB. + // 2) In all cases, the PE COFF file header also contains a timestamp. + // For reproducibility, instead of a timestamp we want to use a hash of the + // binary, however when building with debug info the hash needs to take into + // account the debug info, since it's possible to add blank lines to a file + // which causes the debug info to change but not the generated code. + // + // To handle this, we first set the Guid and Age in the debug directory (but + // only if we're doing a debug build). Then, we hash the binary (thus causing + // the hash to change if only the debug info changes, since the Age will be + // different). Finally, we write that hash into the debug directory (if + // present) as well as the COFF file header (always). + if (Config->Debug) { + assert(BuildId && "BuildId is not set!"); + if (PreviousBuildId.hasValue()) { + *BuildId->BuildId = *PreviousBuildId; + BuildId->BuildId->PDB70.Age = BuildId->BuildId->PDB70.Age + 1; + } else { + BuildId->BuildId->Signature.CVSignature = OMF::Signature::PDB70; + BuildId->BuildId->PDB70.Age = 1; + llvm::getRandomBytes(BuildId->BuildId->PDB70.Signature, 16); + } + } - assert(BuildId && "BuildId is not set!"); + // At this point the only fields in the COFF file which remain unset are the + // "timestamp" in the COFF file header, and the ones in the coff debug + // directory. Now we can hash the file and write that hash to the various + // timestamp fields in the file. + StringRef OutputFileData( + reinterpret_cast(Buffer->getBufferStart()), + Buffer->getBufferSize()); - if (PreviousBuildId.hasValue()) { - *BuildId->BuildId = *PreviousBuildId; - BuildId->BuildId->PDB70.Age = BuildId->BuildId->PDB70.Age + 1; - return; - } + uint32_t Timestamp = Config->Timestamp; + if (Config->Repro) + Timestamp = static_cast(xxHash64(OutputFileData)); - BuildId->BuildId->Signature.CVSignature = OMF::Signature::PDB70; - BuildId->BuildId->PDB70.Age = 1; - llvm::getRandomBytes(BuildId->BuildId->PDB70.Signature, 16); + if (DebugDirectory) + DebugDirectory->setTimeDateStamp(Timestamp); + + uint8_t *Buf = Buffer->getBufferStart(); + Buf += DOSStubSize + sizeof(PEMagic); + object::coff_file_header *CoffHeader = + reinterpret_cast(Buf); + CoffHeader->TimeDateStamp = Timestamp; } // Sort .pdata section contents according to PE/COFF spec 5.5. void Writer::sortExceptionTable() { - OutputSection *Sec = findSection(".pdata"); - if (!Sec) + if (!FirstPdata) return; // We assume .pdata contains function table entries only. - uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff(); - uint8_t *End = Begin + Sec->getVirtualSize(); + auto BufAddr = [&](Chunk *C) { + return Buffer->getBufferStart() + C->getOutputSection()->getFileOff() + + C->getRVA() - C->getOutputSection()->getRVA(); + }; + uint8_t *Begin = BufAddr(FirstPdata); + uint8_t *End = BufAddr(LastPdata) + LastPdata->getSize(); if (Config->Machine == AMD64) { struct Entry { ulittle32_t Begin, End, Unwind; }; sort(parallel::par, (Entry *)Begin, (Entry *)End, [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); return; } if (Config->Machine == ARMNT || Config->Machine == ARM64) { struct Entry { ulittle32_t Begin, Unwind; }; sort(parallel::par, (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) + if (Sec->Name == 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) + if (S->Header.Characteristics & 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) - .Cases(".didat", ".edata", ".idata", ".rdata", DATA | R) - .Case(".reloc", DATA | DISCARDABLE | R) - .Case(".text", CODE | R | X) - .Default(0); - if (!Perms) - llvm_unreachable("unknown section name"); - auto Sec = make(Name); - Sec->addPermissions(Perms); - OutputSections.push_back(Sec); - return Sec; -} - -// Dest is .reloc section. Add contents to that section. -void Writer::addBaserels(OutputSection *Dest) { +// Add base relocations to .reloc section. +void Writer::addBaserels() { + if (!Config->Relocatable) + return; std::vector V; for (OutputSection *Sec : OutputSections) { - if (Sec == Dest) + if (Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) 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); + addBaserelBlocks(V); V.clear(); } } // Add addresses to .reloc section. Note that addresses are grouped by page. -void Writer::addBaserelBlocks(OutputSection *Dest, std::vector &V) { +void Writer::addBaserelBlocks(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; - Dest->addChunk(make(Page, &V[I], &V[0] + J)); + RelocSec->addChunk(make(Page, &V[I], &V[0] + J)); I = J; Page = P; } if (I == J) return; - Dest->addChunk(make(Page, &V[I], &V[0] + J)); + RelocSec->addChunk(make(Page, &V[I], &V[0] + J)); } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/Writer.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/COFF/Writer.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/COFF/Writer.h (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/COFF/Writer.h (revision 336982) @@ -1,73 +1,73 @@ //===- Writer.h -------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_COFF_WRITER_H #define LLD_COFF_WRITER_H #include "Chunks.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/COFF.h" +#include #include #include namespace lld { namespace coff { static const int PageSize = 4096; void writeResult(); // 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(llvm::StringRef N) : Name(N), Header({}) {} - void setRVA(uint64_t); - void setFileOffset(uint64_t); + OutputSection(llvm::StringRef N, uint32_t Chars) : Name(N) { + Header.Characteristics = Chars; + } void addChunk(Chunk *C); - llvm::StringRef getName() { return Name; } + void merge(OutputSection *Other); ArrayRef getChunks() { return Chunks; } void addPermissions(uint32_t C); void setPermissions(uint32_t C); - uint32_t getPermissions() { return Header.Characteristics & PermMask; } - uint32_t getCharacteristics() { return Header.Characteristics; } uint64_t getRVA() { return Header.VirtualAddress; } 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: llvm::StringRef Name; - llvm::object::coff_section Header; + llvm::object::coff_section Header = {}; + +private: uint32_t StringTableOff = 0; std::vector Chunks; }; } } #endif Property changes on: projects/clang700-import/contrib/llvm/tools/lld/COFF/Writer.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/Common/Args.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/Common/Args.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/Common/Args.cpp (revision 336982) @@ -1,62 +1,66 @@ //===- Args.cpp -----------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "lld/Common/Args.h" #include "lld/Common/ErrorHandler.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Option/ArgList.h" using namespace llvm; using namespace lld; int lld::args::getInteger(opt::InputArgList &Args, unsigned Key, int Default) { - int V = Default; - if (auto *Arg = Args.getLastArg(Key)) { - StringRef S = Arg->getValue(); - if (!to_integer(S, V, 10)) - error(Arg->getSpelling() + ": number expected, but got '" + S + "'"); - } - return V; + auto *A = Args.getLastArg(Key); + if (!A) + return Default; + + int V; + if (to_integer(A->getValue(), V, 10)) + return V; + + StringRef Spelling = Args.getArgString(A->getIndex()); + error(Spelling + ": number expected, but got '" + A->getValue() + "'"); + return 0; } std::vector lld::args::getStrings(opt::InputArgList &Args, int Id) { std::vector V; for (auto *Arg : Args.filtered(Id)) V.push_back(Arg->getValue()); return V; } uint64_t lld::args::getZOptionValue(opt::InputArgList &Args, int Id, StringRef Key, uint64_t Default) { for (auto *Arg : Args.filtered(Id)) { std::pair KV = StringRef(Arg->getValue()).split('='); if (KV.first == Key) { uint64_t Result = Default; if (!to_integer(KV.second, Result)) error("invalid " + Key + ": " + KV.second); return Result; } } return Default; } std::vector lld::args::getLines(MemoryBufferRef MB) { SmallVector Arr; MB.getBuffer().split(Arr, '\n'); std::vector Ret; for (StringRef S : Arr) { S = S.trim(); if (!S.empty() && S[0] != '#') Ret.push_back(S); } return Ret; } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/Common/Args.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/Common/CMakeLists.txt =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/Common/CMakeLists.txt (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/Common/CMakeLists.txt (revision 336982) @@ -1,32 +1,33 @@ if(NOT LLD_BUILT_STANDALONE) set(tablegen_deps intrinsics_gen) endif() add_lld_library(lldCommon Args.cpp ErrorHandler.cpp Memory.cpp Reproduce.cpp Strings.cpp TargetOptionsCommandFlags.cpp Threads.cpp + Timer.cpp Version.cpp ADDITIONAL_HEADER_DIRS ${LLD_INCLUDE_DIR}/lld/Common LINK_COMPONENTS Codegen Core Demangle MC Option Support Target LINK_LIBS ${LLVM_PTHREAD_LIB} DEPENDS ${tablegen_deps} ) Property changes on: projects/clang700-import/contrib/llvm/tools/lld/Common/CMakeLists.txt ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/Common/ErrorHandler.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/Common/ErrorHandler.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/Common/ErrorHandler.cpp (revision 336982) @@ -1,118 +1,143 @@ //===- ErrorHandler.cpp ---------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "lld/Common/ErrorHandler.h" #include "lld/Common/Threads.h" #include "llvm/ADT/Twine.h" -#include "llvm/Support/Error.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/DiagnosticPrinter.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/raw_ostream.h" #include #if !defined(_MSC_VER) && !defined(__MINGW32__) #include #endif using namespace llvm; using namespace lld; // The functions defined in this file can be called from multiple threads, // but outs() or errs() are not thread-safe. We protect them using a mutex. static std::mutex Mu; // Prints "\n" or does nothing, depending on Msg contents of // the previous call of this function. static void newline(raw_ostream *ErrorOS, const Twine &Msg) { // True if the previous error message contained "\n". // We want to separate multi-line error messages with a newline. static bool Flag; if (Flag) *ErrorOS << "\n"; Flag = StringRef(Msg.str()).contains('\n'); } ErrorHandler &lld::errorHandler() { static ErrorHandler Handler; return Handler; } void lld::exitLld(int Val) { // Delete the output buffer so that any tempory file is deleted. errorHandler().OutputBuffer.reset(); // Dealloc/destroy ManagedStatic variables before calling // _exit(). In a non-LTO build, this is a nop. In an LTO // build allows us to get the output of -time-passes. llvm_shutdown(); outs().flush(); errs().flush(); _exit(Val); +} + +void lld::diagnosticHandler(const DiagnosticInfo &DI) { + SmallString<128> S; + raw_svector_ostream OS(S); + DiagnosticPrinterRawOStream DP(OS); + DI.print(DP); + switch (DI.getSeverity()) { + case DS_Error: + error(S); + break; + case DS_Warning: + warn(S); + break; + case DS_Remark: + case DS_Note: + message(S); + break; + } +} + +void lld::checkError(Error E) { + handleAllErrors(std::move(E), + [&](ErrorInfoBase &EIB) { error(EIB.message()); }); } void ErrorHandler::print(StringRef S, raw_ostream::Colors C) { *ErrorOS << LogName << ": "; if (ColorDiagnostics) { ErrorOS->changeColor(C, true); *ErrorOS << S; ErrorOS->resetColor(); } else { *ErrorOS << S; } } void ErrorHandler::log(const Twine &Msg) { if (Verbose) { std::lock_guard Lock(Mu); *ErrorOS << LogName << ": " << Msg << "\n"; } } void ErrorHandler::message(const Twine &Msg) { std::lock_guard Lock(Mu); outs() << Msg << "\n"; outs().flush(); } void ErrorHandler::warn(const Twine &Msg) { if (FatalWarnings) { error(Msg); return; } std::lock_guard Lock(Mu); newline(ErrorOS, Msg); print("warning: ", raw_ostream::MAGENTA); *ErrorOS << Msg << "\n"; } void ErrorHandler::error(const Twine &Msg) { std::lock_guard Lock(Mu); newline(ErrorOS, Msg); if (ErrorLimit == 0 || ErrorCount < ErrorLimit) { print("error: ", raw_ostream::RED); *ErrorOS << Msg << "\n"; } else if (ErrorCount == ErrorLimit) { print("error: ", raw_ostream::RED); *ErrorOS << ErrorLimitExceededMsg << "\n"; if (ExitEarly) exitLld(1); } ++ErrorCount; } void ErrorHandler::fatal(const Twine &Msg) { error(Msg); exitLld(1); } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/Common/ErrorHandler.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/Common/Memory.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/Common/Memory.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/Common/Memory.cpp (revision 336982) Property changes on: projects/clang700-import/contrib/llvm/tools/lld/Common/Memory.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/Common/Reproduce.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/Common/Reproduce.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/Common/Reproduce.cpp (revision 336982) Property changes on: projects/clang700-import/contrib/llvm/tools/lld/Common/Reproduce.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/Common/Strings.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/Common/Strings.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/Common/Strings.cpp (revision 336982) @@ -1,32 +1,109 @@ //===- Strings.cpp -------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "lld/Common/Strings.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/LLVM.h" #include "llvm/Demangle/Demangle.h" +#include "llvm/Support/GlobPattern.h" +#include +#include +#include +#if defined(_MSC_VER) +#include + +// DbgHelp.h must be included after Windows.h. +#include +#pragma comment(lib, "dbghelp.lib") +#endif + using namespace llvm; using namespace lld; // Returns the demangled C++ symbol name for Name. Optional lld::demangleItanium(StringRef Name) { // itaniumDemangle can be used to demangle strings other than symbol // names which do not necessarily start with "_Z". Name can be // either a C or C++ symbol. Don't call itaniumDemangle if the name // does not look like a C++ symbol name to avoid getting unexpected // result for a C symbol that happens to match a mangled type name. if (!Name.startswith("_Z")) return None; char *Buf = itaniumDemangle(Name.str().c_str(), nullptr, nullptr, nullptr); if (!Buf) return None; std::string S(Buf); free(Buf); return S; +} + +Optional lld::demangleMSVC(StringRef S) { +#if defined(_MSC_VER) + // UnDecorateSymbolName is not thread-safe, so we need a mutex. + static std::mutex Mu; + std::lock_guard Lock(Mu); + + char Buf[4096]; + if (S.startswith("?")) + if (size_t Len = UnDecorateSymbolName(S.str().c_str(), Buf, sizeof(Buf), 0)) + return std::string(Buf, Len); +#endif + return None; +} + +StringMatcher::StringMatcher(ArrayRef Pat) { + for (StringRef S : Pat) { + Expected Pat = GlobPattern::create(S); + if (!Pat) + error(toString(Pat.takeError())); + else + Patterns.push_back(*Pat); + } +} + +bool StringMatcher::match(StringRef S) const { + for (const GlobPattern &Pat : Patterns) + if (Pat.match(S)) + return true; + return false; +} + +// Converts a hex string (e.g. "deadbeef") to a vector. +std::vector lld::parseHex(StringRef S) { + std::vector Hex; + while (!S.empty()) { + StringRef B = S.substr(0, 2); + S = S.substr(2); + uint8_t H; + if (!to_integer(B, H, 16)) { + error("not a hexadecimal value: " + B); + return {}; + } + Hex.push_back(H); + } + return Hex; +} + +// Returns true if S is valid as a C language identifier. +bool lld::isValidCIdentifier(StringRef S) { + return !S.empty() && (isAlpha(S[0]) || S[0] == '_') && + std::all_of(S.begin() + 1, S.end(), + [](char C) { return C == '_' || isAlnum(C); }); +} + +// Write the contents of the a buffer to a file +void lld::saveBuffer(StringRef Buffer, const Twine &Path) { + std::error_code EC; + raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None); + if (EC) + error("cannot create " + Path + ": " + EC.message()); + OS << Buffer; } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/Common/Strings.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/Common/TargetOptionsCommandFlags.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/Common/TargetOptionsCommandFlags.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/Common/TargetOptionsCommandFlags.cpp (revision 336982) @@ -1,32 +1,34 @@ //===-- TargetOptionsCommandFlags.cpp ---------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file exists as a place for global variables defined in LLVM's -// CodeGen/CommandFlags.def. By putting the resulting object file in +// CodeGen/CommandFlags.inc. By putting the resulting object file in // an archive and linking with it, the definitions will automatically be // included when needed and skipped when already present. // //===----------------------------------------------------------------------===// #include "lld/Common/TargetOptionsCommandFlags.h" -#include "llvm/CodeGen/CommandFlags.def" +#include "llvm/CodeGen/CommandFlags.inc" #include "llvm/Target/TargetOptions.h" // Define an externally visible version of // InitTargetOptionsFromCodeGenFlags, so that its functionality can be -// used without having to include llvm/CodeGen/CommandFlags.def, which +// used without having to include llvm/CodeGen/CommandFlags.inc, which // would lead to multiple definitions of the command line flags. llvm::TargetOptions lld::InitTargetOptionsFromCodeGenFlags() { return ::InitTargetOptionsFromCodeGenFlags(); } llvm::Optional lld::GetCodeModelFromCMModel() { return getCodeModel(); } + +std::string lld::GetCPUStr() { return ::getCPUStr(); } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/Common/TargetOptionsCommandFlags.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/Common/Threads.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/Common/Threads.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/Common/Threads.cpp (revision 336982) Property changes on: projects/clang700-import/contrib/llvm/tools/lld/Common/Threads.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/Common/Timer.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/Common/Timer.cpp (nonexistent) +++ projects/clang700-import/contrib/llvm/tools/lld/Common/Timer.cpp (revision 336982) @@ -0,0 +1,80 @@ +//===- Timer.cpp ----------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Common/Timer.h" +#include "lld/Common/ErrorHandler.h" +#include "llvm/Support/Format.h" + +using namespace lld; +using namespace llvm; + +ScopedTimer::ScopedTimer(Timer &T) : T(&T) { T.start(); } + +void ScopedTimer::stop() { + if (!T) + return; + T->stop(); + T = nullptr; +} + +ScopedTimer::~ScopedTimer() { stop(); } + +Timer::Timer(llvm::StringRef Name) : Name(Name), Parent(nullptr) {} +Timer::Timer(llvm::StringRef Name, Timer &Parent) + : Name(Name), Parent(&Parent) {} + +void Timer::start() { + if (Parent && Total.count() == 0) + Parent->Children.push_back(this); + StartTime = std::chrono::high_resolution_clock::now(); +} + +void Timer::stop() { + Total += (std::chrono::high_resolution_clock::now() - StartTime); +} + +Timer &Timer::root() { + static Timer RootTimer("Total Link Time"); + return RootTimer; +} + +void Timer::print() { + double TotalDuration = static_cast(root().millis()); + + // We want to print the grand total under all the intermediate phases, so we + // print all children first, then print the total under that. + for (const auto &Child : Children) + Child->print(1, TotalDuration); + + message(std::string(49, '-')); + + root().print(0, root().millis(), false); +} + +double Timer::millis() const { + return std::chrono::duration_cast>( + Total) + .count(); +} + +void Timer::print(int Depth, double TotalDuration, bool Recurse) const { + double P = 100.0 * millis() / TotalDuration; + + SmallString<32> Str; + llvm::raw_svector_ostream Stream(Str); + std::string S = std::string(Depth * 2, ' ') + Name + std::string(":"); + Stream << format("%-30s%5d ms (%5.1f%%)", S.c_str(), (int)millis(), P); + + message(Str); + + if (Recurse) { + for (const auto &Child : Children) + Child->print(Depth + 1, TotalDuration); + } +} Property changes on: projects/clang700-import/contrib/llvm/tools/lld/Common/Timer.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/Common/Version.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/Common/Version.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/Common/Version.cpp (revision 336982) Property changes on: projects/clang700-import/contrib/llvm/tools/lld/Common/Version.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/Strings.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/Strings.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/Strings.cpp (nonexistent) @@ -1,62 +0,0 @@ -//===- Strings.cpp -------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Strings.h" -#include "Config.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Demangle/Demangle.h" -#include -#include - -using namespace llvm; -using namespace lld; -using namespace lld::elf; - -StringMatcher::StringMatcher(ArrayRef Pat) { - for (StringRef S : Pat) { - Expected Pat = GlobPattern::create(S); - if (!Pat) - error(toString(Pat.takeError())); - else - Patterns.push_back(*Pat); - } -} - -bool StringMatcher::match(StringRef S) const { - for (const GlobPattern &Pat : Patterns) - if (Pat.match(S)) - return true; - return false; -} - -// Converts a hex string (e.g. "deadbeef") to a vector. -std::vector elf::parseHex(StringRef S) { - std::vector Hex; - while (!S.empty()) { - StringRef B = S.substr(0, 2); - S = S.substr(2); - uint8_t H; - if (!to_integer(B, H, 16)) { - error("not a hexadecimal value: " + B); - return {}; - } - Hex.push_back(H); - } - return Hex; -} - -// Returns true if S is valid as a C language identifier. -bool elf::isValidCIdentifier(StringRef S) { - return !S.empty() && (isAlpha(S[0]) || S[0] == '_') && - std::all_of(S.begin() + 1, S.end(), - [](char C) { return C == '_' || isAlnum(C); }); -} Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/Strings.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/Strings.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/Strings.h (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/Strings.h (nonexistent) @@ -1,75 +0,0 @@ -//===- Strings.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_STRINGS_H -#define LLD_ELF_STRINGS_H - -#include "lld/Common/LLVM.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/GlobPattern.h" -#include - -namespace lld { -namespace elf { - -std::vector parseHex(StringRef S); -bool isValidCIdentifier(StringRef S); - -// This is a lazy version of StringRef. String size is computed lazily -// when it is needed. It is more efficient than StringRef to instantiate -// if you have a string whose size is unknown. -// -// ELF string tables contain a lot of null-terminated strings. -// Most of them are not necessary for the linker because they are names -// of local symbols and the linker doesn't use local symbol names for -// name resolution. So, we use this class to represents strings read -// from string tables. -class StringRefZ { -public: - StringRefZ() : Start(nullptr), Size(0) {} - StringRefZ(const char *S, size_t Size) : Start(S), Size(Size) {} - - /*implicit*/ StringRefZ(const char *S) : Start(S), Size(-1) {} - - /*implicit*/ StringRefZ(llvm::StringRef S) - : Start(S.data()), Size(S.size()) {} - - operator llvm::StringRef() const { - if (Size == (size_t)-1) - Size = strlen(Start); - return {Start, Size}; - } - -private: - const char *Start; - mutable size_t Size; -}; - -// This class represents multiple glob patterns. -class StringMatcher { -public: - StringMatcher() = default; - explicit StringMatcher(ArrayRef Pat); - - bool match(StringRef S) const; - -private: - std::vector Patterns; -}; - -inline ArrayRef toArrayRef(StringRef S) { - return {(const uint8_t *)S.data(), S.size()}; -} -} // namespace elf -} // namespace lld - -#endif Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/Strings.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.cpp (revision 336982) @@ -1,649 +1,647 @@ //===- AArch64ErrataFix.cpp -----------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // This file implements Section Patching for the purpose of working around // errata in CPUs. The general principle is that an erratum sequence of one or // more instructions is detected in the instruction stream, one of the // instructions in the sequence is replaced with a branch to a patch sequence // of replacement instructions. At the end of the replacement sequence the // patch branches back to the instruction stream. // This technique is only suitable for fixing an erratum when: // - There is a set of necessary conditions required to trigger the erratum that // can be detected at static link time. // - There is a set of replacement instructions that can be used to remove at // least one of the necessary conditions that trigger the erratum. // - We can overwrite an instruction in the erratum sequence with a branch to // the replacement sequence. // - We can place the replacement sequence within range of the branch. // FIXME: // - The implementation here only supports one patch, the AArch64 Cortex-53 // errata 843419 that affects r0p0, r0p1, r0p2 and r0p4 versions of the core. // To keep the initial version simple there is no support for multiple // architectures or selection of different patches. //===----------------------------------------------------------------------===// #include "AArch64ErrataFix.h" #include "Config.h" #include "LinkerScript.h" #include "OutputSections.h" #include "Relocations.h" -#include "Strings.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "lld/Common/Memory.h" - +#include "lld/Common/Strings.h" #include "llvm/Support/Endian.h" #include "llvm/Support/raw_ostream.h" #include using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support; using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; // Helper functions to identify instructions and conditions needed to trigger // the Cortex-A53-843419 erratum. // ADRP // | 1 | immlo (2) | 1 | 0 0 0 0 | immhi (19) | Rd (5) | static bool isADRP(uint32_t Instr) { return (Instr & 0x9f000000) == 0x90000000; } // Load and store bit patterns from ARMv8-A ARM ARM. // Instructions appear in order of appearance starting from table in // C4.1.3 Loads and Stores. // All loads and stores have 1 (at bit postion 27), (0 at bit position 25). // | op0 x op1 (2) | 1 op2 0 op3 (2) | x | op4 (5) | xxxx | op5 (2) | x (10) | static bool isLoadStoreClass(uint32_t Instr) { return (Instr & 0x0a000000) == 0x08000000; } // LDN/STN multiple no offset // | 0 Q 00 | 1100 | 0 L 00 | 0000 | opcode (4) | size (2) | Rn (5) | Rt (5) | // LDN/STN multiple post-indexed // | 0 Q 00 | 1100 | 1 L 0 | Rm (5)| opcode (4) | size (2) | Rn (5) | Rt (5) | // L == 0 for stores. // Utility routine to decode opcode field of LDN/STN multiple structure // instructions to find the ST1 instructions. // opcode == 0010 ST1 4 registers. // opcode == 0110 ST1 3 registers. // opcode == 0111 ST1 1 register. // opcode == 1010 ST1 2 registers. static bool isST1MultipleOpcode(uint32_t Instr) { return (Instr & 0x0000f000) == 0x00002000 || (Instr & 0x0000f000) == 0x00006000 || (Instr & 0x0000f000) == 0x00007000 || (Instr & 0x0000f000) == 0x0000a000; } static bool isST1Multiple(uint32_t Instr) { return (Instr & 0xbfff0000) == 0x0c000000 && isST1MultipleOpcode(Instr); } // Writes to Rn (writeback). static bool isST1MultiplePost(uint32_t Instr) { return (Instr & 0xbfe00000) == 0x0c800000 && isST1MultipleOpcode(Instr); } // LDN/STN single no offset // | 0 Q 00 | 1101 | 0 L R 0 | 0000 | opc (3) S | size (2) | Rn (5) | Rt (5)| // LDN/STN single post-indexed // | 0 Q 00 | 1101 | 1 L R | Rm (5) | opc (3) S | size (2) | Rn (5) | Rt (5)| // L == 0 for stores // Utility routine to decode opcode field of LDN/STN single structure // instructions to find the ST1 instructions. // R == 0 for ST1 and ST3, R == 1 for ST2 and ST4. // opcode == 000 ST1 8-bit. // opcode == 010 ST1 16-bit. // opcode == 100 ST1 32 or 64-bit (Size determines which). static bool isST1SingleOpcode(uint32_t Instr) { return (Instr & 0x0040e000) == 0x00000000 || (Instr & 0x0040e000) == 0x00004000 || (Instr & 0x0040e000) == 0x00008000; } static bool isST1Single(uint32_t Instr) { return (Instr & 0xbfff0000) == 0x0d000000 && isST1SingleOpcode(Instr); } // Writes to Rn (writeback). static bool isST1SinglePost(uint32_t Instr) { return (Instr & 0xbfe00000) == 0x0d800000 && isST1SingleOpcode(Instr); } static bool isST1(uint32_t Instr) { return isST1Multiple(Instr) || isST1MultiplePost(Instr) || isST1Single(Instr) || isST1SinglePost(Instr); } // Load/store exclusive // | size (2) 00 | 1000 | o2 L o1 | Rs (5) | o0 | Rt2 (5) | Rn (5) | Rt (5) | // L == 0 for Stores. static bool isLoadStoreExclusive(uint32_t Instr) { return (Instr & 0x3f000000) == 0x08000000; } static bool isLoadExclusive(uint32_t Instr) { return (Instr & 0x3f400000) == 0x08400000; } // Load register literal // | opc (2) 01 | 1 V 00 | imm19 | Rt (5) | static bool isLoadLiteral(uint32_t Instr) { return (Instr & 0x3b000000) == 0x18000000; } // Load/store no-allocate pair // (offset) // | opc (2) 10 | 1 V 00 | 0 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | // L == 0 for stores. // Never writes to register static bool isSTNP(uint32_t Instr) { return (Instr & 0x3bc00000) == 0x28000000; } // Load/store register pair // (post-indexed) // | opc (2) 10 | 1 V 00 | 1 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | // L == 0 for stores, V == 0 for Scalar, V == 1 for Simd/FP // Writes to Rn. static bool isSTPPost(uint32_t Instr) { return (Instr & 0x3bc00000) == 0x28800000; } // (offset) // | opc (2) 10 | 1 V 01 | 0 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | static bool isSTPOffset(uint32_t Instr) { return (Instr & 0x3bc00000) == 0x29000000; } // (pre-index) // | opc (2) 10 | 1 V 01 | 1 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | // Writes to Rn. static bool isSTPPre(uint32_t Instr) { return (Instr & 0x3bc00000) == 0x29800000; } static bool isSTP(uint32_t Instr) { return isSTPPost(Instr) || isSTPOffset(Instr) || isSTPPre(Instr); } // Load/store register (unscaled immediate) // | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 00 | Rn (5) | Rt (5) | // V == 0 for Scalar, V == 1 for Simd/FP. static bool isLoadStoreUnscaled(uint32_t Instr) { return (Instr & 0x3b000c00) == 0x38000000; } // Load/store register (immediate post-indexed) // | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 01 | Rn (5) | Rt (5) | static bool isLoadStoreImmediatePost(uint32_t Instr) { return (Instr & 0x3b200c00) == 0x38000400; } // Load/store register (unprivileged) // | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 10 | Rn (5) | Rt (5) | static bool isLoadStoreUnpriv(uint32_t Instr) { return (Instr & 0x3b200c00) == 0x38000800; } // Load/store register (immediate pre-indexed) // | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 11 | Rn (5) | Rt (5) | static bool isLoadStoreImmediatePre(uint32_t Instr) { return (Instr & 0x3b200c00) == 0x38000c00; } // Load/store register (register offset) // | size (2) 11 | 1 V 00 | opc (2) 1 | Rm (5) | option (3) S | 10 | Rn | Rt | static bool isLoadStoreRegisterOff(uint32_t Instr) { return (Instr & 0x3b200c00) == 0x38200800; } // Load/store register (unsigned immediate) // | size (2) 11 | 1 V 01 | opc (2) | imm12 | Rn (5) | Rt (5) | static bool isLoadStoreRegisterUnsigned(uint32_t Instr) { return (Instr & 0x3b000000) == 0x39000000; } // Rt is always in bit position 0 - 4. static uint32_t getRt(uint32_t Instr) { return (Instr & 0x1f); } // Rn is always in bit position 5 - 9. static uint32_t getRn(uint32_t Instr) { return (Instr >> 5) & 0x1f; } // C4.1.2 Branches, Exception Generating and System instructions // | op0 (3) 1 | 01 op1 (4) | x (22) | // op0 == 010 101 op1 == 0xxx Conditional Branch. // op0 == 110 101 op1 == 1xxx Unconditional Branch Register. // op0 == x00 101 op1 == xxxx Unconditional Branch immediate. // op0 == x01 101 op1 == 0xxx Compare and branch immediate. // op0 == x01 101 op1 == 1xxx Test and branch immediate. static bool isBranch(uint32_t Instr) { return ((Instr & 0xfe000000) == 0xd6000000) || // Cond branch. ((Instr & 0xfe000000) == 0x54000000) || // Uncond branch reg. ((Instr & 0x7c000000) == 0x14000000) || // Uncond branch imm. ((Instr & 0x7c000000) == 0x34000000); // Compare and test branch. } static bool isV8SingleRegisterNonStructureLoadStore(uint32_t Instr) { return isLoadStoreUnscaled(Instr) || isLoadStoreImmediatePost(Instr) || isLoadStoreUnpriv(Instr) || isLoadStoreImmediatePre(Instr) || isLoadStoreRegisterOff(Instr) || isLoadStoreRegisterUnsigned(Instr); } // Note that this function refers to v8.0 only and does not include the // additional load and store instructions added for in later revisions of // the architecture such as the Atomic memory operations introduced // in v8.1. static bool isV8NonStructureLoad(uint32_t Instr) { if (isLoadExclusive(Instr)) return true; if (isLoadLiteral(Instr)) return true; else if (isV8SingleRegisterNonStructureLoadStore(Instr)) { // For Load and Store single register, Loads are derived from a // combination of the Size, V and Opc fields. uint32_t Size = (Instr >> 30) & 0xff; uint32_t V = (Instr >> 26) & 0x1; uint32_t Opc = (Instr >> 22) & 0x3; // For the load and store instructions that we are decoding. // Opc == 0 are all stores. // Opc == 1 with a couple of exceptions are loads. The exceptions are: // Size == 00 (0), V == 1, Opc == 10 (2) which is a store and // Size == 11 (3), V == 0, Opc == 10 (2) which is a prefetch. return Opc != 0 && !(Size == 0 && V == 1 && Opc == 2) && !(Size == 3 && V == 0 && Opc == 2); } return false; } // The following decode instructions are only complete up to the instructions // needed for errata 843419. // Instruction with writeback updates the index register after the load/store. static bool hasWriteback(uint32_t Instr) { return isLoadStoreImmediatePre(Instr) || isLoadStoreImmediatePost(Instr) || isSTPPre(Instr) || isSTPPost(Instr) || isST1SinglePost(Instr) || isST1MultiplePost(Instr); } // For the load and store class of instructions, a load can write to the // destination register, a load and a store can write to the base register when // the instruction has writeback. static bool doesLoadStoreWriteToReg(uint32_t Instr, uint32_t Reg) { return (isV8NonStructureLoad(Instr) && getRt(Instr) == Reg) || (hasWriteback(Instr) && getRn(Instr) == Reg); } // Scanner for Cortex-A53 errata 843419 // Full details are available in the Cortex A53 MPCore revision 0 Software // Developers Errata Notice (ARM-EPM-048406). // // The instruction sequence that triggers the erratum is common in compiled // AArch64 code, however it is sensitive to the offset of the sequence within // a 4k page. This means that by scanning and fixing the patch after we have // assigned addresses we only need to disassemble and fix instances of the // sequence in the range of affected offsets. // // In summary the erratum conditions are a series of 4 instructions: // 1.) An ADRP instruction that writes to register Rn with low 12 bits of // address of instruction either 0xff8 or 0xffc. // 2.) A load or store instruction that can be: // - A single register load or store, of either integer or vector registers. // - An STP or STNP, of either integer or vector registers. // - An Advanced SIMD ST1 store instruction. // - Must not write to Rn, but may optionally read from it. // 3.) An optional instruction that is not a branch and does not write to Rn. // 4.) A load or store from the Load/store register (unsigned immediate) class // that uses Rn as the base address register. // // Note that we do not attempt to scan for Sequence 2 as described in the // Software Developers Errata Notice as this has been assessed to be extremely // unlikely to occur in compiled code. This matches gold and ld.bfd behavior. // Return true if the Instruction sequence Adrp, Instr2, and Instr4 match // the erratum sequence. The Adrp, Instr2 and Instr4 correspond to 1.), 2.), // and 4.) in the Scanner for Cortex-A53 errata comment above. static bool is843419ErratumSequence(uint32_t Instr1, uint32_t Instr2, uint32_t Instr4) { if (!isADRP(Instr1)) return false; uint32_t Rn = getRt(Instr1); return isLoadStoreClass(Instr2) && (isLoadStoreExclusive(Instr2) || isLoadLiteral(Instr2) || isV8SingleRegisterNonStructureLoadStore(Instr2) || isSTP(Instr2) || isSTNP(Instr2) || isST1(Instr2)) && !doesLoadStoreWriteToReg(Instr2, Rn) && isLoadStoreRegisterUnsigned(Instr4) && getRn(Instr4) == Rn; } // Scan the instruction sequence starting at Offset Off from the base of // InputSection IS. We update Off in this function rather than in the caller as // we can skip ahead much further into the section when we know how many // instructions we've scanned. // Return the offset of the load or store instruction in IS that we want to // patch or 0 if no patch required. static uint64_t scanCortexA53Errata843419(InputSection *IS, uint64_t &Off, uint64_t Limit) { - uint64_t ISAddr = IS->getParent()->Addr + IS->OutSecOff; + uint64_t ISAddr = IS->getVA(0); // Advance Off so that (ISAddr + Off) modulo 0x1000 is at least 0xff8. uint64_t InitialPageOff = (ISAddr + Off) & 0xfff; if (InitialPageOff < 0xff8) Off += 0xff8 - InitialPageOff; bool OptionalAllowed = Limit - Off > 12; if (Off >= Limit || Limit - Off < 12) { // Need at least 3 4-byte sized instructions to trigger erratum. Off = Limit; return 0; } uint64_t PatchOff = 0; const uint8_t *Buf = IS->Data.begin(); const ulittle32_t *InstBuf = reinterpret_cast(Buf + Off); uint32_t Instr1 = *InstBuf++; uint32_t Instr2 = *InstBuf++; uint32_t Instr3 = *InstBuf++; if (is843419ErratumSequence(Instr1, Instr2, Instr3)) { PatchOff = Off + 8; } else if (OptionalAllowed && !isBranch(Instr3)) { uint32_t Instr4 = *InstBuf++; if (is843419ErratumSequence(Instr1, Instr2, Instr4)) PatchOff = Off + 12; } if (((ISAddr + Off) & 0xfff) == 0xff8) Off += 4; else Off += 0xffc; return PatchOff; } class lld::elf::Patch843419Section : public SyntheticSection { public: Patch843419Section(InputSection *P, uint64_t Off); void writeTo(uint8_t *Buf) override; size_t getSize() const override { return 8; } uint64_t getLDSTAddr() const; // The Section we are patching. const InputSection *Patchee; // The offset of the instruction in the Patchee section we are patching. uint64_t PatcheeOffset; // A label for the start of the Patch that we can use as a relocation target. Symbol *PatchSym; }; lld::elf::Patch843419Section::Patch843419Section(InputSection *P, uint64_t Off) : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 4, ".text.patch"), Patchee(P), PatcheeOffset(Off) { this->Parent = P->getParent(); PatchSym = addSyntheticLocal( Saver.save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC, 0, getSize(), *this); addSyntheticLocal(Saver.save("$x"), STT_NOTYPE, 0, 0, *this); } uint64_t lld::elf::Patch843419Section::getLDSTAddr() const { - return Patchee->getParent()->Addr + Patchee->OutSecOff + PatcheeOffset; + return Patchee->getVA(PatcheeOffset); } void lld::elf::Patch843419Section::writeTo(uint8_t *Buf) { // Copy the instruction that we will be replacing with a branch in the // Patchee Section. write32le(Buf, read32le(Patchee->Data.begin() + PatcheeOffset)); // Apply any relocation transferred from the original PatcheeSection. // For a SyntheticSection Buf already has OutSecOff added, but relocateAlloc // also adds OutSecOff so we need to subtract to avoid double counting. this->relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + getSize()); // Return address is the next instruction after the one we have just copied. uint64_t S = getLDSTAddr() + 4; uint64_t P = PatchSym->getVA() + 4; Target->relocateOne(Buf + 4, R_AARCH64_JUMP26, S - P); } void AArch64Err843419Patcher::init() { // The AArch64 ABI permits data in executable sections. We must avoid scanning // this data as if it were instructions to avoid false matches. We use the // mapping symbols in the InputObjects to identify this data, caching the // results in SectionMap so we don't have to recalculate it each pass. // The ABI Section 4.5.4 Mapping symbols; defines local symbols that describe // half open intervals [Symbol Value, Next Symbol Value) of code and data // within sections. If there is no next symbol then the half open interval is // [Symbol Value, End of section). The type, code or data, is determined by // the mapping symbol name, $x for code, $d for data. auto IsCodeMapSymbol = [](const Symbol *B) { return B->getName() == "$x" || B->getName().startswith("$x."); }; auto IsDataMapSymbol = [](const Symbol *B) { return B->getName() == "$d" || B->getName().startswith("$d."); }; // Collect mapping symbols for every executable InputSection. for (InputFile *File : ObjectFiles) { auto *F = cast>(File); for (Symbol *B : F->getLocalSymbols()) { auto *Def = dyn_cast(B); if (!Def) continue; if (!IsCodeMapSymbol(Def) && !IsDataMapSymbol(Def)) continue; if (auto *Sec = dyn_cast(Def->Section)) if (Sec->Flags & SHF_EXECINSTR) SectionMap[Sec].push_back(Def); } } // For each InputSection make sure the mapping symbols are in sorted in // ascending order and free from consecutive runs of mapping symbols with // the same type. For example we must remove the redundant $d.1 from $x.0 // $d.0 $d.1 $x.1. for (auto &KV : SectionMap) { std::vector &MapSyms = KV.second; if (MapSyms.size() <= 1) continue; std::stable_sort( MapSyms.begin(), MapSyms.end(), [](const Defined *A, const Defined *B) { return A->Value < B->Value; }); MapSyms.erase( std::unique(MapSyms.begin(), MapSyms.end(), [=](const Defined *A, const Defined *B) { return (IsCodeMapSymbol(A) && IsCodeMapSymbol(B)) || (IsDataMapSymbol(A) && IsDataMapSymbol(B)); }), MapSyms.end()); } Initialized = true; } // Insert the PatchSections we have created back into the // InputSectionDescription. As inserting patches alters the addresses of // InputSections that follow them, we try and place the patches after all the // executable sections, although we may need to insert them earlier if the // InputSectionDescription is larger than the maximum branch range. void AArch64Err843419Patcher::insertPatches( InputSectionDescription &ISD, std::vector &Patches) { uint64_t ISLimit; uint64_t PrevISLimit = ISD.Sections.front()->OutSecOff; uint64_t PatchUpperBound = PrevISLimit + Target->ThunkSectionSpacing; // Set the OutSecOff of patches to the place where we want to insert them. // We use a similar strategy to Thunk placement. Place patches roughly // every multiple of maximum branch range. auto PatchIt = Patches.begin(); auto PatchEnd = Patches.end(); for (const InputSection *IS : ISD.Sections) { ISLimit = IS->OutSecOff + IS->getSize(); if (ISLimit > PatchUpperBound) { while (PatchIt != PatchEnd) { if ((*PatchIt)->getLDSTAddr() >= PrevISLimit) break; (*PatchIt)->OutSecOff = PrevISLimit; ++PatchIt; } PatchUpperBound = PrevISLimit + Target->ThunkSectionSpacing; } PrevISLimit = ISLimit; } for (; PatchIt != PatchEnd; ++PatchIt) { (*PatchIt)->OutSecOff = ISLimit; } // merge all patch sections. We use the OutSecOff assigned above to // determine the insertion point. This is ok as we only merge into an // InputSectionDescription once per pass, and at the end of the pass // assignAddresses() will recalculate all the OutSecOff values. std::vector Tmp; Tmp.reserve(ISD.Sections.size() + Patches.size()); auto MergeCmp = [](const InputSection *A, const InputSection *B) { if (A->OutSecOff < B->OutSecOff) return true; if (A->OutSecOff == B->OutSecOff && isa(A) && !isa(B)) return true; return false; }; std::merge(ISD.Sections.begin(), ISD.Sections.end(), Patches.begin(), Patches.end(), std::back_inserter(Tmp), MergeCmp); ISD.Sections = std::move(Tmp); } // Given an erratum sequence that starts at address AdrpAddr, with an // instruction that we need to patch at PatcheeOffset from the start of // InputSection IS, create a Patch843419 Section and add it to the // Patches that we need to insert. static void implementPatch(uint64_t AdrpAddr, uint64_t PatcheeOffset, InputSection *IS, std::vector &Patches) { // There may be a relocation at the same offset that we are patching. There // are three cases that we need to consider. // Case 1: R_AARCH64_JUMP26 branch relocation. We have already patched this // instance of the erratum on a previous patch and altered the relocation. We // have nothing more to do. // Case 2: A load/store register (unsigned immediate) class relocation. There // are two of these R_AARCH_LD64_ABS_LO12_NC and R_AARCH_LD64_GOT_LO12_NC and // they are both absolute. We need to add the same relocation to the patch, // and replace the relocation with a R_AARCH_JUMP26 branch relocation. // Case 3: No relocation. We must create a new R_AARCH64_JUMP26 branch // relocation at the offset. auto RelIt = std::find_if( IS->Relocations.begin(), IS->Relocations.end(), [=](const Relocation &R) { return R.Offset == PatcheeOffset; }); if (RelIt != IS->Relocations.end() && RelIt->Type == R_AARCH64_JUMP26) return; - if (Config->Verbose) - message("detected cortex-a53-843419 erratum sequence starting at " + - utohexstr(AdrpAddr) + " in unpatched output."); + log("detected cortex-a53-843419 erratum sequence starting at " + + utohexstr(AdrpAddr) + " in unpatched output."); auto *PS = make(IS, PatcheeOffset); Patches.push_back(PS); auto MakeRelToPatch = [](uint64_t Offset, Symbol *PatchSym) { return Relocation{R_PC, R_AARCH64_JUMP26, Offset, 0, PatchSym}; }; if (RelIt != IS->Relocations.end()) { PS->Relocations.push_back( {RelIt->Expr, RelIt->Type, 0, RelIt->Addend, RelIt->Sym}); *RelIt = MakeRelToPatch(PatcheeOffset, PS->PatchSym); } else IS->Relocations.push_back(MakeRelToPatch(PatcheeOffset, PS->PatchSym)); } // Scan all the instructions in InputSectionDescription, for each instance of // the erratum sequence create a Patch843419Section. We return the list of // Patch843419Sections that need to be applied to ISD. std::vector AArch64Err843419Patcher::patchInputSectionDescription( InputSectionDescription &ISD) { std::vector Patches; for (InputSection *IS : ISD.Sections) { // LLD doesn't use the erratum sequence in SyntheticSections. if (isa(IS)) continue; // Use SectionMap to make sure we only scan code and not inline data. // We have already sorted MapSyms in ascending order and removed consecutive // mapping symbols of the same type. Our range of executable instructions to // scan is therefore [CodeSym->Value, DataSym->Value) or [CodeSym->Value, // section size). std::vector &MapSyms = SectionMap[IS]; auto CodeSym = llvm::find_if(MapSyms, [&](const Defined *MS) { return MS->getName().startswith("$x"); }); while (CodeSym != MapSyms.end()) { auto DataSym = std::next(CodeSym); uint64_t Off = (*CodeSym)->Value; uint64_t Limit = (DataSym == MapSyms.end()) ? IS->Data.size() : (*DataSym)->Value; while (Off < Limit) { - uint64_t StartAddr = IS->getParent()->Addr + IS->OutSecOff + Off; + uint64_t StartAddr = IS->getVA(Off); if (uint64_t PatcheeOffset = scanCortexA53Errata843419(IS, Off, Limit)) implementPatch(StartAddr, PatcheeOffset, IS, Patches); } if (DataSym == MapSyms.end()) break; CodeSym = std::next(DataSym); } } return Patches; } // For each InputSectionDescription make one pass over the executable sections // looking for the erratum sequence; creating a synthetic Patch843419Section // for each instance found. We insert these synthetic patch sections after the // executable code in each InputSectionDescription. // // PreConditions: // The Output and Input Sections have had their final addresses assigned. // // PostConditions: // Returns true if at least one patch was added. The addresses of the // Ouptut and Input Sections may have been changed. // Returns false if no patches were required and no changes were made. bool AArch64Err843419Patcher::createFixes() { if (Initialized == false) init(); bool AddressesChanged = false; for (OutputSection *OS : OutputSections) { if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR)) continue; for (BaseCommand *BC : OS->SectionCommands) if (auto *ISD = dyn_cast(BC)) { std::vector Patches = patchInputSectionDescription(*ISD); if (!Patches.empty()) { insertPatches(*ISD, Patches); AddressesChanged = true; } } } return AddressesChanged; } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.h (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.h (revision 336982) @@ -1,52 +1,51 @@ //===- AArch64ErrataFix.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_AARCH64ERRATAFIX_H #define LLD_ELF_AARCH64ERRATAFIX_H #include "lld/Common/LLVM.h" - #include #include namespace lld { namespace elf { class Defined; class InputSection; struct InputSectionDescription; class OutputSection; class Patch843419Section; class AArch64Err843419Patcher { public: // return true if Patches have been added to the OutputSections. bool createFixes(); private: std::vector patchInputSectionDescription(InputSectionDescription &ISD); void insertPatches(InputSectionDescription &ISD, std::vector &Patches); void init(); // A cache of the mapping symbols defined by the InputSecion sorted in order // of ascending value with redundant symbols removed. These describe // the ranges of code and data in an executable InputSection. std::map> SectionMap; bool Initialized = false; }; } // namespace elf } // namespace lld #endif Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp (revision 336982) @@ -1,426 +1,435 @@ //===- AArch64.cpp --------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" using namespace llvm; using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; // Page(Expr) is the page address of the expression Expr, defined // as (Expr & ~0xFFF). (This applies even if the machine page size // supported by the platform has a different value.) uint64_t elf::getAArch64Page(uint64_t Expr) { return Expr & ~static_cast(0xFFF); } namespace { class AArch64 final : public TargetInfo { public: AArch64(); RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; - bool isPicRel(RelType Type) const override; + RelType getDynRel(RelType Type) const override; void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, uint64_t BranchAddr, const Symbol &S) const override; bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override; bool usesOnlyLowPageBits(RelType Type) const override; void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, RelExpr Expr) const override; void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace AArch64::AArch64() { CopyRel = R_AARCH64_COPY; RelativeRel = R_AARCH64_RELATIVE; IRelativeRel = R_AARCH64_IRELATIVE; GotRel = R_AARCH64_GLOB_DAT; PltRel = R_AARCH64_JUMP_SLOT; TlsDescRel = R_AARCH64_TLSDESC; TlsGotRel = R_AARCH64_TLS_TPREL64; GotEntrySize = 8; GotPltEntrySize = 8; PltEntrySize = 16; PltHeaderSize = 32; DefaultMaxPageSize = 65536; // It doesn't seem to be documented anywhere, but tls on aarch64 uses variant // 1 of the tls structures and the tcb size is 16. TcbSize = 16; NeedsThunks = true; // See comment in Arch/ARM.cpp for a more detailed explanation of // ThunkSectionSpacing. For AArch64 the only branches we are permitted to // Thunk have a range of +/- 128 MiB ThunkSectionSpacing = (128 * 1024 * 1024) - 0x30000; } RelExpr AArch64::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { case R_AARCH64_TLSDESC_ADR_PAGE21: return R_TLSDESC_PAGE; case R_AARCH64_TLSDESC_LD64_LO12: case R_AARCH64_TLSDESC_ADD_LO12: return R_TLSDESC; case R_AARCH64_TLSDESC_CALL: return R_TLSDESC_CALL; case R_AARCH64_TLSLE_ADD_TPREL_HI12: case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: + case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: + case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: + case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: + case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: return R_TLS; case R_AARCH64_CALL26: case R_AARCH64_CONDBR19: case R_AARCH64_JUMP26: case R_AARCH64_TSTBR14: return R_PLT_PC; case R_AARCH64_PREL16: case R_AARCH64_PREL32: case R_AARCH64_PREL64: case R_AARCH64_ADR_PREL_LO21: case R_AARCH64_LD_PREL_LO19: return R_PC; case R_AARCH64_ADR_PREL_PG_HI21: return R_PAGE_PC; case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: return R_GOT; case R_AARCH64_ADR_GOT_PAGE: case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: return R_GOT_PAGE_PC; case R_AARCH64_NONE: return R_NONE; default: return R_ABS; } } RelExpr AArch64::adjustRelaxExpr(RelType Type, const uint8_t *Data, RelExpr Expr) const { if (Expr == R_RELAX_TLS_GD_TO_IE) { if (Type == R_AARCH64_TLSDESC_ADR_PAGE21) return R_RELAX_TLS_GD_TO_IE_PAGE_PC; return R_RELAX_TLS_GD_TO_IE_ABS; } return Expr; } bool AArch64::usesOnlyLowPageBits(RelType Type) const { switch (Type) { default: return false; case R_AARCH64_ADD_ABS_LO12_NC: case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_LDST128_ABS_LO12_NC: case R_AARCH64_LDST16_ABS_LO12_NC: case R_AARCH64_LDST32_ABS_LO12_NC: case R_AARCH64_LDST64_ABS_LO12_NC: case R_AARCH64_LDST8_ABS_LO12_NC: case R_AARCH64_TLSDESC_ADD_LO12: case R_AARCH64_TLSDESC_LD64_LO12: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: return true; } } -bool AArch64::isPicRel(RelType Type) const { - return Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64; +RelType AArch64::getDynRel(RelType Type) const { + if (Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64) + return Type; + return R_AARCH64_NONE; } void AArch64::writeGotPlt(uint8_t *Buf, const Symbol &) const { write64le(Buf, InX::Plt->getVA()); } void AArch64::writePltHeader(uint8_t *Buf) const { const uint8_t PltData[] = { 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]! 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2])) 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[2]))] 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[2])) 0x20, 0x02, 0x1f, 0xd6, // br x17 0x1f, 0x20, 0x03, 0xd5, // nop 0x1f, 0x20, 0x03, 0xd5, // nop 0x1f, 0x20, 0x03, 0xd5 // nop }; memcpy(Buf, PltData, sizeof(PltData)); uint64_t Got = InX::GotPlt->getVA(); uint64_t Plt = InX::Plt->getVA(); relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, getAArch64Page(Got + 16) - getAArch64Page(Plt + 4)); relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16); relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16); } void AArch64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Inst[] = { 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n])) 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))] 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[n])) 0x20, 0x02, 0x1f, 0xd6 // br x17 }; memcpy(Buf, Inst, sizeof(Inst)); relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21, getAArch64Page(GotPltEntryAddr) - getAArch64Page(PltEntryAddr)); relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotPltEntryAddr); relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotPltEntryAddr); } bool AArch64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, uint64_t BranchAddr, const Symbol &S) const { // ELF for the ARM 64-bit architecture, section Call and Jump relocations // only permits range extension thunks for R_AARCH64_CALL26 and // R_AARCH64_JUMP26 relocation types. if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26) return false; uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA(); return !inBranchRange(Type, BranchAddr, Dst); } bool AArch64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26) return true; // The AArch64 call and unconditional branch instructions have a range of // +/- 128 MiB. uint64_t Range = 128 * 1024 * 1024; if (Dst > Src) { // Immediate of branch is signed. Range -= 4; return Dst - Src <= Range; } return Src - Dst <= Range; } static void write32AArch64Addr(uint8_t *L, uint64_t Imm) { uint32_t ImmLo = (Imm & 0x3) << 29; uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi); } // Return the bits [Start, End] from Val shifted Start bits. // For instance, getBits(0xF0, 4, 8) returns 0xF. static uint64_t getBits(uint64_t Val, int Start, int End) { uint64_t Mask = ((uint64_t)1 << (End + 1 - Start)) - 1; return (Val >> Start) & Mask; } static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); } // Update the immediate field in a AARCH64 ldr, str, and add instruction. static void or32AArch64Imm(uint8_t *L, uint64_t Imm) { or32le(L, (Imm & 0xFFF) << 10); } void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_AARCH64_ABS16: case R_AARCH64_PREL16: - checkIntUInt<16>(Loc, Val, Type); + checkIntUInt(Loc, Val, 16, Type); write16le(Loc, Val); break; case R_AARCH64_ABS32: case R_AARCH64_PREL32: - checkIntUInt<32>(Loc, Val, Type); + checkIntUInt(Loc, Val, 32, Type); write32le(Loc, Val); break; case R_AARCH64_ABS64: case R_AARCH64_GLOB_DAT: case R_AARCH64_PREL64: write64le(Loc, Val); break; case R_AARCH64_ADD_ABS_LO12_NC: or32AArch64Imm(Loc, Val); break; case R_AARCH64_ADR_GOT_PAGE: case R_AARCH64_ADR_PREL_PG_HI21: case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case R_AARCH64_TLSDESC_ADR_PAGE21: - checkInt<33>(Loc, Val, Type); + checkInt(Loc, Val, 33, Type); write32AArch64Addr(Loc, Val >> 12); break; case R_AARCH64_ADR_PREL_LO21: - checkInt<21>(Loc, Val, Type); + checkInt(Loc, Val, 21, Type); write32AArch64Addr(Loc, Val); break; case R_AARCH64_JUMP26: // Normally we would just write the bits of the immediate field, however // when patching instructions for the cpu errata fix -fix-cortex-a53-843419 // we want to replace a non-branch instruction with a branch immediate // instruction. By writing all the bits of the instruction including the // opcode and the immediate (0 001 | 01 imm26) we can do this // transformation by placing a R_AARCH64_JUMP26 relocation at the offset of // the instruction we want to patch. write32le(Loc, 0x14000000); LLVM_FALLTHROUGH; case R_AARCH64_CALL26: - checkInt<28>(Loc, Val, Type); + checkInt(Loc, Val, 28, Type); or32le(Loc, (Val & 0x0FFFFFFC) >> 2); break; case R_AARCH64_CONDBR19: case R_AARCH64_LD_PREL_LO19: - checkAlignment<4>(Loc, Val, Type); - checkInt<21>(Loc, Val, Type); + checkAlignment(Loc, Val, 4, Type); + checkInt(Loc, Val, 21, Type); or32le(Loc, (Val & 0x1FFFFC) << 3); break; - case R_AARCH64_LD64_GOT_LO12_NC: - case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: - case R_AARCH64_TLSDESC_LD64_LO12: - checkAlignment<8>(Loc, Val, Type); - or32le(Loc, (Val & 0xFF8) << 7); - break; case R_AARCH64_LDST8_ABS_LO12_NC: + case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: or32AArch64Imm(Loc, getBits(Val, 0, 11)); break; case R_AARCH64_LDST16_ABS_LO12_NC: - checkAlignment<2>(Loc, Val, Type); + case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: + checkAlignment(Loc, Val, 2, Type); or32AArch64Imm(Loc, getBits(Val, 1, 11)); break; case R_AARCH64_LDST32_ABS_LO12_NC: - checkAlignment<4>(Loc, Val, Type); + case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: + checkAlignment(Loc, Val, 4, Type); or32AArch64Imm(Loc, getBits(Val, 2, 11)); break; case R_AARCH64_LDST64_ABS_LO12_NC: - checkAlignment<8>(Loc, Val, Type); + case R_AARCH64_LD64_GOT_LO12_NC: + case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: + case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: + case R_AARCH64_TLSDESC_LD64_LO12: + checkAlignment(Loc, Val, 8, Type); or32AArch64Imm(Loc, getBits(Val, 3, 11)); break; case R_AARCH64_LDST128_ABS_LO12_NC: - checkAlignment<16>(Loc, Val, Type); + case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: + checkAlignment(Loc, Val, 16, Type); or32AArch64Imm(Loc, getBits(Val, 4, 11)); break; case R_AARCH64_MOVW_UABS_G0_NC: or32le(Loc, (Val & 0xFFFF) << 5); break; case R_AARCH64_MOVW_UABS_G1_NC: or32le(Loc, (Val & 0xFFFF0000) >> 11); break; case R_AARCH64_MOVW_UABS_G2_NC: or32le(Loc, (Val & 0xFFFF00000000) >> 27); break; case R_AARCH64_MOVW_UABS_G3: or32le(Loc, (Val & 0xFFFF000000000000) >> 43); break; case R_AARCH64_TSTBR14: - checkInt<16>(Loc, Val, Type); + checkInt(Loc, Val, 16, Type); or32le(Loc, (Val & 0xFFFC) << 3); break; case R_AARCH64_TLSLE_ADD_TPREL_HI12: - checkInt<24>(Loc, Val, Type); + checkInt(Loc, Val, 24, Type); or32AArch64Imm(Loc, Val >> 12); break; case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: case R_AARCH64_TLSDESC_ADD_LO12: or32AArch64Imm(Loc, Val); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } void AArch64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { // TLSDESC Global-Dynamic relocation are in the form: // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] // add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12] // .tlsdesccall [R_AARCH64_TLSDESC_CALL] // blr x1 // And it can optimized to: // movz x0, #0x0, lsl #16 // movk x0, #0x10 // nop // nop - checkUInt<32>(Loc, Val, Type); + checkUInt(Loc, Val, 32, Type); switch (Type) { case R_AARCH64_TLSDESC_ADD_LO12: case R_AARCH64_TLSDESC_CALL: write32le(Loc, 0xd503201f); // nop return; case R_AARCH64_TLSDESC_ADR_PAGE21: write32le(Loc, 0xd2a00000 | (((Val >> 16) & 0xffff) << 5)); // movz return; case R_AARCH64_TLSDESC_LD64_LO12: write32le(Loc, 0xf2800000 | ((Val & 0xffff) << 5)); // movk return; default: llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); } } void AArch64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { // TLSDESC Global-Dynamic relocation are in the form: // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] // add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12] // .tlsdesccall [R_AARCH64_TLSDESC_CALL] // blr x1 // And it can optimized to: // adrp x0, :gottprel:v // ldr x0, [x0, :gottprel_lo12:v] // nop // nop switch (Type) { case R_AARCH64_TLSDESC_ADD_LO12: case R_AARCH64_TLSDESC_CALL: write32le(Loc, 0xd503201f); // nop break; case R_AARCH64_TLSDESC_ADR_PAGE21: write32le(Loc, 0x90000000); // adrp relocateOne(Loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, Val); break; case R_AARCH64_TLSDESC_LD64_LO12: write32le(Loc, 0xf9400000); // ldr relocateOne(Loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, Val); break; default: llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); } } void AArch64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { - checkUInt<32>(Loc, Val, Type); + checkUInt(Loc, Val, 32, Type); if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) { // Generate MOVZ. uint32_t RegNo = read32le(Loc) & 0x1f; write32le(Loc, (0xd2a00000 | RegNo) | (((Val >> 16) & 0xffff) << 5)); return; } if (Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) { // Generate MOVK. uint32_t RegNo = read32le(Loc) & 0x1f; write32le(Loc, (0xf2800000 | RegNo) | ((Val & 0xffff) << 5)); return; } llvm_unreachable("invalid relocation for TLS IE to LE relaxation"); } TargetInfo *elf::getAArch64TargetInfo() { static AArch64 Target; return &Target; } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp (revision 336982) @@ -1,102 +1,104 @@ //===- AMDGPU.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "InputFiles.h" #include "Symbols.h" #include "Target.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" using namespace llvm; using namespace llvm::object; using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; namespace { class AMDGPU final : public TargetInfo { public: AMDGPU(); uint32_t calcEFlags() const override; void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; }; } // namespace AMDGPU::AMDGPU() { RelativeRel = R_AMDGPU_RELATIVE64; GotRel = R_AMDGPU_ABS64; GotEntrySize = 8; } static uint32_t getEFlags(InputFile *File) { return cast>(File)->getObj().getHeader()->e_flags; } uint32_t AMDGPU::calcEFlags() const { assert(!ObjectFiles.empty()); uint32_t Ret = getEFlags(ObjectFiles[0]); // Verify that all input files have the same e_flags. for (InputFile *F : makeArrayRef(ObjectFiles).slice(1)) { if (Ret == getEFlags(F)) continue; error("incompatible e_flags: " + toString(F)); return 0; } return Ret; } void AMDGPU::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_AMDGPU_ABS32: case R_AMDGPU_GOTPCREL: case R_AMDGPU_GOTPCREL32_LO: case R_AMDGPU_REL32: case R_AMDGPU_REL32_LO: write32le(Loc, Val); break; case R_AMDGPU_ABS64: + case R_AMDGPU_REL64: write64le(Loc, Val); break; case R_AMDGPU_GOTPCREL32_HI: case R_AMDGPU_REL32_HI: write32le(Loc, Val >> 32); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } RelExpr AMDGPU::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { case R_AMDGPU_ABS32: case R_AMDGPU_ABS64: return R_ABS; case R_AMDGPU_REL32: case R_AMDGPU_REL32_LO: case R_AMDGPU_REL32_HI: + case R_AMDGPU_REL64: return R_PC; case R_AMDGPU_GOTPCREL: case R_AMDGPU_GOTPCREL32_LO: case R_AMDGPU_GOTPCREL32_HI: return R_GOT_PC; default: return R_INVALID; } } TargetInfo *elf::getAMDGPUTargetInfo() { static AMDGPU Target; return &Target; } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp (revision 336982) @@ -1,583 +1,575 @@ //===- ARM.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" using namespace llvm; using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; namespace { class ARM final : public TargetInfo { public: ARM(); uint32_t calcEFlags() const override; RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; - bool isPicRel(RelType Type) const override; RelType getDynRel(RelType Type) const override; int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; void writeIgotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void addPltSymbols(InputSection &IS, uint64_t Off) const override; void addPltHeaderSymbols(InputSection &ISD) const override; bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, uint64_t BranchAddr, const Symbol &S) const override; bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override; void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace ARM::ARM() { CopyRel = R_ARM_COPY; RelativeRel = R_ARM_RELATIVE; IRelativeRel = R_ARM_IRELATIVE; GotRel = R_ARM_GLOB_DAT; PltRel = R_ARM_JUMP_SLOT; TlsGotRel = R_ARM_TLS_TPOFF32; TlsModuleIndexRel = R_ARM_TLS_DTPMOD32; TlsOffsetRel = R_ARM_TLS_DTPOFF32; + GotBaseSymInGotPlt = false; GotEntrySize = 4; GotPltEntrySize = 4; PltEntrySize = 16; PltHeaderSize = 32; TrapInstr = 0xd4d4d4d4; // ARM uses Variant 1 TLS TcbSize = 8; NeedsThunks = true; // The placing of pre-created ThunkSections is controlled by the // ThunkSectionSpacing parameter. The aim is to place the // ThunkSection such that all branches from the InputSections prior to the // ThunkSection can reach a Thunk placed at the end of the ThunkSection. // Graphically: // | up to ThunkSectionSpacing .text input sections | // | ThunkSection | // | up to ThunkSectionSpacing .text input sections | // | ThunkSection | // Pre-created ThunkSections are spaced roughly 16MiB apart on ARM. This is to // match the most common expected case of a Thumb 2 encoded BL, BLX or B.W // ARM B, BL, BLX range +/- 32MiB // Thumb B.W, BL, BLX range +/- 16MiB // Thumb B.W range +/- 1MiB // If a branch cannot reach a pre-created ThunkSection a new one will be // created so we can handle the rare cases of a Thumb 2 conditional branch. // We intentionally use a lower size for ThunkSectionSpacing than the maximum // branch range so the end of the ThunkSection is more likely to be within // range of the branch instruction that is furthest away. The value we shorten // ThunkSectionSpacing by is set conservatively to allow us to create 16,384 // 12 byte Thunks at any offset in a ThunkSection without risk of a branch to // one of the Thunks going out of range. // FIXME: lld assumes that the Thumb BL and BLX encoding permits the J1 and // J2 bits to be used to extend the branch range. On earlier Architectures // such as ARMv4, ARMv5 and ARMv6 (except ARMv6T2) the range is +/- 4MiB. If // support for the earlier encodings is added then when they are used the // ThunkSectionSpacing will need lowering. ThunkSectionSpacing = 0x1000000 - 0x30000; } uint32_t ARM::calcEFlags() const { // We don't currently use any features incompatible with EF_ARM_EABI_VER5, // but we don't have any firm guarantees of conformance. Linux AArch64 // kernels (as of 2016) require an EABI version to be set. return EF_ARM_EABI_VER5; } RelExpr ARM::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { case R_ARM_THM_JUMP11: return R_PC; case R_ARM_CALL: case R_ARM_JUMP24: case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_PREL31: case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP24: case R_ARM_THM_CALL: return R_PLT_PC; case R_ARM_GOTOFF32: // (S + A) - GOT_ORG return R_GOTREL; case R_ARM_GOT_BREL: // GOT(S) + A - GOT_ORG return R_GOT_OFF; case R_ARM_GOT_PREL: case R_ARM_TLS_IE32: // GOT(S) + A - P return R_GOT_PC; case R_ARM_SBREL32: return R_ARM_SBREL; case R_ARM_TARGET1: return Config->Target1Rel ? R_PC : R_ABS; case R_ARM_TARGET2: if (Config->Target2 == Target2Policy::Rel) return R_PC; if (Config->Target2 == Target2Policy::Abs) return R_ABS; return R_GOT_PC; case R_ARM_TLS_GD32: return R_TLSGD_PC; case R_ARM_TLS_LDM32: return R_TLSLD_PC; case R_ARM_BASE_PREL: // B(S) + A - P // FIXME: currently B(S) assumed to be .got, this may not hold for all // platforms. return R_GOTONLY_PC; case R_ARM_MOVW_PREL_NC: case R_ARM_MOVT_PREL: case R_ARM_REL32: case R_ARM_THM_MOVW_PREL_NC: case R_ARM_THM_MOVT_PREL: return R_PC; case R_ARM_NONE: return R_NONE; case R_ARM_TLS_LE32: return R_TLS; default: return R_ABS; } } -bool ARM::isPicRel(RelType Type) const { - return (Type == R_ARM_TARGET1 && !Config->Target1Rel) || - (Type == R_ARM_ABS32); -} - RelType ARM::getDynRel(RelType Type) const { - if (Type == R_ARM_TARGET1 && !Config->Target1Rel) + if ((Type == R_ARM_ABS32) || (Type == R_ARM_TARGET1 && !Config->Target1Rel)) return R_ARM_ABS32; - if (Type == R_ARM_ABS32) - return Type; - // Keep it going with a dummy value so that we can find more reloc errors. - return R_ARM_ABS32; + return R_ARM_NONE; } void ARM::writeGotPlt(uint8_t *Buf, const Symbol &) const { write32le(Buf, InX::Plt->getVA()); } void ARM::writeIgotPlt(uint8_t *Buf, const Symbol &S) const { // An ARM entry is the address of the ifunc resolver function. write32le(Buf, S.getVA()); } // Long form PLT Header that does not have any restrictions on the displacement // of the .plt from the .plt.got. static void writePltHeaderLong(uint8_t *Buf) { const uint8_t PltData[] = { 0x04, 0xe0, 0x2d, 0xe5, // str lr, [sp,#-4]! 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, L2 0x0e, 0xe0, 0x8f, 0xe0, // L1: add lr, pc, lr 0x08, 0xf0, 0xbe, 0xe5, // ldr pc, [lr, #8] 0x00, 0x00, 0x00, 0x00, // L2: .word &(.got.plt) - L1 - 8 0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary 0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary 0xd4, 0xd4, 0xd4, 0xd4}; memcpy(Buf, PltData, sizeof(PltData)); uint64_t GotPlt = InX::GotPlt->getVA(); uint64_t L1 = InX::Plt->getVA() + 8; write32le(Buf + 16, GotPlt - L1 - 8); } // The default PLT header requires the .plt.got to be within 128 Mb of the // .plt in the positive direction. void ARM::writePltHeader(uint8_t *Buf) const { // Use a similar sequence to that in writePlt(), the difference is the calling // conventions mean we use lr instead of ip. The PLT entry is responsible for // saving lr on the stack, the dynamic loader is responsible for reloading // it. const uint32_t PltData[] = { 0xe52de004, // L1: str lr, [sp,#-4]! 0xe28fe600, // add lr, pc, #0x0NN00000 &(.got.plt - L1 - 4) 0xe28eea00, // add lr, lr, #0x000NN000 &(.got.plt - L1 - 4) 0xe5bef000, // ldr pc, [lr, #0x00000NNN] &(.got.plt -L1 - 4) }; uint64_t Offset = InX::GotPlt->getVA() - InX::Plt->getVA() - 4; if (!llvm::isUInt<27>(Offset)) { // We cannot encode the Offset, use the long form. writePltHeaderLong(Buf); return; } write32le(Buf + 0, PltData[0]); write32le(Buf + 4, PltData[1] | ((Offset >> 20) & 0xff)); write32le(Buf + 8, PltData[2] | ((Offset >> 12) & 0xff)); write32le(Buf + 12, PltData[3] | (Offset & 0xfff)); write32le(Buf + 16, TrapInstr); // Pad to 32-byte boundary write32le(Buf + 20, TrapInstr); write32le(Buf + 24, TrapInstr); write32le(Buf + 28, TrapInstr); } void ARM::addPltHeaderSymbols(InputSection &IS) const { addSyntheticLocal("$a", STT_NOTYPE, 0, 0, IS); addSyntheticLocal("$d", STT_NOTYPE, 16, 0, IS); } // Long form PLT entries that do not have any restrictions on the displacement // of the .plt from the .plt.got. static void writePltLong(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) { const uint8_t PltData[] = { 0x04, 0xc0, 0x9f, 0xe5, // ldr ip, L2 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc 0x00, 0xf0, 0x9c, 0xe5, // ldr pc, [ip] 0x00, 0x00, 0x00, 0x00, // L2: .word Offset(&(.plt.got) - L1 - 8 }; memcpy(Buf, PltData, sizeof(PltData)); uint64_t L1 = PltEntryAddr + 4; write32le(Buf + 12, GotPltEntryAddr - L1 - 8); } // The default PLT entries require the .plt.got to be within 128 Mb of the // .plt in the positive direction. void ARM::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { // The PLT entry is similar to the example given in Appendix A of ELF for // the Arm Architecture. Instead of using the Group Relocations to find the // optimal rotation for the 8-bit immediate used in the add instructions we // hard code the most compact rotations for simplicity. This saves a load // instruction over the long plt sequences. const uint32_t PltData[] = { 0xe28fc600, // L1: add ip, pc, #0x0NN00000 Offset(&(.plt.got) - L1 - 8 0xe28cca00, // add ip, ip, #0x000NN000 Offset(&(.plt.got) - L1 - 8 0xe5bcf000, // ldr pc, [ip, #0x00000NNN] Offset(&(.plt.got) - L1 - 8 }; uint64_t Offset = GotPltEntryAddr - PltEntryAddr - 8; if (!llvm::isUInt<27>(Offset)) { // We cannot encode the Offset, use the long form. writePltLong(Buf, GotPltEntryAddr, PltEntryAddr, Index, RelOff); return; } write32le(Buf + 0, PltData[0] | ((Offset >> 20) & 0xff)); write32le(Buf + 4, PltData[1] | ((Offset >> 12) & 0xff)); write32le(Buf + 8, PltData[2] | (Offset & 0xfff)); write32le(Buf + 12, TrapInstr); // Pad to 16-byte boundary } void ARM::addPltSymbols(InputSection &IS, uint64_t Off) const { addSyntheticLocal("$a", STT_NOTYPE, Off, 0, IS); addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS); } bool ARM::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, uint64_t BranchAddr, const Symbol &S) const { // If S is an undefined weak symbol and does not have a PLT entry then it // will be resolved as a branch to the next instruction. if (S.isUndefWeak() && !S.isInPlt()) return false; // A state change from ARM to Thumb and vice versa must go through an // interworking thunk if the relocation type is not R_ARM_CALL or // R_ARM_THM_CALL. switch (Type) { case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_JUMP24: // Source is ARM, all PLT entries are ARM so no interworking required. // Otherwise we need to interwork if Symbol has bit 0 set (Thumb). if (Expr == R_PC && ((S.getVA() & 1) == 1)) return true; LLVM_FALLTHROUGH; case R_ARM_CALL: { uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA(); return !inBranchRange(Type, BranchAddr, Dst); } case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP24: // Source is Thumb, all PLT entries are ARM so interworking is required. // Otherwise we need to interwork if Symbol has bit 0 clear (ARM). if (Expr == R_PLT_PC || ((S.getVA() & 1) == 0)) return true; LLVM_FALLTHROUGH; case R_ARM_THM_CALL: { uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA(); return !inBranchRange(Type, BranchAddr, Dst); } } return false; } bool ARM::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { uint64_t Range; uint64_t InstrSize; switch (Type) { case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_JUMP24: case R_ARM_CALL: Range = 0x2000000; InstrSize = 4; break; case R_ARM_THM_JUMP19: Range = 0x100000; InstrSize = 2; break; case R_ARM_THM_JUMP24: case R_ARM_THM_CALL: Range = 0x1000000; InstrSize = 2; break; default: return true; } // PC at Src is 2 instructions ahead, immediate of branch is signed if (Src > Dst) Range -= 2 * InstrSize; else Range += InstrSize; if ((Dst & 0x1) == 0) // Destination is ARM, if ARM caller then Src is already 4-byte aligned. // If Thumb Caller (BLX) the Src address has bottom 2 bits cleared to ensure // destination will be 4 byte aligned. Src &= ~0x3; else // Bit 0 == 1 denotes Thumb state, it is not part of the range Dst &= ~0x1; uint64_t Distance = (Src > Dst) ? Src - Dst : Dst - Src; return Distance <= Range; } void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_ARM_ABS32: case R_ARM_BASE_PREL: case R_ARM_GLOB_DAT: case R_ARM_GOTOFF32: case R_ARM_GOT_BREL: case R_ARM_GOT_PREL: case R_ARM_REL32: case R_ARM_RELATIVE: case R_ARM_SBREL32: case R_ARM_TARGET1: case R_ARM_TARGET2: case R_ARM_TLS_GD32: case R_ARM_TLS_IE32: case R_ARM_TLS_LDM32: case R_ARM_TLS_LDO32: case R_ARM_TLS_LE32: case R_ARM_TLS_TPOFF32: case R_ARM_TLS_DTPOFF32: write32le(Loc, Val); break; case R_ARM_TLS_DTPMOD32: write32le(Loc, 1); break; case R_ARM_PREL31: - checkInt<31>(Loc, Val, Type); + checkInt(Loc, Val, 31, Type); write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000)); break; case R_ARM_CALL: // R_ARM_CALL is used for BL and BLX instructions, depending on the // value of bit 0 of Val, we must select a BL or BLX instruction if (Val & 1) { // If bit 0 of Val is 1 the target is Thumb, we must select a BLX. // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1' - checkInt<26>(Loc, Val, Type); + checkInt(Loc, Val, 26, Type); write32le(Loc, 0xfa000000 | // opcode ((Val & 2) << 23) | // H ((Val >> 2) & 0x00ffffff)); // imm24 break; } if ((read32le(Loc) & 0xfe000000) == 0xfa000000) // BLX (always unconditional) instruction to an ARM Target, select an // unconditional BL. write32le(Loc, 0xeb000000 | (read32le(Loc) & 0x00ffffff)); // fall through as BL encoding is shared with B LLVM_FALLTHROUGH; case R_ARM_JUMP24: case R_ARM_PC24: case R_ARM_PLT32: - checkInt<26>(Loc, Val, Type); + checkInt(Loc, Val, 26, Type); write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff)); break; case R_ARM_THM_JUMP11: - checkInt<12>(Loc, Val, Type); + checkInt(Loc, Val, 12, Type); write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff)); break; case R_ARM_THM_JUMP19: // Encoding T3: Val = S:J2:J1:imm6:imm11:0 - checkInt<21>(Loc, Val, Type); + checkInt(Loc, Val, 21, Type); write16le(Loc, (read16le(Loc) & 0xfbc0) | // opcode cond ((Val >> 10) & 0x0400) | // S ((Val >> 12) & 0x003f)); // imm6 write16le(Loc + 2, 0x8000 | // opcode ((Val >> 8) & 0x0800) | // J2 ((Val >> 5) & 0x2000) | // J1 ((Val >> 1) & 0x07ff)); // imm11 break; case R_ARM_THM_CALL: // R_ARM_THM_CALL is used for BL and BLX instructions, depending on the // value of bit 0 of Val, we must select a BL or BLX instruction if ((Val & 1) == 0) { // Ensure BLX destination is 4-byte aligned. As BLX instruction may // only be two byte aligned. This must be done before overflow check Val = alignTo(Val, 4); } // Bit 12 is 0 for BLX, 1 for BL write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12); // Fall through as rest of encoding is the same as B.W LLVM_FALLTHROUGH; case R_ARM_THM_JUMP24: // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0 // FIXME: Use of I1 and I2 require v6T2ops - checkInt<25>(Loc, Val, Type); + checkInt(Loc, Val, 25, Type); write16le(Loc, 0xf000 | // opcode ((Val >> 14) & 0x0400) | // S ((Val >> 12) & 0x03ff)); // imm10 write16le(Loc + 2, (read16le(Loc + 2) & 0xd000) | // opcode (((~(Val >> 10)) ^ (Val >> 11)) & 0x2000) | // J1 (((~(Val >> 11)) ^ (Val >> 13)) & 0x0800) | // J2 ((Val >> 1) & 0x07ff)); // imm11 break; case R_ARM_MOVW_ABS_NC: case R_ARM_MOVW_PREL_NC: write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) | (Val & 0x0fff)); break; case R_ARM_MOVT_ABS: case R_ARM_MOVT_PREL: - checkInt<32>(Loc, Val, Type); + checkInt(Loc, Val, 32, Type); write32le(Loc, (read32le(Loc) & ~0x000f0fff) | (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff)); break; case R_ARM_THM_MOVT_ABS: case R_ARM_THM_MOVT_PREL: // Encoding T1: A = imm4:i:imm3:imm8 - checkInt<32>(Loc, Val, Type); + checkInt(Loc, Val, 32, Type); write16le(Loc, 0xf2c0 | // opcode ((Val >> 17) & 0x0400) | // i ((Val >> 28) & 0x000f)); // imm4 write16le(Loc + 2, (read16le(Loc + 2) & 0x8f00) | // opcode ((Val >> 12) & 0x7000) | // imm3 ((Val >> 16) & 0x00ff)); // imm8 break; case R_ARM_THM_MOVW_ABS_NC: case R_ARM_THM_MOVW_PREL_NC: // Encoding T3: A = imm4:i:imm3:imm8 write16le(Loc, 0xf240 | // opcode ((Val >> 1) & 0x0400) | // i ((Val >> 12) & 0x000f)); // imm4 write16le(Loc + 2, (read16le(Loc + 2) & 0x8f00) | // opcode ((Val << 4) & 0x7000) | // imm3 (Val & 0x00ff)); // imm8 break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } int64_t ARM::getImplicitAddend(const uint8_t *Buf, RelType Type) const { switch (Type) { default: return 0; case R_ARM_ABS32: case R_ARM_BASE_PREL: case R_ARM_GOTOFF32: case R_ARM_GOT_BREL: case R_ARM_GOT_PREL: case R_ARM_REL32: case R_ARM_TARGET1: case R_ARM_TARGET2: case R_ARM_TLS_GD32: case R_ARM_TLS_LDM32: case R_ARM_TLS_LDO32: case R_ARM_TLS_IE32: case R_ARM_TLS_LE32: return SignExtend64<32>(read32le(Buf)); case R_ARM_PREL31: return SignExtend64<31>(read32le(Buf)); case R_ARM_CALL: case R_ARM_JUMP24: case R_ARM_PC24: case R_ARM_PLT32: return SignExtend64<26>(read32le(Buf) << 2); case R_ARM_THM_JUMP11: return SignExtend64<12>(read16le(Buf) << 1); case R_ARM_THM_JUMP19: { // Encoding T3: A = S:J2:J1:imm10:imm6:0 uint16_t Hi = read16le(Buf); uint16_t Lo = read16le(Buf + 2); return SignExtend64<20>(((Hi & 0x0400) << 10) | // S ((Lo & 0x0800) << 8) | // J2 ((Lo & 0x2000) << 5) | // J1 ((Hi & 0x003f) << 12) | // imm6 ((Lo & 0x07ff) << 1)); // imm11:0 } case R_ARM_THM_CALL: case R_ARM_THM_JUMP24: { // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0 // I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S) // FIXME: I1 and I2 require v6T2ops uint16_t Hi = read16le(Buf); uint16_t Lo = read16le(Buf + 2); return SignExtend64<24>(((Hi & 0x0400) << 14) | // S (~((Lo ^ (Hi << 3)) << 10) & 0x00800000) | // I1 (~((Lo ^ (Hi << 1)) << 11) & 0x00400000) | // I2 ((Hi & 0x003ff) << 12) | // imm0 ((Lo & 0x007ff) << 1)); // imm11:0 } // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and // MOVT is in the range -32768 <= A < 32768 case R_ARM_MOVW_ABS_NC: case R_ARM_MOVT_ABS: case R_ARM_MOVW_PREL_NC: case R_ARM_MOVT_PREL: { uint64_t Val = read32le(Buf) & 0x000f0fff; return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff)); } case R_ARM_THM_MOVW_ABS_NC: case R_ARM_THM_MOVT_ABS: case R_ARM_THM_MOVW_PREL_NC: case R_ARM_THM_MOVT_PREL: { // Encoding T3: A = imm4:i:imm3:imm8 uint16_t Hi = read16le(Buf); uint16_t Lo = read16le(Buf + 2); return SignExtend64<16>(((Hi & 0x000f) << 12) | // imm4 ((Hi & 0x0400) << 1) | // i ((Lo & 0x7000) >> 4) | // imm3 (Lo & 0x00ff)); // imm8 } } } TargetInfo *elf::getARMTargetInfo() { static ARM Target; return &Target; } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/AVR.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/AVR.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/AVR.cpp (revision 336982) Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/AVR.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/Hexagon.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/Hexagon.cpp (nonexistent) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/Hexagon.cpp (revision 336982) @@ -0,0 +1,97 @@ +//===-- Hexagon.cpp -------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "InputFiles.h" +#include "Symbols.h" +#include "Target.h" +#include "lld/Common/ErrorHandler.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support::endian; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +namespace { +class Hexagon final : public TargetInfo { +public: + uint32_t calcEFlags() const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; +}; +} // namespace + +// Support V60 only at the moment. +uint32_t Hexagon::calcEFlags() const { return 0x60; } + +static uint32_t applyMask(uint32_t Mask, uint32_t Data) { + uint32_t Result = 0; + size_t Off = 0; + + for (size_t Bit = 0; Bit != 32; ++Bit) { + uint32_t ValBit = (Data >> Off) & 1; + uint32_t MaskBit = (Mask >> Bit) & 1; + if (MaskBit) { + Result |= (ValBit << Bit); + ++Off; + } + } + return Result; +} + +RelExpr Hexagon::getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const { + switch (Type) { + case R_HEX_B15_PCREL: + case R_HEX_B15_PCREL_X: + case R_HEX_B22_PCREL: + case R_HEX_B22_PCREL_X: + case R_HEX_B32_PCREL_X: + return R_PC; + default: + return R_ABS; + } +} + +static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); } + +void Hexagon::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { + case R_HEX_NONE: + break; + case R_HEX_B15_PCREL: + or32le(Loc, applyMask(0x00df20fe, Val >> 2)); + break; + case R_HEX_B15_PCREL_X: + or32le(Loc, applyMask(0x00df20fe, Val & 0x3f)); + break; + case R_HEX_B22_PCREL: + or32le(Loc, applyMask(0x1ff3ffe, Val >> 2)); + break; + case R_HEX_B22_PCREL_X: + or32le(Loc, applyMask(0x1ff3ffe, Val & 0x3f)); + break; + case R_HEX_B32_PCREL_X: + or32le(Loc, applyMask(0x0fff3fff, Val >> 6)); + break; + default: + error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type)); + break; + } +} + +TargetInfo *elf::getHexagonTargetInfo() { + static Hexagon Target; + return &Target; +} Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/Hexagon.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp (revision 336982) @@ -1,686 +1,673 @@ //===- MIPS.cpp -----------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "InputFiles.h" #include "OutputSections.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" using namespace llvm; using namespace llvm::object; using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; namespace { template class MIPS final : public TargetInfo { public: MIPS(); uint32_t calcEFlags() const override; RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; - bool isPicRel(RelType Type) const override; RelType getDynRel(RelType Type) const override; void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, uint64_t BranchAddr, const Symbol &S) const override; void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; bool usesOnlyLowPageBits(RelType Type) const override; }; } // namespace template MIPS::MIPS() { GotPltHeaderEntriesNum = 2; DefaultMaxPageSize = 65536; GotEntrySize = sizeof(typename ELFT::uint); GotPltEntrySize = sizeof(typename ELFT::uint); + GotBaseSymInGotPlt = false; PltEntrySize = 16; PltHeaderSize = 32; CopyRel = R_MIPS_COPY; PltRel = R_MIPS_JUMP_SLOT; NeedsThunks = true; TrapInstr = 0xefefefef; if (ELFT::Is64Bits) { RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32; TlsGotRel = R_MIPS_TLS_TPREL64; TlsModuleIndexRel = R_MIPS_TLS_DTPMOD64; TlsOffsetRel = R_MIPS_TLS_DTPREL64; } else { RelativeRel = R_MIPS_REL32; TlsGotRel = R_MIPS_TLS_TPREL32; TlsModuleIndexRel = R_MIPS_TLS_DTPMOD32; TlsOffsetRel = R_MIPS_TLS_DTPREL32; } } template uint32_t MIPS::calcEFlags() const { return calcMipsEFlags(); } template RelExpr MIPS::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { // See comment in the calculateMipsRelChain. if (ELFT::Is64Bits || Config->MipsN32Abi) Type &= 0xff; switch (Type) { case R_MIPS_JALR: case R_MICROMIPS_JALR: return R_HINT; case R_MIPS_GPREL16: case R_MIPS_GPREL32: case R_MICROMIPS_GPREL16: case R_MICROMIPS_GPREL7_S2: return R_MIPS_GOTREL; case R_MIPS_26: case R_MICROMIPS_26_S1: return R_PLT; case R_MICROMIPS_PC26_S1: return R_PLT_PC; case R_MIPS_HI16: case R_MIPS_LO16: case R_MIPS_HIGHER: case R_MIPS_HIGHEST: case R_MICROMIPS_HI16: case R_MICROMIPS_LO16: - case R_MICROMIPS_HIGHER: - case R_MICROMIPS_HIGHEST: // R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate // offset between start of function and 'gp' value which by default // equal to the start of .got section. In that case we consider these // relocations as relative. if (&S == ElfSym::MipsGpDisp) return R_MIPS_GOT_GP_PC; if (&S == ElfSym::MipsLocalGp) return R_MIPS_GOT_GP; LLVM_FALLTHROUGH; case R_MIPS_32: case R_MIPS_64: case R_MIPS_GOT_OFST: case R_MIPS_SUB: case R_MIPS_TLS_DTPREL_HI16: case R_MIPS_TLS_DTPREL_LO16: case R_MIPS_TLS_DTPREL32: case R_MIPS_TLS_DTPREL64: case R_MIPS_TLS_TPREL_HI16: case R_MIPS_TLS_TPREL_LO16: case R_MIPS_TLS_TPREL32: case R_MIPS_TLS_TPREL64: - case R_MICROMIPS_GOT_OFST: - case R_MICROMIPS_SUB: case R_MICROMIPS_TLS_DTPREL_HI16: case R_MICROMIPS_TLS_DTPREL_LO16: case R_MICROMIPS_TLS_TPREL_HI16: case R_MICROMIPS_TLS_TPREL_LO16: return R_ABS; case R_MIPS_PC32: case R_MIPS_PC16: case R_MIPS_PC19_S2: case R_MIPS_PC21_S2: case R_MIPS_PC26_S2: case R_MIPS_PCHI16: case R_MIPS_PCLO16: case R_MICROMIPS_PC7_S1: case R_MICROMIPS_PC10_S1: case R_MICROMIPS_PC16_S1: case R_MICROMIPS_PC18_S3: case R_MICROMIPS_PC19_S2: case R_MICROMIPS_PC23_S2: case R_MICROMIPS_PC21_S1: return R_PC; case R_MIPS_GOT16: case R_MICROMIPS_GOT16: if (S.isLocal()) return R_MIPS_GOT_LOCAL_PAGE; LLVM_FALLTHROUGH; case R_MIPS_CALL16: case R_MIPS_GOT_DISP: case R_MIPS_TLS_GOTTPREL: case R_MICROMIPS_CALL16: - case R_MICROMIPS_GOT_DISP: case R_MICROMIPS_TLS_GOTTPREL: return R_MIPS_GOT_OFF; case R_MIPS_CALL_HI16: case R_MIPS_CALL_LO16: case R_MIPS_GOT_HI16: case R_MIPS_GOT_LO16: case R_MICROMIPS_CALL_HI16: case R_MICROMIPS_CALL_LO16: case R_MICROMIPS_GOT_HI16: case R_MICROMIPS_GOT_LO16: return R_MIPS_GOT_OFF32; case R_MIPS_GOT_PAGE: - case R_MICROMIPS_GOT_PAGE: return R_MIPS_GOT_LOCAL_PAGE; case R_MIPS_TLS_GD: case R_MICROMIPS_TLS_GD: return R_MIPS_TLSGD; case R_MIPS_TLS_LDM: case R_MICROMIPS_TLS_LDM: return R_MIPS_TLSLD; case R_MIPS_NONE: return R_NONE; default: return R_INVALID; } } -template bool MIPS::isPicRel(RelType Type) const { - return Type == R_MIPS_32 || Type == R_MIPS_64; -} - template RelType MIPS::getDynRel(RelType Type) const { - return RelativeRel; + if (Type == R_MIPS_32 || Type == R_MIPS_64) + return RelativeRel; + return R_MIPS_NONE; } template void MIPS::writeGotPlt(uint8_t *Buf, const Symbol &) const { uint64_t VA = InX::Plt->getVA(); if (isMicroMips()) VA |= 1; write32(Buf, VA); } template static uint32_t readShuffle(const uint8_t *Loc) { // The major opcode of a microMIPS instruction needs to appear // in the first 16-bit word (lowest address) for efficient hardware // decode so that it knows if the instruction is 16-bit or 32-bit // as early as possible. To do so, little-endian binaries keep 16-bit // words in a big-endian order. That is why we have to swap these // words to get a correct value. uint32_t V = read32(Loc); if (E == support::little) return (V << 16) | (V >> 16); return V; } template -static void writeRelocation(uint8_t *Loc, uint64_t V, uint8_t BitsSize, - uint8_t Shift) { +static void writeValue(uint8_t *Loc, uint64_t V, uint8_t BitsSize, + uint8_t Shift) { uint32_t Instr = read32(Loc); uint32_t Mask = 0xffffffff >> (32 - BitsSize); uint32_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask); write32(Loc, Data); } template -static void writeMicroRelocation32(uint8_t *Loc, uint64_t V, uint8_t BitsSize, - uint8_t Shift) { +static void writeShuffleValue(uint8_t *Loc, uint64_t V, uint8_t BitsSize, + uint8_t Shift) { // See comments in readShuffle for purpose of this code. uint16_t *Words = (uint16_t *)Loc; if (E == support::little) std::swap(Words[0], Words[1]); - writeRelocation(Loc, V, BitsSize, Shift); + writeValue(Loc, V, BitsSize, Shift); if (E == support::little) std::swap(Words[0], Words[1]); } template static void writeMicroRelocation16(uint8_t *Loc, uint64_t V, uint8_t BitsSize, uint8_t Shift) { uint16_t Instr = read16(Loc); uint16_t Mask = 0xffff >> (16 - BitsSize); uint16_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask); write16(Loc, Data); } template void MIPS::writePltHeader(uint8_t *Buf) const { const endianness E = ELFT::TargetEndianness; if (isMicroMips()) { uint64_t GotPlt = InX::GotPlt->getVA(); uint64_t Plt = InX::Plt->getVA(); // Overwrite trap instructions written by Writer::writeTrapInstr. memset(Buf, 0, PltHeaderSize); write16(Buf, isMipsR6() ? 0x7860 : 0x7980); // addiupc v1, (GOTPLT) - . write16(Buf + 4, 0xff23); // lw $25, 0($3) write16(Buf + 8, 0x0535); // subu16 $2, $2, $3 write16(Buf + 10, 0x2525); // srl16 $2, $2, 2 write16(Buf + 12, 0x3302); // addiu $24, $2, -2 write16(Buf + 14, 0xfffe); write16(Buf + 16, 0x0dff); // move $15, $31 if (isMipsR6()) { write16(Buf + 18, 0x0f83); // move $28, $3 write16(Buf + 20, 0x472b); // jalrc $25 write16(Buf + 22, 0x0c00); // nop relocateOne(Buf, R_MICROMIPS_PC19_S2, GotPlt - Plt); } else { write16(Buf + 18, 0x45f9); // jalrc $25 write16(Buf + 20, 0x0f83); // move $28, $3 write16(Buf + 22, 0x0c00); // nop relocateOne(Buf, R_MICROMIPS_PC23_S2, GotPlt - Plt); } return; } if (Config->MipsN32Abi) { write32(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0]) write32(Buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14) write32(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0]) write32(Buf + 12, 0x030ec023); // subu $24, $24, $14 write32(Buf + 16, 0x03e07825); // move $15, $31 write32(Buf + 20, 0x0018c082); // srl $24, $24, 2 } else if (ELFT::Is64Bits) { write32(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0]) write32(Buf + 4, 0xddd90000); // ld $25, %lo(&GOTPLT[0])($14) write32(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0]) write32(Buf + 12, 0x030ec023); // subu $24, $24, $14 write32(Buf + 16, 0x03e07825); // move $15, $31 write32(Buf + 20, 0x0018c0c2); // srl $24, $24, 3 } else { write32(Buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0]) write32(Buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28) write32(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0]) write32(Buf + 12, 0x031cc023); // subu $24, $24, $28 write32(Buf + 16, 0x03e07825); // move $15, $31 write32(Buf + 20, 0x0018c082); // srl $24, $24, 2 } uint32_t JalrInst = Config->ZHazardplt ? 0x0320fc09 : 0x0320f809; write32(Buf + 24, JalrInst); // jalr.hb $25 or jalr $25 write32(Buf + 28, 0x2718fffe); // subu $24, $24, 2 uint64_t GotPlt = InX::GotPlt->getVA(); - writeRelocation(Buf, GotPlt + 0x8000, 16, 16); - writeRelocation(Buf + 4, GotPlt, 16, 0); - writeRelocation(Buf + 8, GotPlt, 16, 0); + writeValue(Buf, GotPlt + 0x8000, 16, 16); + writeValue(Buf + 4, GotPlt, 16, 0); + writeValue(Buf + 8, GotPlt, 16, 0); } template void MIPS::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const endianness E = ELFT::TargetEndianness; if (isMicroMips()) { // Overwrite trap instructions written by Writer::writeTrapInstr. memset(Buf, 0, PltEntrySize); if (isMipsR6()) { write16(Buf, 0x7840); // addiupc $2, (GOTPLT) - . write16(Buf + 4, 0xff22); // lw $25, 0($2) write16(Buf + 8, 0x0f02); // move $24, $2 write16(Buf + 10, 0x4723); // jrc $25 / jr16 $25 relocateOne(Buf, R_MICROMIPS_PC19_S2, GotPltEntryAddr - PltEntryAddr); } else { write16(Buf, 0x7900); // addiupc $2, (GOTPLT) - . write16(Buf + 4, 0xff22); // lw $25, 0($2) write16(Buf + 8, 0x4599); // jrc $25 / jr16 $25 write16(Buf + 10, 0x0f02); // move $24, $2 relocateOne(Buf, R_MICROMIPS_PC23_S2, GotPltEntryAddr - PltEntryAddr); } return; } uint32_t JrInst = isMipsR6() ? (Config->ZHazardplt ? 0x03200409 : 0x03200009) : (Config->ZHazardplt ? 0x03200408 : 0x03200008); write32(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry) write32(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15) write32(Buf + 8, JrInst); // jr $25 / jr.hb $25 write32(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry) - writeRelocation(Buf, GotPltEntryAddr + 0x8000, 16, 16); - writeRelocation(Buf + 4, GotPltEntryAddr, 16, 0); - writeRelocation(Buf + 12, GotPltEntryAddr, 16, 0); + writeValue(Buf, GotPltEntryAddr + 0x8000, 16, 16); + writeValue(Buf + 4, GotPltEntryAddr, 16, 0); + writeValue(Buf + 12, GotPltEntryAddr, 16, 0); } template bool MIPS::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, uint64_t BranchAddr, const Symbol &S) const { // Any MIPS PIC code function is invoked with its address in register $t9. // So if we have a branch instruction from non-PIC code to the PIC one // we cannot make the jump directly and need to create a small stubs // to save the target function address. // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf if (Type != R_MIPS_26 && Type != R_MICROMIPS_26_S1 && Type != R_MICROMIPS_PC26_S1) return false; auto *F = dyn_cast_or_null>(File); if (!F) return false; // If current file has PIC code, LA25 stub is not required. if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC) return false; auto *D = dyn_cast(&S); // LA25 is required if target file has PIC code // or target symbol is a PIC symbol. return D && isMipsPIC(D); } template int64_t MIPS::getImplicitAddend(const uint8_t *Buf, RelType Type) const { const endianness E = ELFT::TargetEndianness; switch (Type) { case R_MIPS_32: case R_MIPS_GPREL32: case R_MIPS_TLS_DTPREL32: case R_MIPS_TLS_TPREL32: return SignExtend64<32>(read32(Buf)); case R_MIPS_26: // FIXME (simon): If the relocation target symbol is not a PLT entry // we should use another expression for calculation: // ((A << 2) | (P & 0xf0000000)) >> 2 return SignExtend64<28>(read32(Buf) << 2); case R_MIPS_GOT16: case R_MIPS_HI16: case R_MIPS_PCHI16: return SignExtend64<16>(read32(Buf)) << 16; case R_MIPS_GPREL16: case R_MIPS_LO16: case R_MIPS_PCLO16: case R_MIPS_TLS_DTPREL_HI16: case R_MIPS_TLS_DTPREL_LO16: case R_MIPS_TLS_TPREL_HI16: case R_MIPS_TLS_TPREL_LO16: return SignExtend64<16>(read32(Buf)); case R_MICROMIPS_GOT16: case R_MICROMIPS_HI16: return SignExtend64<16>(readShuffle(Buf)) << 16; case R_MICROMIPS_GPREL16: case R_MICROMIPS_LO16: case R_MICROMIPS_TLS_DTPREL_HI16: case R_MICROMIPS_TLS_DTPREL_LO16: case R_MICROMIPS_TLS_TPREL_HI16: case R_MICROMIPS_TLS_TPREL_LO16: return SignExtend64<16>(readShuffle(Buf)); case R_MICROMIPS_GPREL7_S2: return SignExtend64<9>(readShuffle(Buf) << 2); case R_MIPS_PC16: return SignExtend64<18>(read32(Buf) << 2); case R_MIPS_PC19_S2: return SignExtend64<21>(read32(Buf) << 2); case R_MIPS_PC21_S2: return SignExtend64<23>(read32(Buf) << 2); case R_MIPS_PC26_S2: return SignExtend64<28>(read32(Buf) << 2); case R_MIPS_PC32: return SignExtend64<32>(read32(Buf)); case R_MICROMIPS_26_S1: return SignExtend64<27>(readShuffle(Buf) << 1); case R_MICROMIPS_PC7_S1: return SignExtend64<8>(read16(Buf) << 1); case R_MICROMIPS_PC10_S1: return SignExtend64<11>(read16(Buf) << 1); case R_MICROMIPS_PC16_S1: return SignExtend64<17>(readShuffle(Buf) << 1); case R_MICROMIPS_PC18_S3: return SignExtend64<21>(readShuffle(Buf) << 3); case R_MICROMIPS_PC19_S2: return SignExtend64<21>(readShuffle(Buf) << 2); case R_MICROMIPS_PC21_S1: return SignExtend64<22>(readShuffle(Buf) << 1); case R_MICROMIPS_PC23_S2: return SignExtend64<25>(readShuffle(Buf) << 2); case R_MICROMIPS_PC26_S1: return SignExtend64<27>(readShuffle(Buf) << 1); default: return 0; } } static std::pair calculateMipsRelChain(uint8_t *Loc, RelType Type, uint64_t Val) { // MIPS N64 ABI packs multiple relocations into the single relocation // record. In general, all up to three relocations can have arbitrary // types. In fact, Clang and GCC uses only a few combinations. For now, // we support two of them. That is allow to pass at least all LLVM // test suite cases. // / R_MIPS_SUB / R_MIPS_HI16 | R_MIPS_LO16 // / R_MIPS_64 / R_MIPS_NONE // The first relocation is a 'real' relocation which is calculated // using the corresponding symbol's value. The second and the third // relocations used to modify result of the first one: extend it to // 64-bit, extract high or low part etc. For details, see part 2.9 Relocation // at the https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf RelType Type2 = (Type >> 8) & 0xff; RelType Type3 = (Type >> 16) & 0xff; if (Type2 == R_MIPS_NONE && Type3 == R_MIPS_NONE) return std::make_pair(Type, Val); if (Type2 == R_MIPS_64 && Type3 == R_MIPS_NONE) return std::make_pair(Type2, Val); if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16)) return std::make_pair(Type3, -Val); - if (Type2 == R_MICROMIPS_SUB && - (Type3 == R_MICROMIPS_HI16 || Type3 == R_MICROMIPS_LO16)) - return std::make_pair(Type3, -Val); error(getErrorLocation(Loc) + "unsupported relocations combination " + Twine(Type)); return std::make_pair(Type & 0xff, Val); } template void MIPS::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { const endianness E = ELFT::TargetEndianness; + if (ELFT::Is64Bits || Config->MipsN32Abi) + std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val); + // Thread pointer and DRP offsets from the start of TLS data area. // https://www.linux-mips.org/wiki/NPTL if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16 || Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64 || Type == R_MICROMIPS_TLS_DTPREL_HI16 || Type == R_MICROMIPS_TLS_DTPREL_LO16) { Val -= 0x8000; } else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16 || Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64 || Type == R_MICROMIPS_TLS_TPREL_HI16 || Type == R_MICROMIPS_TLS_TPREL_LO16) { Val -= 0x7000; } - if (ELFT::Is64Bits || Config->MipsN32Abi) - std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val); - switch (Type) { case R_MIPS_32: case R_MIPS_GPREL32: case R_MIPS_TLS_DTPREL32: case R_MIPS_TLS_TPREL32: write32(Loc, Val); break; case R_MIPS_64: case R_MIPS_TLS_DTPREL64: case R_MIPS_TLS_TPREL64: write64(Loc, Val); break; case R_MIPS_26: - writeRelocation(Loc, Val, 26, 2); + writeValue(Loc, Val, 26, 2); break; case R_MIPS_GOT16: // The R_MIPS_GOT16 relocation's value in "relocatable" linking mode // is updated addend (not a GOT index). In that case write high 16 bits // to store a correct addend value. if (Config->Relocatable) { - writeRelocation(Loc, Val + 0x8000, 16, 16); + writeValue(Loc, Val + 0x8000, 16, 16); } else { - checkInt<16>(Loc, Val, Type); - writeRelocation(Loc, Val, 16, 0); + checkInt(Loc, Val, 16, Type); + writeValue(Loc, Val, 16, 0); } break; case R_MICROMIPS_GOT16: if (Config->Relocatable) { - writeMicroRelocation32(Loc, Val + 0x8000, 16, 16); + writeShuffleValue(Loc, Val + 0x8000, 16, 16); } else { - checkInt<16>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 16, 0); + checkInt(Loc, Val, 16, Type); + writeShuffleValue(Loc, Val, 16, 0); } break; case R_MIPS_CALL16: case R_MIPS_GOT_DISP: case R_MIPS_GOT_PAGE: case R_MIPS_GPREL16: case R_MIPS_TLS_GD: case R_MIPS_TLS_GOTTPREL: case R_MIPS_TLS_LDM: - checkInt<16>(Loc, Val, Type); + checkInt(Loc, Val, 16, Type); LLVM_FALLTHROUGH; case R_MIPS_CALL_LO16: case R_MIPS_GOT_LO16: case R_MIPS_GOT_OFST: case R_MIPS_LO16: case R_MIPS_PCLO16: case R_MIPS_TLS_DTPREL_LO16: case R_MIPS_TLS_TPREL_LO16: - writeRelocation(Loc, Val, 16, 0); + writeValue(Loc, Val, 16, 0); break; - case R_MICROMIPS_GOT_DISP: - case R_MICROMIPS_GOT_PAGE: case R_MICROMIPS_GPREL16: case R_MICROMIPS_TLS_GD: case R_MICROMIPS_TLS_LDM: - checkInt<16>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 16, 0); + checkInt(Loc, Val, 16, Type); + writeShuffleValue(Loc, Val, 16, 0); break; case R_MICROMIPS_CALL16: case R_MICROMIPS_CALL_LO16: - case R_MICROMIPS_GOT_OFST: case R_MICROMIPS_LO16: case R_MICROMIPS_TLS_DTPREL_LO16: case R_MICROMIPS_TLS_GOTTPREL: case R_MICROMIPS_TLS_TPREL_LO16: - writeMicroRelocation32(Loc, Val, 16, 0); + writeShuffleValue(Loc, Val, 16, 0); break; case R_MICROMIPS_GPREL7_S2: - checkInt<7>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 7, 2); + checkInt(Loc, Val, 7, Type); + writeShuffleValue(Loc, Val, 7, 2); break; case R_MIPS_CALL_HI16: case R_MIPS_GOT_HI16: case R_MIPS_HI16: case R_MIPS_PCHI16: case R_MIPS_TLS_DTPREL_HI16: case R_MIPS_TLS_TPREL_HI16: - writeRelocation(Loc, Val + 0x8000, 16, 16); + writeValue(Loc, Val + 0x8000, 16, 16); break; case R_MICROMIPS_CALL_HI16: case R_MICROMIPS_GOT_HI16: case R_MICROMIPS_HI16: case R_MICROMIPS_TLS_DTPREL_HI16: case R_MICROMIPS_TLS_TPREL_HI16: - writeMicroRelocation32(Loc, Val + 0x8000, 16, 16); + writeShuffleValue(Loc, Val + 0x8000, 16, 16); break; case R_MIPS_HIGHER: - writeRelocation(Loc, Val + 0x80008000, 16, 32); + writeValue(Loc, Val + 0x80008000, 16, 32); break; case R_MIPS_HIGHEST: - writeRelocation(Loc, Val + 0x800080008000, 16, 48); + writeValue(Loc, Val + 0x800080008000, 16, 48); break; - case R_MICROMIPS_HIGHER: - writeMicroRelocation32(Loc, Val + 0x80008000, 16, 32); - break; - case R_MICROMIPS_HIGHEST: - writeMicroRelocation32(Loc, Val + 0x800080008000, 16, 48); - break; case R_MIPS_JALR: case R_MICROMIPS_JALR: // Ignore this optimization relocation for now break; case R_MIPS_PC16: - checkAlignment<4>(Loc, Val, Type); - checkInt<18>(Loc, Val, Type); - writeRelocation(Loc, Val, 16, 2); + checkAlignment(Loc, Val, 4, Type); + checkInt(Loc, Val, 18, Type); + writeValue(Loc, Val, 16, 2); break; case R_MIPS_PC19_S2: - checkAlignment<4>(Loc, Val, Type); - checkInt<21>(Loc, Val, Type); - writeRelocation(Loc, Val, 19, 2); + checkAlignment(Loc, Val, 4, Type); + checkInt(Loc, Val, 21, Type); + writeValue(Loc, Val, 19, 2); break; case R_MIPS_PC21_S2: - checkAlignment<4>(Loc, Val, Type); - checkInt<23>(Loc, Val, Type); - writeRelocation(Loc, Val, 21, 2); + checkAlignment(Loc, Val, 4, Type); + checkInt(Loc, Val, 23, Type); + writeValue(Loc, Val, 21, 2); break; case R_MIPS_PC26_S2: - checkAlignment<4>(Loc, Val, Type); - checkInt<28>(Loc, Val, Type); - writeRelocation(Loc, Val, 26, 2); + checkAlignment(Loc, Val, 4, Type); + checkInt(Loc, Val, 28, Type); + writeValue(Loc, Val, 26, 2); break; case R_MIPS_PC32: - writeRelocation(Loc, Val, 32, 0); + writeValue(Loc, Val, 32, 0); break; case R_MICROMIPS_26_S1: case R_MICROMIPS_PC26_S1: - checkInt<27>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 26, 1); + checkInt(Loc, Val, 27, Type); + writeShuffleValue(Loc, Val, 26, 1); break; case R_MICROMIPS_PC7_S1: - checkInt<8>(Loc, Val, Type); + checkInt(Loc, Val, 8, Type); writeMicroRelocation16(Loc, Val, 7, 1); break; case R_MICROMIPS_PC10_S1: - checkInt<11>(Loc, Val, Type); + checkInt(Loc, Val, 11, Type); writeMicroRelocation16(Loc, Val, 10, 1); break; case R_MICROMIPS_PC16_S1: - checkInt<17>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 16, 1); + checkInt(Loc, Val, 17, Type); + writeShuffleValue(Loc, Val, 16, 1); break; case R_MICROMIPS_PC18_S3: - checkInt<21>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 18, 3); + checkInt(Loc, Val, 21, Type); + writeShuffleValue(Loc, Val, 18, 3); break; case R_MICROMIPS_PC19_S2: - checkInt<21>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 19, 2); + checkInt(Loc, Val, 21, Type); + writeShuffleValue(Loc, Val, 19, 2); break; case R_MICROMIPS_PC21_S1: - checkInt<22>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 21, 1); + checkInt(Loc, Val, 22, Type); + writeShuffleValue(Loc, Val, 21, 1); break; case R_MICROMIPS_PC23_S2: - checkInt<25>(Loc, Val, Type); - writeMicroRelocation32(Loc, Val, 23, 2); + checkInt(Loc, Val, 25, Type); + writeShuffleValue(Loc, Val, 23, 2); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } template bool MIPS::usesOnlyLowPageBits(RelType Type) const { return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST || - Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_GOT_OFST; + Type == R_MICROMIPS_LO16; } // Return true if the symbol is a PIC function. template bool elf::isMipsPIC(const Defined *Sym) { - typedef typename ELFT::Ehdr Elf_Ehdr; - if (!Sym->Section || !Sym->isFunc()) + if (!Sym->isFunc()) return false; - auto *Sec = cast(Sym->Section); - const Elf_Ehdr *Hdr = Sec->template getFile()->getObj().getHeader(); - return (Sym->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC || - (Hdr->e_flags & EF_MIPS_PIC); + if (Sym->StOther & STO_MIPS_PIC) + return true; + + if (!Sym->Section) + return false; + + ObjFile *File = + cast(Sym->Section)->template getFile(); + if (!File) + return false; + + return File->getObj().getHeader()->e_flags & EF_MIPS_PIC; } template TargetInfo *elf::getMipsTargetInfo() { static MIPS Target; return &Target; } template TargetInfo *elf::getMipsTargetInfo(); template TargetInfo *elf::getMipsTargetInfo(); template TargetInfo *elf::getMipsTargetInfo(); template TargetInfo *elf::getMipsTargetInfo(); template bool elf::isMipsPIC(const Defined *); template bool elf::isMipsPIC(const Defined *); template bool elf::isMipsPIC(const Defined *); template bool elf::isMipsPIC(const Defined *); Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp (revision 336982) @@ -1,383 +1,390 @@ //===- MipsArchTree.cpp --------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===---------------------------------------------------------------------===// // // This file contains a helper function for the Writer. // //===---------------------------------------------------------------------===// #include "InputFiles.h" #include "SymbolTable.h" #include "Writer.h" #include "lld/Common/ErrorHandler.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELF.h" #include "llvm/Support/MipsABIFlags.h" using namespace llvm; using namespace llvm::object; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; namespace { struct ArchTreeEdge { uint32_t Child; uint32_t Parent; }; struct FileFlags { InputFile *File; uint32_t Flags; }; } // namespace static StringRef getAbiName(uint32_t Flags) { switch (Flags) { case 0: return "n64"; case EF_MIPS_ABI2: return "n32"; case EF_MIPS_ABI_O32: return "o32"; case EF_MIPS_ABI_O64: return "o64"; case EF_MIPS_ABI_EABI32: return "eabi32"; case EF_MIPS_ABI_EABI64: return "eabi64"; default: return "unknown"; } } static StringRef getNanName(bool IsNan2008) { return IsNan2008 ? "2008" : "legacy"; } static StringRef getFpName(bool IsFp64) { return IsFp64 ? "64" : "32"; } static void checkFlags(ArrayRef Files) { + assert(!Files.empty() && "expected non-empty file list"); + uint32_t ABI = Files[0].Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); bool Nan = Files[0].Flags & EF_MIPS_NAN2008; bool Fp = Files[0].Flags & EF_MIPS_FP64; - for (const FileFlags &F : Files.slice(1)) { + for (const FileFlags &F : Files) { + if (Config->Is64 && F.Flags & EF_MIPS_MICROMIPS) + error(toString(F.File) + ": microMIPS 64-bit is not supported"); + uint32_t ABI2 = F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); if (ABI != ABI2) - error("target ABI '" + getAbiName(ABI) + "' is incompatible with '" + - getAbiName(ABI2) + "': " + toString(F.File)); + error(toString(F.File) + ": ABI '" + getAbiName(ABI2) + + "' is incompatible with target ABI '" + getAbiName(ABI) + "'"); bool Nan2 = F.Flags & EF_MIPS_NAN2008; if (Nan != Nan2) - error("target -mnan=" + getNanName(Nan) + " is incompatible with -mnan=" + - getNanName(Nan2) + ": " + toString(F.File)); + error(toString(F.File) + ": -mnan=" + getNanName(Nan2) + + " is incompatible with target -mnan=" + getNanName(Nan)); bool Fp2 = F.Flags & EF_MIPS_FP64; if (Fp != Fp2) - error("target -mfp" + getFpName(Fp) + " is incompatible with -mfp" + - getFpName(Fp2) + ": " + toString(F.File)); + error(toString(F.File) + ": -mfp" + getFpName(Fp2) + + " is incompatible with target -mfp" + getFpName(Fp)); } } static uint32_t getMiscFlags(ArrayRef Files) { uint32_t Ret = 0; for (const FileFlags &F : Files) Ret |= F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2 | EF_MIPS_ARCH_ASE | EF_MIPS_NOREORDER | EF_MIPS_MICROMIPS | EF_MIPS_NAN2008 | EF_MIPS_32BITMODE); return Ret; } static uint32_t getPicFlags(ArrayRef Files) { // Check PIC/non-PIC compatibility. bool IsPic = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); for (const FileFlags &F : Files.slice(1)) { bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); if (IsPic && !IsPic2) - warn("linking abicalls code " + toString(Files[0].File) + - " with non-abicalls file: " + toString(F.File)); + warn(toString(F.File) + + ": linking non-abicalls code with abicalls code " + + toString(Files[0].File)); if (!IsPic && IsPic2) - warn("linking non-abicalls code " + toString(Files[0].File) + - " with abicalls file: " + toString(F.File)); + warn(toString(F.File) + + ": linking abicalls code with non-abicalls code " + + toString(Files[0].File)); } // Compute the result PIC/non-PIC flag. uint32_t Ret = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); for (const FileFlags &F : Files.slice(1)) Ret &= F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); // PIC code is inherently CPIC and may not set CPIC flag explicitly. if (Ret & EF_MIPS_PIC) Ret |= EF_MIPS_CPIC; return Ret; } static ArchTreeEdge ArchTree[] = { // MIPS32R6 and MIPS64R6 are not compatible with other extensions // MIPS64R2 extensions. {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, EF_MIPS_ARCH_64R2}, {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, EF_MIPS_ARCH_64R2}, {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, EF_MIPS_ARCH_64R2}, {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, EF_MIPS_ARCH_64R2}, // MIPS64 extensions. {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, EF_MIPS_ARCH_64}, {EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, EF_MIPS_ARCH_64}, {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64}, // MIPS V extensions. {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5}, // R5000 extensions. {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400}, // MIPS IV extensions. {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, EF_MIPS_ARCH_4}, {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, EF_MIPS_ARCH_4}, {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4}, // VR4100 extensions. {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, // MIPS III extensions. {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, EF_MIPS_ARCH_3}, {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, EF_MIPS_ARCH_3}, {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, EF_MIPS_ARCH_3}, {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, EF_MIPS_ARCH_3}, {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, EF_MIPS_ARCH_3}, {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, EF_MIPS_ARCH_3}, {EF_MIPS_ARCH_4, EF_MIPS_ARCH_3}, // MIPS32 extensions. {EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32}, // MIPS II extensions. {EF_MIPS_ARCH_3, EF_MIPS_ARCH_2}, {EF_MIPS_ARCH_32, EF_MIPS_ARCH_2}, // MIPS I extensions. {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, EF_MIPS_ARCH_1}, {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1}, }; static bool isArchMatched(uint32_t New, uint32_t Res) { if (New == Res) return true; if (New == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, Res)) return true; if (New == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, Res)) return true; for (const auto &Edge : ArchTree) { if (Res == Edge.Child) { Res = Edge.Parent; if (Res == New) return true; } } return false; } static StringRef getMachName(uint32_t Flags) { switch (Flags & EF_MIPS_MACH) { case EF_MIPS_MACH_NONE: return ""; case EF_MIPS_MACH_3900: return "r3900"; case EF_MIPS_MACH_4010: return "r4010"; case EF_MIPS_MACH_4100: return "r4100"; case EF_MIPS_MACH_4650: return "r4650"; case EF_MIPS_MACH_4120: return "r4120"; case EF_MIPS_MACH_4111: return "r4111"; case EF_MIPS_MACH_5400: return "vr5400"; case EF_MIPS_MACH_5900: return "vr5900"; case EF_MIPS_MACH_5500: return "vr5500"; case EF_MIPS_MACH_9000: return "rm9000"; case EF_MIPS_MACH_LS2E: return "loongson2e"; case EF_MIPS_MACH_LS2F: return "loongson2f"; case EF_MIPS_MACH_LS3A: return "loongson3a"; case EF_MIPS_MACH_OCTEON: return "octeon"; case EF_MIPS_MACH_OCTEON2: return "octeon2"; case EF_MIPS_MACH_OCTEON3: return "octeon3"; case EF_MIPS_MACH_SB1: return "sb1"; case EF_MIPS_MACH_XLR: return "xlr"; default: return "unknown machine"; } } static StringRef getArchName(uint32_t Flags) { switch (Flags & EF_MIPS_ARCH) { case EF_MIPS_ARCH_1: return "mips1"; case EF_MIPS_ARCH_2: return "mips2"; case EF_MIPS_ARCH_3: return "mips3"; case EF_MIPS_ARCH_4: return "mips4"; case EF_MIPS_ARCH_5: return "mips5"; case EF_MIPS_ARCH_32: return "mips32"; case EF_MIPS_ARCH_64: return "mips64"; case EF_MIPS_ARCH_32R2: return "mips32r2"; case EF_MIPS_ARCH_64R2: return "mips64r2"; case EF_MIPS_ARCH_32R6: return "mips32r6"; case EF_MIPS_ARCH_64R6: return "mips64r6"; default: return "unknown arch"; } } static std::string getFullArchName(uint32_t Flags) { StringRef Arch = getArchName(Flags); StringRef Mach = getMachName(Flags); if (Mach.empty()) return Arch.str(); return (Arch + " (" + Mach + ")").str(); } // There are (arguably too) many MIPS ISAs out there. Their relationships // can be represented as a forest. If all input files have ISAs which // reachable by repeated proceeding from the single child to the parent, // these input files are compatible. In that case we need to return "highest" // ISA. If there are incompatible input files, we show an error. // For example, mips1 is a "parent" of mips2 and such files are compatible. // Output file gets EF_MIPS_ARCH_2 flag. From the other side mips3 and mips32 // are incompatible because nor mips3 is a parent for misp32, nor mips32 // is a parent for mips3. static uint32_t getArchFlags(ArrayRef Files) { uint32_t Ret = Files[0].Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); for (const FileFlags &F : Files.slice(1)) { uint32_t New = F.Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); // Check ISA compatibility. if (isArchMatched(New, Ret)) continue; if (!isArchMatched(Ret, New)) { error("incompatible target ISA:\n>>> " + toString(Files[0].File) + ": " + getFullArchName(Ret) + "\n>>> " + toString(F.File) + ": " + getFullArchName(New)); return 0; } Ret = New; } return Ret; } template uint32_t elf::calcMipsEFlags() { std::vector V; for (InputFile *F : ObjectFiles) V.push_back({F, cast>(F)->getObj().getHeader()->e_flags}); if (V.empty()) return 0; checkFlags(V); return getMiscFlags(V) | getPicFlags(V) | getArchFlags(V); } static int compareMipsFpAbi(uint8_t FpA, uint8_t FpB) { if (FpA == FpB) return 0; if (FpB == Mips::Val_GNU_MIPS_ABI_FP_ANY) return 1; if (FpB == Mips::Val_GNU_MIPS_ABI_FP_64A && FpA == Mips::Val_GNU_MIPS_ABI_FP_64) return 1; if (FpB != Mips::Val_GNU_MIPS_ABI_FP_XX) return -1; if (FpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE || FpA == Mips::Val_GNU_MIPS_ABI_FP_64 || FpA == Mips::Val_GNU_MIPS_ABI_FP_64A) return 1; return -1; } static StringRef getMipsFpAbiName(uint8_t FpAbi) { switch (FpAbi) { case Mips::Val_GNU_MIPS_ABI_FP_ANY: return "any"; case Mips::Val_GNU_MIPS_ABI_FP_DOUBLE: return "-mdouble-float"; case Mips::Val_GNU_MIPS_ABI_FP_SINGLE: return "-msingle-float"; case Mips::Val_GNU_MIPS_ABI_FP_SOFT: return "-msoft-float"; case Mips::Val_GNU_MIPS_ABI_FP_OLD_64: - return "-mips32r2 -mfp64 (old)"; + return "-mgp32 -mfp64 (old)"; case Mips::Val_GNU_MIPS_ABI_FP_XX: return "-mfpxx"; case Mips::Val_GNU_MIPS_ABI_FP_64: return "-mgp32 -mfp64"; case Mips::Val_GNU_MIPS_ABI_FP_64A: return "-mgp32 -mfp64 -mno-odd-spreg"; default: return "unknown"; } } uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag, StringRef FileName) { if (compareMipsFpAbi(NewFlag, OldFlag) >= 0) return NewFlag; if (compareMipsFpAbi(OldFlag, NewFlag) < 0) - error("target floating point ABI '" + getMipsFpAbiName(OldFlag) + - "' is incompatible with '" + getMipsFpAbiName(NewFlag) + - "': " + FileName); + error(FileName + ": floating point ABI '" + getMipsFpAbiName(NewFlag) + + "' is incompatible with target floating point ABI '" + + getMipsFpAbiName(OldFlag) + "'"); return OldFlag; } template static bool isN32Abi(const InputFile *F) { if (auto *EF = dyn_cast>(F)) return EF->getObj().getHeader()->e_flags & EF_MIPS_ABI2; return false; } bool elf::isMipsN32Abi(const InputFile *F) { switch (Config->EKind) { case ELF32LEKind: return isN32Abi(F); case ELF32BEKind: return isN32Abi(F); case ELF64LEKind: return isN32Abi(F); case ELF64BEKind: return isN32Abi(F); default: llvm_unreachable("unknown Config->EKind"); } } bool elf::isMicroMips() { return Config->EFlags & EF_MIPS_MICROMIPS; } bool elf::isMipsR6() { uint32_t Arch = Config->EFlags & EF_MIPS_ARCH; return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6; } template uint32_t elf::calcMipsEFlags(); template uint32_t elf::calcMipsEFlags(); template uint32_t elf::calcMipsEFlags(); template uint32_t elf::calcMipsEFlags(); Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp (revision 336982) @@ -1,71 +1,76 @@ //===- PPC.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Symbols.h" #include "Target.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" using namespace llvm; using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; namespace { class PPC final : public TargetInfo { public: - PPC() { GotBaseSymOff = 0x8000; } + PPC(); void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; }; } // namespace + +PPC::PPC() { + GotBaseSymOff = 0x8000; + GotBaseSymInGotPlt = false; +} RelExpr PPC::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { case R_PPC_REL24: case R_PPC_REL32: return R_PC; case R_PPC_PLTREL24: return R_PLT_PC; default: return R_ABS; } } void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_PPC_ADDR16_HA: write16be(Loc, (Val + 0x8000) >> 16); break; case R_PPC_ADDR16_HI: write16be(Loc, Val >> 16); break; case R_PPC_ADDR16_LO: write16be(Loc, Val); break; case R_PPC_ADDR32: case R_PPC_REL32: write32be(Loc, Val); break; case R_PPC_PLTREL24: case R_PPC_REL24: write32be(Loc, read32be(Loc) | (Val & 0x3FFFFFC)); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } TargetInfo *elf::getPPCTargetInfo() { static PPC Target; return &Target; } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp (revision 336982) @@ -1,217 +1,532 @@ //===- PPC64.cpp ----------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" using namespace llvm; +using namespace llvm::object; using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; static uint64_t PPC64TocOffset = 0x8000; +static uint64_t DynamicThreadPointerOffset = 0x8000; uint64_t elf::getPPC64TocBase() { // The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The // TOC starts where the first of these sections starts. We always create a // .got when we see a relocation that uses it, so for us the start is always // the .got. uint64_t TocVA = InX::Got->getVA(); // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 // thus permitting a full 64 Kbytes segment. Note that the glibc startup // code (crt1.o) assumes that you can get from the TOC base to the // start of the .toc section with only a single (signed) 16-bit relocation. return TocVA + PPC64TocOffset; } namespace { class PPC64 final : public TargetInfo { public: PPC64(); + uint32_t calcEFlags() const override; RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; + void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void writeGotHeader(uint8_t *Buf) const override; + bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const override; + RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, + RelExpr Expr) const override; + void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace // Relocation masks following the #lo(value), #hi(value), #ha(value), // #higher(value), #highera(value), #highest(value), and #highesta(value) // macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi // document. -static uint16_t applyPPCLo(uint64_t V) { return V; } -static uint16_t applyPPCHi(uint64_t V) { return V >> 16; } -static uint16_t applyPPCHa(uint64_t V) { return (V + 0x8000) >> 16; } -static uint16_t applyPPCHigher(uint64_t V) { return V >> 32; } -static uint16_t applyPPCHighera(uint64_t V) { return (V + 0x8000) >> 32; } -static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; } -static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; } +static uint16_t lo(uint64_t V) { return V; } +static uint16_t hi(uint64_t V) { return V >> 16; } +static uint16_t ha(uint64_t V) { return (V + 0x8000) >> 16; } +static uint16_t higher(uint64_t V) { return V >> 32; } +static uint16_t highera(uint64_t V) { return (V + 0x8000) >> 32; } +static uint16_t highest(uint64_t V) { return V >> 48; } +static uint16_t highesta(uint64_t V) { return (V + 0x8000) >> 48; } PPC64::PPC64() { - PltRel = GotRel = R_PPC64_GLOB_DAT; + GotRel = R_PPC64_GLOB_DAT; + PltRel = R_PPC64_JMP_SLOT; RelativeRel = R_PPC64_RELATIVE; + IRelativeRel = R_PPC64_IRELATIVE; GotEntrySize = 8; + PltEntrySize = 4; GotPltEntrySize = 8; - PltEntrySize = 32; - PltHeaderSize = 0; + GotBaseSymInGotPlt = false; + GotBaseSymOff = 0x8000; + GotHeaderEntriesNum = 1; + GotPltHeaderEntriesNum = 2; + PltHeaderSize = 60; + NeedsThunks = true; + TcbSize = 8; + TlsTpOffset = 0x7000; + TlsModuleIndexRel = R_PPC64_DTPMOD64; + TlsOffsetRel = R_PPC64_DTPREL64; + + TlsGotRel = R_PPC64_TPREL64; + // We need 64K pages (at least under glibc/Linux, the loader won't // set different permissions on a finer granularity than that). DefaultMaxPageSize = 65536; // The PPC64 ELF ABI v1 spec, says: // // It is normally desirable to put segments with different characteristics // in separate 256 Mbyte portions of the address space, to give the // operating system full paging flexibility in the 64-bit address space. // // And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers // use 0x10000000 as the starting address. DefaultImageBase = 0x10000000; + + TrapInstr = + (Config->IsLE == sys::IsLittleEndianHost) ? 0x7fe00008 : 0x0800e07f; } +static uint32_t getEFlags(InputFile *File) { + if (Config->EKind == ELF64BEKind) + return cast>(File)->getObj().getHeader()->e_flags; + return cast>(File)->getObj().getHeader()->e_flags; +} + +// This file implements v2 ABI. This function makes sure that all +// object files have v2 or an unspecified version as an ABI version. +uint32_t PPC64::calcEFlags() const { + for (InputFile *F : ObjectFiles) { + uint32_t Flag = getEFlags(F); + if (Flag == 1) + error(toString(F) + ": ABI version 1 is not supported"); + else if (Flag > 2) + error(toString(F) + ": unrecognized e_flags: " + Twine(Flag)); + } + return 2; +} + +void PPC64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { + // Reference: 3.7.4.2 of the 64-bit ELF V2 abi supplement. + // The general dynamic code sequence for a global `x` will look like: + // Instruction Relocation Symbol + // addis r3, r2, x@got@tlsgd@ha R_PPC64_GOT_TLSGD16_HA x + // addi r3, r3, x@got@tlsgd@l R_PPC64_GOT_TLSGD16_LO x + // bl __tls_get_addr(x@tlsgd) R_PPC64_TLSGD x + // R_PPC64_REL24 __tls_get_addr + // nop None None + + // Relaxing to local exec entails converting: + // addis r3, r2, x@got@tlsgd@ha into nop + // addi r3, r3, x@got@tlsgd@l into addis r3, r13, x@tprel@ha + // bl __tls_get_addr(x@tlsgd) into nop + // nop into addi r3, r3, x@tprel@l + + uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U; + + switch (Type) { + case R_PPC64_GOT_TLSGD16_HA: + write32(Loc - EndianOffset, 0x60000000); // nop + break; + case R_PPC64_GOT_TLSGD16_LO: + write32(Loc - EndianOffset, 0x3c6d0000); // addis r3, r13 + relocateOne(Loc, R_PPC64_TPREL16_HA, Val); + break; + case R_PPC64_TLSGD: + write32(Loc, 0x60000000); // nop + write32(Loc + 4, 0x38630000); // addi r3, r3 + relocateOne(Loc + 4 + EndianOffset, R_PPC64_TPREL16_LO, Val); + break; + default: + llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); + } +} + + +void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { + // Reference: 3.7.4.3 of the 64-bit ELF V2 abi supplement. + // The local dynamic code sequence for a global `x` will look like: + // Instruction Relocation Symbol + // addis r3, r2, x@got@tlsld@ha R_PPC64_GOT_TLSLD16_HA x + // addi r3, r3, x@got@tlsld@l R_PPC64_GOT_TLSLD16_LO x + // bl __tls_get_addr(x@tlsgd) R_PPC64_TLSLD x + // R_PPC64_REL24 __tls_get_addr + // nop None None + + // Relaxing to local exec entails converting: + // addis r3, r2, x@got@tlsld@ha into nop + // addi r3, r3, x@got@tlsld@l into addis r3, r13, 0 + // bl __tls_get_addr(x@tlsgd) into nop + // nop into addi r3, r3, 4096 + + uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U; + switch (Type) { + case R_PPC64_GOT_TLSLD16_HA: + write32(Loc - EndianOffset, 0x60000000); // nop + break; + case R_PPC64_GOT_TLSLD16_LO: + write32(Loc - EndianOffset, 0x3c6d0000); // addis r3, r13, 0 + break; + case R_PPC64_TLSLD: + write32(Loc, 0x60000000); // nop + write32(Loc + 4, 0x38631000); // addi r3, r3, 4096 + break; + case R_PPC64_DTPREL16: + case R_PPC64_DTPREL16_HA: + case R_PPC64_DTPREL16_HI: + case R_PPC64_DTPREL16_DS: + case R_PPC64_DTPREL16_LO: + case R_PPC64_DTPREL16_LO_DS: + case R_PPC64_GOT_DTPREL16_HA: + case R_PPC64_GOT_DTPREL16_LO_DS: + case R_PPC64_GOT_DTPREL16_DS: + case R_PPC64_GOT_DTPREL16_HI: + relocateOne(Loc, Type, Val); + break; + default: + llvm_unreachable("unsupported relocation for TLS LD to LE relaxation"); + } +} + RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { case R_PPC64_TOC16: case R_PPC64_TOC16_DS: case R_PPC64_TOC16_HA: case R_PPC64_TOC16_HI: case R_PPC64_TOC16_LO: case R_PPC64_TOC16_LO_DS: return R_GOTREL; case R_PPC64_TOC: return R_PPC_TOC; case R_PPC64_REL24: - return R_PPC_PLT_OPD; + return R_PPC_CALL_PLT; + case R_PPC64_REL16_LO: + case R_PPC64_REL16_HA: + case R_PPC64_REL32: + case R_PPC64_REL64: + return R_PC; + case R_PPC64_GOT_TLSGD16: + case R_PPC64_GOT_TLSGD16_HA: + case R_PPC64_GOT_TLSGD16_HI: + case R_PPC64_GOT_TLSGD16_LO: + return R_TLSGD_GOT; + case R_PPC64_GOT_TLSLD16: + case R_PPC64_GOT_TLSLD16_HA: + case R_PPC64_GOT_TLSLD16_HI: + case R_PPC64_GOT_TLSLD16_LO: + return R_TLSLD_GOT; + case R_PPC64_GOT_TPREL16_HA: + case R_PPC64_GOT_TPREL16_LO_DS: + case R_PPC64_GOT_TPREL16_DS: + case R_PPC64_GOT_TPREL16_HI: + return R_GOT_OFF; + case R_PPC64_GOT_DTPREL16_HA: + case R_PPC64_GOT_DTPREL16_LO_DS: + case R_PPC64_GOT_DTPREL16_DS: + case R_PPC64_GOT_DTPREL16_HI: + return R_TLSLD_GOT_OFF; + case R_PPC64_TPREL16: + case R_PPC64_TPREL16_HA: + case R_PPC64_TPREL16_LO: + case R_PPC64_TPREL16_HI: + case R_PPC64_TPREL16_DS: + case R_PPC64_TPREL16_LO_DS: + case R_PPC64_TPREL16_HIGHER: + case R_PPC64_TPREL16_HIGHERA: + case R_PPC64_TPREL16_HIGHEST: + case R_PPC64_TPREL16_HIGHESTA: + return R_TLS; + case R_PPC64_DTPREL16: + case R_PPC64_DTPREL16_DS: + case R_PPC64_DTPREL16_HA: + case R_PPC64_DTPREL16_HI: + case R_PPC64_DTPREL16_HIGHER: + case R_PPC64_DTPREL16_HIGHERA: + case R_PPC64_DTPREL16_HIGHEST: + case R_PPC64_DTPREL16_HIGHESTA: + case R_PPC64_DTPREL16_LO: + case R_PPC64_DTPREL16_LO_DS: + case R_PPC64_DTPREL64: + return R_ABS; + case R_PPC64_TLSGD: + return R_TLSDESC_CALL; + case R_PPC64_TLSLD: + return R_TLSLD_HINT; + case R_PPC64_TLS: + return R_HINT; default: return R_ABS; } } +void PPC64::writeGotHeader(uint8_t *Buf) const { + write64(Buf, getPPC64TocBase()); +} + +void PPC64::writePltHeader(uint8_t *Buf) const { + // The generic resolver stub goes first. + write32(Buf + 0, 0x7c0802a6); // mflr r0 + write32(Buf + 4, 0x429f0005); // bcl 20,4*cr7+so,8 <_glink+0x8> + write32(Buf + 8, 0x7d6802a6); // mflr r11 + write32(Buf + 12, 0x7c0803a6); // mtlr r0 + write32(Buf + 16, 0x7d8b6050); // subf r12, r11, r12 + write32(Buf + 20, 0x380cffcc); // subi r0,r12,52 + write32(Buf + 24, 0x7800f082); // srdi r0,r0,62,2 + write32(Buf + 28, 0xe98b002c); // ld r12,44(r11) + write32(Buf + 32, 0x7d6c5a14); // add r11,r12,r11 + write32(Buf + 36, 0xe98b0000); // ld r12,0(r11) + write32(Buf + 40, 0xe96b0008); // ld r11,8(r11) + write32(Buf + 44, 0x7d8903a6); // mtctr r12 + write32(Buf + 48, 0x4e800420); // bctr + + // The 'bcl' instruction will set the link register to the address of the + // following instruction ('mflr r11'). Here we store the offset from that + // instruction to the first entry in the GotPlt section. + int64_t GotPltOffset = InX::GotPlt->getVA() - (InX::Plt->getVA() + 8); + write64(Buf + 52, GotPltOffset); +} + void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { - uint64_t Off = GotPltEntryAddr - getPPC64TocBase(); - - // FIXME: What we should do, in theory, is get the offset of the function - // descriptor in the .opd section, and use that as the offset from %r2 (the - // TOC-base pointer). Instead, we have the GOT-entry offset, and that will - // be a pointer to the function descriptor in the .opd section. Using - // this scheme is simpler, but requires an extra indirection per PLT dispatch. - - write32be(Buf, 0xf8410028); // std %r2, 40(%r1) - write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha - write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11) - write32be(Buf + 12, 0xe96c0000); // ld %r11,0(%r12) - write32be(Buf + 16, 0x7d6903a6); // mtctr %r11 - write32be(Buf + 20, 0xe84c0008); // ld %r2,8(%r12) - write32be(Buf + 24, 0xe96c0010); // ld %r11,16(%r12) - write32be(Buf + 28, 0x4e800420); // bctr + int32_t Offset = PltHeaderSize + Index * PltEntrySize; + // bl __glink_PLTresolve + write32(Buf, 0x48000000 | ((-Offset) & 0x03FFFFFc)); } static std::pair toAddr16Rel(RelType Type, uint64_t Val) { - uint64_t V = Val - PPC64TocOffset; + // Relocations relative to the toc-base need to be adjusted by the Toc offset. + uint64_t TocBiasedVal = Val - PPC64TocOffset; + // Relocations relative to dtv[dtpmod] need to be adjusted by the DTP offset. + uint64_t DTPBiasedVal = Val - DynamicThreadPointerOffset; + switch (Type) { + // TOC biased relocation. + case R_PPC64_GOT_TLSGD16: + case R_PPC64_GOT_TLSLD16: case R_PPC64_TOC16: - return {R_PPC64_ADDR16, V}; + return {R_PPC64_ADDR16, TocBiasedVal}; case R_PPC64_TOC16_DS: - return {R_PPC64_ADDR16_DS, V}; + case R_PPC64_GOT_TPREL16_DS: + case R_PPC64_GOT_DTPREL16_DS: + return {R_PPC64_ADDR16_DS, TocBiasedVal}; + case R_PPC64_GOT_TLSGD16_HA: + case R_PPC64_GOT_TLSLD16_HA: + case R_PPC64_GOT_TPREL16_HA: + case R_PPC64_GOT_DTPREL16_HA: case R_PPC64_TOC16_HA: - return {R_PPC64_ADDR16_HA, V}; + return {R_PPC64_ADDR16_HA, TocBiasedVal}; + case R_PPC64_GOT_TLSGD16_HI: + case R_PPC64_GOT_TLSLD16_HI: + case R_PPC64_GOT_TPREL16_HI: + case R_PPC64_GOT_DTPREL16_HI: case R_PPC64_TOC16_HI: - return {R_PPC64_ADDR16_HI, V}; + return {R_PPC64_ADDR16_HI, TocBiasedVal}; + case R_PPC64_GOT_TLSGD16_LO: + case R_PPC64_GOT_TLSLD16_LO: case R_PPC64_TOC16_LO: - return {R_PPC64_ADDR16_LO, V}; + return {R_PPC64_ADDR16_LO, TocBiasedVal}; case R_PPC64_TOC16_LO_DS: - return {R_PPC64_ADDR16_LO_DS, V}; + case R_PPC64_GOT_TPREL16_LO_DS: + case R_PPC64_GOT_DTPREL16_LO_DS: + return {R_PPC64_ADDR16_LO_DS, TocBiasedVal}; + + // Dynamic Thread pointer biased relocation types. + case R_PPC64_DTPREL16: + return {R_PPC64_ADDR16, DTPBiasedVal}; + case R_PPC64_DTPREL16_DS: + return {R_PPC64_ADDR16_DS, DTPBiasedVal}; + case R_PPC64_DTPREL16_HA: + return {R_PPC64_ADDR16_HA, DTPBiasedVal}; + case R_PPC64_DTPREL16_HI: + return {R_PPC64_ADDR16_HI, DTPBiasedVal}; + case R_PPC64_DTPREL16_HIGHER: + return {R_PPC64_ADDR16_HIGHER, DTPBiasedVal}; + case R_PPC64_DTPREL16_HIGHERA: + return {R_PPC64_ADDR16_HIGHERA, DTPBiasedVal}; + case R_PPC64_DTPREL16_HIGHEST: + return {R_PPC64_ADDR16_HIGHEST, DTPBiasedVal}; + case R_PPC64_DTPREL16_HIGHESTA: + return {R_PPC64_ADDR16_HIGHESTA, DTPBiasedVal}; + case R_PPC64_DTPREL16_LO: + return {R_PPC64_ADDR16_LO, DTPBiasedVal}; + case R_PPC64_DTPREL16_LO_DS: + return {R_PPC64_ADDR16_LO_DS, DTPBiasedVal}; + case R_PPC64_DTPREL64: + return {R_PPC64_ADDR64, DTPBiasedVal}; + default: return {Type, Val}; } } void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { // For a TOC-relative relocation, proceed in terms of the corresponding // ADDR16 relocation type. std::tie(Type, Val) = toAddr16Rel(Type, Val); switch (Type) { case R_PPC64_ADDR14: { - checkAlignment<4>(Loc, Val, Type); + checkAlignment(Loc, Val, 4, Type); // Preserve the AA/LK bits in the branch instruction uint8_t AALK = Loc[3]; - write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc)); + write16(Loc + 2, (AALK & 3) | (Val & 0xfffc)); break; } case R_PPC64_ADDR16: - checkInt<16>(Loc, Val, Type); - write16be(Loc, Val); + case R_PPC64_TPREL16: + checkInt(Loc, Val, 16, Type); + write16(Loc, Val); break; case R_PPC64_ADDR16_DS: - checkInt<16>(Loc, Val, Type); - write16be(Loc, (read16be(Loc) & 3) | (Val & ~3)); + case R_PPC64_TPREL16_DS: + checkInt(Loc, Val, 16, Type); + write16(Loc, (read16(Loc) & 3) | (Val & ~3)); break; case R_PPC64_ADDR16_HA: case R_PPC64_REL16_HA: - write16be(Loc, applyPPCHa(Val)); + case R_PPC64_TPREL16_HA: + write16(Loc, ha(Val)); break; case R_PPC64_ADDR16_HI: case R_PPC64_REL16_HI: - write16be(Loc, applyPPCHi(Val)); + case R_PPC64_TPREL16_HI: + write16(Loc, hi(Val)); break; case R_PPC64_ADDR16_HIGHER: - write16be(Loc, applyPPCHigher(Val)); + case R_PPC64_TPREL16_HIGHER: + write16(Loc, higher(Val)); break; case R_PPC64_ADDR16_HIGHERA: - write16be(Loc, applyPPCHighera(Val)); + case R_PPC64_TPREL16_HIGHERA: + write16(Loc, highera(Val)); break; case R_PPC64_ADDR16_HIGHEST: - write16be(Loc, applyPPCHighest(Val)); + case R_PPC64_TPREL16_HIGHEST: + write16(Loc, highest(Val)); break; case R_PPC64_ADDR16_HIGHESTA: - write16be(Loc, applyPPCHighesta(Val)); + case R_PPC64_TPREL16_HIGHESTA: + write16(Loc, highesta(Val)); break; case R_PPC64_ADDR16_LO: - write16be(Loc, applyPPCLo(Val)); + case R_PPC64_REL16_LO: + case R_PPC64_TPREL16_LO: + write16(Loc, lo(Val)); break; case R_PPC64_ADDR16_LO_DS: - case R_PPC64_REL16_LO: - write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(Val) & ~3)); + case R_PPC64_TPREL16_LO_DS: + write16(Loc, (read16(Loc) & 3) | (lo(Val) & ~3)); break; case R_PPC64_ADDR32: case R_PPC64_REL32: - checkInt<32>(Loc, Val, Type); - write32be(Loc, Val); + checkInt(Loc, Val, 32, Type); + write32(Loc, Val); break; case R_PPC64_ADDR64: case R_PPC64_REL64: case R_PPC64_TOC: - write64be(Loc, Val); + write64(Loc, Val); break; case R_PPC64_REL24: { uint32_t Mask = 0x03FFFFFC; - checkInt<24>(Loc, Val, Type); - write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask)); + checkInt(Loc, Val, 24, Type); + write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask)); break; } + case R_PPC64_DTPREL64: + write64(Loc, Val - DynamicThreadPointerOffset); + break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); + } +} + +bool PPC64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const { + // If a function is in the plt it needs to be called through + // a call stub. + return Type == R_PPC64_REL24 && S.isInPlt(); +} + +RelExpr PPC64::adjustRelaxExpr(RelType Type, const uint8_t *Data, + RelExpr Expr) const { + if (Expr == R_RELAX_TLS_GD_TO_IE) + return R_RELAX_TLS_GD_TO_IE_GOT_OFF; + if (Expr == R_RELAX_TLS_LD_TO_LE) + return R_RELAX_TLS_LD_TO_LE_ABS; + return Expr; +} + +// Reference: 3.7.4.1 of the 64-bit ELF V2 abi supplement. +// The general dynamic code sequence for a global `x` uses 4 instructions. +// Instruction Relocation Symbol +// addis r3, r2, x@got@tlsgd@ha R_PPC64_GOT_TLSGD16_HA x +// addi r3, r3, x@got@tlsgd@l R_PPC64_GOT_TLSGD16_LO x +// bl __tls_get_addr(x@tlsgd) R_PPC64_TLSGD x +// R_PPC64_REL24 __tls_get_addr +// nop None None +// +// Relaxing to initial-exec entails: +// 1) Convert the addis/addi pair that builds the address of the tls_index +// struct for 'x' to an addis/ld pair that loads an offset from a got-entry. +// 2) Convert the call to __tls_get_addr to a nop. +// 3) Convert the nop following the call to an add of the loaded offset to the +// thread pointer. +// Since the nop must directly follow the call, the R_PPC64_TLSGD relocation is +// used as the relaxation hint for both steps 2 and 3. +void PPC64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { + case R_PPC64_GOT_TLSGD16_HA: + // This is relaxed from addis rT, r2, sym@got@tlsgd@ha to + // addis rT, r2, sym@got@tprel@ha. + relocateOne(Loc, R_PPC64_GOT_TPREL16_HA, Val); + return; + case R_PPC64_GOT_TLSGD16_LO: { + // Relax from addi r3, rA, sym@got@tlsgd@l to + // ld r3, sym@got@tprel@l(rA) + uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U; + uint32_t InputRegister = (read32(Loc - EndianOffset) & (0x1f << 16)); + write32(Loc - EndianOffset, 0xE8600000 | InputRegister); + relocateOne(Loc, R_PPC64_GOT_TPREL16_LO_DS, Val); + return; + } + case R_PPC64_TLSGD: + write32(Loc, 0x60000000); // bl __tls_get_addr(sym@tlsgd) --> nop + write32(Loc + 4, 0x7c636A14); // nop --> add r3, r3, r13 + return; + default: + llvm_unreachable("unsupported relocation for TLS GD to IE relaxation"); } } TargetInfo *elf::getPPC64TargetInfo() { static PPC64 Target; return &Target; } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp (revision 336982) @@ -1,148 +1,148 @@ //===- SPARCV9.cpp --------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" using namespace llvm; using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; namespace { class SPARCV9 final : public TargetInfo { public: SPARCV9(); RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace SPARCV9::SPARCV9() { CopyRel = R_SPARC_COPY; GotRel = R_SPARC_GLOB_DAT; PltRel = R_SPARC_JMP_SLOT; RelativeRel = R_SPARC_RELATIVE; GotEntrySize = 8; PltEntrySize = 32; PltHeaderSize = 4 * PltEntrySize; PageSize = 8192; DefaultMaxPageSize = 0x100000; DefaultImageBase = 0x100000; } RelExpr SPARCV9::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { case R_SPARC_32: case R_SPARC_UA32: case R_SPARC_64: case R_SPARC_UA64: return R_ABS; case R_SPARC_PC10: case R_SPARC_PC22: case R_SPARC_DISP32: case R_SPARC_WDISP30: return R_PC; case R_SPARC_GOT10: return R_GOT_OFF; case R_SPARC_GOT22: return R_GOT_OFF; case R_SPARC_WPLT30: return R_PLT_PC; case R_SPARC_NONE: return R_NONE; default: return R_INVALID; } } void SPARCV9::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_SPARC_32: case R_SPARC_UA32: // V-word32 - checkUInt<32>(Loc, Val, Type); + checkUInt(Loc, Val, 32, Type); write32be(Loc, Val); break; case R_SPARC_DISP32: // V-disp32 - checkInt<32>(Loc, Val, Type); + checkInt(Loc, Val, 32, Type); write32be(Loc, Val); break; case R_SPARC_WDISP30: case R_SPARC_WPLT30: // V-disp30 - checkInt<32>(Loc, Val, Type); + checkInt(Loc, Val, 32, Type); write32be(Loc, (read32be(Loc) & ~0x3fffffff) | ((Val >> 2) & 0x3fffffff)); break; case R_SPARC_22: // V-imm22 - checkUInt<22>(Loc, Val, Type); + checkUInt(Loc, Val, 22, Type); write32be(Loc, (read32be(Loc) & ~0x003fffff) | (Val & 0x003fffff)); break; case R_SPARC_GOT22: case R_SPARC_PC22: // T-imm22 write32be(Loc, (read32be(Loc) & ~0x003fffff) | ((Val >> 10) & 0x003fffff)); break; case R_SPARC_WDISP19: // V-disp19 - checkInt<21>(Loc, Val, Type); + checkInt(Loc, Val, 21, Type); write32be(Loc, (read32be(Loc) & ~0x0007ffff) | ((Val >> 2) & 0x0007ffff)); break; case R_SPARC_GOT10: case R_SPARC_PC10: // T-simm10 write32be(Loc, (read32be(Loc) & ~0x000003ff) | (Val & 0x000003ff)); break; case R_SPARC_64: case R_SPARC_UA64: case R_SPARC_GLOB_DAT: // V-xword64 write64be(Loc, Val); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } void SPARCV9::writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t PltData[] = { 0x03, 0x00, 0x00, 0x00, // sethi (. - .PLT0), %g1 0x30, 0x68, 0x00, 0x00, // ba,a %xcc, .PLT1 0x01, 0x00, 0x00, 0x00, // nop 0x01, 0x00, 0x00, 0x00, // nop 0x01, 0x00, 0x00, 0x00, // nop 0x01, 0x00, 0x00, 0x00, // nop 0x01, 0x00, 0x00, 0x00, // nop 0x01, 0x00, 0x00, 0x00 // nop }; memcpy(Buf, PltData, sizeof(PltData)); - uint64_t Off = PltHeaderSize + Index * PltEntrySize; + uint64_t Off = getPltEntryOffset(Index); relocateOne(Buf, R_SPARC_22, Off); relocateOne(Buf + 4, R_SPARC_WDISP19, -(Off + 4 - PltEntrySize)); } TargetInfo *elf::getSPARCV9TargetInfo() { static SPARCV9 Target; return &Target; } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/X86.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/X86.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/X86.cpp (revision 336982) @@ -1,543 +1,549 @@ //===- X86.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" using namespace llvm; using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; namespace { class X86 : public TargetInfo { public: X86(); RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; void writeGotPltHeader(uint8_t *Buf) const override; RelType getDynRel(RelType Type) const override; void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; void writeIgotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, RelExpr Expr) const override; void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace X86::X86() { - GotBaseSymOff = -1; CopyRel = R_386_COPY; GotRel = R_386_GLOB_DAT; PltRel = R_386_JUMP_SLOT; IRelativeRel = R_386_IRELATIVE; RelativeRel = R_386_RELATIVE; TlsGotRel = R_386_TLS_TPOFF; TlsModuleIndexRel = R_386_TLS_DTPMOD32; TlsOffsetRel = R_386_TLS_DTPOFF32; GotEntrySize = 4; GotPltEntrySize = 4; PltEntrySize = 16; PltHeaderSize = 16; TlsGdRelaxSkip = 2; TrapInstr = 0xcccccccc; // 0xcc = INT3 } static bool hasBaseReg(uint8_t ModRM) { return (ModRM & 0xc7) != 0x5; } RelExpr X86::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { case R_386_8: case R_386_16: case R_386_32: case R_386_TLS_LDO_32: return R_ABS; case R_386_TLS_GD: - return R_TLSGD; + return R_TLSGD_GOT_FROM_END; case R_386_TLS_LDM: - return R_TLSLD; + return R_TLSLD_GOT_FROM_END; case R_386_PLT32: return R_PLT_PC; case R_386_PC8: case R_386_PC16: case R_386_PC32: return R_PC; case R_386_GOTPC: return R_GOTONLY_PC_FROM_END; case R_386_TLS_IE: return R_GOT; case R_386_GOT32: case R_386_GOT32X: // These relocations are arguably mis-designed because their calculations // depend on the instructions they are applied to. This is bad because we // usually don't care about whether the target section contains valid // machine instructions or not. But this is part of the documented ABI, so // we had to implement as the standard requires. // // x86 does not support PC-relative data access. Therefore, in order to // access GOT contents, a GOT address needs to be known at link-time // (which means non-PIC) or compilers have to emit code to get a GOT // address at runtime (which means code is position-independent but // compilers need to emit extra code for each GOT access.) This decision // is made at compile-time. In the latter case, compilers emit code to // load an GOT address to a register, which is usually %ebx. // // So, there are two ways to refer to symbol foo's GOT entry: foo@GOT or // foo@GOT(%reg). // // foo@GOT is not usable in PIC. If we are creating a PIC output and if we // find such relocation, we should report an error. foo@GOT is resolved to // an *absolute* address of foo's GOT entry, because both GOT address and // foo's offset are known. In other words, it's G + A. // // foo@GOT(%reg) needs to be resolved to a *relative* offset from a GOT to // foo's GOT entry in the table, because GOT address is not known but foo's // offset in the table is known. It's G + A - GOT. // // It's unfortunate that compilers emit the same relocation for these // different use cases. In order to distinguish them, we have to read a // machine instruction. // // The following code implements it. We assume that Loc[0] is the first // byte of a displacement or an immediate field of a valid machine // instruction. That means a ModRM byte is at Loc[-1]. By taking a look at // the byte, we can determine whether the instruction is register-relative // (i.e. it was generated for foo@GOT(%reg)) or absolute (i.e. foo@GOT). return hasBaseReg(Loc[-1]) ? R_GOT_FROM_END : R_GOT; case R_386_TLS_GOTIE: return R_GOT_FROM_END; case R_386_GOTOFF: return R_GOTREL_FROM_END; case R_386_TLS_LE: return R_TLS; case R_386_TLS_LE_32: return R_NEG_TLS; case R_386_NONE: return R_NONE; default: return R_INVALID; } } RelExpr X86::adjustRelaxExpr(RelType Type, const uint8_t *Data, RelExpr Expr) const { switch (Expr) { default: return Expr; case R_RELAX_TLS_GD_TO_IE: return R_RELAX_TLS_GD_TO_IE_END; case R_RELAX_TLS_GD_TO_LE: return R_RELAX_TLS_GD_TO_LE_NEG; } } void X86::writeGotPltHeader(uint8_t *Buf) const { write32le(Buf, InX::Dynamic->getVA()); } void X86::writeGotPlt(uint8_t *Buf, const Symbol &S) const { // Entries in .got.plt initially points back to the corresponding // PLT entries with a fixed offset to skip the first instruction. write32le(Buf, S.getPltVA() + 6); } void X86::writeIgotPlt(uint8_t *Buf, const Symbol &S) const { // An x86 entry is the address of the ifunc resolver function. write32le(Buf, S.getVA()); } RelType X86::getDynRel(RelType Type) const { if (Type == R_386_TLS_LE) return R_386_TLS_TPOFF; if (Type == R_386_TLS_LE_32) return R_386_TLS_TPOFF32; return Type; } void X86::writePltHeader(uint8_t *Buf) const { if (Config->Pic) { const uint8_t V[] = { 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl GOTPLT+4(%ebx) 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *GOTPLT+8(%ebx) 0x90, 0x90, 0x90, 0x90 // nop }; memcpy(Buf, V, sizeof(V)); uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); uint32_t GotPlt = InX::GotPlt->getVA() - Ebx; write32le(Buf + 2, GotPlt + 4); write32le(Buf + 8, GotPlt + 8); return; } const uint8_t PltData[] = { 0xff, 0x35, 0, 0, 0, 0, // pushl (GOTPLT+4) 0xff, 0x25, 0, 0, 0, 0, // jmp *(GOTPLT+8) 0x90, 0x90, 0x90, 0x90, // nop }; memcpy(Buf, PltData, sizeof(PltData)); uint32_t GotPlt = InX::GotPlt->getVA(); write32le(Buf + 2, GotPlt + 4); write32le(Buf + 8, GotPlt + 8); } void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Inst[] = { 0xff, 0x00, 0, 0, 0, 0, // jmp *foo_in_GOT or jmp *foo@GOT(%ebx) 0x68, 0, 0, 0, 0, // pushl $reloc_offset 0xe9, 0, 0, 0, 0, // jmp .PLT0@PC }; memcpy(Buf, Inst, sizeof(Inst)); if (Config->Pic) { // jmp *foo@GOT(%ebx) uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); Buf[1] = 0xa3; write32le(Buf + 2, GotPltEntryAddr - Ebx); } else { // jmp *foo_in_GOT Buf[1] = 0x25; write32le(Buf + 2, GotPltEntryAddr); } write32le(Buf + 7, RelOff); - write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); + write32le(Buf + 12, -getPltEntryOffset(Index) - 16); } int64_t X86::getImplicitAddend(const uint8_t *Buf, RelType Type) const { switch (Type) { case R_386_8: case R_386_PC8: return SignExtend64<8>(*Buf); case R_386_16: case R_386_PC16: return SignExtend64<16>(read16le(Buf)); case R_386_32: case R_386_GOT32: case R_386_GOT32X: case R_386_GOTOFF: case R_386_GOTPC: case R_386_PC32: case R_386_PLT32: case R_386_TLS_LDO_32: case R_386_TLS_LE: return SignExtend64<32>(read32le(Buf)); default: return 0; } } void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_386_8: // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are // being used for some 16-bit programs such as boot loaders, so // we want to support them. - checkUInt<8>(Loc, Val, Type); + checkIntUInt(Loc, Val, 8, Type); *Loc = Val; break; case R_386_PC8: - checkInt<8>(Loc, Val, Type); + checkInt(Loc, Val, 8, Type); *Loc = Val; break; case R_386_16: - checkUInt<16>(Loc, Val, Type); + checkIntUInt(Loc, Val, 16, Type); write16le(Loc, Val); break; case R_386_PC16: // R_386_PC16 is normally used with 16 bit code. In that situation // the PC is 16 bits, just like the addend. This means that it can // point from any 16 bit address to any other if the possibility // of wrapping is included. // The only restriction we have to check then is that the destination // address fits in 16 bits. That is impossible to do here. The problem is // that we are passed the final value, which already had the // current location subtracted from it. // We just check that Val fits in 17 bits. This misses some cases, but // should have no false positives. - checkInt<17>(Loc, Val, Type); + checkInt(Loc, Val, 17, Type); write16le(Loc, Val); break; case R_386_32: case R_386_GLOB_DAT: case R_386_GOT32: case R_386_GOT32X: case R_386_GOTOFF: case R_386_GOTPC: case R_386_PC32: case R_386_PLT32: case R_386_RELATIVE: case R_386_TLS_DTPMOD32: case R_386_TLS_DTPOFF32: case R_386_TLS_GD: case R_386_TLS_GOTIE: case R_386_TLS_IE: case R_386_TLS_LDM: case R_386_TLS_LDO_32: case R_386_TLS_LE: case R_386_TLS_LE_32: case R_386_TLS_TPOFF: case R_386_TLS_TPOFF32: - checkInt<32>(Loc, Val, Type); + checkInt(Loc, Val, 32, Type); write32le(Loc, Val); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } void X86::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { // Convert // leal x@tlsgd(, %ebx, 1), // call __tls_get_addr@plt // to // movl %gs:0,%eax // subl $x@ntpoff,%eax const uint8_t Inst[] = { 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax 0x81, 0xe8, 0, 0, 0, 0, // subl Val(%ebx), %eax }; memcpy(Loc - 3, Inst, sizeof(Inst)); write32le(Loc + 5, Val); } void X86::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { // Convert // leal x@tlsgd(, %ebx, 1), // call __tls_get_addr@plt // to // movl %gs:0, %eax // addl x@gotntpoff(%ebx), %eax const uint8_t Inst[] = { 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax 0x03, 0x83, 0, 0, 0, 0, // addl Val(%ebx), %eax }; memcpy(Loc - 3, Inst, sizeof(Inst)); write32le(Loc + 5, Val); } // In some conditions, relocations can be optimized to avoid using GOT. // This function does that for Initial Exec to Local Exec case. void X86::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { // Ulrich's document section 6.2 says that @gotntpoff can // be used with MOVL or ADDL instructions. // @indntpoff is similar to @gotntpoff, but for use in // position dependent code. uint8_t Reg = (Loc[-1] >> 3) & 7; if (Type == R_386_TLS_IE) { if (Loc[-1] == 0xa1) { // "movl foo@indntpoff,%eax" -> "movl $foo,%eax" // This case is different from the generic case below because // this is a 5 byte instruction while below is 6 bytes. Loc[-1] = 0xb8; } else if (Loc[-2] == 0x8b) { // "movl foo@indntpoff,%reg" -> "movl $foo,%reg" Loc[-2] = 0xc7; Loc[-1] = 0xc0 | Reg; } else { // "addl foo@indntpoff,%reg" -> "addl $foo,%reg" Loc[-2] = 0x81; Loc[-1] = 0xc0 | Reg; } } else { assert(Type == R_386_TLS_GOTIE); if (Loc[-2] == 0x8b) { // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg" Loc[-2] = 0xc7; Loc[-1] = 0xc0 | Reg; } else { // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg" Loc[-2] = 0x8d; Loc[-1] = 0x80 | (Reg << 3) | Reg; } } write32le(Loc, Val); } void X86::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { if (Type == R_386_TLS_LDO_32) { write32le(Loc, Val); return; } // Convert // leal foo(%reg),%eax // call ___tls_get_addr // to // movl %gs:0,%eax // nop // leal 0(%esi,1),%esi const uint8_t Inst[] = { 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax 0x90, // nop 0x8d, 0x74, 0x26, 0x00, // leal 0(%esi,1),%esi }; memcpy(Loc - 2, Inst, sizeof(Inst)); } namespace { class RetpolinePic : public X86 { public: RetpolinePic(); void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; }; class RetpolineNoPic : public X86 { public: RetpolineNoPic(); void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; }; } // namespace RetpolinePic::RetpolinePic() { PltHeaderSize = 48; PltEntrySize = 32; } void RetpolinePic::writeGotPlt(uint8_t *Buf, const Symbol &S) const { write32le(Buf, S.getPltVA() + 17); } void RetpolinePic::writePltHeader(uint8_t *Buf) const { const uint8_t Insn[] = { 0xff, 0xb3, 0, 0, 0, 0, // 0: pushl GOTPLT+4(%ebx) 0x50, // 6: pushl %eax 0x8b, 0x83, 0, 0, 0, 0, // 7: mov GOTPLT+8(%ebx), %eax 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: call next 0xf3, 0x90, // 12: loop: pause 0x0f, 0xae, 0xe8, // 14: lfence 0xeb, 0xf9, // 17: jmp loop 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) 0x89, 0xc8, // 2b: mov %ecx, %eax 0x59, // 2d: pop %ecx 0xc3, // 2e: ret + 0xcc, // 2f: int3; padding }; memcpy(Buf, Insn, sizeof(Insn)); uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); uint32_t GotPlt = InX::GotPlt->getVA() - Ebx; write32le(Buf + 2, GotPlt + 4); write32le(Buf + 9, GotPlt + 8); } void RetpolinePic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Insn[] = { - 0x50, // pushl %eax - 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax - 0xe8, 0, 0, 0, 0, // call plt+0x20 - 0xe9, 0, 0, 0, 0, // jmp plt+0x12 - 0x68, 0, 0, 0, 0, // pushl $reloc_offset - 0xe9, 0, 0, 0, 0, // jmp plt+0 + 0x50, // pushl %eax + 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax + 0xe8, 0, 0, 0, 0, // call plt+0x20 + 0xe9, 0, 0, 0, 0, // jmp plt+0x12 + 0x68, 0, 0, 0, 0, // pushl $reloc_offset + 0xe9, 0, 0, 0, 0, // jmp plt+0 + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding }; memcpy(Buf, Insn, sizeof(Insn)); uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); + unsigned Off = getPltEntryOffset(Index); write32le(Buf + 3, GotPltEntryAddr - Ebx); - write32le(Buf + 8, -Index * PltEntrySize - PltHeaderSize - 12 + 32); - write32le(Buf + 13, -Index * PltEntrySize - PltHeaderSize - 17 + 18); + write32le(Buf + 8, -Off - 12 + 32); + write32le(Buf + 13, -Off - 17 + 18); write32le(Buf + 18, RelOff); - write32le(Buf + 23, -Index * PltEntrySize - PltHeaderSize - 27); + write32le(Buf + 23, -Off - 27); } RetpolineNoPic::RetpolineNoPic() { PltHeaderSize = 48; PltEntrySize = 32; } void RetpolineNoPic::writeGotPlt(uint8_t *Buf, const Symbol &S) const { write32le(Buf, S.getPltVA() + 16); } void RetpolineNoPic::writePltHeader(uint8_t *Buf) const { - const uint8_t PltData[] = { + const uint8_t Insn[] = { 0xff, 0x35, 0, 0, 0, 0, // 0: pushl GOTPLT+4 0x50, // 6: pushl %eax 0xa1, 0, 0, 0, 0, // 7: mov GOTPLT+8, %eax 0xe8, 0x0f, 0x00, 0x00, 0x00, // c: call next 0xf3, 0x90, // 11: loop: pause 0x0f, 0xae, 0xe8, // 13: lfence 0xeb, 0xf9, // 16: jmp loop 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 18: int3 0xcc, 0xcc, 0xcc, // 1f: int3; .align 16 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) 0x89, 0xc8, // 2b: mov %ecx, %eax 0x59, // 2d: pop %ecx 0xc3, // 2e: ret + 0xcc, // 2f: int3; padding }; - memcpy(Buf, PltData, sizeof(PltData)); + memcpy(Buf, Insn, sizeof(Insn)); uint32_t GotPlt = InX::GotPlt->getVA(); write32le(Buf + 2, GotPlt + 4); write32le(Buf + 8, GotPlt + 8); } void RetpolineNoPic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Insn[] = { - 0x50, // 0: pushl %eax - 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax - 0xe8, 0, 0, 0, 0, // 6: call plt+0x20 - 0xe9, 0, 0, 0, 0, // b: jmp plt+0x11 - 0x68, 0, 0, 0, 0, // 10: pushl $reloc_offset - 0xe9, 0, 0, 0, 0, // 15: jmp plt+0 + 0x50, // 0: pushl %eax + 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax + 0xe8, 0, 0, 0, 0, // 6: call plt+0x20 + 0xe9, 0, 0, 0, 0, // b: jmp plt+0x11 + 0x68, 0, 0, 0, 0, // 10: pushl $reloc_offset + 0xe9, 0, 0, 0, 0, // 15: jmp plt+0 + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding + 0xcc, // 1f: int3; padding }; memcpy(Buf, Insn, sizeof(Insn)); + unsigned Off = getPltEntryOffset(Index); write32le(Buf + 2, GotPltEntryAddr); - write32le(Buf + 7, -Index * PltEntrySize - PltHeaderSize - 11 + 32); - write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16 + 17); + write32le(Buf + 7, -Off - 11 + 32); + write32le(Buf + 12, -Off - 16 + 17); write32le(Buf + 17, RelOff); - write32le(Buf + 22, -Index * PltEntrySize - PltHeaderSize - 26); + write32le(Buf + 22, -Off - 26); } TargetInfo *elf::getX86TargetInfo() { if (Config->ZRetpolineplt) { if (Config->Pic) { static RetpolinePic T; return &T; } static RetpolineNoPic T; return &T; } static X86 T; return &T; } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/X86.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp (revision 336982) @@ -1,584 +1,650 @@ //===- X86_64.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" using namespace llvm; using namespace llvm::object; using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; namespace { template class X86_64 : public TargetInfo { public: X86_64(); RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; - bool isPicRel(RelType Type) const override; + RelType getDynRel(RelType Type) const override; void writeGotPltHeader(uint8_t *Buf) const override; void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, RelExpr Expr) const override; void relaxGot(uint8_t *Loc, uint64_t Val) const override; void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + bool adjustPrologueForCrossSplitStack(uint8_t *Loc, + uint8_t *End) const override; private: void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, uint8_t ModRm) const; }; } // namespace template X86_64::X86_64() { - GotBaseSymOff = -1; CopyRel = R_X86_64_COPY; GotRel = R_X86_64_GLOB_DAT; PltRel = R_X86_64_JUMP_SLOT; RelativeRel = R_X86_64_RELATIVE; IRelativeRel = R_X86_64_IRELATIVE; TlsGotRel = R_X86_64_TPOFF64; TlsModuleIndexRel = R_X86_64_DTPMOD64; TlsOffsetRel = R_X86_64_DTPOFF64; GotEntrySize = 8; GotPltEntrySize = 8; PltEntrySize = 16; PltHeaderSize = 16; TlsGdRelaxSkip = 2; TrapInstr = 0xcccccccc; // 0xcc = INT3 // Align to the large page size (known as a superpage or huge page). // FreeBSD automatically promotes large, superpage-aligned allocations. DefaultImageBase = 0x200000; } template RelExpr X86_64::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { case R_X86_64_8: case R_X86_64_16: case R_X86_64_32: case R_X86_64_32S: case R_X86_64_64: case R_X86_64_DTPOFF32: case R_X86_64_DTPOFF64: return R_ABS; case R_X86_64_TPOFF32: return R_TLS; case R_X86_64_TLSLD: return R_TLSLD_PC; case R_X86_64_TLSGD: return R_TLSGD_PC; case R_X86_64_SIZE32: case R_X86_64_SIZE64: return R_SIZE; case R_X86_64_PLT32: return R_PLT_PC; case R_X86_64_PC32: case R_X86_64_PC64: return R_PC; case R_X86_64_GOT32: case R_X86_64_GOT64: return R_GOT_FROM_END; case R_X86_64_GOTPCREL: case R_X86_64_GOTPCRELX: case R_X86_64_REX_GOTPCRELX: case R_X86_64_GOTTPOFF: return R_GOT_PC; + case R_X86_64_GOTOFF64: + return R_GOTREL_FROM_END; + case R_X86_64_GOTPC32: + case R_X86_64_GOTPC64: + return R_GOTONLY_PC_FROM_END; case R_X86_64_NONE: return R_NONE; default: return R_INVALID; } } template void X86_64::writeGotPltHeader(uint8_t *Buf) const { // The first entry holds the value of _DYNAMIC. It is not clear why that is // required, but it is documented in the psabi and the glibc dynamic linker // seems to use it (note that this is relevant for linking ld.so, not any // other program). write64le(Buf, InX::Dynamic->getVA()); } template void X86_64::writeGotPlt(uint8_t *Buf, const Symbol &S) const { // See comments in X86::writeGotPlt. - write32le(Buf, S.getPltVA() + 6); + write64le(Buf, S.getPltVA() + 6); } template void X86_64::writePltHeader(uint8_t *Buf) const { const uint8_t PltData[] = { 0xff, 0x35, 0, 0, 0, 0, // pushq GOTPLT+8(%rip) 0xff, 0x25, 0, 0, 0, 0, // jmp *GOTPLT+16(%rip) 0x0f, 0x1f, 0x40, 0x00, // nop }; memcpy(Buf, PltData, sizeof(PltData)); uint64_t GotPlt = InX::GotPlt->getVA(); uint64_t Plt = InX::Plt->getVA(); write32le(Buf + 2, GotPlt - Plt + 2); // GOTPLT+8 write32le(Buf + 8, GotPlt - Plt + 4); // GOTPLT+16 } template void X86_64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Inst[] = { 0xff, 0x25, 0, 0, 0, 0, // jmpq *got(%rip) 0x68, 0, 0, 0, 0, // pushq 0xe9, 0, 0, 0, 0, // jmpq plt[0] }; memcpy(Buf, Inst, sizeof(Inst)); write32le(Buf + 2, GotPltEntryAddr - PltEntryAddr - 6); write32le(Buf + 7, Index); - write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); + write32le(Buf + 12, -getPltEntryOffset(Index) - 16); } -template bool X86_64::isPicRel(RelType Type) const { - return Type != R_X86_64_PC32 && Type != R_X86_64_32 && - Type != R_X86_64_TPOFF32; +template RelType X86_64::getDynRel(RelType Type) const { + if (Type == R_X86_64_64 || Type == R_X86_64_PC64 || Type == R_X86_64_SIZE32 || + Type == R_X86_64_SIZE64) + return Type; + return R_X86_64_NONE; } template void X86_64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { // Convert // .byte 0x66 // leaq x@tlsgd(%rip), %rdi // .word 0x6666 // rex64 // call __tls_get_addr@plt // to // mov %fs:0x0,%rax // lea x@tpoff,%rax const uint8_t Inst[] = { 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax 0x48, 0x8d, 0x80, 0, 0, 0, 0, // lea x@tpoff,%rax }; memcpy(Loc - 4, Inst, sizeof(Inst)); // The original code used a pc relative relocation and so we have to // compensate for the -4 in had in the addend. write32le(Loc + 8, Val + 4); } template void X86_64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { // Convert // .byte 0x66 // leaq x@tlsgd(%rip), %rdi // .word 0x6666 // rex64 // call __tls_get_addr@plt // to // mov %fs:0x0,%rax // addq x@tpoff,%rax const uint8_t Inst[] = { 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax 0x48, 0x03, 0x05, 0, 0, 0, 0, // addq x@tpoff,%rax }; memcpy(Loc - 4, Inst, sizeof(Inst)); // Both code sequences are PC relatives, but since we are moving the constant // forward by 8 bytes we have to subtract the value by 8. write32le(Loc + 8, Val - 8); } // In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to // R_X86_64_TPOFF32 so that it does not use GOT. template void X86_64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { uint8_t *Inst = Loc - 3; uint8_t Reg = Loc[-1] >> 3; uint8_t *RegSlot = Loc - 1; // Note that ADD with RSP or R12 is converted to ADD instead of LEA // because LEA with these registers needs 4 bytes to encode and thus // wouldn't fit the space. if (memcmp(Inst, "\x48\x03\x25", 3) == 0) { // "addq foo@gottpoff(%rip),%rsp" -> "addq $foo,%rsp" memcpy(Inst, "\x48\x81\xc4", 3); } else if (memcmp(Inst, "\x4c\x03\x25", 3) == 0) { // "addq foo@gottpoff(%rip),%r12" -> "addq $foo,%r12" memcpy(Inst, "\x49\x81\xc4", 3); } else if (memcmp(Inst, "\x4c\x03", 2) == 0) { // "addq foo@gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]" memcpy(Inst, "\x4d\x8d", 2); *RegSlot = 0x80 | (Reg << 3) | Reg; } else if (memcmp(Inst, "\x48\x03", 2) == 0) { // "addq foo@gottpoff(%rip),%reg -> "leaq foo(%reg),%reg" memcpy(Inst, "\x48\x8d", 2); *RegSlot = 0x80 | (Reg << 3) | Reg; } else if (memcmp(Inst, "\x4c\x8b", 2) == 0) { // "movq foo@gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]" memcpy(Inst, "\x49\xc7", 2); *RegSlot = 0xc0 | Reg; } else if (memcmp(Inst, "\x48\x8b", 2) == 0) { // "movq foo@gottpoff(%rip),%reg" -> "movq $foo,%reg" memcpy(Inst, "\x48\xc7", 2); *RegSlot = 0xc0 | Reg; } else { error(getErrorLocation(Loc - 3) + "R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only"); } // The original code used a PC relative relocation. // Need to compensate for the -4 it had in the addend. write32le(Loc, Val + 4); } template void X86_64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { // Convert // leaq bar@tlsld(%rip), %rdi // callq __tls_get_addr@PLT // leaq bar@dtpoff(%rax), %rcx // to // .word 0x6666 // .byte 0x66 // mov %fs:0,%rax // leaq bar@tpoff(%rax), %rcx if (Type == R_X86_64_DTPOFF64) { write64le(Loc, Val); return; } if (Type == R_X86_64_DTPOFF32) { write32le(Loc, Val); return; } const uint8_t Inst[] = { 0x66, 0x66, // .word 0x6666 0x66, // .byte 0x66 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0,%rax }; memcpy(Loc - 3, Inst, sizeof(Inst)); } template void X86_64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_X86_64_8: - checkUInt<8>(Loc, Val, Type); + checkUInt(Loc, Val, 8, Type); *Loc = Val; break; case R_X86_64_16: - checkUInt<16>(Loc, Val, Type); + checkUInt(Loc, Val, 16, Type); write16le(Loc, Val); break; case R_X86_64_32: - checkUInt<32>(Loc, Val, Type); + checkUInt(Loc, Val, 32, Type); write32le(Loc, Val); break; case R_X86_64_32S: case R_X86_64_TPOFF32: case R_X86_64_GOT32: + case R_X86_64_GOTPC32: case R_X86_64_GOTPCREL: case R_X86_64_GOTPCRELX: case R_X86_64_REX_GOTPCRELX: case R_X86_64_PC32: case R_X86_64_GOTTPOFF: case R_X86_64_PLT32: case R_X86_64_TLSGD: case R_X86_64_TLSLD: case R_X86_64_DTPOFF32: case R_X86_64_SIZE32: - checkInt<32>(Loc, Val, Type); + checkInt(Loc, Val, 32, Type); write32le(Loc, Val); break; case R_X86_64_64: case R_X86_64_DTPOFF64: case R_X86_64_GLOB_DAT: case R_X86_64_PC64: case R_X86_64_SIZE64: case R_X86_64_GOT64: + case R_X86_64_GOTOFF64: + case R_X86_64_GOTPC64: write64le(Loc, Val); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } template RelExpr X86_64::adjustRelaxExpr(RelType Type, const uint8_t *Data, RelExpr RelExpr) const { if (Type != R_X86_64_GOTPCRELX && Type != R_X86_64_REX_GOTPCRELX) return RelExpr; const uint8_t Op = Data[-2]; const uint8_t ModRm = Data[-1]; // FIXME: When PIC is disabled and foo is defined locally in the // lower 32 bit address space, memory operand in mov can be converted into // immediate operand. Otherwise, mov must be changed to lea. We support only // latter relaxation at this moment. if (Op == 0x8b) return R_RELAX_GOT_PC; // Relax call and jmp. if (Op == 0xff && (ModRm == 0x15 || ModRm == 0x25)) return R_RELAX_GOT_PC; // Relaxation of test, adc, add, and, cmp, or, sbb, sub, xor. // If PIC then no relaxation is available. // We also don't relax test/binop instructions without REX byte, // they are 32bit operations and not common to have. assert(Type == R_X86_64_REX_GOTPCRELX); return Config->Pic ? RelExpr : R_RELAX_GOT_PC_NOPIC; } // A subset of relaxations can only be applied for no-PIC. This method // handles such relaxations. Instructions encoding information was taken from: // "Intel 64 and IA-32 Architectures Software Developer's Manual V2" // (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/ // 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf) template void X86_64::relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, uint8_t ModRm) const { const uint8_t Rex = Loc[-3]; // Convert "test %reg, foo@GOTPCREL(%rip)" to "test $foo, %reg". if (Op == 0x85) { // See "TEST-Logical Compare" (4-428 Vol. 2B), // TEST r/m64, r64 uses "full" ModR / M byte (no opcode extension). // ModR/M byte has form XX YYY ZZZ, where // YYY is MODRM.reg(register 2), ZZZ is MODRM.rm(register 1). // XX has different meanings: // 00: The operand's memory address is in reg1. // 01: The operand's memory address is reg1 + a byte-sized displacement. // 10: The operand's memory address is reg1 + a word-sized displacement. // 11: The operand is reg1 itself. // If an instruction requires only one operand, the unused reg2 field // holds extra opcode bits rather than a register code // 0xC0 == 11 000 000 binary. // 0x38 == 00 111 000 binary. // We transfer reg2 to reg1 here as operand. // See "2.1.3 ModR/M and SIB Bytes" (Vol. 2A 2-3). Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3; // ModR/M byte. // Change opcode from TEST r/m64, r64 to TEST r/m64, imm32 // See "TEST-Logical Compare" (4-428 Vol. 2B). Loc[-2] = 0xf7; // Move R bit to the B bit in REX byte. // REX byte is encoded as 0100WRXB, where // 0100 is 4bit fixed pattern. // REX.W When 1, a 64-bit operand size is used. Otherwise, when 0, the // default operand size is used (which is 32-bit for most but not all // instructions). // REX.R This 1-bit value is an extension to the MODRM.reg field. // REX.X This 1-bit value is an extension to the SIB.index field. // REX.B This 1-bit value is an extension to the MODRM.rm field or the // SIB.base field. // See "2.2.1.2 More on REX Prefix Fields " (2-8 Vol. 2A). Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2; write32le(Loc, Val); return; } // If we are here then we need to relax the adc, add, and, cmp, or, sbb, sub // or xor operations. // Convert "binop foo@GOTPCREL(%rip), %reg" to "binop $foo, %reg". // Logic is close to one for test instruction above, but we also // write opcode extension here, see below for details. Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3 | (Op & 0x3c); // ModR/M byte. // Primary opcode is 0x81, opcode extension is one of: // 000b = ADD, 001b is OR, 010b is ADC, 011b is SBB, // 100b is AND, 101b is SUB, 110b is XOR, 111b is CMP. // This value was wrote to MODRM.reg in a line above. // See "3.2 INSTRUCTIONS (A-M)" (Vol. 2A 3-15), // "INSTRUCTION SET REFERENCE, N-Z" (Vol. 2B 4-1) for // descriptions about each operation. Loc[-2] = 0x81; Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2; write32le(Loc, Val); } template void X86_64::relaxGot(uint8_t *Loc, uint64_t Val) const { const uint8_t Op = Loc[-2]; const uint8_t ModRm = Loc[-1]; // Convert "mov foo@GOTPCREL(%rip),%reg" to "lea foo(%rip),%reg". if (Op == 0x8b) { Loc[-2] = 0x8d; write32le(Loc, Val); return; } if (Op != 0xff) { // We are relaxing a rip relative to an absolute, so compensate // for the old -4 addend. assert(!Config->Pic); relaxGotNoPic(Loc, Val + 4, Op, ModRm); return; } // Convert call/jmp instructions. if (ModRm == 0x15) { // ABI says we can convert "call *foo@GOTPCREL(%rip)" to "nop; call foo". // Instead we convert to "addr32 call foo" where addr32 is an instruction // prefix. That makes result expression to be a single instruction. Loc[-2] = 0x67; // addr32 prefix Loc[-1] = 0xe8; // call write32le(Loc, Val); return; } // Convert "jmp *foo@GOTPCREL(%rip)" to "jmp foo; nop". // jmp doesn't return, so it is fine to use nop here, it is just a stub. assert(ModRm == 0x25); Loc[-2] = 0xe9; // jmp Loc[3] = 0x90; // nop write32le(Loc - 1, Val + 1); } +// This anonymous namespace works around a warning bug in +// old versions of gcc. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 namespace { + +// A split-stack prologue starts by checking the amount of stack remaining +// in one of two ways: +// A) Comparing of the stack pointer to a field in the tcb. +// B) Or a load of a stack pointer offset with an lea to r10 or r11. +template <> +bool X86_64::adjustPrologueForCrossSplitStack(uint8_t *Loc, + uint8_t *End) const { + // Replace "cmp %fs:0x70,%rsp" and subsequent branch + // with "stc, nopl 0x0(%rax,%rax,1)" + if (Loc + 8 < End && memcmp(Loc, "\x64\x48\x3b\x24\x25", 4) == 0) { + memcpy(Loc, "\xf9\x0f\x1f\x84\x00\x00\x00\x00", 8); + return true; + } + + // Adjust "lea -0x200(%rsp),%r10" to lea "-0x4200(%rsp),%r10" + if (Loc + 7 < End && memcmp(Loc, "\x4c\x8d\x94\x24\x00\xfe\xff", 7) == 0) { + memcpy(Loc, "\x4c\x8d\x94\x24\x00\xbe\xff", 7); + return true; + } + + // Adjust "lea -0x200(%rsp),%r11" to lea "-0x4200(%rsp),%r11" + if (Loc + 7 < End && memcmp(Loc, "\x4c\x8d\x9c\x24\x00\xfe\xff", 7) == 0) { + memcpy(Loc, "\x4c\x8d\x9c\x24\x00\xbe\xff", 7); + return true; + } + return false; +} + +template <> +bool X86_64::adjustPrologueForCrossSplitStack(uint8_t *Loc, + uint8_t *End) const { + llvm_unreachable("Target doesn't support split stacks."); +} + +} // namespace + +// These nonstandard PLT entries are to migtigate Spectre v2 security +// vulnerability. In order to mitigate Spectre v2, we want to avoid indirect +// branch instructions such as `jmp *GOTPLT(%rip)`. So, in the following PLT +// entries, we use a CALL followed by MOV and RET to do the same thing as an +// indirect jump. That instruction sequence is so-called "retpoline". +// +// We have two types of retpoline PLTs as a size optimization. If `-z now` +// is specified, all dynamic symbols are resolved at load-time. Thus, when +// that option is given, we can omit code for symbol lazy resolution. +namespace { template class Retpoline : public X86_64 { public: Retpoline(); void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; }; template class RetpolineZNow : public X86_64 { public: RetpolineZNow(); void writeGotPlt(uint8_t *Buf, const Symbol &S) const override {} void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; }; } // namespace template Retpoline::Retpoline() { TargetInfo::PltHeaderSize = 48; TargetInfo::PltEntrySize = 32; } template void Retpoline::writeGotPlt(uint8_t *Buf, const Symbol &S) const { - write32le(Buf, S.getPltVA() + 17); + write64le(Buf, S.getPltVA() + 17); } template void Retpoline::writePltHeader(uint8_t *Buf) const { const uint8_t Insn[] = { 0xff, 0x35, 0, 0, 0, 0, // 0: pushq GOTPLT+8(%rip) 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 6: mov GOTPLT+16(%rip), %r11 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: callq next 0xf3, 0x90, // 12: loop: pause 0x0f, 0xae, 0xe8, // 14: lfence 0xeb, 0xf9, // 17: jmp loop 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16 0x4c, 0x89, 0x1c, 0x24, // 20: next: mov %r11, (%rsp) 0xc3, // 24: ret + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 25: int3; padding + 0xcc, 0xcc, 0xcc, 0xcc, // 2c: int3; padding }; memcpy(Buf, Insn, sizeof(Insn)); uint64_t GotPlt = InX::GotPlt->getVA(); uint64_t Plt = InX::Plt->getVA(); write32le(Buf + 2, GotPlt - Plt - 6 + 8); write32le(Buf + 9, GotPlt - Plt - 13 + 16); } template void Retpoline::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Insn[] = { 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 0: mov foo@GOTPLT(%rip), %r11 - 0xe8, 0, 0, 0, 0, // 7: callq plt+0x20 - 0xe9, 0, 0, 0, 0, // c: jmp plt+0x12 - 0x68, 0, 0, 0, 0, // 11: pushq - 0xe9, 0, 0, 0, 0, // 16: jmp plt+0 + 0xe8, 0, 0, 0, 0, // 7: callq plt+0x20 + 0xe9, 0, 0, 0, 0, // c: jmp plt+0x12 + 0x68, 0, 0, 0, 0, // 11: pushq + 0xe9, 0, 0, 0, 0, // 16: jmp plt+0 + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1b: int3; padding }; memcpy(Buf, Insn, sizeof(Insn)); - uint64_t Off = TargetInfo::PltHeaderSize + TargetInfo::PltEntrySize * Index; + uint64_t Off = TargetInfo::getPltEntryOffset(Index); write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7); write32le(Buf + 8, -Off - 12 + 32); write32le(Buf + 13, -Off - 17 + 18); write32le(Buf + 18, Index); write32le(Buf + 23, -Off - 27); } template RetpolineZNow::RetpolineZNow() { TargetInfo::PltHeaderSize = 32; TargetInfo::PltEntrySize = 16; } template void RetpolineZNow::writePltHeader(uint8_t *Buf) const { const uint8_t Insn[] = { 0xe8, 0x0b, 0x00, 0x00, 0x00, // 0: call next 0xf3, 0x90, // 5: loop: pause 0x0f, 0xae, 0xe8, // 7: lfence 0xeb, 0xf9, // a: jmp loop 0xcc, 0xcc, 0xcc, 0xcc, // c: int3; .align 16 0x4c, 0x89, 0x1c, 0x24, // 10: next: mov %r11, (%rsp) 0xc3, // 14: ret + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 15: int3; padding + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding + 0xcc, // 1f: int3; padding }; memcpy(Buf, Insn, sizeof(Insn)); } template void RetpolineZNow::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Insn[] = { - 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // mov foo@GOTPLT(%rip), %r11 - 0xe9, 0, 0, 0, 0, // jmp plt+0 + 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // mov foo@GOTPLT(%rip), %r11 + 0xe9, 0, 0, 0, 0, // jmp plt+0 + 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding }; memcpy(Buf, Insn, sizeof(Insn)); write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7); - write32le(Buf + 8, - -Index * TargetInfo::PltEntrySize - TargetInfo::PltHeaderSize - 12); + write32le(Buf + 8, -TargetInfo::getPltEntryOffset(Index) - 12); } -template TargetInfo *getTargetInfo() { +template static TargetInfo *getTargetInfo() { if (Config->ZRetpolineplt) { if (Config->ZNow) { static RetpolineZNow T; return &T; } static Retpoline T; return &T; } static X86_64 T; return &T; } TargetInfo *elf::getX32TargetInfo() { return getTargetInfo(); } TargetInfo *elf::getX86_64TargetInfo() { return getTargetInfo(); } Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/Bits.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/Bits.h (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/Bits.h (revision 336982) Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/Bits.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/CMakeLists.txt =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/CMakeLists.txt (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/CMakeLists.txt (revision 336982) @@ -1,64 +1,66 @@ set(LLVM_TARGET_DEFINITIONS Options.td) tablegen(LLVM Options.inc -gen-opt-parser-defs) add_public_tablegen_target(ELFOptionsTableGen) if(NOT LLD_BUILT_STANDALONE) set(tablegen_deps intrinsics_gen) endif() add_lld_library(lldELF AArch64ErrataFix.cpp Arch/AArch64.cpp Arch/AMDGPU.cpp Arch/ARM.cpp Arch/AVR.cpp + Arch/Hexagon.cpp Arch/Mips.cpp Arch/MipsArchTree.cpp Arch/PPC.cpp Arch/PPC64.cpp Arch/SPARCV9.cpp Arch/X86.cpp Arch/X86_64.cpp + CallGraphSort.cpp Driver.cpp DriverUtils.cpp EhFrame.cpp Filesystem.cpp GdbIndex.cpp ICF.cpp InputFiles.cpp InputSection.cpp LTO.cpp LinkerScript.cpp MapFile.cpp MarkLive.cpp OutputSections.cpp Relocations.cpp ScriptLexer.cpp ScriptParser.cpp - Strings.cpp SymbolTable.cpp Symbols.cpp SyntheticSections.cpp Target.cpp Thunks.cpp Writer.cpp LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} BinaryFormat + BitWriter Core DebugInfoDWARF LTO MC Object Option Support LINK_LIBS lldCommon ${LLVM_PTHREAD_LIB} DEPENDS ELFOptionsTableGen ${tablegen_deps} ) Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/CMakeLists.txt ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/CallGraphSort.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/CallGraphSort.cpp (nonexistent) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/CallGraphSort.cpp (revision 336982) @@ -0,0 +1,249 @@ +//===- CallGraphSort.cpp --------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Implementation of Call-Chain Clustering from: Optimizing Function Placement +/// for Large-Scale Data-Center Applications +/// https://research.fb.com/wp-content/uploads/2017/01/cgo2017-hfsort-final1.pdf +/// +/// The goal of this algorithm is to improve runtime performance of the final +/// executable by arranging code sections such that page table and i-cache +/// misses are minimized. +/// +/// Definitions: +/// * Cluster +/// * An ordered list of input sections which are layed out as a unit. At the +/// beginning of the algorithm each input section has its own cluster and +/// the weight of the cluster is the sum of the weight of all incomming +/// edges. +/// * Call-Chain Clustering (C³) Heuristic +/// * Defines when and how clusters are combined. Pick the highest weighted +/// input section then add it to its most likely predecessor if it wouldn't +/// penalize it too much. +/// * Density +/// * The weight of the cluster divided by the size of the cluster. This is a +/// proxy for the ammount of execution time spent per byte of the cluster. +/// +/// It does so given a call graph profile by the following: +/// * Build a weighted call graph from the call graph profile +/// * Sort input sections by weight +/// * For each input section starting with the highest weight +/// * Find its most likely predecessor cluster +/// * Check if the combined cluster would be too large, or would have too low +/// a density. +/// * If not, then combine the clusters. +/// * Sort non-empty clusters by density +/// +//===----------------------------------------------------------------------===// + +#include "CallGraphSort.h" +#include "OutputSections.h" +#include "SymbolTable.h" +#include "Symbols.h" + +using namespace llvm; +using namespace lld; +using namespace lld::elf; + +namespace { +struct Edge { + int From; + uint64_t Weight; +}; + +struct Cluster { + Cluster(int Sec, size_t S) { + Sections.push_back(Sec); + Size = S; + } + + double getDensity() const { + if (Size == 0) + return 0; + return double(Weight) / double(Size); + } + + std::vector Sections; + size_t Size = 0; + uint64_t Weight = 0; + uint64_t InitialWeight = 0; + std::vector Preds; +}; + +class CallGraphSort { +public: + CallGraphSort(); + + DenseMap run(); + +private: + std::vector Clusters; + std::vector Sections; + + void groupClusters(); +}; + +// Maximum ammount the combined cluster density can be worse than the original +// cluster to consider merging. +constexpr int MAX_DENSITY_DEGRADATION = 8; + +// Maximum cluster size in bytes. +constexpr uint64_t MAX_CLUSTER_SIZE = 1024 * 1024; +} // end anonymous namespace + +// Take the edge list in Config->CallGraphProfile, resolve symbol names to +// Symbols, and generate a graph between InputSections with the provided +// weights. +CallGraphSort::CallGraphSort() { + llvm::MapVector, + uint64_t> &Profile = Config->CallGraphProfile; + DenseMap SecToCluster; + + auto GetOrCreateNode = [&](const InputSectionBase *IS) -> int { + auto Res = SecToCluster.insert(std::make_pair(IS, Clusters.size())); + if (Res.second) { + Sections.push_back(IS); + Clusters.emplace_back(Clusters.size(), IS->getSize()); + } + return Res.first->second; + }; + + // Create the graph. + for (const auto &C : Profile) { + const auto *FromSB = cast(C.first.first->Repl); + const auto *ToSB = cast(C.first.second->Repl); + uint64_t Weight = C.second; + + // Ignore edges between input sections belonging to different output + // sections. This is done because otherwise we would end up with clusters + // containing input sections that can't actually be placed adjacently in the + // output. This messes with the cluster size and density calculations. We + // would also end up moving input sections in other output sections without + // moving them closer to what calls them. + if (FromSB->getOutputSection() != ToSB->getOutputSection()) + continue; + + int From = GetOrCreateNode(FromSB); + int To = GetOrCreateNode(ToSB); + + Clusters[To].Weight += Weight; + + if (From == To) + continue; + + // Add an edge + Clusters[To].Preds.push_back({From, Weight}); + } + for (Cluster &C : Clusters) + C.InitialWeight = C.Weight; +} + +// It's bad to merge clusters which would degrade the density too much. +static bool isNewDensityBad(Cluster &A, Cluster &B) { + double NewDensity = double(A.Weight + B.Weight) / double(A.Size + B.Size); + if (NewDensity < A.getDensity() / MAX_DENSITY_DEGRADATION) + return true; + return false; +} + +static void mergeClusters(Cluster &Into, Cluster &From) { + Into.Sections.insert(Into.Sections.end(), From.Sections.begin(), + From.Sections.end()); + Into.Size += From.Size; + Into.Weight += From.Weight; + From.Sections.clear(); + From.Size = 0; + From.Weight = 0; +} + +// Group InputSections into clusters using the Call-Chain Clustering heuristic +// then sort the clusters by density. +void CallGraphSort::groupClusters() { + std::vector SortedSecs(Clusters.size()); + std::vector SecToCluster(Clusters.size()); + + for (int SI = 0, SE = Clusters.size(); SI != SE; ++SI) { + SortedSecs[SI] = SI; + SecToCluster[SI] = &Clusters[SI]; + } + + std::stable_sort(SortedSecs.begin(), SortedSecs.end(), [&](int A, int B) { + return Clusters[B].getDensity() < Clusters[A].getDensity(); + }); + + for (int SI : SortedSecs) { + // Clusters[SI] is the same as SecToClusters[SI] here because it has not + // been merged into another cluster yet. + Cluster &C = Clusters[SI]; + + int BestPred = -1; + uint64_t BestWeight = 0; + + for (Edge &E : C.Preds) { + if (BestPred == -1 || E.Weight > BestWeight) { + BestPred = E.From; + BestWeight = E.Weight; + } + } + + // don't consider merging if the edge is unlikely. + if (BestWeight * 10 <= C.InitialWeight) + continue; + + Cluster *PredC = SecToCluster[BestPred]; + if (PredC == &C) + continue; + + if (C.Size + PredC->Size > MAX_CLUSTER_SIZE) + continue; + + if (isNewDensityBad(*PredC, C)) + continue; + + // NOTE: Consider using a disjoint-set to track section -> cluster mapping + // if this is ever slow. + for (int SI : C.Sections) + SecToCluster[SI] = PredC; + + mergeClusters(*PredC, C); + } + + // Remove empty or dead nodes. Invalidates all cluster indices. + llvm::erase_if(Clusters, [](const Cluster &C) { + return C.Size == 0 || C.Sections.empty(); + }); + + // Sort by density. + std::stable_sort(Clusters.begin(), Clusters.end(), + [](const Cluster &A, const Cluster &B) { + return A.getDensity() > B.getDensity(); + }); +} + +DenseMap CallGraphSort::run() { + groupClusters(); + + // Generate order. + llvm::DenseMap OrderMap; + ssize_t CurOrder = 1; + + for (const Cluster &C : Clusters) + for (int SecIndex : C.Sections) + OrderMap[Sections[SecIndex]] = CurOrder++; + + return OrderMap; +} + +// Sort sections by the profile data provided by -callgraph-profile-file +// +// This first builds a call graph based on the profile data then merges sections +// according to the C³ huristic. All clusters are then sorted by a density +// metric to further improve locality. +DenseMap elf::computeCallGraphProfileOrder() { + return CallGraphSort().run(); +} Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/CallGraphSort.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/CallGraphSort.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/CallGraphSort.h (nonexistent) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/CallGraphSort.h (revision 336982) @@ -0,0 +1,23 @@ +//===- CallGraphSort.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_CALL_GRAPH_SORT_H +#define LLD_ELF_CALL_GRAPH_SORT_H + +#include "llvm/ADT/DenseMap.h" + +namespace lld { +namespace elf { +class InputSectionBase; + +llvm::DenseMap computeCallGraphProfileOrder(); +} // namespace elf +} // namespace lld + +#endif Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/CallGraphSort.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/Config.h =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/Config.h (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/Config.h (revision 336982) @@ -1,246 +1,279 @@ //===- 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 "lld/Common/ErrorHandler.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/CachePruning.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Endian.h" - #include namespace lld { namespace elf { class InputFile; +class InputSectionBase; 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 --icf={none,safe,all}. +enum class ICFLevel { None, Safe, All }; + // For --strip-{all,debug}. enum class StripPolicy { None, All, Debug }; // For --unresolved-symbols. enum class UnresolvedPolicy { ReportError, Warn, Ignore, IgnoreAll }; // For --orphan-handling. enum class OrphanHandlingPolicy { Place, Warn, Error }; // 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 { uint8_t OSABI = 0; llvm::CachePruningPolicy ThinLTOCachePolicy; llvm::StringMap SectionStartMap; llvm::StringRef Chroot; llvm::StringRef DynamicLinker; + llvm::StringRef DwoDir; llvm::StringRef Entry; llvm::StringRef Emulation; llvm::StringRef Fini; llvm::StringRef Init; llvm::StringRef LTOAAPipeline; llvm::StringRef LTONewPmPasses; + llvm::StringRef LTOObjPath; + llvm::StringRef LTOSampleProfile; llvm::StringRef MapFile; llvm::StringRef OutputFile; llvm::StringRef OptRemarksFilename; + llvm::StringRef ProgName; llvm::StringRef SoName; llvm::StringRef Sysroot; llvm::StringRef ThinLTOCacheDir; + llvm::StringRef ThinLTOIndexOnlyArg; + std::pair ThinLTOObjectSuffixReplace; + std::pair ThinLTOPrefixReplace; std::string Rpath; std::vector VersionDefinitions; - std::vector Argv; std::vector AuxiliaryList; std::vector FilterList; std::vector SearchPaths; std::vector SymbolOrderingFile; std::vector Undefined; std::vector DynamicList; std::vector VersionScriptGlobals; std::vector VersionScriptLocals; std::vector BuildIdVector; + llvm::MapVector, + uint64_t> + CallGraphProfile; bool AllowMultipleDefinition; - bool AndroidPackDynRelocs = false; + bool AndroidPackDynRelocs; bool ARMHasBlx = false; bool ARMHasMovtMovw = false; bool ARMJ1J2BranchEncoding = false; bool AsNeeded = false; bool Bsymbolic; bool BsymbolicFunctions; + bool CheckSections; bool CompressDebugSections; + bool Cref; bool DefineCommon; bool Demangle = true; bool DisableVerify; bool EhFrameHdr; bool EmitRelocs; bool EnableNewDtags; bool ExportDynamic; bool FixCortexA53Errata843419; bool GcSections; bool GdbIndex; bool GnuHash = false; + bool GnuUnique; bool HasDynamicList = false; bool HasDynSymTab; - bool ICF; - bool ICFData; + bool IgnoreDataAddressEquality; + bool IgnoreFunctionAddressEquality; + bool LTODebugPassManager; + bool LTONewPassManager; bool MergeArmExidx; bool MipsN32Abi = false; - bool NoGnuUnique; - bool NoUndefinedVersion; bool NoinhibitExec; bool Nostdlib; bool OFormatBinary; bool Omagic; bool OptRemarksWithHotness; bool Pie; bool PrintGcSections; + bool PrintIcfSections; bool Relocatable; + bool RelrPackDynRelocs; bool SaveTemps; bool SingleRoRx; bool Shared; bool Static = false; bool SysvHash = false; bool Target1Rel; bool Trace; - bool Verbose; + bool ThinLTOEmitImportsFiles; + bool ThinLTOIndexOnly; + bool UndefinedVersion; + bool UseAndroidRelrTags = false; + bool WarnBackrefs; bool WarnCommon; bool WarnMissingEntry; + bool WarnSymbolOrdering; + bool WriteAddends; bool ZCombreloc; + bool ZCopyreloc; bool ZExecstack; bool ZHazardplt; - bool ZNocopyreloc; + bool ZInitfirst; + bool ZKeepTextSectionPrefix; bool ZNodelete; bool ZNodlopen; bool ZNow; bool ZOrigin; bool ZRelro; bool ZRodynamic; bool ZText; bool ZRetpolineplt; - bool ExitEarly; bool ZWxneeded; DiscardPolicy Discard; + ICFLevel ICF; OrphanHandlingPolicy OrphanHandling; 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; llvm::Optional ImageBase; uint64_t MaxPageSize; + uint64_t MipsGotSize; 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; // Holds set of ELF header flags for the target. uint32_t EFlags = 0; // 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; +static inline void errorOrWarn(const Twine &Msg) { + if (!Config->NoinhibitExec) + error(Msg); + else + warn(Msg); +} } // namespace elf } // namespace lld #endif Property changes on: projects/clang700-import/contrib/llvm/tools/lld/ELF/Config.h ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: projects/clang700-import/contrib/llvm/tools/lld/ELF/Driver.cpp =================================================================== --- projects/clang700-import/contrib/llvm/tools/lld/ELF/Driver.cpp (revision 336981) +++ projects/clang700-import/contrib/llvm/tools/lld/ELF/Driver.cpp (revision 336982) @@ -1,1134 +1,1490 @@ //===- 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 "Filesystem.h" #include "ICF.h" #include "InputFiles.h" #include "InputSection.h" #include "LinkerScript.h" +#include "MarkLive.h" #include "OutputSections.h" #include "ScriptParser.h" -#include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Writer.h" #include "lld/Common/Args.h" #include "lld/Common/Driver.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" +#include "lld/Common/TargetOptionsCommandFlags.h" #include "lld/Common/Threads.h" #include "lld/Common/Version.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" +#include "llvm/Support/LEB128.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; -static void setConfigs(); +static void setConfigs(opt::InputArgList &Args); bool elf::link(ArrayRef Args, bool CanExitEarly, raw_ostream &Error) { - errorHandler().LogName = Args[0]; + errorHandler().LogName = sys::path::filename(Args[0]); errorHandler().ErrorLimitExceededMsg = "too many errors emitted, stopping now (use " "-error-limit=0 to see all errors)"; errorHandler().ErrorOS = &Error; + errorHandler().ExitEarly = CanExitEarly; errorHandler().ColorDiagnostics = Error.has_colors(); + InputSections.clear(); OutputSections.clear(); Tar = nullptr; BinaryFiles.clear(); BitcodeFiles.clear(); ObjectFiles.clear(); SharedFiles.clear(); Config = make(); Driver = make(); Script = make(); Symtab = make(); - Config->Argv = {Args.begin(), Args.end()}; + Config->ProgName = Args[0]; - Driver->main(Args, CanExitEarly); + Driver->main(Args); // Exit immediately if we don't need to return to the caller. // This saves time because the overhead of calling destructors // for all globally-allocated objects is not negligible. - if (Config->ExitEarly) + if (CanExitEarly) exitLld(errorCount() ? 1 : 0); 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}) + .Cases("aarch64elf", "aarch64linux", "aarch64_elf64_le_vec", + {ELF64LEKind, EM_AARCH64}) .Cases("armelf", "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}) + .Case("elf64lppc", {ELF64LEKind, 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) 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::unique_ptr File = CHECK(Archive::create(MB), MB.getBufferIdentifier() + ": failed to parse archive"); std::vector> V; Error Err = Error::success(); bool AddToTar = File->isThin() && Tar; 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"); if (AddToTar) Tar->append(relativeToRoot(check(C.getFullName())), MBRef.getBuffer()); 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 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: { // Handle -whole-archive. if (InWholeArchive) { for (const auto &P : getArchiveMembers(MBRef)) Files.push_back(createObjectFile(P.first, Path, P.second)); return; } 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->isEmpty() && !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 ? path::filename(Path) : Path)); return; - default: + case file_magic::bitcode: + case file_magic::elf_relocatable: if (InLib) Files.push_back(make(MBRef, "", 0)); else Files.push_back(createObjectFile(MBRef)); + break; + default: + error(Path + ": unknown file type"); } } // 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) { +static void initLLVM() { 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->FixCortexA53Errata843419 && Config->EMachine != EM_AARCH64) error("--fix-cortex-a53-843419 is only supported on AArch64 targets."); if (Config->Pie && Config->Shared) error("-shared and -pie may not be used together"); if (!Config->Shared && !Config->FilterList.empty()) error("-F may not be used without -shared"); if (!Config->Shared && !Config->AuxiliaryList.empty()) error("-f may not be used without -shared"); if (!Config->Relocatable && !Config->DefineCommon) error("-no-define-common not supported in non relocatable output"); 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) + if (Config->GdbIndex) + error("-r and --gdb-index may not be used together"); + if (Config->ICF != ICFLevel::None) error("-r and --icf may not be used together"); if (Config->Pie) error("-r and -pie may not be used together"); } } 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; } -void LinkerDriver::main(ArrayRef ArgsArr, bool CanExitEarly) { +static bool getZFlag(opt::InputArgList &Args, StringRef K1, StringRef K2, + bool Default) { + for (auto *Arg : Args.filtered_reverse(OPT_z)) { + if (K1 == Arg->getValue()) + return true; + if (K2 == Arg->getValue()) + return false; + } + return Default; +} + +static bool isKnown(StringRef S) { + return S == "combreloc" || S == "copyreloc" || S == "defs" || + S == "execstack" || S == "hazardplt" || S == "initfirst" || + S == "keep-text-section-prefix" || S == "lazy" || S == "muldefs" || + S == "nocombreloc" || S == "nocopyreloc" || S == "nodelete" || + S == "nodlopen" || S == "noexecstack" || + S == "nokeep-text-section-prefix" || S == "norelro" || S == "notext" || + S == "now" || S == "origin" || S == "relro" || S == "retpolineplt" || + S == "rodynamic" || S == "text" || S == "wxneeded" || + S.startswith("max-page-size=") || S.startswith("stack-size="); +} + +// Report an error for an unknown -z option. +static void checkZOptions(opt::InputArgList &Args) { + for (auto *Arg : Args.filtered(OPT_z)) + if (!isKnown(Arg->getValue())) + error("unknown -z value: " + StringRef(Arg->getValue())); +} + +void LinkerDriver::main(ArrayRef ArgsArr) { ELFOptTable Parser; opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); // Interpret this flag early because error() depends on them. errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20); // Handle -help if (Args.hasArg(OPT_help)) { - printHelp(ArgsArr[0]); + printHelp(); 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)"); // The behavior of -v or --version is a bit strange, but this is // needed for compatibility with GNU linkers. if (Args.hasArg(OPT_v) && !Args.hasArg(OPT_INPUT)) return; if (Args.hasArg(OPT_version)) return; - Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown); - errorHandler().ExitEarly = Config->ExitEarly; - 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); + checkZOptions(Args); + initLLVM(); createFiles(Args); + if (errorCount()) + return; + inferMachineType(); - setConfigs(); + setConfigs(Args); 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 std::string getRpath(opt::InputArgList &Args) { std::vector V = args::getStrings(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) { if (Args.hasArg(OPT_relocatable)) return UnresolvedPolicy::IgnoreAll; UnresolvedPolicy ErrorOrWarn = Args.hasFlag(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 = Args.getLastArgValue(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 ICFLevel getICF(opt::InputArgList &Args) { + auto *Arg = Args.getLastArg(OPT_icf_none, OPT_icf_safe, OPT_icf_all); + if (!Arg || Arg->getOption().getID() == OPT_icf_none) + return ICFLevel::None; + if (Arg->getOption().getID() == OPT_icf_safe) + return ICFLevel::Safe; + return ICFLevel::All; +} + 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, const opt::Arg &Arg) { uint64_t VA = 0; if (S.startswith("0x")) S = S.drop_front(2); if (!to_integer(S, VA, 16)) 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 = Args.getLastArgValue(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 OrphanHandlingPolicy getOrphanHandling(opt::InputArgList &Args) { StringRef S = Args.getLastArgValue(OPT_orphan_handling, "place"); if (S == "warn") return OrphanHandlingPolicy::Warn; if (S == "error") return OrphanHandlingPolicy::Error; if (S != "place") error("unknown --orphan-handling mode: " + S); return OrphanHandlingPolicy::Place; } // Parse --build-id or --build-id=