Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/Chunks.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/Chunks.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/Chunks.cpp (revision 343217) @@ -1,644 +1,863 @@ //===- 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 "SymbolTable.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)) { // 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(); } +// Initialize the RelocTargets vector, to allow redirecting certain relocations +// to a thunk instead of the actual symbol the relocation's symbol table index +// indicates. +void SectionChunk::readRelocTargets() { + assert(RelocTargets.empty()); + RelocTargets.reserve(Relocs.size()); + for (const coff_relocation &Rel : Relocs) + RelocTargets.push_back(File->getSymbol(Rel.SymbolTableIndex)); +} + +// Reset RelocTargets to their original targets before thunks were added. +void SectionChunk::resetRelocTargets() { + for (size_t I = 0, E = Relocs.size(); I < E; ++I) + RelocTargets[I] = File->getSymbol(Relocs[I].SymbolTableIndex); +} + 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"); + error("SECREL relocation cannot be applied to absolute symbols"); + return false; } static void applySecRel(const SectionChunk *Sec, uint8_t *Off, OutputSection *OS, uint64_t S) { 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) { // 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) + " in " + + error("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) + " in " + + error("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) { +static uint16_t readMOV(uint8_t *Off, bool MOVT) { uint16_t Op1 = read16le(Off); + if ((Op1 & 0xfbf0) != (MOVT ? 0xf2c0 : 0xf240)) + error("unexpected instruction in " + Twine(MOVT ? "MOVT" : "MOVW") + + " instruction in MOV32T relocation"); uint16_t Op2 = read16le(Off + 2); + if ((Op2 & 0x8000) != 0) + error("unexpected instruction in " + Twine(MOVT ? "MOVT" : "MOVW") + + " instruction in MOV32T relocation"); 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 + uint16_t ImmW = readMOV(Off, false); // read MOVW operand + uint16_t ImmT = readMOV(Off + 4, true); // 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"); + error("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"); + error("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->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) + " in " + + error("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, int Shift) { +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 >> 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) { +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"); + error("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) { +void applyArm64Branch26(uint8_t *Off, int64_t V) { if (!isInt<28>(V)) - fatal("relocation out of range"); + error("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"); + error("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"); + error("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, 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: 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) + " in " + + error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + toString(File)); } } +static void maybeReportRelocationToDiscarded(const SectionChunk *FromChunk, + Defined *Sym, + const coff_relocation &Rel) { + // Don't report these errors when the relocation comes from a debug info + // section or in mingw mode. MinGW mode object files (built by GCC) can + // have leftover sections with relocations against discarded comdat + // sections. Such sections are left as is, with relocations untouched. + if (FromChunk->isCodeView() || FromChunk->isDWARF() || Config->MinGW) + return; + + // Get the name of the symbol. If it's null, it was discarded early, so we + // have to go back to the object file. + ObjFile *File = FromChunk->File; + StringRef Name; + if (Sym) { + Name = Sym->getName(); + } else { + COFFSymbolRef COFFSym = + check(File->getCOFFObj()->getSymbol(Rel.SymbolTableIndex)); + File->getCOFFObj()->getSymbolName(COFFSym, Name); + } + + error("relocation against symbol in discarded section: " + Name + + getSymbolLocations(File, Rel.SymbolTableIndex)); +} + void SectionChunk::writeTo(uint8_t *Buf) const { if (!hasData()) return; // Copy section contents from source object file to output file. ArrayRef A = getContents(); if (!A.empty()) memcpy(Buf + OutputSectionOff, A.data(), A.size()); // Apply relocations. size_t InputSize = getSize(); - for (const coff_relocation &Rel : Relocs) { + for (size_t I = 0, E = Relocs.size(); I < E; I++) { + const coff_relocation &Rel = Relocs[I]; + // 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"); + if (Rel.VirtualAddress >= InputSize) { + error("relocation points beyond the end of its parent section"); + continue; + } uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress; + // Use the potentially remapped Symbol instead of the one that the + // relocation points to. + auto *Sym = dyn_cast_or_null(RelocTargets[I]); + // 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(); + Chunk *C = Sym ? Sym->getChunk() : nullptr; 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()); + // Skip the relocation if it refers to a discarded section, and diagnose it + // as an error if appropriate. If a symbol was discarded early, it may be + // null. If it was discarded late, the output section will be null, unless + // it was an absolute or synthetic symbol. + if (!Sym || + (!OS && !isa(Sym) && !isa(Sym))) { + maybeReportRelocationToDiscarded(this, Sym, Rel); + continue; } + 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) { + for (size_t I = 0, E = Relocs.size(); I < E; I++) { + const coff_relocation &Rel = Relocs[I]; uint8_t Ty = getBaserelType(Rel); if (Ty == IMAGE_REL_BASED_ABSOLUTE) continue; - Symbol *Target = File->getSymbol(Rel.SymbolTableIndex); + // Use the potentially remapped Symbol instead of the one that the + // relocation points to. + Symbol *Target = RelocTargets[I]; if (!Target || isa(Target)) continue; Res->emplace_back(RVA + Rel.VirtualAddress, Ty); } } +// MinGW specific. +// Check whether a static relocation of type Type can be deferred and +// handled at runtime as a pseudo relocation (for references to a module +// local variable, which turned out to actually need to be imported from +// another DLL) This returns the size the relocation is supposed to update, +// in bits, or 0 if the relocation cannot be handled as a runtime pseudo +// relocation. +static int getRuntimePseudoRelocSize(uint16_t Type) { + // Relocations that either contain an absolute address, or a plain + // relative offset, since the runtime pseudo reloc implementation + // adds 8/16/32/64 bit values to a memory address. + // + // Given a pseudo relocation entry, + // + // typedef struct { + // DWORD sym; + // DWORD target; + // DWORD flags; + // } runtime_pseudo_reloc_item_v2; + // + // the runtime relocation performs this adjustment: + // *(base + .target) += *(base + .sym) - (base + .sym) + // + // This works for both absolute addresses (IMAGE_REL_*_ADDR32/64, + // IMAGE_REL_I386_DIR32, where the memory location initially contains + // the address of the IAT slot, and for relative addresses (IMAGE_REL*_REL32), + // where the memory location originally contains the relative offset to the + // IAT slot. + // + // This requires the target address to be writable, either directly out of + // the image, or temporarily changed at runtime with VirtualProtect. + // Since this only operates on direct address values, it doesn't work for + // ARM/ARM64 relocations, other than the plain ADDR32/ADDR64 relocations. + switch (Config->Machine) { + case AMD64: + switch (Type) { + case IMAGE_REL_AMD64_ADDR64: + return 64; + case IMAGE_REL_AMD64_ADDR32: + case IMAGE_REL_AMD64_REL32: + case IMAGE_REL_AMD64_REL32_1: + case IMAGE_REL_AMD64_REL32_2: + case IMAGE_REL_AMD64_REL32_3: + case IMAGE_REL_AMD64_REL32_4: + case IMAGE_REL_AMD64_REL32_5: + return 32; + default: + return 0; + } + case I386: + switch (Type) { + case IMAGE_REL_I386_DIR32: + case IMAGE_REL_I386_REL32: + return 32; + default: + return 0; + } + case ARMNT: + switch (Type) { + case IMAGE_REL_ARM_ADDR32: + return 32; + default: + return 0; + } + case ARM64: + switch (Type) { + case IMAGE_REL_ARM64_ADDR64: + return 64; + case IMAGE_REL_ARM64_ADDR32: + return 32; + default: + return 0; + } + default: + llvm_unreachable("unknown machine type"); + } +} + +// MinGW specific. +// Append information to the provided vector about all relocations that +// need to be handled at runtime as runtime pseudo relocations (references +// to a module local variable, which turned out to actually need to be +// imported from another DLL). +void SectionChunk::getRuntimePseudoRelocs( + std::vector &Res) { + for (const coff_relocation &Rel : Relocs) { + auto *Target = + dyn_cast_or_null(File->getSymbol(Rel.SymbolTableIndex)); + if (!Target || !Target->IsRuntimePseudoReloc) + continue; + int SizeInBits = getRuntimePseudoRelocSize(Rel.Type); + if (SizeInBits == 0) { + error("unable to automatically import from " + Target->getName() + + " with relocation type " + + File->getCOFFObj()->getRelocationTypeName(Rel.Type) + " in " + + toString(File)); + continue; + } + // SizeInBits is used to initialize the Flags field; currently no + // other flags are defined. + Res.emplace_back( + RuntimePseudoReloc(Target, this, Rel.VirtualAddress, SizeInBits)); + } +} + bool SectionChunk::hasData() const { return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA); } 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; } +uint32_t SectionChunk::getSectionNumber() const { + DataRefImpl R; + R.p = reinterpret_cast(Header); + SectionRef S(R, File->getCOFFObj()); + return S.getIndex() + 1; +} + 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::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()); + Buf[OutputSectionOff + Str.size()] = '\0'; } 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, 12); applyArm64Ldr(Buf + OutputSectionOff + 4, Off); } +// A Thumb2, PIC, non-interworking range extension thunk. +const uint8_t ArmThunk[] = { + 0x40, 0xf2, 0x00, 0x0c, // P: movw ip,:lower16:S - (P + (L1-P) + 4) + 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4) + 0xe7, 0x44, // L1: add pc, ip +}; + +size_t RangeExtensionThunk::getSize() const { + assert(Config->Machine == ARMNT); + return sizeof(ArmThunk); +} + +void RangeExtensionThunk::writeTo(uint8_t *Buf) const { + assert(Config->Machine == ARMNT); + uint64_t Offset = Target->getRVA() - RVA - 12; + memcpy(Buf + OutputSectionOff, ArmThunk, sizeof(ArmThunk)); + applyMOV32T(Buf + OutputSectionOff, uint32_t(Offset)); +} + void LocalImportChunk::getBaserels(std::vector *Res) { Res->emplace_back(getRVA()); } -size_t LocalImportChunk::getSize() const { - return Config->is64() ? 8 : 4; -} +size_t LocalImportChunk::getSize() const { return Config->Wordsize; } 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 RVATableChunk::writeTo(uint8_t *Buf) const { ulittle32_t *Begin = reinterpret_cast(Buf + OutputSectionOff); size_t Cnt = 0; 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"); } +// MinGW specific, for the "automatic import of variables from DLLs" feature. +size_t PseudoRelocTableChunk::getSize() const { + if (Relocs.empty()) + return 0; + return 12 + 12 * Relocs.size(); +} + +// MinGW specific. +void PseudoRelocTableChunk::writeTo(uint8_t *Buf) const { + if (Relocs.empty()) + return; + + ulittle32_t *Table = reinterpret_cast(Buf + OutputSectionOff); + // This is the list header, to signal the runtime pseudo relocation v2 + // format. + Table[0] = 0; + Table[1] = 0; + Table[2] = 1; + + size_t Idx = 3; + for (const RuntimePseudoReloc &RPR : Relocs) { + Table[Idx + 0] = RPR.Sym->getRVA(); + Table[Idx + 1] = RPR.Target->getRVA() + RPR.TargetOffset; + Table[Idx + 2] = RPR.Flags; + Idx += 3; + } +} + // 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(); + if (!Finalized) { + for (SectionChunk *C : Sections) + if (C->Live) + Builder.add(toStringRef(C->getContents())); + Builder.finalize(); + Finalized = true; + } for (SectionChunk *C : Sections) { - if (!C->isLive()) + if (!C->Live) 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); +} + +// MinGW specific. +size_t AbsolutePointerChunk::getSize() const { return Config->Wordsize; } + +void AbsolutePointerChunk::writeTo(uint8_t *Buf) const { + if (Config->is64()) { + write64le(Buf + OutputSectionOff, Value); + } else { + write32le(Buf + OutputSectionOff, Value); + } } } // namespace coff } // namespace lld Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/Chunks.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/Chunks.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/Chunks.h (revision 343217) @@ -1,431 +1,518 @@ //===- 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 RuntimePseudoReloc; class Symbol; // 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 once before assigning addresses and writing + // the output. + virtual void readRelocTargets() {} + + // Called if restarting thunk addition. + virtual void resetRelocTargets() {} + // 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 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; + + // Whether this section needs to be kept distinct from other sections during + // ICF. This is set by the driver using address-significance tables. + bool KeepUnique = false; }; // 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; } + void readRelocTargets() override; + void resetRelocTargets() override; size_t getSize() const override { return Header->SizeOfRawData; } ArrayRef getContents() const; void writeTo(uint8_t *Buf) const override; bool hasData() 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; + void getRuntimePseudoRelocs(std::vector &Res); + // 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; } + // The section ID this chunk belongs to in its Obj. + uint32_t getSectionNumber() const; + // A pointer pointing to a replacement for this chunk. // Initially it points to "this" object. If this chunk is merged // with other chunk by ICF, it points to another chunk, - // and this chunk is considrered as dead. + // and this chunk is considered 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; + // Used by the garbage collector. + bool Live; + + // When inserting a thunk, we need to adjust a relocation to point to + // the thunk instead of the actual original target Symbol. + std::vector RelocTargets; + private: StringRef SectionName; std::vector AssocChildren; - // 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; + bool Finalized = false; }; // 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 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 +// A chunk for DLL import jump table entry. In a final output, its // 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; }; +class RangeExtensionThunk : public Chunk { +public: + explicit RangeExtensionThunk(Defined *T) : Target(T) {} + size_t getSize() const override; + void writeTo(uint8_t *Buf) const override; + + Defined *Target; +}; + // Windows-specific. // See comments for DefinedLocalImport class. class LocalImportChunk : public Chunk { public: explicit LocalImportChunk(Defined *S) : Sym(S) { - Alignment = Config->is64() ? 8 : 4; + Alignment = Config->Wordsize; } size_t getSize() const override; void getBaserels(std::vector *Res) override; void writeTo(uint8_t *Buf) const override; private: Defined *Sym; }; // 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 RVATableChunk(SymbolRVASet S) : Syms(std::move(S)) {} size_t getSize() const override { return Syms.size() * 4; } void writeTo(uint8_t *Buf) const override; private: 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; }; +// This is a placeholder Chunk, to allow attaching a DefinedSynthetic to a +// specific place in a section, without any data. This is used for the MinGW +// specific symbol __RUNTIME_PSEUDO_RELOC_LIST_END__, even though the concept +// of an empty chunk isn't MinGW specific. +class EmptyChunk : public Chunk { +public: + EmptyChunk() {} + size_t getSize() const override { return 0; } + void writeTo(uint8_t *Buf) const override {} +}; + +// MinGW specific, for the "automatic import of variables from DLLs" feature. +// This provides the table of runtime pseudo relocations, for variable +// references that turned out to need to be imported from a DLL even though +// the reference didn't use the dllimport attribute. The MinGW runtime will +// process this table after loading, before handling control over to user +// code. +class PseudoRelocTableChunk : public Chunk { +public: + PseudoRelocTableChunk(std::vector &Relocs) + : Relocs(std::move(Relocs)) { + Alignment = 4; + } + size_t getSize() const override; + void writeTo(uint8_t *Buf) const override; + +private: + std::vector Relocs; +}; + +// MinGW specific; information about one individual location in the image +// that needs to be fixed up at runtime after loading. This represents +// one individual element in the PseudoRelocTableChunk table. +class RuntimePseudoReloc { +public: + RuntimePseudoReloc(Defined *Sym, SectionChunk *Target, uint32_t TargetOffset, + int Flags) + : Sym(Sym), Target(Target), TargetOffset(TargetOffset), Flags(Flags) {} + + Defined *Sym; + SectionChunk *Target; + uint32_t TargetOffset; + // The Flags field contains the size of the relocation, in bits. No other + // flags are currently defined. + int Flags; +}; + +// MinGW specific. A Chunk that contains one pointer-sized absolute value. +class AbsolutePointerChunk : public Chunk { +public: + AbsolutePointerChunk(uint64_t Value) : Value(Value) { + Alignment = getSize(); + } + size_t getSize() const override; + void writeTo(uint8_t *Buf) const override; + +private: + uint64_t Value; +}; + void applyMOV32T(uint8_t *Off, uint32_t V); void applyBranch24T(uint8_t *Off, int32_t V); + +void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift); +void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit); +void applyArm64Branch26(uint8_t *Off, int64_t V); } // namespace coff } // namespace lld namespace llvm { template <> struct DenseMapInfo : lld::coff::ChunkAndOffset::DenseMapInfo {}; } #endif Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/Config.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/Config.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/Config.h (revision 343217) @@ -1,209 +1,212 @@ //===- 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; + size_t Wordsize; 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 ForceMultiple = false; + bool ForceUnresolved = 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 LTOO = 2; // Used for /opt:lldltojobs=N 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; 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 WarnDebugInfoUnusable = true; bool Incremental = true; bool IntegrityCheck = false; bool KillAt = false; bool Repro = false; }; extern Configuration *Config; } // namespace coff } // namespace lld #endif Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/DLL.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/DLL.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/DLL.cpp (revision 343217) @@ -1,597 +1,631 @@ //===- 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 "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(); } + explicit LookupChunk(Chunk *C) : HintName(C) { Alignment = Config->Wordsize; } + size_t getSize() const override { return Config->Wordsize; } 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(); } + explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) { + Alignment = Config->Wordsize; + } + size_t getSize() const override { return Config->Wordsize; } 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 }; +static const uint8_t ThunkARM64[] = { + 0x11, 0x00, 0x00, 0x90, // adrp x17, #0 __imp_ + 0x31, 0x02, 0x00, 0x91, // add x17, x17, #0 :lo12:__imp_ + 0xfd, 0x7b, 0xb3, 0xa9, // stp x29, x30, [sp, #-208]! + 0xfd, 0x03, 0x00, 0x91, // mov x29, sp + 0xe0, 0x07, 0x01, 0xa9, // stp x0, x1, [sp, #16] + 0xe2, 0x0f, 0x02, 0xa9, // stp x2, x3, [sp, #32] + 0xe4, 0x17, 0x03, 0xa9, // stp x4, x5, [sp, #48] + 0xe6, 0x1f, 0x04, 0xa9, // stp x6, x7, [sp, #64] + 0xe0, 0x87, 0x02, 0xad, // stp q0, q1, [sp, #80] + 0xe2, 0x8f, 0x03, 0xad, // stp q2, q3, [sp, #112] + 0xe4, 0x97, 0x04, 0xad, // stp q4, q5, [sp, #144] + 0xe6, 0x9f, 0x05, 0xad, // stp q6, q7, [sp, #176] + 0xe1, 0x03, 0x11, 0xaa, // mov x1, x17 + 0x00, 0x00, 0x00, 0x90, // adrp x0, #0 DELAY_IMPORT_DESCRIPTOR + 0x00, 0x00, 0x00, 0x91, // add x0, x0, #0 :lo12:DELAY_IMPORT_DESCRIPTOR + 0x00, 0x00, 0x00, 0x94, // bl #0 __delayLoadHelper2 + 0xf0, 0x03, 0x00, 0xaa, // mov x16, x0 + 0xe6, 0x9f, 0x45, 0xad, // ldp q6, q7, [sp, #176] + 0xe4, 0x97, 0x44, 0xad, // ldp q4, q5, [sp, #144] + 0xe2, 0x8f, 0x43, 0xad, // ldp q2, q3, [sp, #112] + 0xe0, 0x87, 0x42, 0xad, // ldp q0, q1, [sp, #80] + 0xe6, 0x1f, 0x44, 0xa9, // ldp x6, x7, [sp, #64] + 0xe4, 0x17, 0x43, 0xa9, // ldp x4, x5, [sp, #48] + 0xe2, 0x0f, 0x42, 0xa9, // ldp x2, x3, [sp, #32] + 0xe0, 0x07, 0x41, 0xa9, // ldp x0, x1, [sp, #16] + 0xfd, 0x7b, 0xcd, 0xa8, // ldp x29, x30, [sp], #208 + 0x00, 0x02, 0x1f, 0xd6, // br x16 +}; + // 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; }; +class ThunkChunkARM64 : public Chunk { +public: + ThunkChunkARM64(Defined *I, Chunk *D, Defined *H) + : Imp(I), Desc(D), Helper(H) {} + + size_t getSize() const override { return sizeof(ThunkARM64); } + + void writeTo(uint8_t *Buf) const override { + memcpy(Buf + OutputSectionOff, ThunkARM64, sizeof(ThunkARM64)); + applyArm64Addr(Buf + OutputSectionOff + 0, Imp->getRVA(), RVA + 0, 12); + applyArm64Imm(Buf + OutputSectionOff + 4, Imp->getRVA() & 0xfff, 0); + applyArm64Addr(Buf + OutputSectionOff + 52, Desc->getRVA(), RVA + 52, 12); + applyArm64Imm(Buf + OutputSectionOff + 56, Desc->getRVA() & 0xfff, 0); + applyArm64Branch26(Buf + OutputSectionOff + 60, + Helper->getRVA() - RVA - 60); + } + + 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(); } + explicit DelayAddressChunk(Chunk *C) : Thunk(C) { + Alignment = Config->Wordsize; + } + size_t getSize() const override { return Config->Wordsize; } 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 { + memset(Buf + OutputSectionOff, 0, getSize()); + 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())); + Lookups.push_back(make(Config->Wordsize)); + Addresses.push_back(make(Config->Wordsize)); 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); + case ARM64: + 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 Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/DLL.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/DLL.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/DLL.h (revision 343217) @@ -1,89 +1,82 @@ //===- 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. +// call create() to populate the chunk vectors. 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 Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/Driver.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/Driver.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/Driver.cpp (revision 343217) @@ -1,1590 +1,1681 @@ //===- 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/LEB128.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 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 = sys::path::filename(Args[0]); + errorHandler().LogName = args::getFilenameWithoutExe(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)"; errorHandler().ExitEarly = CanExitEarly; Config = make(); 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 _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, /*FileSize*/ -1, /*RequiresNullTerminator*/ false); if (!MBOrErr) return MBErrPair{nullptr, MBOrErr.getError()}; return MBErrPair{std::move(*MBOrErr), std::error_code()}; }); } // Symbol names are mangled by prepending "_" on x86. static StringRef mangle(StringRef Sym) { assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN); if (Config->Machine == I386) return Saver.save("_" + Sym); return Sym; } static bool findUnderscoreMangle(StringRef Sym) { StringRef Entry = Symtab->findMangle(mangle(Sym)); return !Entry.empty() && !isa(Symtab->find(Entry)); } 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(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), Filename + ": failed to parse archive"); for (MemoryBufferRef M : getArchiveMembers(File.get())) 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(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: 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. // /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_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); 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; } +// MinGW specific. If an embedded directive specified to link to +// foo.lib, but it isn't found, try libfoo.a instead. +StringRef LinkerDriver::doFindLibMinGW(StringRef Filename) { + if (Filename.contains('/') || Filename.contains('\\')) + return Filename; + + SmallString<128> S = Filename; + sys::path::replace_extension(S, ".a"); + StringRef LibName = Saver.save("lib" + S.str()); + return doFindFile(LibName); +} + // 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); + StringRef Ret = doFindFile(Filename); + // For MinGW, if the find above didn't turn up anything, try + // looking for a MinGW formatted library name. + if (Config->MinGW && Ret == Filename) + return doFindLibMinGW(Filename); + return Ret; } // 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 (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; } // 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() { assert(Config->Subsystem != IMAGE_SUBSYSTEM_UNKNOWN && "must handle /subsystem before calling this"); - // 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". - bool FindMain = !Config->NoDefaultLibAll; + if (Config->MinGW) + return mangle(Config->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI + ? "WinMainCRTStartup" + : "mainCRTStartup"); + if (Config->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) { - if (findUnderscoreMangle(FindMain ? "WinMain" : "WinMainCRTStartup")) - return mangle("WinMainCRTStartup"); - if (findUnderscoreMangle(FindMain ? "wWinMain" : "wWinMainCRTStartup")) - return mangle("wWinMainCRTStartup"); + if (findUnderscoreMangle("wWinMain")) { + if (!findUnderscoreMangle("WinMain")) + return mangle("wWinMainCRTStartup"); + warn("found both wWinMain and WinMain; using latter"); + } + return mangle("WinMainCRTStartup"); } - if (findUnderscoreMangle(FindMain ? "main" : "mainCRTStartup")) - return mangle("mainCRTStartup"); - if (findUnderscoreMangle(FindMain ? "wmain" : "wmainCRTStartup")) - return mangle("wmainCRTStartup"); - return ""; + if (findUnderscoreMangle("wmain")) { + if (!findUnderscoreMangle("main")) + return mangle("wmainCRTStartup"); + warn("found both wmain and main; using latter"); + } + return mangle("mainCRTStartup"); } WindowsSubsystem LinkerDriver::inferSubsystem() { if (Config->DLL) return IMAGE_SUBSYSTEM_WINDOWS_GUI; - if (findUnderscoreMangle("main") || findUnderscoreMangle("wmain")) + if (Config->MinGW) return IMAGE_SUBSYSTEM_WINDOWS_CUI; - if (findUnderscoreMangle("WinMain") || findUnderscoreMangle("wWinMain")) + // Note that link.exe infers the subsystem from the presence of these + // functions even if /entry: or /nodefaultlib are passed which causes them + // to not be called. + bool HaveMain = findUnderscoreMangle("main"); + bool HaveWMain = findUnderscoreMangle("wmain"); + bool HaveWinMain = findUnderscoreMangle("WinMain"); + bool HaveWWinMain = findUnderscoreMangle("wWinMain"); + if (HaveMain || HaveWMain) { + if (HaveWinMain || HaveWWinMain) { + warn(std::string("found ") + (HaveMain ? "main" : "wmain") + " and " + + (HaveWinMain ? "WinMain" : "wWinMain") + + "; defaulting to /subsystem:console"); + } + return IMAGE_SUBSYSTEM_WINDOWS_CUI; + } + if (HaveWinMain || HaveWWinMain) 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); +enum class DebugKind { Unknown, None, Full, FastLink, GHash, Dwarf, Symtab }; + +static DebugKind parseDebugKind(const opt::InputArgList &Args) { + auto *A = Args.getLastArg(OPT_debug, OPT_debug_opt); + if (!A) + return DebugKind::None; + if (A->getNumValues() == 0) + return DebugKind::Full; + + DebugKind Debug = StringSwitch(A->getValue()) + .CaseLower("none", DebugKind::None) + .CaseLower("full", DebugKind::Full) + .CaseLower("fastlink", DebugKind::FastLink) + // LLD extensions + .CaseLower("ghash", DebugKind::GHash) + .CaseLower("dwarf", DebugKind::Dwarf) + .CaseLower("symtab", DebugKind::Symtab) + .Default(DebugKind::Unknown); + + if (Debug == DebugKind::FastLink) { + warn("/debug:fastlink unsupported; using /debug:full"); + return DebugKind::Full; + } + if (Debug == DebugKind::Unknown) { + error("/debug: unknown option: " + Twine(A->getValue())); + return DebugKind::None; + } + return Debug; +} + +static unsigned parseDebugTypes(const opt::InputArgList &Args) { + unsigned DebugTypes = static_cast(DebugType::None); + + if (auto *A = Args.getLastArg(OPT_debugtype)) { + SmallVector Types; + A->getSpelling().split(Types, ',', /*KeepEmpty=*/false); + + for (StringRef Type : Types) { + unsigned V = StringSwitch(Type.lower()) + .Case("cv", static_cast(DebugType::CV)) + .Case("pdata", static_cast(DebugType::PData)) + .Case("fixup", static_cast(DebugType::Fixup)) + .Default(0); + if (V == 0) { + warn("/debugtype: unknown option: " + Twine(A->getValue())); + continue; + } + DebugTypes |= V; + } + return DebugTypes; + } + + // Default debug types + 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 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); 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 (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(); } } +static void markAddrsig(Symbol *S) { + if (auto *D = dyn_cast_or_null(S)) + if (Chunk *C = D->getChunk()) + C->KeepUnique = true; +} + +static void findKeepUniqueSections() { + // Exported symbols could be address-significant in other executables or DSOs, + // so we conservatively mark them as address-significant. + for (Export &R : Config->Exports) + markAddrsig(R.Sym); + + // Visit the address-significance table in each object file and mark each + // referenced symbol as address-significant. + for (ObjFile *Obj : ObjFile::Instances) { + ArrayRef Syms = Obj->getSymbols(); + if (Obj->AddrsigSec) { + ArrayRef Contents; + Obj->getCOFFObj()->getSectionContents(Obj->AddrsigSec, Contents); + const uint8_t *Cur = Contents.begin(); + while (Cur != Contents.end()) { + unsigned Size; + const char *Err; + uint64_t SymIndex = decodeULEB128(Cur, &Size, Contents.end(), &Err); + if (Err) + fatal(toString(Obj) + ": could not decode addrsig section: " + Err); + if (SymIndex >= Syms.size()) + fatal(toString(Obj) + ": invalid symbol index in addrsig section"); + markAddrsig(Syms[SymIndex]); + Cur += Size; + } + } else { + // If an object file does not have an address-significance table, + // conservatively mark all of its symbols as address-significant. + for (Symbol *S : Syms) + markAddrsig(S); + } + } +} + +// link.exe replaces each %foo% in AltPath with the contents of environment +// variable foo, and adds the two magic env vars _PDB (expands to the basename +// of pdb's output path) and _EXT (expands to the extension of the output +// binary). +// lld only supports %_PDB% and %_EXT% and warns on references to all other env +// vars. +static void parsePDBAltPath(StringRef AltPath) { + SmallString<128> Buf; + StringRef PDBBasename = + sys::path::filename(Config->PDBPath, sys::path::Style::windows); + StringRef BinaryExtension = + sys::path::extension(Config->OutputFile, sys::path::Style::windows); + if (!BinaryExtension.empty()) + BinaryExtension = BinaryExtension.substr(1); // %_EXT% does not include '.'. + + // Invariant: + // +--------- Cursor ('a...' might be the empty string). + // | +----- FirstMark + // | | +- SecondMark + // v v v + // a...%...%... + size_t Cursor = 0; + while (Cursor < AltPath.size()) { + size_t FirstMark, SecondMark; + if ((FirstMark = AltPath.find('%', Cursor)) == StringRef::npos || + (SecondMark = AltPath.find('%', FirstMark + 1)) == StringRef::npos) { + // Didn't find another full fragment, treat rest of string as literal. + Buf.append(AltPath.substr(Cursor)); + break; + } + + // Found a full fragment. Append text in front of first %, and interpret + // text between first and second % as variable name. + Buf.append(AltPath.substr(Cursor, FirstMark - Cursor)); + StringRef Var = AltPath.substr(FirstMark, SecondMark - FirstMark + 1); + if (Var.equals_lower("%_pdb%")) + Buf.append(PDBBasename); + else if (Var.equals_lower("%_ext%")) + Buf.append(BinaryExtension); + else { + warn("only %_PDB% and %_EXT% supported in /pdbaltpath:, keeping " + + Var + " as literal"); + Buf.append(Var); + } + + Cursor = SecondMark + 1; + } + + Config->PDBAltPath = Buf; +} + 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(); // Parse command line options. ArgParser Parser; 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()) == "4037") - Config->WarnMissingOrderSymbol = false; - else if (StringRef(Arg->getValue()) == "4217") - Config->WarnLocallyDefinedImported = false; - // Other warning numbers are ignored. + SmallVector Vec; + StringRef(Arg->getValue()).split(Vec, ','); + for (StringRef S : Vec) { + if (S == "4037") + Config->WarnMissingOrderSymbol = false; + else if (S == "4099") + Config->WarnDebugInfoUnusable = false; + else if (S == "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; + Config->ForceUnresolved = true; + // Handle /force or /force:multiple + if (Args.hasArg(OPT_force, OPT_force_multiple)) + Config->ForceMultiple = true; + // Handle /debug - if (Args.hasArg(OPT_debug, OPT_debug_dwarf, OPT_debug_ghash)) { + DebugKind Debug = parseDebugKind(Args); + if (Debug == DebugKind::Full || Debug == DebugKind::Dwarf || + Debug == DebugKind::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 /debugtype + Config->DebugTypes = parseDebugTypes(Args); + // Handle /pdb - bool ShouldCreatePDB = Args.hasArg(OPT_debug, OPT_debug_ghash); + bool ShouldCreatePDB = + (Debug == DebugKind::Full || Debug == DebugKind::GHash); 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) || Args.hasArg(OPT_profile); + bool DoGC = Debug == DebugKind::None || 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->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->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"); + if (Config->MinGW) { + parseMerge(".ctors=.rdata"); + parseMerge(".dtors=.rdata"); + parseMerge(".CRT=.rdata"); + } + // 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"); } // 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 = !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->DebugDwarf = Debug == DebugKind::Dwarf; + Config->DebugGHashes = Debug == DebugKind::GHash; + Config->DebugSymtab = Debug == DebugKind::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; std::set WholeArchives; - for (auto *Arg : Args.filtered(OPT_wholearchive_file)) - if (Optional Path = doFindFile(Arg->getValue())) + AutoExporter Exporter; + for (auto *Arg : Args.filtered(OPT_wholearchive_file)) { + if (Optional Path = doFindFile(Arg->getValue())) { if (Optional ID = getUniqueID(*Path)) WholeArchives.insert(*ID); + Exporter.addWholeArchive(*Path); + } + } // 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. 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(); + if (errorCount()) + return; + // 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; } + Config->Wordsize = Config->is64() ? 8 : 4; // 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 /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; } // Windows specific -- if no /subsystem is given, we need to infer // that from entry point name. Must happen before /entry handling, // and after the early return when just writing an import library. if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) { Config->Subsystem = inferSubsystem(); if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) fatal("subsystem must be defined"); } // 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 /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()); } 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); + } else { + // Don't do this earlier, so that Config->OutputFile is ready. + parsePDBAltPath(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); } Symtab->addAbsolute(mangle("__guard_fids_count"), 0); Symtab->addAbsolute(mangle("__guard_fids_table"), 0); 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); + if (Config->MinGW) { + Symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0); + Symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0); + Symtab->addAbsolute(mangle("__CTOR_LIST__"), 0); + Symtab->addAbsolute(mangle("__DTOR_LIST__"), 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(); + if (Config->MinGW) { + // Load any further object files that might be needed for doing automatic + // imports. + // + // For cases with no automatically imported symbols, this iterates once + // over the symbol table and doesn't do anything. + // + // For the normal case with a few automatically imported symbols, this + // should only need to be run once, since each new object file imported + // is an import library and wouldn't add any new undefined references, + // but there's nothing stopping the __imp_ symbols from coming from a + // normal object file as well (although that won't be used for the + // actual autoimport later on). If this pass adds new undefined references, + // we won't iterate further to resolve them. + Symtab->loadMinGWAutomaticImports(); + run(); + } + // Make sure we have resolved all symbols. Symtab->reportRemainingUndefines(); if (errorCount()) return; // Handle /safeseh. if (Args.hasFlag(OPT_safeseh, OPT_safeseh_no, false)) { for (ObjFile *File : ObjFile::Instances) 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; + Exporter.initSymbolExcludes(); 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()->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; } // If the symbol isn't common, it must have been replaced with a regular // symbol, which will carry its own alignment. auto *DC = dyn_cast(Sym); if (!DC) 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) + if (Config->DoICF) { + findKeepUniqueSections(); 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 Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/Driver.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/Driver.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/Driver.h (revision 343217) @@ -1,198 +1,197 @@ //===- 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; 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. /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); + StringRef doFindLibMinGW(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; // 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); // 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 Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/DriverUtils.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/DriverUtils.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/DriverUtils.cpp (revision 343217) @@ -1,890 +1,872 @@ //===- 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); 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 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 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 = createMemoryBufferForManifestRes(Manifest.size()); 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 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; // 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(Argv, MissingIndex, MissingCount); // Expand response files (arguments in the form of @) // and then parse the argument again. 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() != ExpandedArgv.size()) { std::string Msg = "Command line:"; 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. // /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(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 {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(std::next(Argv.begin()), V.begin(), V.end()); } if (Optional S = Process::GetEnv("_LINK_")) { std::vector V = tokenize(*S); 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); + COFFOptTable().PrintHelp(outs(), + (std::string(Argv0) + " [options] file...").c_str(), + "LLVM Linker", false); } } // namespace coff } // namespace lld Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/ICF.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/ICF.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/ICF.cpp (revision 343217) @@ -1,301 +1,316 @@ //===- 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/Threads.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 "llvm/Support/xxhash.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 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 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->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE; - if (!C->isCOMDAT() || !C->isLive() || Writable) + if (!C->isCOMDAT() || !C->Live || Writable) return false; // Code sections are eligible. if (C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE) return true; // .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"); + if (C->Sym && C->Sym->getName().startswith("??_7")) + return true; + + // Anything else not in an address-significance table is eligible. + return !C->KeepUnique; } // 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->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->getOutputCharacteristics() == B->getOutputCharacteristics() && A->SectionName == B->SectionName && A->Header->SizeOfRawData == B->Header->SizeOfRawData && 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) && 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) { while (Begin < End) { 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; } // 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; size_t Boundaries[NumShards + 1]; Boundaries[0] = 0; Boundaries[NumShards] = Chunks.size(); - for_each_n(parallel::par, size_t(1), NumShards, [&](size_t I) { + parallelForEachN(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) { + parallelForEachN(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) { + parallelForEach(Chunks, [&](SectionChunk *SC) { + SC->Class[1] = xxHash64(SC->getContents()); + }); + + // Combine the hashes of the sections referenced by each section into its + // hash. + parallelForEach(Chunks, [&](SectionChunk *SC) { + uint32_t Hash = SC->Class[1]; + for (Symbol *B : SC->symbols()) + if (auto *Sym = dyn_cast_or_null(B)) + Hash ^= Sym->getChunk()->Class[1]; // Set MSB to 1 to avoid collisions with non-hash classs. - SC->Class[0] = xxHash64(SC->getContents()) | (1 << 31); + SC->Class[0] = Hash | (1U << 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 Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/InputFiles.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/InputFiles.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/InputFiles.cpp (revision 343217) @@ -1,563 +1,590 @@ //===- 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) + if (U->WeakAlias && U->WeakAlias != Target) { + // Weak aliases as produced by GCC are named in the form + // .weak.., where is the name + // of another symbol emitted near the weak symbol. + // Just use the definition from the first object file that defined + // this weak symbol. + if (Config->MinGW) + return; 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, ""); } } SectionChunk *ObjFile::readSection(uint32_t SectionNumber, 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()); + + StringRef Name; if (auto EC = COFFObj->getSectionName(Sec, Name)) fatal("getSectionName failed: #" + Twine(SectionNumber) + ": " + EC.message()); if (Name == ".drectve") { ArrayRef Data; COFFObj->getSectionContents(Sec, Data); Directives = std::string((const char *)Data.data(), Data.size()); return nullptr; } + if (Name == ".llvm_addrsig") { + AddrsigSec = Sec; + 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. + // CodeView needs linker support. We need to interpret debug info, + // and then write it to a separate .pdb file. // 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) { readAssociativeDefinition(Sym, Def, Def->getNumber(Sym.isBigObj())); } void ObjFile::readAssociativeDefinition(COFFSymbolRef Sym, const coff_aux_section_definition *Def, uint32_t ParentSection) { SectionChunk *Parent = SparseChunks[ParentSection]; // 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, ""); if (SparseChunks[SectionNumber]) Parent->addAssociative(SparseChunks[SectionNumber]); } else { SparseChunks[SectionNumber] = nullptr; } } void ObjFile::recordPrevailingSymbolForMingw( COFFSymbolRef Sym, DenseMap &PrevailingSectionMap) { // For comdat symbols in executable sections, where this is the copy // of the section chunk we actually include instead of discarding it, // add the symbol to a map to allow using it for implicitly // associating .[px]data$ sections to it. int32_t SectionNumber = Sym.getSectionNumber(); SectionChunk *SC = SparseChunks[SectionNumber]; if (SC && SC->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) { StringRef Name; COFFObj->getSymbolName(Sym, Name); PrevailingSectionMap[Name] = SectionNumber; } } void ObjFile::maybeAssociateSEHForMingw( COFFSymbolRef Sym, const coff_aux_section_definition *Def, const DenseMap &PrevailingSectionMap) { StringRef Name; COFFObj->getSymbolName(Sym, Name); if (Name.consume_front(".pdata$") || Name.consume_front(".xdata$")) { // For MinGW, treat .[px]data$ as implicitly associative to // the symbol . auto ParentSym = PrevailingSectionMap.find(Name); if (ParentSym != PrevailingSectionMap.end()) readAssociativeDefinition(Sym, Def, ParentSym->second); } } 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); + // For MinGW symbols named .weak.* that point to a discarded section, + // don't create an Undefined symbol. If nothing ever refers to the symbol, + // everything should be fine. If something actually refers to the symbol + // (e.g. the undefined weak alias), linking will fail due to undefined + // references at the end. + if (Config->MinGW && Name.startswith(".weak.")) + return nullptr; return Symtab->addUndefined(Name, this, false); } if (SC) - return make(this, /*Name*/ "", false, + return make(this, /*Name*/ "", /*IsCOMDAT*/ 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); DenseMap PrevailingSectionMap; std::vector ComdatDefs( COFFObj->getNumberOfSections() + 1); for (uint32_t I = 0; I < NumSymbols; ++I) { COFFSymbolRef COFFSym = check(COFFObj->getSymbol(I)); bool PrevailingComdat; 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, PrevailingComdat)) { Symbols[I] = *OptSym; if (Config->MinGW && PrevailingComdat) recordPrevailingSymbolForMingw(COFFSym, PrevailingSectionMap); } 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 (const coff_aux_section_definition *Def = Sym.getSectionDefinition()) { if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) readAssociativeDefinition(Sym, Def); else if (Config->MinGW) maybeAssociateSEHForMingw(Sym, Def, PrevailingSectionMap); } 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, bool &Prevailing) { Prevailing = false; auto GetName = [&]() { StringRef S; COFFObj->getSymbolName(Sym, S); return S; }; if (Sym.isCommon()) { auto *C = make(Sym); Chunks.push_back(C); return Symtab->addCommon(this, GetName(), Sym.getValue(), Sym.getGeneric(), C); } if (Sym.isAbsolute()) { StringRef Name = GetName(); // Skip special symbols. if (Name == "@comp.id") return nullptr; if (Name == "@feat.00") { Feat00Flags = Sym.getValue(); return nullptr; } if (Sym.isExternal()) return Symtab->addAbsolute(Name, Sym); return make(Name, Sym); } int32_t SectionNumber = Sym.getSectionNumber(); if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG) return nullptr; if (llvm::COFF::isReservedSectionNumber(SectionNumber)) fatal(toString(this) + ": " + GetName() + " should not refer to special section " + Twine(SectionNumber)); if ((uint32_t)SectionNumber >= SparseChunks.size()) 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; if (Sym.isExternal()) { std::tie(Leader, Prevailing) = Symtab->addComdat(this, GetName(), Sym.getGeneric()); } else { - Leader = make(this, /*Name*/ "", false, + Leader = make(this, /*Name*/ "", /*IsCOMDAT*/ false, /*IsExternal*/ false, Sym.getGeneric()); Prevailing = true; } if (Prevailing) { 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 (const coff_aux_section_definition *Def = Sym.getSectionDefinition()) { if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) readAssociativeDefinition(Sym, Def); else ComdatDefs[SectionNumber] = Def; } } + // readAssociativeDefinition() writes to SparseChunks, so need to check again. 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 this was a duplicate, we logged an error but may continue; + // in this case, ImpSym is nullptr. + if (!ImpSym) + return; 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, 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); } 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) { 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(); } Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/InputFiles.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/InputFiles.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/InputFiles.h (revision 343217) @@ -1,269 +1,280 @@ //===- 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/DenseMap.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.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. + // Returns the underlying COFF file. COFFObjectFile *getCOFFObj() { return COFFObj.get(); } + // Whether the object was already merged into the final PDB or not + bool wasProcessedForPDB() const { return !!ModuleDBI; } + static std::vector Instances; // 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; // 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; + + const coff_section *AddrsigSec = nullptr; + + // When using Microsoft precompiled headers, this is the PCH's key. + // The same key is used by both the precompiled object, and objects using the + // precompiled object. Any difference indicates out-of-date objects. + llvm::Optional PCHSignature; private: void initializeChunks(); void initializeSymbols(); SectionChunk * readSection(uint32_t SectionNumber, const llvm::object::coff_aux_section_definition *Def, StringRef LeaderName); void readAssociativeDefinition( COFFSymbolRef COFFSym, const llvm::object::coff_aux_section_definition *Def); void readAssociativeDefinition( COFFSymbolRef COFFSym, const llvm::object::coff_aux_section_definition *Def, uint32_t ParentSection); void recordPrevailingSymbolForMingw( COFFSymbolRef COFFSym, llvm::DenseMap &PrevailingSectionMap); void maybeAssociateSEHForMingw( COFFSymbolRef Sym, const llvm::object::coff_aux_section_definition *Def, const llvm::DenseMap &PrevailingSectionMap); llvm::Optional createDefined(COFFSymbolRef Sym, std::vector &ComdatDefs, bool &PrevailingComdat); 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) {} static bool classof(const InputFile *F) { return F->kind() == ImportKind; } static std::vector Instances; 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. // 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. 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 Symbols; } MachineTypes getMachineType() override; static std::vector Instances; std::unique_ptr Obj; private: void parse() override; std::vector Symbols; }; } // namespace coff std::string toString(const coff::InputFile *File); } // namespace lld #endif Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/LTO.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/LTO.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/LTO.cpp (revision 343217) @@ -1,149 +1,152 @@ //===- 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 std::unique_ptr createLTO() { lto::Config C; C.Options = InitTargetOptionsFromCodeGenFlags(); // 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; // 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) C.RelocModel = Reloc::Static; else C.RelocModel = Reloc::PIC_; C.DisableVerify = true; C.DiagHandler = diagnosticHandler; C.OptLevel = Config->LTOO; + C.CPU = GetCPUStr(); + C.MAttrs = GetMAttrs(); + if (Config->SaveTemps) checkError(C.addSaveTemps(std::string(Config->OutputFile) + ".", /*UseInputModulePath*/ true)); lto::ThinBackend 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(); 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) { Files[Task] = std::move(MB); })); checkError(LTOObj->run( [&](size_t Task) { return llvm::make_unique( 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 (Buf[I].empty()) continue; if (Config->SaveTemps) { if (I == 0) saveBuffer(Buf[I], Config->OutputFile + ".lto.obj"); else saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.obj"); } Ret.emplace_back(Buf[I].data(), Buf[I].size()); } for (std::unique_ptr &File : Files) if (File) Ret.push_back(File->getBuffer()); return Ret; } Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/MapFile.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/MapFile.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/MapFile.cpp (revision 343217) @@ -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); } // 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 << 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->Name << '\n'; - for (Chunk *C : Sec->getChunks()) { + for (Chunk *C : Sec->Chunks) { auto *SC = dyn_cast(C); if (!SC) continue; writeHeader(OS, SC->getRVA(), SC->getSize(), SC->Alignment); OS << Indent8 << SC->File->getName() << ":(" << SC->getSectionName() << ")\n"; for (DefinedRegular *Sym : SectionSyms[SC]) OS << SymStr[Sym] << '\n'; } } } Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/MarkLive.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/MarkLive.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/MarkLive.cpp (revision 343217) @@ -1,74 +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()) + if (SC->Live) Worklist.push_back(SC); auto Enqueue = [&](SectionChunk *C) { - if (C->isLive()) + if (C->Live) return; - C->markLive(); + C->Live = true; 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 = 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!"); + assert(SC->Live && "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); } } } } Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/MinGW.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/MinGW.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/MinGW.cpp (revision 343217) @@ -1,146 +1,176 @@ //===- 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() { +void AutoExporter::initSymbolExcludes() { + ExcludeSymbolPrefixes = { + // Import symbols + "__imp_", + "__IMPORT_DESCRIPTOR_", + // Extra import symbols from GNU import libraries + "__nm_", + // C++ symbols + "__rtti_", + "__builtin_", + // Artifical symbols such as .refptr + ".", + }; + ExcludeSymbolSuffixes = { + "_iname", + "_NULL_THUNK_DATA", + }; 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", }; + ExcludeSymbolPrefixes.insert("__head_"); } else { ExcludeSymbols = { - "_NULL_IMPORT_DESCRIPTOR", + "__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", }; + ExcludeSymbolPrefixes.insert("_head_"); } +} +AutoExporter::AutoExporter() { ExcludeLibs = { "libgcc", "libgcc_s", "libstdc++", "libmingw32", "libmingwex", "libg2c", "libsupc++", "libobjc", "libgcj", + "libclang_rt.builtins", "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", }; } +void AutoExporter::addWholeArchive(StringRef Path) { + StringRef LibName = sys::path::filename(Path); + // Drop the file extension, to match the processing below. + LibName = LibName.substr(0, LibName.rfind('.')); + ExcludeLibs.erase(LibName); +} + 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; + for (StringRef Prefix : ExcludeSymbolPrefixes.keys()) + if (Sym->getName().startswith(Prefix)) + return false; + for (StringRef Suffix : ExcludeSymbolSuffixes.keys()) + if (Sym->getName().endswith(Suffix)) + 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()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) OS << " DATA"; } OS << "\n"; } } Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/MinGW.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/MinGW.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/MinGW.h (revision 343217) @@ -1,38 +1,44 @@ //===- MinGW.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_MINGW_H #define LLD_COFF_MINGW_H #include "Config.h" #include "Symbols.h" #include "lld/Common/LLVM.h" namespace lld { namespace coff { // Logic for deciding what symbols to export, when exporting all // symbols for MinGW. class AutoExporter { public: AutoExporter(); + void initSymbolExcludes(); + + void addWholeArchive(StringRef Path); + llvm::StringSet<> ExcludeSymbols; + llvm::StringSet<> ExcludeSymbolPrefixes; + llvm::StringSet<> ExcludeSymbolSuffixes; llvm::StringSet<> ExcludeLibs; llvm::StringSet<> ExcludeObjects; bool shouldExport(Defined *Sym) const; }; void writeDefFile(StringRef Name); } // namespace coff } // namespace lld #endif Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/Options.td =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/Options.td (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/Options.td (revision 343217) @@ -1,187 +1,194 @@ 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 manifest : F<"manifest">, HelpText<"Create .manifest file">; +def manifest_colon : P< + "manifest", + "NO disables manifest output; EMBED[,ID=#] embeds manifest as resource in the image">; 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">; +def manifestfile : P<"manifestfile", "Manifest output path, with /manifest">; +def manifestdependency : P< + "manifestdependency", + "Attributes for element in manifest file; implies /manifest">; +def manifestinput : P< + "manifestinput", + "Additional manifest inputs; only valid with /manifest:embed">; // 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 debug_opt : P<"debug", "Embed a symbol table in the image with option">; 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 nodefaultlib_all : F<"nodefaultlib">, + HelpText<"Remove all default libraries">; +def noentry : F<"noentry">, + HelpText<"Don't add reference to DllMainCRTStartup; only valid with /dll">; def profile : F<"profile">; -def repro : F<"Brepro">, HelpText<"Use a hash of the executable as the PE header timestamp">; +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 and multiply defined symbols when creating executables">; +def force_unresolved : F<"force:unresolved">, HelpText<"Allow undefined symbols when creating executables">; -def force_unresolved : F<"force:unresolved">; +def force_multiple : F<"force:multiple">, + HelpText<"Allow multiply defined symbols when creating executables">; 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 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 tlbid : QF<"tlbid">; def tlbout : QF<"tlbout">; def verbose_all : QF<"verbose">; def guardsym : QF<"guardsym">; Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/PDB.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/PDB.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/PDB.cpp (revision 343217) @@ -1,1334 +1,1765 @@ //===- 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 "lld/Common/Timer.h" +#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.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/SymbolRecordHelpers.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/Errc.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/JamCRC.h" +#include "llvm/Support/Parallel.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; + bool IsPrecompiledTypeMap = false; }; +class DebugSHandler; + class PDBLinker { + friend DebugSHandler; + public: PDBLinker(SymbolTable *Symtab) : Alloc(), Symtab(Symtab), Builder(Alloc), TypeTable(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); + void initialize(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); + /// Link CodeView from a single object file into the target (output) PDB. + /// When a precompiled headers object is linked, its TPI map might be provided + /// externally. + void addObjFile(ObjFile *File, CVIndexMap *ExternIndexMap = nullptr); /// 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 mergeDebugT(ObjFile *File, + CVIndexMap *ObjectIndexMap); - Expected maybeMergeTypeServerPDB(ObjFile *File, - TypeServer2Record &TS); + /// Reads and makes available a PDB. + Expected maybeMergeTypeServerPDB(ObjFile *File, + const CVType &FirstType); + /// Merges a precompiled headers TPI map into the current TPI map. The + /// precompiled headers object will also be loaded and remapped in the + /// process. + Expected + mergeInPrecompHeaderObj(ObjFile *File, const CVType &FirstType, + CVIndexMap *ObjectIndexMap); + + /// Reads and makes available a precompiled headers object. + /// + /// This is a requirement for objects compiled with cl.exe /Yu. In that + /// case, the referenced object (which was compiled with /Yc) has to be loaded + /// first. This is mainly because the current object's TPI stream has external + /// references to the precompiled headers object. + /// + /// If the precompiled headers object was already loaded, this function will + /// simply return its (remapped) TPI map. + Expected aquirePrecompObj(ObjFile *File, + PrecompRecord Precomp); + + /// Adds a precompiled headers object signature -> TPI mapping. + std::pair + registerPrecompiledHeaders(uint32_t Signature); + + void mergeSymbolRecords(ObjFile *File, const CVIndexMap &IndexMap, + std::vector &StringTableRefs, + BinaryStreamRef SymData); + /// Add the section map and section contributions to the PDB. void addSections(ArrayRef OutputSections, ArrayRef SectionTable); - /// Write the PDB to disk. - void commit(); + /// Get the type table or the global type table if /DEBUG:GHASH is enabled. + TypeCollection &getTypeTable() { + if (Config->DebugGHashes) + return GlobalTypeTable; + return TypeTable; + } + /// Get the ID table or the global ID table if /DEBUG:GHASH is enabled. + TypeCollection &getIDTable() { + if (Config->DebugGHashes) + return GlobalIDTable; + return IDTable; + } + + /// Write the PDB to disk and store the Guid generated for it in *Guid. + void commit(codeview::GUID *Guid); + 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; + std::map TypeServerIndexMappings; + /// Type index mappings of precompiled objects type map that we've loaded so + /// far. + std::map PrecompTypeIndexMappings; + /// List of TypeServer PDBs which cannot be loaded. /// Cached to prevent repeated load attempts. - std::set MissingTypeServerPDBs; + std::map MissingTypeServerPDBs; }; + +class DebugSHandler { + PDBLinker &Linker; + + /// The object file whose .debug$S sections we're processing. + ObjFile &File; + + /// The result of merging type indices. + const CVIndexMap &IndexMap; + + /// The DEBUG_S_STRINGTABLE subsection. These strings are referred to by + /// index from other records in the .debug$S section. All of these strings + /// need to be added to the global PDB string table, and all references to + /// these strings need to have their indices re-written to refer to the + /// global PDB string table. + DebugStringTableSubsectionRef CVStrTab; + + /// The DEBUG_S_FILECHKSMS subsection. As above, these are referred to + /// by other records in the .debug$S section and need to be merged into the + /// PDB. + DebugChecksumsSubsectionRef Checksums; + + /// The DEBUG_S_FRAMEDATA subsection(s). There can be more than one of + /// these and they need not appear in any specific order. However, they + /// contain string table references which need to be re-written, so we + /// collect them all here and re-write them after all subsections have been + /// discovered and processed. + std::vector NewFpoFrames; + + /// Pointers to raw memory that we determine have string table references + /// that need to be re-written. We first process all .debug$S subsections + /// to ensure that we can handle subsections written in any order, building + /// up this list as we go. At the end, we use the string table (which must + /// have been discovered by now else it is an error) to re-write these + /// references. + std::vector StringTableReferences; + +public: + DebugSHandler(PDBLinker &Linker, ObjFile &File, const CVIndexMap &IndexMap) + : Linker(Linker), File(File), IndexMap(IndexMap) {} + + void handleDebugS(lld::coff::SectionChunk &DebugS); + void finish(); +}; } +// Visual Studio's debugger requires absolute paths in various places in the +// PDB to work without additional configuration: +// https://docs.microsoft.com/en-us/visualstudio/debugger/debug-source-files-common-properties-solution-property-pages-dialog-box +static void pdbMakeAbsolute(SmallVectorImpl &FileName) { + // The default behavior is to produce paths that are valid within the context + // of the machine that you perform the link on. If the linker is running on + // a POSIX system, we will output absolute POSIX paths. If the linker is + // running on a Windows system, we will output absolute Windows paths. If the + // user desires any other kind of behavior, they should explicitly pass + // /pdbsourcepath, in which case we will treat the exact string the user + // passed in as the gospel and not normalize, canonicalize it. + if (sys::path::is_absolute(FileName, sys::path::Style::windows) || + sys::path::is_absolute(FileName, sys::path::Style::posix)) + return; + + // It's not absolute in any path syntax. Relative paths necessarily refer to + // the local file system, so we can make it native without ending up with a + // nonsensical path. + sys::path::native(FileName); + if (Config->PDBSourcePath.empty()) { + sys::fs::make_absolute(FileName); + return; + } + // Only apply native and dot removal to the relative file path. We want to + // leave the path the user specified untouched since we assume they specified + // it for a reason. + sys::path::remove_dots(FileName, /*remove_dot_dots=*/true); + + SmallString<128> AbsoluteFileName = Config->PDBSourcePath; + sys::path::append(AbsoluteFileName, FileName); + FileName = std::move(AbsoluteFileName); +} + 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_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); +// OBJs usually start their symbol stream with a S_OBJNAME record. This record +// also contains the signature/key of the current PCH session. The signature +// must be same for all objects which depend on the precompiled object. +// Recompiling the precompiled headers will generate a new PCH key and thus +// invalidate all the dependent objects. +static uint32_t extractPCHSignature(ObjFile *File) { + auto DbgIt = find_if(File->getDebugChunks(), [](SectionChunk *C) { + return C->getSectionName() == ".debug$S"; + }); + if (!DbgIt) + return 0; + + ArrayRef Contents = + consumeDebugMagic((*DbgIt)->getContents(), ".debug$S"); + DebugSubsectionArray Subsections; + BinaryStreamReader Reader(Contents, support::little); + ExitOnErr(Reader.readArray(Subsections, Contents.size())); + + for (const DebugSubsectionRecord &SS : Subsections) { + if (SS.kind() != DebugSubsectionKind::Symbols) + continue; + + // If it's there, the S_OBJNAME record shall come first in the stream. + Expected Sym = readSymbolFromStream(SS.getRecordData(), 0); + if (!Sym) { + consumeError(Sym.takeError()); + continue; + } + if (auto ObjName = SymbolDeserializer::deserializeAs(Sym.get())) + return ObjName->Signature; + } + return 0; } -Expected PDBLinker::mergeDebugT(ObjFile *File, - CVIndexMap &ObjectIndexMap) { +Expected +PDBLinker::mergeDebugT(ObjFile *File, CVIndexMap *ObjectIndexMap) { ScopedTimer T(TypeMergingTimer); + bool IsPrecompiledHeader = false; + ArrayRef Data = getDebugSection(File, ".debug$T"); + if (Data.empty()) { + // Try again, Microsoft precompiled headers use .debug$P instead of + // .debug$T + Data = getDebugSection(File, ".debug$P"); + IsPrecompiledHeader = true; + } if (Data.empty()) - return ObjectIndexMap; + return *ObjectIndexMap; // no debug info + // Precompiled headers objects need to save the index map for further + // reference by other objects which use the precompiled headers. + if (IsPrecompiledHeader) { + uint32_t PCHSignature = extractPCHSignature(File); + if (PCHSignature == 0) + fatal("No signature found for the precompiled headers OBJ (" + + File->getName() + ")"); + + // When a precompiled headers object comes first on the command-line, we + // update the mapping here. Otherwise, if an object referencing the + // precompiled headers object comes first, the mapping is created in + // aquirePrecompObj(), thus we would skip this block. + if (!ObjectIndexMap->IsPrecompiledTypeMap) { + auto R = registerPrecompiledHeaders(PCHSignature); + if (R.second) + fatal( + "A precompiled headers OBJ with the same signature was already " + "provided! (" + + File->getName() + ")"); + + ObjectIndexMap = &R.first; + } + } + 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); + auto FirstType = Types.begin(); + if (FirstType == Types.end()) + return *ObjectIndexMap; - // This is a /Z7 object. Fill in the temporary, caller-provided - // ObjectIndexMap. + if (FirstType->kind() == LF_TYPESERVER2) { + // Look through type servers. If we've already seen this type server, + // don't merge any type information. + return maybeMergeTypeServerPDB(File, *FirstType); + } else if (FirstType->kind() == LF_PRECOMP) { + // This object was compiled with /Yu, so process the corresponding + // precompiled headers object (/Yc) first. Some type indices in the current + // object are referencing data in the precompiled headers object, so we need + // both to be loaded. + auto E = mergeInPrecompHeaderObj(File, *FirstType, ObjectIndexMap); + if (!E) + return E.takeError(); + + // Drop LF_PRECOMP record from the input stream, as it needs to be replaced + // with the precompiled headers object type stream. + // Note that we can't just call Types.drop_front(), as we explicitly want to + // rebase the stream. + Types.setUnderlyingStream( + Types.getUnderlyingStream().drop_front(FirstType->RecordData.size())); + } + + // 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)) + ObjectIndexMap->TPIMap, Types, Hashes, + File->PCHSignature)) fatal("codeview::mergeTypeAndIdRecords failed: " + toString(std::move(Err))); } else { - if (auto Err = mergeTypeAndIdRecords(IDTable, TypeTable, - ObjectIndexMap.TPIMap, Types)) + if (auto Err = + mergeTypeAndIdRecords(IDTable, TypeTable, ObjectIndexMap->TPIMap, + Types, File->PCHSignature)) fatal("codeview::mergeTypeAndIdRecords failed: " + toString(std::move(Err))); } - return ObjectIndexMap; + return *ObjectIndexMap; } static Expected> -tryToLoadPDB(const GUID &GuidFromObj, StringRef TSPath) { +tryToLoadPDB(const codeview::GUID &GuidFromObj, StringRef TSPath) { + // Ensure the file exists before anything else. We want to return ENOENT, + // "file not found", even if the path points to a removable device (in which + // case the return message would be EAGAIN, "resource unavailable try again") + if (!llvm::sys::fs::exists(TSPath)) + return errorCodeToError(std::error_code(ENOENT, std::generic_category())); + 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 make_error(pdb::pdb_error_code::signature_out_of_date); return std::move(NS); } -Expected PDBLinker::maybeMergeTypeServerPDB(ObjFile *File, - TypeServer2Record &TS) { - const GUID& TSId = TS.getGuid(); +Expected +PDBLinker::maybeMergeTypeServerPDB(ObjFile *File, const CVType &FirstType) { + TypeServer2Record TS; + if (auto EC = + TypeDeserializer::deserializeAs(const_cast(FirstType), TS)) + fatal("error reading record: " + toString(std::move(EC))); + + const codeview::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); + auto PrevErr = MissingTypeServerPDBs.find(TSId); + if (PrevErr != MissingTypeServerPDBs.end()) + return createFileError( + TSPath, + make_error(PrevErr->second, inconvertibleErrorCode())); // 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); - } + auto ExpectedSession = handleExpected( + tryToLoadPDB(TSId, TSPath), + [&]() { + StringRef LocalPath = + !File->ParentName.empty() ? File->ParentName : File->getName(); + SmallString<128> Path = sys::path::parent_path(LocalPath); + // Currently, type server PDBs are only created by cl, which only runs + // on Windows, so we can assume type server paths are Windows style. + sys::path::append( + Path, sys::path::filename(TSPath, sys::path::Style::windows)); + return tryToLoadPDB(TSId, Path); + }, + [&](std::unique_ptr EC) -> Error { + auto SysErr = EC->convertToErrorCode(); + // Only re-try loading if the previous error was "No such file or + // directory" + if (SysErr.category() == std::generic_category() && + SysErr.value() == ENOENT) + return Error::success(); + return Error(std::move(EC)); + }); + if (auto E = ExpectedSession.takeError()) { TypeServerIndexMappings.erase(TSId); - MissingTypeServerPDBs.emplace(TSId); - return std::move(E); + + // Flatten the error to a string, for later display, if the error occurs + // again on the same PDB. + std::string ErrMsg; + raw_string_ostream S(ErrMsg); + S << E; + MissingTypeServerPDBs.emplace(TSId, S.str()); + + return createFileError(TSPath, std::move(E)); } 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 = 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); + Optional EndPrecomp; // Merge TPI first, because the IPI stream will reference type indices. if (auto Err = mergeTypeRecords(GlobalTypeTable, IndexMap.TPIMap, - ExpectedTpi->typeArray(), TpiHashes)) + ExpectedTpi->typeArray(), TpiHashes, EndPrecomp)) 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; } +Expected +PDBLinker::mergeInPrecompHeaderObj(ObjFile *File, const CVType &FirstType, + CVIndexMap *ObjectIndexMap) { + PrecompRecord Precomp; + if (auto EC = TypeDeserializer::deserializeAs(const_cast(FirstType), + Precomp)) + fatal("error reading record: " + toString(std::move(EC))); + + auto E = aquirePrecompObj(File, Precomp); + if (!E) + return E.takeError(); + + const CVIndexMap &PrecompIndexMap = *E; + assert(PrecompIndexMap.IsPrecompiledTypeMap); + + if (PrecompIndexMap.TPIMap.empty()) + return PrecompIndexMap; + + assert(Precomp.getStartTypeIndex() == TypeIndex::FirstNonSimpleIndex); + assert(Precomp.getTypesCount() <= PrecompIndexMap.TPIMap.size()); + // Use the previously remapped index map from the precompiled headers. + ObjectIndexMap->TPIMap.append(PrecompIndexMap.TPIMap.begin(), + PrecompIndexMap.TPIMap.begin() + + Precomp.getTypesCount()); + return *ObjectIndexMap; +} + +static bool equals_path(StringRef path1, StringRef path2) { +#if defined(_WIN32) + return path1.equals_lower(path2); +#else + return path1.equals(path2); +#endif +} + +// Find by name an OBJ provided on the command line +static ObjFile *findObjByName(StringRef FileNameOnly) { + SmallString<128> CurrentPath; + + for (ObjFile *F : ObjFile::Instances) { + StringRef CurrentFileName = sys::path::filename(F->getName()); + + // Compare based solely on the file name (link.exe behavior) + if (equals_path(CurrentFileName, FileNameOnly)) + return F; + } + return nullptr; +} + +std::pair +PDBLinker::registerPrecompiledHeaders(uint32_t Signature) { + auto Insertion = PrecompTypeIndexMappings.insert({Signature, CVIndexMap()}); + CVIndexMap &IndexMap = Insertion.first->second; + if (!Insertion.second) + return {IndexMap, true}; + // Mark this map as a precompiled types map. + IndexMap.IsPrecompiledTypeMap = true; + return {IndexMap, false}; +} + +Expected +PDBLinker::aquirePrecompObj(ObjFile *File, PrecompRecord Precomp) { + // First, check if we already loaded the precompiled headers object with this + // signature. Return the type index mapping if we've already seen it. + auto R = registerPrecompiledHeaders(Precomp.getSignature()); + if (R.second) + return R.first; + + CVIndexMap &IndexMap = R.first; + + // Cross-compile warning: given that Clang doesn't generate LF_PRECOMP + // records, we assume the OBJ comes from a Windows build of cl.exe. Thusly, + // the paths embedded in the OBJs are in the Windows format. + SmallString<128> PrecompFileName = sys::path::filename( + Precomp.getPrecompFilePath(), sys::path::Style::windows); + + // link.exe requires that a precompiled headers object must always be provided + // on the command-line, even if that's not necessary. + auto PrecompFile = findObjByName(PrecompFileName); + if (!PrecompFile) + return createFileError( + PrecompFileName.str(), + make_error(pdb::pdb_error_code::external_cmdline_ref)); + + addObjFile(PrecompFile, &IndexMap); + + if (!PrecompFile->PCHSignature) + fatal(PrecompFile->getName() + " is not a precompiled headers object"); + + if (Precomp.getSignature() != PrecompFile->PCHSignature.getValueOr(0)) + return createFileError( + Precomp.getPrecompFilePath().str(), + make_error(pdb::pdb_error_code::signature_out_of_date)); + + 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, + MutableArrayRef RecordBytes, const CVIndexMap &IndexMap, ArrayRef TypeRefs) { + MutableArrayRef Contents = + RecordBytes.drop_front(sizeof(RecordPrefix)); 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); + recordStringTableReferenceAtOffset(Contents, 8, 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) { +static MutableArrayRef +copyAndAlignSymbol(const CVSymbol &Sym, MutableArrayRef &AlignedMem) { 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); + assert(AlignedMem.size() >= Size && "didn't preallocate enough"); // Copy the symbol record and zero out any padding bytes. - MutableArrayRef NewData(reinterpret_cast(Mem), Size); + MutableArrayRef NewData = AlignedMem.take_front(Size); + AlignedMem = AlignedMem.drop_front(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); + auto *Prefix = reinterpret_cast(NewData.data()); 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) { +static bool symbolGoesInModuleStream(const CVSymbol &Sym, bool IsGlobalScope) { 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_UDT records go in the module stream if it is not a global S_UDT. + case SymbolKind::S_UDT: + return !IsGlobalScope; // 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) { +static bool symbolGoesInGlobalsStream(const CVSymbol &Sym, bool IsGlobalScope) { 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. + // S_UDT records go in the globals stream if it is a global S_UDT. case SymbolKind::S_UDT: + return IsGlobalScope; default: return false; } } -static void addGlobalSymbol(pdb::GSIStreamBuilder &Builder, ObjFile &File, - const CVSymbol &Sym) { +static void addGlobalSymbol(pdb::GSIStreamBuilder &Builder, uint16_t ModIndex, + unsigned SymOffset, 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()); + PS.Module = ModIndex; // 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(); + PS.SymOffset = SymOffset; 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. +void PDBLinker::mergeSymbolRecords(ObjFile *File, const CVIndexMap &IndexMap, + std::vector &StringTableRefs, + BinaryStreamRef SymData) { ArrayRef SymsBuffer; cantFail(SymData.readBytes(0, SymData.getLength(), SymsBuffer)); SmallVector Scopes; + // Iterate every symbol to check if any need to be realigned, and if so, how + // much space we need to allocate for them. + bool NeedsRealignment = false; + unsigned TotalRealignedSize = 0; auto EC = forEachCodeViewRecord( - SymsBuffer, [&](const CVSymbol &Sym) -> llvm::Error { + SymsBuffer, [&](CVSymbol Sym) -> llvm::Error { + unsigned RealignedSize = + alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb)); + NeedsRealignment |= RealignedSize != Sym.length(); + TotalRealignedSize += RealignedSize; + return Error::success(); + }); + + // If any of the symbol record lengths was corrupt, ignore them all, warn + // about it, and move on. + if (EC) { + warn("corrupt symbol records in " + File->getName()); + consumeError(std::move(EC)); + return; + } + + // If any symbol needed realignment, allocate enough contiguous memory for + // them all. Typically symbol subsections are small enough that this will not + // cause fragmentation. + MutableArrayRef AlignedSymbolMem; + if (NeedsRealignment) { + void *AlignedData = + Alloc.Allocate(TotalRealignedSize, alignOf(CodeViewContainer::Pdb)); + AlignedSymbolMem = makeMutableArrayRef( + reinterpret_cast(AlignedData), TotalRealignedSize); + } + + // Iterate again, this time doing the real work. + unsigned CurSymOffset = File->ModuleDBI->getNextSymbolOffset(); + ArrayRef BulkSymbols; + cantFail(forEachCodeViewRecord( + SymsBuffer, [&](CVSymbol Sym) -> llvm::Error { + // Align the record if required. + MutableArrayRef RecordBytes; + if (NeedsRealignment) { + RecordBytes = copyAndAlignSymbol(Sym, AlignedSymbolMem); + Sym = CVSymbol(Sym.kind(), RecordBytes); + } else { + // Otherwise, we can actually mutate the symbol directly, since we + // copied it to apply relocations. + RecordBytes = makeMutableArrayRef( + const_cast(Sym.data().data()), Sym.length()); + } + // 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(); } - // Copy the symbol record so we can mutate it. - MutableArrayRef NewData = copySymbolForPdb(Sym, Alloc); - // Re-map all the type index references. - MutableArrayRef Contents = - NewData.drop_front(sizeof(RecordPrefix)); - remapTypesInSymbolRecord(File, Sym.kind(), Contents, IndexMap, + remapTypesInSymbolRecord(File, Sym.kind(), RecordBytes, IndexMap, TypeRefs); // An object file may have S_xxx_ID symbols, but these get converted to // "real" symbols in a PDB. - translateIdSymbols(NewData, IDTable); + translateIdSymbols(RecordBytes, getIDTable()); + Sym = CVSymbol(symbolKind(RecordBytes), RecordBytes); // 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); + recordStringTableReferences(Sym.kind(), RecordBytes, StringTableRefs); - SymbolKind NewKind = symbolKind(NewData); - // 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 (symbolOpensScope(Sym.kind())) + scopeStackOpen(Scopes, CurSymOffset, Sym); + else if (symbolEndsScope(Sym.kind())) + scopeStackClose(Scopes, CurSymOffset, 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); + if (symbolGoesInGlobalsStream(Sym, Scopes.empty())) + addGlobalSymbol(Builder.getGsiBuilder(), + File->ModuleDBI->getModuleIndex(), CurSymOffset, Sym); - // Add the symbol to the module. - if (symbolGoesInModuleStream(NewSym)) - File->ModuleDBI->addSymbol(NewSym); + if (symbolGoesInModuleStream(Sym, Scopes.empty())) { + // Add symbols to the module in bulk. If this symbol is contiguous + // with the previous run of symbols to add, combine the ranges. If + // not, close the previous range of symbols and start a new one. + if (Sym.data().data() == BulkSymbols.end()) { + BulkSymbols = makeArrayRef(BulkSymbols.data(), + BulkSymbols.size() + Sym.length()); + } else { + File->ModuleDBI->addSymbolsInBulk(BulkSymbols); + BulkSymbols = RecordBytes; + } + CurSymOffset += Sym.length(); + } return Error::success(); - }); - cantFail(std::move(EC)); + })); + + // Add any remaining symbols we've accumulated. + File->ModuleDBI->addSymbolsInBulk(BulkSymbols); } -// Allocate memory for a .debug$S section and relocate it. +// Allocate memory for a .debug$S / .debug$F section and relocate it. static ArrayRef relocateDebugChunk(BumpPtrAllocator &Alloc, - SectionChunk *DebugChunk) { - uint8_t *Buffer = Alloc.Allocate(DebugChunk->getSize()); - assert(DebugChunk->OutputSectionOff == 0 && + 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"); + DebugChunk.readRelocTargets(); + DebugChunk.writeTo(Buffer); + return makeArrayRef(Buffer, DebugChunk.getSize()); } 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) { +static uint32_t +translateStringTableIndex(uint32_t ObjIndex, + const DebugStringTableSubsectionRef &ObjStrTable, + DebugStringTableSubsection &PdbStrTable) { + auto ExpectedString = ObjStrTable.getString(ObjIndex); + if (!ExpectedString) { + warn("Invalid string table reference"); + consumeError(ExpectedString.takeError()); + return 0; + } + + return PdbStrTable.insert(*ExpectedString); +} + +void DebugSHandler::handleDebugS(lld::coff::SectionChunk &DebugS) { + DebugSubsectionArray Subsections; + + ArrayRef RelocatedDebugContents = consumeDebugMagic( + relocateDebugChunk(Linker.Alloc, DebugS), DebugS.getSectionName()); + + BinaryStreamReader Reader(RelocatedDebugContents, support::little); + ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.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: + // 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::FrameData: { + // We need to re-write string table indices here, so save off all + // frame data subsections until we've processed the entire list of + // subsections so that we can be sure we have the string table. + DebugFrameDataSubsectionRef FDS; + ExitOnErr(FDS.initialize(SS.getRecordData())); + NewFpoFrames.push_back(std::move(FDS)); + break; + } + case DebugSubsectionKind::Symbols: { + Linker.mergeSymbolRecords(&File, IndexMap, StringTableReferences, + SS.getRecordData()); + break; + } + default: + // FIXME: Process the rest of the subsections. + break; + } + } +} + +void DebugSHandler::finish() { + pdb::DbiStreamBuilder &DbiBuilder = Linker.Builder.getDbiBuilder(); + + // 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 string table indices in the Fpo Data and symbol records to refer to + // the global PDB string table instead of the object file string table. + for (DebugFrameDataSubsectionRef &FDS : NewFpoFrames) { + const ulittle32_t *Reloc = FDS.getRelocPtr(); + for (codeview::FrameData FD : FDS) { + FD.RvaStart += *Reloc; + FD.FrameFunc = + translateStringTableIndex(FD.FrameFunc, CVStrTab, Linker.PDBStrTab); + DbiBuilder.addNewFpoData(FD); + } + } + + for (ulittle32_t *Ref : StringTableReferences) + *Ref = translateStringTableIndex(*Ref, CVStrTab, Linker.PDBStrTab); + + // 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(Linker.PDBStrTab); + for (FileChecksumEntry &FC : Checksums) { + SmallString<128> FileName = + ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); + pdbMakeAbsolute(FileName); + ExitOnErr(Linker.Builder.getDbiBuilder().addModuleSourceFile( + *File.ModuleDBI, FileName)); + NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum); + } + File.ModuleDBI->addDebugSubsection(std::move(NewChecksums)); +} + +void PDBLinker::addObjFile(ObjFile *File, CVIndexMap *ExternIndexMap) { + if (File->wasProcessedForPDB()) + return; // 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); + pdbMakeAbsolute(Path); StringRef Name = InArchive ? File->getName() : StringRef(Path); - File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name)); + pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); + File->ModuleDBI = &ExitOnErr(DbiBuilder.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()) + if (!SecChunk || !SecChunk->Live) 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); + auto IndexMapResult = + mergeDebugT(File, ExternIndexMap ? ExternIndexMap : &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())); + if (!Config->WarnDebugInfoUnusable) { + consumeError(IndexMapResult.takeError()); + return; + } + StringRef FileName = sys::path::filename(Path); + warn("Cannot use debug info for '" + FileName + "' [LNK4099]\n" + + ">>> failed to load reference " + + StringRef(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; + DebugSHandler DSH(*this, *File, *IndexMapResult); + // Now do all live .debug$S and .debug$F sections. for (SectionChunk *DebugChunk : File->getDebugChunks()) { - if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S") + if (!DebugChunk->Live || DebugChunk->getSize() == 0) continue; - ArrayRef RelocatedDebugContents = - relocateDebugChunk(Alloc, DebugChunk); - if (RelocatedDebugContents.empty()) + if (DebugChunk->getSectionName() == ".debug$S") { + DSH.handleDebugS(*DebugChunk); continue; - - DebugSubsectionArray Subsections; - BinaryStreamReader Reader(RelocatedDebugContents, support::little); - ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.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: - // 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, StringTableReferences, - SS.getRecordData()); - } else { - mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap, - IDTable, StringTableReferences, - SS.getRecordData()); - } - break; - default: - // FIXME: Process the rest of the subsections. - break; - } } - } - // 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 (DebugChunk->getSectionName() == ".debug$F") { + ArrayRef RelocatedDebugContents = + relocateDebugChunk(Alloc, *DebugChunk); - if (!StringTableReferences.empty()) - warn("No StringTable subsection was encountered, but there are string " - "table references"); - return; - } + FixedStreamArray FpoRecords; + BinaryStreamReader Reader(RelocatedDebugContents, support::little); + uint32_t Count = RelocatedDebugContents.size() / sizeof(object::FpoData); + ExitOnErr(Reader.readArray(FpoRecords, Count)); - // 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()); + // These are already relocated and don't refer to the string table, so we + // can just copy it. + for (const object::FpoData &FD : FpoRecords) + DbiBuilder.addOldFpoData(FD); 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)); + // Do any post-processing now that all .debug$S sections have been processed. + DSH.finish(); } 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); - } + addTypeInfo(Builder.getTpiBuilder(), getTypeTable()); + addTypeInfo(Builder.getIpiBuilder(), getIDTable()); 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; - }); + sort(parallel::par, 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"); } } +// Mimic MSVC which surrounds arguments containing whitespace with quotes. +// Double double-quotes are handled, so that the resulting string can be +// executed again on the cmd-line. +static std::string quote(ArrayRef Args) { + std::string R; + R.reserve(256); + for (StringRef A : Args) { + if (!R.empty()) + R.push_back(' '); + bool HasWS = A.find(' ') != StringRef::npos; + bool HasQ = A.find('"') != StringRef::npos; + if (HasWS || HasQ) + R.push_back('"'); + if (HasQ) { + SmallVector S; + A.split(S, '"'); + R.append(join(S, "\"\"")); + } else { + R.append(A); + } + if (HasWS || HasQ) + R.push_back('"'); + } + return R; +} + 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 = 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, " "); + std::string ArgStr = quote(Args); EBS.Fields.push_back("cwd"); SmallString<64> cwd; - sys::fs::current_path(cwd); + if (Config->PDBSourcePath.empty()) + sys::fs::current_path(cwd); + else + cwd = Config->PDBSourcePath; EBS.Fields.push_back(cwd); EBS.Fields.push_back("exe"); SmallString<64> exe = Config->Argv[0]; - llvm::sys::fs::make_absolute(exe); + pdbMakeAbsolute(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.Header.Characteristics; Sym.Length = OS.getVirtualSize(); 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) { + 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(); + codeview::GUID Guid; + PDB.commit(&Guid); + memcpy(&BuildId->PDB70.Signature, &Guid, 16); } -void PDBLinker::initialize(const llvm::codeview::DebugInfo &BuildId) { +void PDBLinker::initialize(llvm::codeview::DebugInfo *BuildId) { ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize + BuildId->Signature.CVSignature = OMF::Signature::PDB70; + // Signature is set to a hash of the PDB contents when the PDB is done. + memset(BuildId->PDB70.Signature, 0, 16); + BuildId->PDB70.Age = 1; + // 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(); - GUID uuid; - memcpy(&uuid, &BuildId.PDB70.Signature, sizeof(uuid)); - InfoBuilder.setAge(BuildId.PDB70.Age); - InfoBuilder.setGuid(uuid); InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70); + InfoBuilder.setHashPDBContentsToGUID(true); // Add an empty DBI stream. pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); - DbiBuilder.setAge(BuildId.PDB70.Age); + DbiBuilder.setAge(BuildId->PDB70.Age); DbiBuilder.setVersionHeader(pdb::PdbDbiV70); 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::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); + pdbMakeAbsolute(NativePath); 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()) { + for (Chunk *C : OS->Chunks) { 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() { +void PDBLinker::commit(codeview::GUID *Guid) { // Write to a file. - ExitOnErr(Builder.commit(Config->PDBPath)); + ExitOnErr(Builder.commit(Config->PDBPath, Guid)); } 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; + Optional NameIndex; + Optional LineNumber; for (LineColumnEntry &Entry : Lines) { for (const LineNumberEntry &LN : Entry.LineNumbers) { + LineInfo LI(LN.Flags); if (LN.Offset > OffsetInLinetable) { + if (!NameIndex) { + NameIndex = Entry.NameIndex; + LineNumber = LI.getStartLine(); + } StringRef Filename = - ExitOnErr(getFileName(CVStrTab, Checksums, NameIndex)); - return {Filename, LineNumber}; + 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}; + if (!NameIndex) + return {"", 0}; + StringRef Filename = ExitOnErr(getFileName(CVStrTab, Checksums, *NameIndex)); + return {Filename, *LineNumber}; } Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/PDB.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/PDB.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/PDB.h (revision 343217) @@ -1,38 +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); + llvm::codeview::DebugInfo *BuildId); std::pair getFileLine(const SectionChunk *C, uint32_t Addr); } } #endif Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/SymbolTable.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/SymbolTable.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/SymbolTable.cpp (revision 343217) @@ -1,461 +1,548 @@ //===- 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) { 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) + if (Config->ForceUnresolved) 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) { +// Returns the symbol in SC whose value is <= Addr that is closest to Addr. +// This is generally the global variable or function whose definition contains +// Addr. +static Symbol *getSymbol(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(); + return Candidate; } -static std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) { +std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) { struct Location { - StringRef SymName; + Symbol *Sym; 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}); + Symbol *Sym = getSymbol(SC, R.VirtualAddress); + if (!FileLine.first.empty() || Sym) + Locations.push_back({Sym, FileLine}); } } if (Locations.empty()) - return "\n>>> referenced by " + toString(File) + "\n"; + return "\n>>> referenced by " + toString(File); 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 << ')'; + if (Loc.Sym) + OS << ":(" << toString(*Loc.Sym) << ')'; } - OS << '\n'; return OS.str(); } +void SymbolTable::loadMinGWAutomaticImports() { + for (auto &I : SymMap) { + Symbol *Sym = I.second; + auto *Undef = dyn_cast(Sym); + if (!Undef) + continue; + if (!Sym->IsUsedInRegularObj) + continue; + + StringRef Name = Undef->getName(); + + if (Name.startswith("__imp_")) + continue; + // If we have an undefined symbol, but we have a Lazy representing a + // symbol we could load from file, make sure to load that. + Lazy *L = dyn_cast_or_null(find(("__imp_" + Name).str())); + if (!L || L->PendingArchiveLoad) + continue; + + log("Loading lazy " + L->getName() + " from " + L->File->getName() + + " for automatic import"); + L->PendingArchiveLoad = true; + L->File->addMember(&L->Sym); + } +} + +bool SymbolTable::handleMinGWAutomaticImport(Symbol *Sym, StringRef Name) { + if (Name.startswith("__imp_")) + return false; + Defined *Imp = dyn_cast_or_null(find(("__imp_" + Name).str())); + if (!Imp) + return false; + + // Replace the reference directly to a variable with a reference + // to the import address table instead. This obviously isn't right, + // but we mark the symbol as IsRuntimePseudoReloc, and a later pass + // will add runtime pseudo relocations for every relocation against + // this Symbol. The runtime pseudo relocation framework expects the + // reference itself to point at the IAT entry. + size_t ImpSize = 0; + if (isa(Imp)) { + log("Automatically importing " + Name + " from " + + cast(Imp)->getDLLName()); + ImpSize = sizeof(DefinedImportData); + } else if (isa(Imp)) { + log("Automatically importing " + Name + " from " + + toString(cast(Imp)->File)); + ImpSize = sizeof(DefinedRegular); + } else { + warn("unable to automatically import " + Name + " from " + Imp->getName() + + " from " + toString(cast(Imp)->File) + + "; unexpected symbol type"); + return false; + } + Sym->replaceKeepingName(Imp, ImpSize); + Sym->IsRuntimePseudoReloc = true; + + // There may exist symbols named .refptr. which only consist + // of a single pointer to . If it turns out is + // automatically imported, we don't need to keep the .refptr. + // pointer at all, but redirect all accesses to it to the IAT entry + // for __imp_ instead, and drop the whole .refptr. chunk. + DefinedRegular *Refptr = + dyn_cast_or_null(find((".refptr." + Name).str())); + if (Refptr && Refptr->getChunk()->getSize() == Config->Wordsize) { + SectionChunk *SC = dyn_cast_or_null(Refptr->getChunk()); + if (SC && SC->Relocs.size() == 1 && *SC->symbols().begin() == Sym) { + log("Replacing .refptr." + Name + " with " + Imp->getName()); + Refptr->getChunk()->Live = false; + Refptr->replaceKeepingName(Imp, ImpSize); + } + } + return true; +} + 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; } } + // We don't want to report missing Microsoft precompiled headers symbols. + // A proper message will be emitted instead in PDBLinker::aquirePrecompObj + if (Name.contains("_PchSym_")) + continue; + + if (Config->MinGW && handleMinGWAutomaticImport(Sym, Name)) + continue; + // Remaining undefined symbols are not fatal if /force is specified. // They are replaced with dummy defined symbols. - if (Config->Force) + if (Config->ForceUnresolved) 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()); + errorOrWarn(": undefined symbol: " + toString(*B)); if (Config->WarnLocallyDefinedImported) if (Symbol *Imp = LocalImports.lookup(B)) - warn(": locally defined symbol imported: " + Imp->getName() + + warn(": locally defined symbol imported: " + toString(*Imp) + " (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("undefined symbol: " + Sym->getName() + + errorOrWarn("undefined symbol: " + toString(*Sym) + 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]"); + warn(toString(File) + + ": locally defined symbol imported: " + toString(*Imp) + + " (defined in " + toString(Imp->getFile()) + ") [LNK4217]"); } } } std::pair SymbolTable::insert(StringRef Name) { + bool Inserted = false; Symbol *&Sym = SymMap[CachedHashStringRef(Name)]; - if (Sym) - return {Sym, false}; - Sym = reinterpret_cast(make()); - Sym->IsUsedInRegularObj = false; - Sym->PendingArchiveLoad = false; - return {Sym, true}; + if (!Sym) { + Sym = reinterpret_cast(make()); + Sym->IsUsedInRegularObj = false; + Sym->PendingArchiveLoad = false; + Inserted = true; + } + return {Sym, Inserted}; } +std::pair SymbolTable::insert(StringRef Name, InputFile *File) { + std::pair Result = insert(Name); + if (!File || !isa(File)) + Result.first->IsUsedInRegularObj = true; + return Result; +} + 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; + std::tie(S, WasInserted) = insert(Name, F); 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)); + std::string Msg = "duplicate symbol: " + toString(*Existing) + " in " + + toString(Existing->getFile()) + " and in " + + toString(NewFile); + + if (Config->ForceMultiple) + warn(Msg); + else + error(Msg); } Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) { Symbol *S; bool WasInserted; - std::tie(S, WasInserted) = insert(N); + std::tie(S, WasInserted) = insert(N, nullptr); 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); + std::tie(S, WasInserted) = insert(N, nullptr); 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); + std::tie(S, WasInserted) = insert(N, nullptr); 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; + std::tie(S, WasInserted) = insert(N, F); 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; + std::tie(S, WasInserted) = insert(N, F); 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; + std::tie(S, WasInserted) = insert(N, F); 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; } Symbol *SymbolTable::addImportData(StringRef N, ImportFile *F) { Symbol *S; bool WasInserted; - std::tie(S, WasInserted) = insert(N); + std::tie(S, WasInserted) = insert(N, nullptr); S->IsUsedInRegularObj = true; if (WasInserted || isa(S) || isa(S)) { replaceSymbol(S, N, F); return S; } reportDuplicate(S, F); return nullptr; } Symbol *SymbolTable::addImportThunk(StringRef Name, DefinedImportData *ID, uint16_t Machine) { Symbol *S; bool WasInserted; - std::tie(S, WasInserted) = insert(Name); + std::tie(S, WasInserted) = insert(Name, nullptr); S->IsUsedInRegularObj = true; if (WasInserted || isa(S) || isa(S)) { replaceSymbol(S, Name, ID, Machine); 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) { 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 Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/SymbolTable.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/SymbolTable.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/SymbolTable.h (revision 343217) @@ -1,123 +1,131 @@ //===- 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(); + void loadMinGWAutomaticImports(); + bool handleMinGWAutomaticImport(Symbol *Sym, StringRef Name); + // 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); 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: + /// Inserts symbol if not already present. std::pair insert(StringRef Name); + /// Same as insert(Name), but also sets IsUsedInRegularObj. + std::pair insert(StringRef Name, InputFile *F); StringRef findByPrefix(StringRef Prefix); llvm::DenseMap SymMap; std::unique_ptr LTO; }; extern SymbolTable *Symtab; + +std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex); } // namespace coff } // namespace lld #endif Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/Symbols.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/Symbols.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/Symbols.cpp (revision 343217) @@ -1,100 +1,107 @@ //===- 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 "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 = 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(); + return R->getChunk()->Live; if (auto *Imp = dyn_cast(this)) return Imp->File->Live; if (auto *Imp = dyn_cast(this)) return Imp->WrappedSym->File->ThunkLive; // Assume any other kind of symbol is live. return true; +} + +// MinGW specific. +void Symbol::replaceKeepingName(Symbol *Other, size_t Size) { + StringRef OrigName = Name; + memcpy(this, Other, Size); + Name = OrigName; } 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::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 Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/Symbols.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/Symbols.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/Symbols.h (revision 343217) @@ -1,432 +1,436 @@ //===- 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 + // symbols as those are the most prevalent 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 + // the higher kind when testing whether 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(); + void replaceKeepingName(Symbol *Other, size_t Size); + // 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) {} + IsRuntimePseudoReloc(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; + unsigned IsRuntimePseudoReloc : 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; } // 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". +// If you have a symbol "foo" in your object file, a symbol name +// "__imp_foo" becomes automatically available as a pointer to "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 Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/Writer.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/Writer.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/Writer.cpp (revision 343217) @@ -1,1292 +1,1719 @@ //===- 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 = sizeof(dos_header) + sizeof(DOSProgram); static_assert(DOSStubSize % 8 == 0, "DOSStub size must be multiple of 8"); -static const int NumberfOfDataDirectory = 16; +static const int NumberOfDataDirectory = 16; namespace { class DebugDirectoryChunk : public Chunk { public: - DebugDirectoryChunk(const std::vector &R) : Records(R) {} + DebugDirectoryChunk(const std::vector &R, bool WriteRepro) + : Records(R), WriteRepro(WriteRepro) {} size_t getSize() const override { - return Records.size() * sizeof(debug_directory); + return (Records.size() + int(WriteRepro)) * 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); + fillEntry(D, COFF::IMAGE_DEBUG_TYPE_CODEVIEW, Record->getSize(), + Record->getRVA(), Offs); ++D; } + + if (WriteRepro) { + // FIXME: The COFF spec allows either a 0-sized entry to just say + // "the timestamp field is really a hash", or a 4-byte size field + // followed by that many bytes containing a longer hash (with the + // lowest 4 bytes usually being the timestamp in little-endian order). + // Consider storing the full 8 bytes computed by xxHash64 here. + fillEntry(D, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0); + } } void setTimeDateStamp(uint32_t TimeDateStamp) { for (support::ulittle32_t *TDS : TimeDateStamps) *TDS = TimeDateStamp; } private: + void fillEntry(debug_directory *D, COFF::DebugType DebugType, size_t Size, + uint64_t RVA, uint64_t Offs) const { + D->Characteristics = 0; + D->TimeDateStamp = 0; + D->MajorVersion = 0; + D->MinorVersion = 0; + D->Type = DebugType; + D->SizeOfData = Size; + D->AddressOfRawData = RVA; + D->PointerToRawData = Offs; + + TimeDateStamps.push_back(&D->TimeDateStamp); + } + mutable std::vector TimeDateStamps; const std::vector &Records; + bool WriteRepro; }; class CVDebugRecordChunk : public Chunk { public: size_t getSize() const override { 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 (!Config->PDBAltPath.empty()) memcpy(P, Config->PDBAltPath.data(), Config->PDBAltPath.size()); P[Config->PDBAltPath.size()] = '\0'; } 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 appendImportThunks(); + void locateImportTables( + std::map, std::vector> &Map); void createExportTable(); void mergeSections(); + void readRelocTargets(); + void removeUnusedSections(); void assignAddresses(); + void finalizeAddresses(); void removeEmptySections(); void createSymbolAndStringTable(); void openFile(StringRef OutputPath); template void writeHeader(); void createSEHTable(); + void createRuntimePseudoRelocs(); + void insertCtorDtorSymbols(); 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(); + void sortCRTSectionChunks(std::vector &Chunks); llvm::Optional createSymbol(Defined *D); size_t addEntryToStringTable(StringRef Str); OutputSection *findSection(StringRef Name); 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; + Chunk *ImportTableStart = nullptr; + uint64_t ImportTableSize = 0; + Chunk *IATStart = nullptr; + uint64_t IATSize = 0; DelayLoadContents DelayIdata; EdataContents Edata; bool SetNoSEHCharacteristic = false; 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; + OutputSection *CtorsSec; + OutputSection *DtorsSec; // 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::addChunk(Chunk *C) { Chunks.push_back(C); C->setOutputSection(this); } +void OutputSection::insertChunkAtStart(Chunk *C) { + Chunks.insert(Chunks.begin(), C); + C->setOutputSection(this); +} + void OutputSection::setPermissions(uint32_t C) { Header.Characteristics &= ~PermMask; Header.Characteristics |= C; } 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. +// Check whether the target address S is in range from a relocation +// of type RelType at address P. +static bool isInRange(uint16_t RelType, uint64_t S, uint64_t P, int Margin) { + assert(Config->Machine == ARMNT); + int64_t Diff = AbsoluteDifference(S, P + 4) + Margin; + switch (RelType) { + case IMAGE_REL_ARM_BRANCH20T: + return isInt<21>(Diff); + case IMAGE_REL_ARM_BRANCH24T: + case IMAGE_REL_ARM_BLX23T: + return isInt<25>(Diff); + default: + return true; + } +} + +// Return the last thunk for the given target if it is in range, +// or create a new one. +static std::pair +getThunk(DenseMap &LastThunks, Defined *Target, uint64_t P, + uint16_t Type, int Margin) { + Defined *&LastThunk = LastThunks[Target->getRVA()]; + if (LastThunk && isInRange(Type, LastThunk->getRVA(), P, Margin)) + return {LastThunk, false}; + RangeExtensionThunk *C = make(Target); + Defined *D = make("", C); + LastThunk = D; + return {D, true}; +} + +// This checks all relocations, and for any relocation which isn't in range +// it adds a thunk after the section chunk that contains the relocation. +// If the latest thunk for the specific target is in range, that is used +// instead of creating a new thunk. All range checks are done with the +// specified margin, to make sure that relocations that originally are in +// range, but only barely, also get thunks - in case other added thunks makes +// the target go out of range. // -// 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; +// After adding thunks, we verify that all relocations are in range (with +// no extra margin requirements). If this failed, we restart (throwing away +// the previously created thunks) and retry with a wider margin. +static bool createThunks(std::vector &Chunks, int Margin) { + bool AddressesChanged = false; + DenseMap LastThunks; + size_t ThunksSize = 0; + // Recheck Chunks.size() each iteration, since we can insert more + // elements into it. + for (size_t I = 0; I != Chunks.size(); ++I) { + SectionChunk *SC = dyn_cast_or_null(Chunks[I]); + if (!SC) + continue; + size_t ThunkInsertionSpot = I + 1; - auto ExpectedBinary = llvm::object::createBinary(Path); - if (!ExpectedBinary) { - consumeError(ExpectedBinary.takeError()); - return None; - } + // Try to get a good enough estimate of where new thunks will be placed. + // Offset this by the size of the new thunks added so far, to make the + // estimate slightly better. + size_t ThunkInsertionRVA = SC->getRVA() + SC->getSize() + ThunksSize; + for (size_t J = 0, E = SC->Relocs.size(); J < E; ++J) { + const coff_relocation &Rel = SC->Relocs[J]; + Symbol *&RelocTarget = SC->RelocTargets[J]; - auto Binary = std::move(*ExpectedBinary); - if (!Binary.getBinary()->isCOFF()) - return None; + // The estimate of the source address P should be pretty accurate, + // but we don't know whether the target Symbol address should be + // offset by ThunkSize or not (or by some of ThunksSize but not all of + // it), giving us some uncertainty once we have added one thunk. + uint64_t P = SC->getRVA() + Rel.VirtualAddress + ThunksSize; - std::error_code EC; - COFFObjectFile File(Binary.getBinary()->getMemoryBufferRef(), EC); - if (EC) - return None; + Defined *Sym = dyn_cast_or_null(RelocTarget); + if (!Sym) + continue; - // 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; + uint64_t S = Sym->getRVA(); - for (const auto &DebugDir : File.debug_directories()) { - if (DebugDir.Type != IMAGE_DEBUG_TYPE_CODEVIEW) + if (isInRange(Rel.Type, S, P, Margin)) + continue; + + // If the target isn't in range, hook it up to an existing or new + // thunk. + Defined *Thunk; + bool WasNew; + std::tie(Thunk, WasNew) = getThunk(LastThunks, Sym, P, Rel.Type, Margin); + if (WasNew) { + Chunk *ThunkChunk = Thunk->getChunk(); + ThunkChunk->setRVA( + ThunkInsertionRVA); // Estimate of where it will be located. + Chunks.insert(Chunks.begin() + ThunkInsertionSpot, ThunkChunk); + ThunkInsertionSpot++; + ThunksSize += ThunkChunk->getSize(); + ThunkInsertionRVA += ThunkChunk->getSize(); + AddressesChanged = true; + } + RelocTarget = Thunk; + } + } + return AddressesChanged; +} + +// Verify that all relocations are in range, with no extra margin requirements. +static bool verifyRanges(const std::vector Chunks) { + for (Chunk *C : Chunks) { + SectionChunk *SC = dyn_cast_or_null(C); + if (!SC) continue; - const codeview::DebugInfo *ExistingDI = nullptr; - StringRef PDBFileName; - if (auto EC = File.getDebugPDBInfo(ExistingDI, PDBFileName)) { - (void)EC; - return None; + for (size_t J = 0, E = SC->Relocs.size(); J < E; ++J) { + const coff_relocation &Rel = SC->Relocs[J]; + Symbol *RelocTarget = SC->RelocTargets[J]; + + Defined *Sym = dyn_cast_or_null(RelocTarget); + if (!Sym) + continue; + + uint64_t P = SC->getRVA() + Rel.VirtualAddress; + uint64_t S = Sym->getRVA(); + + if (!isInRange(Rel.Type, S, P, 0)) + return false; } - // 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; + return true; } +// Assign addresses and add thunks if necessary. +void Writer::finalizeAddresses() { + assignAddresses(); + if (Config->Machine != ARMNT) + return; + + size_t OrigNumChunks = 0; + for (OutputSection *Sec : OutputSections) { + Sec->OrigChunks = Sec->Chunks; + OrigNumChunks += Sec->Chunks.size(); + } + + int Pass = 0; + int Margin = 1024 * 100; + while (true) { + // First check whether we need thunks at all, or if the previous pass of + // adding them turned out ok. + bool RangesOk = true; + size_t NumChunks = 0; + for (OutputSection *Sec : OutputSections) { + if (!verifyRanges(Sec->Chunks)) { + RangesOk = false; + break; + } + NumChunks += Sec->Chunks.size(); + } + if (RangesOk) { + if (Pass > 0) + log("Added " + Twine(NumChunks - OrigNumChunks) + " thunks with " + + "margin " + Twine(Margin) + " in " + Twine(Pass) + " passes"); + return; + } + + if (Pass >= 10) + fatal("adding thunks hasn't converged after " + Twine(Pass) + " passes"); + + if (Pass > 0) { + // If the previous pass didn't work out, reset everything back to the + // original conditions before retrying with a wider margin. This should + // ideally never happen under real circumstances. + for (OutputSection *Sec : OutputSections) { + Sec->Chunks = Sec->OrigChunks; + for (Chunk *C : Sec->Chunks) + C->resetRelocTargets(); + } + Margin *= 2; + } + + // Try adding thunks everywhere where it is needed, with a margin + // to avoid things going out of range due to the added thunks. + bool AddressesChanged = false; + for (OutputSection *Sec : OutputSections) + AddressesChanged |= createThunks(Sec->Chunks, Margin); + // If the verification above thought we needed thunks, we should have + // added some. + assert(AddressesChanged); + + // Recalculate the layout for the whole image (and verify the ranges at + // the start of the next round). + assignAddresses(); + + Pass++; + } +} + // The main function of the writer. void Writer::run() { ScopedTimer T1(CodeLayoutTimer); + createImportTables(); createSections(); createMiscChunks(); - createImportTables(); + appendImportThunks(); createExportTable(); mergeSections(); - assignAddresses(); + readRelocTargets(); + removeUnusedSections(); + finalizeAddresses(); 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(); T1.stop(); if (!Config->PDBPath.empty() && Config->Debug) { assert(BuildId); - createPDB(Symtab, OutputSections, SectionTable, *BuildId->BuildId); + createPDB(Symtab, OutputSections, SectionTable, BuildId->BuildId); } + writeBuildId(); writeMapFile(OutputSections); ScopedTimer T2(DiskCommitTimer); if (auto E = Buffer->commit()) fatal("failed to write the output file: " + toString(std::move(E))); } static StringRef getOutputSectionName(StringRef Name) { StringRef S = Name.split('$').first; // Treat a later period as a separator for MinGW, for sections like // ".ctors.01234". return S.substr(0, S.find('.', 1)); } // 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); }); } +// Sort concrete section chunks from GNU import libraries. +// +// GNU binutils doesn't use short import files, but instead produces import +// libraries that consist of object files, with section chunks for the .idata$* +// sections. These are linked just as regular static libraries. Each import +// library consists of one header object, one object file for every imported +// symbol, and one trailer object. In order for the .idata tables/lists to +// be formed correctly, the section chunks within each .idata$* section need +// to be grouped by library, and sorted alphabetically within each library +// (which makes sure the header comes first and the trailer last). +static bool fixGnuImportChunks( + std::map, std::vector> &Map) { + uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; + + // Make sure all .idata$* section chunks are mapped as RDATA in order to + // be sorted into the same sections as our own synthesized .idata chunks. + for (auto &Pair : Map) { + StringRef SectionName = Pair.first.first; + uint32_t OutChars = Pair.first.second; + if (!SectionName.startswith(".idata")) + continue; + if (OutChars == RDATA) + continue; + std::vector &SrcVect = Pair.second; + std::vector &DestVect = Map[{SectionName, RDATA}]; + DestVect.insert(DestVect.end(), SrcVect.begin(), SrcVect.end()); + SrcVect.clear(); + } + + bool HasIdata = false; + // Sort all .idata$* chunks, grouping chunks from the same library, + // with alphabetical ordering of the object fils within a library. + for (auto &Pair : Map) { + StringRef SectionName = Pair.first.first; + if (!SectionName.startswith(".idata")) + continue; + + std::vector &Chunks = Pair.second; + if (!Chunks.empty()) + HasIdata = true; + std::stable_sort(Chunks.begin(), Chunks.end(), [&](Chunk *S, Chunk *T) { + SectionChunk *SC1 = dyn_cast_or_null(S); + SectionChunk *SC2 = dyn_cast_or_null(T); + if (!SC1 || !SC2) { + // if SC1, order them ascending. If SC2 or both null, + // S is not less than T. + return SC1 != nullptr; + } + // Make a string with "libraryname/objectfile" for sorting, achieving + // both grouping by library and sorting of objects within a library, + // at once. + std::string Key1 = + (SC1->File->ParentName + "/" + SC1->File->getName()).str(); + std::string Key2 = + (SC2->File->ParentName + "/" + SC2->File->getName()).str(); + return Key1 < Key2; + }); + } + return HasIdata; +} + +// Add generated idata chunks, for imported symbols and DLLs, and a +// terminator in .idata$2. +static void addSyntheticIdata( + IdataContents &Idata, + std::map, std::vector> &Map) { + uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; + Idata.create(); + + // Add the .idata content in the right section groups, to allow + // chunks from other linked in object files to be grouped together. + // See Microsoft PE/COFF spec 5.4 for details. + auto Add = [&](StringRef N, std::vector &V) { + std::vector &DestVect = Map[{N, RDATA}]; + DestVect.insert(DestVect.end(), V.begin(), V.end()); + }; + + // The loader assumes a specific order of data. + // Add each type in the correct order. + Add(".idata$2", Idata.Dirs); + Add(".idata$4", Idata.Lookups); + Add(".idata$5", Idata.Addresses); + Add(".idata$6", Idata.Hints); + Add(".idata$7", Idata.DLLNames); +} + +// Locate the first Chunk and size of the import directory list and the +// IAT. +void Writer::locateImportTables( + std::map, std::vector> &Map) { + uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; + std::vector &ImportTables = Map[{".idata$2", RDATA}]; + if (!ImportTables.empty()) + ImportTableStart = ImportTables.front(); + for (Chunk *C : ImportTables) + ImportTableSize += C->getSize(); + + std::vector &IAT = Map[{".idata$5", RDATA}]; + if (!IAT.empty()) + IATStart = IAT.front(); + for (Chunk *C : IAT) + IATSize += C->getSize(); +} + // Create output section objects and add them to OutputSections. void Writer::createSections() { // 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); + CtorsSec = CreateSection(".ctors", DATA | R | W); + DtorsSec = CreateSection(".dtors", DATA | R | W); // 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 (SC && !SC->Live) { if (Config->Verbose) SC->printDiscardedMessage(); continue; } Map[{C->getSectionName(), C->getOutputCharacteristics()}].push_back(C); } + // Even in non MinGW cases, we might need to link against GNU import + // libraries. + bool HasIdata = fixGnuImportChunks(Map); + if (!Idata.empty()) + HasIdata = true; + + if (HasIdata) + addSyntheticIdata(Idata, Map); + // Process an /order option. if (!Config->Order.empty()) for (auto &Pair : Map) sortBySectionOrder(Pair.second); + if (HasIdata) + locateImportTables(Map); + // 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. - for (auto Pair : Map) { + for (auto &Pair : Map) { 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") + if (Name == ".CRT") { + // 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. OutChars = DATA | R; + log("Processing section " + Pair.first.first + " -> " + Name); + + sortCRTSectionChunks(Pair.second); + } + OutputSection *Sec = CreateSection(Name, OutChars); std::vector &Chunks = Pair.second; for (Chunk *C : Chunks) Sec->addChunk(C); } // 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() { for (auto &P : MergeChunk::Instances) RdataSec->addChunk(P.second); // Create thunks for locally-dllimported symbols. if (!Symtab->LocalImportChunks.empty()) { for (Chunk *C : Symtab->LocalImportChunks) RdataSec->addChunk(C); } // Create Debug Information Chunks - if (Config->Debug) { - DebugDirectory = make(DebugRecords); + OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec; + if (Config->Debug || Config->Repro) { + DebugDirectory = make(DebugRecords, Config->Repro); + DebugInfoSec->addChunk(DebugDirectory); + } - OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec; - + if (Config->Debug) { // 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); + BuildId = make(); + DebugRecords.push_back(BuildId); - DebugInfoSec->addChunk(DebugDirectory); for (Chunk *C : DebugRecords) DebugInfoSec->addChunk(C); } // Create SEH table. x86-only. if (Config->Machine == I386) createSEHTable(); // Create /guard:cf tables if requested. if (Config->GuardCF != GuardCFLevel::Off) createGuardCFTables(); + + if (Config->MinGW) { + createRuntimePseudoRelocs(); + + insertCtorDtorSymbols(); + } } // 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(); - 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 (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(*ImpSym)); DelayIdata.add(ImpSym); } else { Idata.add(ImpSym); } } +} - if (!Idata.empty()) - for (Chunk *C : Idata.getChunks()) - IdataSec->addChunk(C); +void Writer::appendImportThunks() { + if (ImportFile::Instances.empty()) + return; + for (ImportFile *File : ImportFile::Instances) { + if (!File->Live) + continue; + + if (!File->ThunkSym) + continue; + + if (!isa(File->ThunkSym)) + fatal(toString(*File->ThunkSym) + " was replaced"); + DefinedImportThunk *Thunk = cast(File->ThunkSym); + if (File->ThunkLive) + TextSec->addChunk(Thunk->getChunk()); + } + if (!DelayIdata.empty()) { Defined *Helper = cast(Config->DelayLoadHelper); DelayIdata.create(Helper); for (Chunk *C : DelayIdata.getChunks()) DidatSec->addChunk(C); for (Chunk *C : DelayIdata.getDataChunks()) DataSec->addChunk(C); for (Chunk *C : DelayIdata.getCodeChunks()) TextSec->addChunk(C); } } void Writer::createExportTable() { if (Config->Exports.empty()) return; for (Chunk *C : Edata.Chunks) EdataSec->addChunk(C); } +void Writer::removeUnusedSections() { + // Remove sections that we can be sure won't get content, to avoid + // allocating space for their section headers. + auto IsUnused = [this](OutputSection *S) { + if (S == RelocSec) + return false; // This section is populated later. + // MergeChunks have zero size at this point, as their size is finalized + // later. Only remove sections that have no Chunks at all. + return S->Chunks.empty(); + }; + OutputSections.erase( + std::remove_if(OutputSections.begin(), OutputSections.end(), IsUnused), + OutputSections.end()); +} + // 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) { 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; 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; 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; return Sym; } void Writer::createSymbolAndStringTable() { // 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) { if (Sec->Name.size() <= COFF::NameSize) continue; if ((Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) continue; Sec->setStringTableOff(addEntryToStringTable(Sec->Name)); } 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; // We position the symbol table to be adjacent to the end of the last section. 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(); + if (!PdataSec->Chunks.empty()) { + FirstPdata = PdataSec->Chunks.front(); + LastPdata = PdataSec->Chunks.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 initialize their relocation targets. +void Writer::readRelocTargets() { + for (OutputSection *Sec : OutputSections) + for_each(parallel::par, Sec->Chunks.begin(), Sec->Chunks.end(), + [&](Chunk *C) { C->readRelocTargets(); }); +} + // 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(data_directory) * NumberOfDataDirectory + sizeof(coff_section) * OutputSections.size(); SizeOfHeaders += Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); SizeOfHeaders = alignTo(SizeOfHeaders, SectorSize); uint64_t RVA = PageSize; // The first page is kept unmapped. FileSize = SizeOfHeaders; for (OutputSection *Sec : OutputSections) { if (Sec == RelocSec) addBaserels(); uint64_t RawSize = 0, VirtualSize = 0; Sec->Header.VirtualAddress = RVA; - for (Chunk *C : Sec->getChunks()) { + for (Chunk *C : Sec->Chunks) { 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 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 += 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; + sizeof(PEHeaderTy) + sizeof(data_directory) * NumberOfDataDirectory; // 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->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; + PE->NumberOfRvaAndSize = NumberOfDataDirectory; 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; + Buf += sizeof(*Dir) * NumberOfDataDirectory; 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 (ImportTableStart) { + Dir[IMPORT_TABLE].RelativeVirtualAddress = ImportTableStart->getRVA(); + Dir[IMPORT_TABLE].Size = ImportTableSize; } + if (IATStart) { + Dir[IAT].RelativeVirtualAddress = IATStart->getRVA(); + Dir[IAT].Size = IATSize; + } if (RsrcSec->getVirtualSize()) { Dir[RESOURCE_TABLE].RelativeVirtualAddress = RsrcSec->getRVA(); Dir[RESOURCE_TABLE].Size = RsrcSec->getVirtualSize(); } if (FirstPdata) { Dir[EXCEPTION_TABLE].RelativeVirtualAddress = FirstPdata->getRVA(); Dir[EXCEPTION_TABLE].Size = LastPdata->getRVA() + LastPdata->getSize() - FirstPdata->getRVA(); } 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) { + if (DebugDirectory) { 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() { // Set the no SEH characteristic on x86 binaries unless we find exception // handlers. SetNoSEHCharacteristic = true; SymbolRVASet Handlers; for (ObjFile *File : ObjFile::Instances) { // FIXME: We should error here instead of earlier unless /safeseh:no was // passed. if (!File->hasSafeSEH()) return; markSymbolsForRVATable(File, File->getSXDataChunks(), Handlers); } // 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}); } +// Given a symbol, add it to the GFIDs table if it is a live, defined, function +// symbol in an executable section. +static void maybeAddAddressTakenFunction(SymbolRVASet &AddressTakenSyms, + Symbol *S) { + auto *D = dyn_cast_or_null(S); + + // Ignore undefined symbols and references to non-functions (e.g. globals and + // labels). + if (!D || + D->getCOFFSymbol().getComplexType() != COFF::IMAGE_SYM_DTYPE_FUNCTION) + return; + + // Mark the symbol as address taken if it's in an executable section. + Chunk *RefChunk = D->getChunk(); + OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr; + if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE) + addSymbolToRVASet(AddressTakenSyms, D); +} + // 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()) + if (!SC || !SC->Live) 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); - } + for (const coff_relocation &Reloc : SC->Relocs) { + if (Config->Machine == I386 && Reloc.Type == COFF::IMAGE_REL_I386_REL32) + // Ignore relative relocations on x86. On x86_64 they can't be ignored + // since they're also used to compute absolute addresses. + continue; + + Symbol *Ref = SC->File->getSymbol(Reloc.SymbolTableIndex); + maybeAddAddressTakenFunction(UsedSymbols, Ref); } } } // 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)); + maybeAddAddressTakenFunction(AddressTakenSyms, Config->Entry); + // Mark exported symbols in executable sections as address-taken. + for (Export &E : Config->Exports) + maybeAddAddressTakenFunction(AddressTakenSyms, E.Sym); + // 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()) + if (!C->Live) 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; RVATableChunk *TableChunk = make(std::move(TableSymbols)); RdataSec->addChunk(TableChunk); Symbol *T = Symtab->findUnderscore(TableSym); Symbol *C = Symtab->findUnderscore(CountSym); replaceSymbol(T, T->getName(), TableChunk); cast(C)->setVA(TableChunk->getSize() / 4); } +// MinGW specific. Gather all relocations that are imported from a DLL even +// though the code didn't expect it to, produce the table that the runtime +// uses for fixing them up, and provide the synthetic symbols that the +// runtime uses for finding the table. +void Writer::createRuntimePseudoRelocs() { + std::vector Rels; + + for (Chunk *C : Symtab->getChunks()) { + auto *SC = dyn_cast(C); + if (!SC || !SC->Live) + continue; + SC->getRuntimePseudoRelocs(Rels); + } + + if (!Rels.empty()) + log("Writing " + Twine(Rels.size()) + " runtime pseudo relocations"); + PseudoRelocTableChunk *Table = make(Rels); + RdataSec->addChunk(Table); + EmptyChunk *EndOfList = make(); + RdataSec->addChunk(EndOfList); + + Symbol *HeadSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__"); + Symbol *EndSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__"); + replaceSymbol(HeadSym, HeadSym->getName(), Table); + replaceSymbol(EndSym, EndSym->getName(), EndOfList); +} + +// MinGW specific. +// The MinGW .ctors and .dtors lists have sentinels at each end; +// a (uintptr_t)-1 at the start and a (uintptr_t)0 at the end. +// There's a symbol pointing to the start sentinel pointer, __CTOR_LIST__ +// and __DTOR_LIST__ respectively. +void Writer::insertCtorDtorSymbols() { + AbsolutePointerChunk *CtorListHead = make(-1); + AbsolutePointerChunk *CtorListEnd = make(0); + AbsolutePointerChunk *DtorListHead = make(-1); + AbsolutePointerChunk *DtorListEnd = make(0); + CtorsSec->insertChunkAtStart(CtorListHead); + CtorsSec->addChunk(CtorListEnd); + DtorsSec->insertChunkAtStart(DtorListHead); + DtorsSec->addChunk(DtorListEnd); + + Symbol *CtorListSym = Symtab->findUnderscore("__CTOR_LIST__"); + Symbol *DtorListSym = Symtab->findUnderscore("__DTOR_LIST__"); + replaceSymbol(CtorListSym, CtorListSym->getName(), + CtorListHead); + replaceSymbol(DtorListSym, DtorListSym->getName(), + DtorListHead); +} + // 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; for (OutputSection *Sec : OutputSections) if (Sec->Name == Name) Sec->setPermissions(Perm); } } // Write section contents to a mmap'ed file. void Writer::writeSections() { // 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->Header.Characteristics & IMAGE_SCN_CNT_CODE) memset(SecBuf, 0xCC, Sec->getRawSize()); - for_each(parallel::par, Sec->getChunks().begin(), Sec->getChunks().end(), + for_each(parallel::par, Sec->Chunks.begin(), Sec->Chunks.end(), [&](Chunk *C) { C->writeTo(SecBuf); }); } } void Writer::writeBuildId() { // 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). + // PE contents. 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); - } + // BuildId->BuildId was filled in when the PDB was written. } // 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()); uint32_t Timestamp = Config->Timestamp; + uint64_t Hash = 0; + bool GenerateSyntheticBuildId = + Config->MinGW && Config->Debug && Config->PDBPath.empty(); + + if (Config->Repro || GenerateSyntheticBuildId) + Hash = xxHash64(OutputFileData); + if (Config->Repro) - Timestamp = static_cast(xxHash64(OutputFileData)); + Timestamp = static_cast(Hash); + if (GenerateSyntheticBuildId) { + // For MinGW builds without a PDB file, we still generate a build id + // to allow associating a crash dump to the executable. + BuildId->BuildId->PDB70.CVSignature = OMF::Signature::PDB70; + BuildId->BuildId->PDB70.Age = 1; + memcpy(BuildId->BuildId->PDB70.Signature, &Hash, 8); + // xxhash only gives us 8 bytes, so put some fixed data in the other half. + memcpy(&BuildId->BuildId->PDB70.Signature[8], "LLD PDB.", 8); + } + 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() { if (!FirstPdata) return; // We assume .pdata contains function table entries only. 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"; } +// The CRT section contains, among other things, the array of function +// pointers that initialize every global variable that is not trivially +// constructed. The CRT calls them one after the other prior to invoking +// main(). +// +// As per C++ spec, 3.6.2/2.3, +// "Variables with ordered initialization defined within a single +// translation unit shall be initialized in the order of their definitions +// in the translation unit" +// +// It is therefore critical to sort the chunks containing the function +// pointers in the order that they are listed in the object file (top to +// bottom), otherwise global objects might not be initialized in the +// correct order. +void Writer::sortCRTSectionChunks(std::vector &Chunks) { + auto SectionChunkOrder = [](const Chunk *A, const Chunk *B) { + auto SA = dyn_cast(A); + auto SB = dyn_cast(B); + assert(SA && SB && "Non-section chunks in CRT section!"); + + StringRef SAObj = SA->File->MB.getBufferIdentifier(); + StringRef SBObj = SB->File->MB.getBufferIdentifier(); + + return SAObj == SBObj && SA->getSectionNumber() < SB->getSectionNumber(); + }; + std::stable_sort(Chunks.begin(), Chunks.end(), SectionChunkOrder); + + if (Config->Verbose) { + for (auto &C : Chunks) { + auto SC = dyn_cast(C); + log(" " + SC->File->MB.getBufferIdentifier().str() + + ", SectionID: " + Twine(SC->getSectionNumber())); + } + } +} + OutputSection *Writer::findSection(StringRef Name) { for (OutputSection *Sec : OutputSections) if (Sec->Name == Name) return Sec; return nullptr; } uint32_t Writer::getSizeOfInitializedData() { uint32_t Res = 0; for (OutputSection *S : OutputSections) if (S->Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) Res += S->getRawSize(); return Res; } // Add base relocations to .reloc section. void Writer::addBaserels() { if (!Config->Relocatable) return; + RelocSec->Chunks.clear(); std::vector V; for (OutputSection *Sec : OutputSections) { if (Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) continue; // Collect all locations for base relocations. - for (Chunk *C : Sec->getChunks()) + for (Chunk *C : Sec->Chunks) C->getBaserels(&V); // Add the addresses to .reloc section. if (!V.empty()) addBaserelBlocks(V); V.clear(); } } // Add addresses to .reloc section. Note that addresses are grouped by page. 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; RelocSec->addChunk(make(Page, &V[I], &V[0] + J)); I = J; Page = P; } if (I == J) return; RelocSec->addChunk(make(Page, &V[I], &V[0] + J)); } Index: projects/clang800-import/contrib/llvm/tools/lld/COFF/Writer.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/COFF/Writer.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/COFF/Writer.h (revision 343217) @@ -1,73 +1,75 @@ //===- 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, uint32_t Chars) : Name(N) { Header.Characteristics = Chars; } void addChunk(Chunk *C); + void insertChunkAtStart(Chunk *C); void merge(OutputSection *Other); - ArrayRef getChunks() { return Chunks; } void addPermissions(uint32_t C); void setPermissions(uint32_t C); 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; llvm::StringRef Name; llvm::object::coff_section Header = {}; + std::vector Chunks; + std::vector OrigChunks; + private: uint32_t StringTableOff = 0; - std::vector Chunks; }; } } #endif Index: projects/clang800-import/contrib/llvm/tools/lld/Common/Args.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/Common/Args.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/Common/Args.cpp (revision 343217) @@ -1,66 +1,73 @@ //===- 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" +#include "llvm/Support/Path.h" using namespace llvm; using namespace lld; int lld::args::getInteger(opt::InputArgList &Args, unsigned Key, int Default) { 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)) { + for (auto *Arg : Args.filtered_reverse(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; +} + +StringRef lld::args::getFilenameWithoutExe(StringRef Path) { + if (Path.endswith_lower(".exe")) + return sys::path::stem(Path); + return sys::path::filename(Path); } Index: projects/clang800-import/contrib/llvm/tools/lld/Common/ErrorHandler.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/Common/ErrorHandler.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/Common/ErrorHandler.cpp (revision 343217) @@ -1,143 +1,144 @@ //===- 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/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(); + // Delete any temporary file, while keeping the memory mapping open. + if (errorHandler().OutputBuffer) + errorHandler().OutputBuffer->discard(); // 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); } Index: projects/clang800-import/contrib/llvm/tools/lld/Common/Strings.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/Common/Strings.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/Common/Strings.cpp (revision 343217) @@ -1,109 +1,104 @@ //===- 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); +Optional lld::demangleMSVC(StringRef Name) { + std::string Prefix; + if (Name.consume_front("__imp_")) + Prefix = "__declspec(dllimport) "; - 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; + // Demangle only C++ names. + if (!Name.startswith("?")) + return None; + + char *Buf = microsoftDemangle(Name.str().c_str(), nullptr, nullptr, nullptr); + if (!Buf) + return None; + std::string S(Buf); + free(Buf); + return Prefix + S; } 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; } Index: projects/clang800-import/contrib/llvm/tools/lld/Common/TargetOptionsCommandFlags.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/Common/TargetOptionsCommandFlags.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/Common/TargetOptionsCommandFlags.cpp (revision 343217) @@ -1,34 +1,35 @@ //===-- 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.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.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.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(); } +std::vector lld::GetMAttrs() { return ::MAttrs; } Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/GdbIndex.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/GdbIndex.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/GdbIndex.h (nonexistent) @@ -1,70 +0,0 @@ -//===- GdbIndex.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_GDB_INDEX_H -#define LLD_ELF_GDB_INDEX_H - -#include "InputFiles.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/Object/ELF.h" - -namespace lld { -namespace elf { - -class InputSection; - -struct LLDDWARFSection final : public llvm::DWARFSection { - InputSectionBase *Sec = nullptr; -}; - -template class LLDDwarfObj final : public llvm::DWARFObject { - LLDDWARFSection InfoSection; - LLDDWARFSection RangeSection; - LLDDWARFSection LineSection; - StringRef AbbrevSection; - StringRef GnuPubNamesSection; - StringRef GnuPubTypesSection; - StringRef StrSection; - - template - llvm::Optional findAux(const InputSectionBase &Sec, - uint64_t Pos, - ArrayRef Rels) const; - -public: - explicit LLDDwarfObj(ObjFile *Obj); - const llvm::DWARFSection &getInfoSection() const override { - return InfoSection; - } - const llvm::DWARFSection &getRangeSection() const override { - return RangeSection; - } - const llvm::DWARFSection &getLineSection() const override { - return LineSection; - } - StringRef getFileName() const override { return ""; } - StringRef getAbbrevSection() const override { return AbbrevSection; } - StringRef getStringSection() const override { return StrSection; } - StringRef getGnuPubNamesSection() const override { - return GnuPubNamesSection; - } - StringRef getGnuPubTypesSection() const override { - return GnuPubTypesSection; - } - bool isLittleEndian() const override { - return ELFT::TargetEndianness == llvm::support::little; - } - llvm::Optional find(const llvm::DWARFSection &Sec, - uint64_t Pos) const override; -}; - -} // namespace elf -} // namespace lld - -#endif Property changes on: projects/clang800-import/contrib/llvm/tools/lld/ELF/GdbIndex.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/GdbIndex.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/GdbIndex.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/GdbIndex.cpp (nonexistent) @@ -1,101 +0,0 @@ -//===- GdbIndex.cpp -------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// The -gdb-index option instructs the linker to emit a .gdb_index section. -// The section contains information to make gdb startup faster. -// The format of the section is described at -// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html. -// -//===----------------------------------------------------------------------===// - -#include "GdbIndex.h" -#include "Symbols.h" -#include "lld/Common/Memory.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" -#include "llvm/Object/ELFObjectFile.h" - -using namespace llvm; -using namespace llvm::object; -using namespace lld; -using namespace lld::elf; - -template LLDDwarfObj::LLDDwarfObj(ObjFile *Obj) { - for (InputSectionBase *Sec : Obj->getSections()) { - if (!Sec) - continue; - if (LLDDWARFSection *M = StringSwitch(Sec->Name) - .Case(".debug_info", &InfoSection) - .Case(".debug_ranges", &RangeSection) - .Case(".debug_line", &LineSection) - .Default(nullptr)) { - Sec->maybeDecompress(); - M->Data = toStringRef(Sec->Data); - M->Sec = Sec; - continue; - } - if (Sec->Name == ".debug_abbrev") - AbbrevSection = toStringRef(Sec->Data); - else if (Sec->Name == ".debug_gnu_pubnames") - GnuPubNamesSection = toStringRef(Sec->Data); - else if (Sec->Name == ".debug_gnu_pubtypes") - GnuPubTypesSection = toStringRef(Sec->Data); - else if (Sec->Name == ".debug_str") - StrSection = toStringRef(Sec->Data); - } -} - -// Find if there is a relocation at Pos in Sec. The code is a bit -// more complicated than usual because we need to pass a section index -// to llvm since it has no idea about InputSection. -template -template -Optional -LLDDwarfObj::findAux(const InputSectionBase &Sec, uint64_t Pos, - ArrayRef Rels) const { - auto It = std::lower_bound( - Rels.begin(), Rels.end(), Pos, - [](const RelTy &A, uint64_t B) { return A.r_offset < B; }); - if (It == Rels.end() || It->r_offset != Pos) - return None; - const RelTy &Rel = *It; - - const ObjFile *File = Sec.getFile(); - uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL); - const typename ELFT::Sym &Sym = File->getELFSyms()[SymIndex]; - uint32_t SecIndex = File->getSectionIndex(Sym); - - // Broken debug info can point to a non-Defined symbol. - auto *DR = dyn_cast(&File->getRelocTargetSym(Rel)); - if (!DR) { - error("unsupported relocation target while parsing debug info"); - return None; - } - uint64_t Val = DR->Value + getAddend(Rel); - - // FIXME: We should be consistent about always adding the file - // offset or not. - if (DR->Section->Flags & ELF::SHF_ALLOC) - Val += cast(DR->Section)->getOffsetInFile(); - - return RelocAddrEntry{SecIndex, Val}; -} - -template -Optional LLDDwarfObj::find(const llvm::DWARFSection &S, - uint64_t Pos) const { - auto &Sec = static_cast(S); - if (Sec.Sec->AreRelocsRela) - return findAux(*Sec.Sec, Pos, Sec.Sec->template relas()); - return findAux(*Sec.Sec, Pos, Sec.Sec->template rels()); -} - -template class elf::LLDDwarfObj; -template class elf::LLDDwarfObj; -template class elf::LLDDwarfObj; -template class elf::LLDDwarfObj; Property changes on: projects/clang800-import/contrib/llvm/tools/lld/ELF/GdbIndex.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/AArch64ErrataFix.cpp (revision 343217) @@ -1,647 +1,652 @@ //===- 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 "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->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 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->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)); + 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 (auto *Sec = dyn_cast_or_null(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; + uint64_t PatchUpperBound = PrevISLimit + Target->getThunkSectionSpacing(); + uint64_t OutSecAddr = ISD.Sections.front()->getParent()->Addr; // 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) + if ((*PatchIt)->getLDSTAddr() - OutSecAddr >= PrevISLimit) break; (*PatchIt)->OutSecOff = PrevISLimit; ++PatchIt; } - PatchUpperBound = PrevISLimit + Target->ThunkSectionSpacing; + PatchUpperBound = PrevISLimit + Target->getThunkSectionSpacing(); } 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. + // are four 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 + // Case 2: A TLS Relaxation R_RELAX_TLS_IE_TO_LE. In this case the ADRP that + // we read will be transformed into a MOVZ later so we actually don't match + // the sequence and have nothing more to do. + // Case 3: 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 + // Case 4: 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) + if (RelIt != IS->Relocations.end() && + (RelIt->Type == R_AARCH64_JUMP26 || RelIt->Expr == R_RELAX_TLS_IE_TO_LE)) return; 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; + (DataSym == MapSyms.end()) ? IS->data().size() : (*DataSym)->Value; while (Off < Limit) { 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; } Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp (revision 343217) @@ -1,439 +1,440 @@ //===- 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; 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; + uint32_t getThunkSectionSpacing() 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; + NoneRel = R_AARCH64_NONE; PltRel = R_AARCH64_JUMP_SLOT; TlsDescRel = R_AARCH64_TLSDESC; TlsGotRel = R_AARCH64_TLS_TPREL64; GotEntrySize = 8; GotPltEntrySize = 8; PltEntrySize = 16; PltHeaderSize = 32; DefaultMaxPageSize = 65536; // Align to the 2 MiB page size (known as a superpage or huge page). // FreeBSD automatically promotes 2 MiB-aligned allocations. DefaultImageBase = 0x200000; - // 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; + return R_AARCH64_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; + return R_AARCH64_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; + return R_AARCH64_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_AARCH64_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; } } 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()); + write64le(Buf, In.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(); + uint64_t Got = In.GotPlt->getVA(); + uint64_t Plt = In.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); } +uint32_t AArch64::getThunkSectionSpacing() const { + // See comment in Arch/ARM.cpp for a more detailed explanation of + // getThunkSectionSpacing(). For AArch64 the only branches we are permitted to + // Thunk have a range of +/- 128 MiB + return (128 * 1024 * 1024) - 0x30000; +} + 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(Loc, Val, 16, Type); write16le(Loc, Val); break; case R_AARCH64_ABS32: case R_AARCH64_PREL32: 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(Loc, Val, 33, Type); write32AArch64Addr(Loc, Val >> 12); break; case R_AARCH64_ADR_PREL_LO21: 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(Loc, Val, 28, Type); or32le(Loc, (Val & 0x0FFFFFFC) >> 2); break; case R_AARCH64_CONDBR19: case R_AARCH64_LD_PREL_LO19: checkAlignment(Loc, Val, 4, Type); checkInt(Loc, Val, 21, Type); or32le(Loc, (Val & 0x1FFFFC) << 3); 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: 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: 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: 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: 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(Loc, Val, 16, Type); or32le(Loc, (Val & 0xFFFC) << 3); break; case R_AARCH64_TLSLE_ADD_TPREL_HI12: - checkInt(Loc, Val, 24, Type); + checkUInt(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(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(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; } Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp (revision 343217) @@ -1,104 +1,105 @@ //===- 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; + NoneRel = R_AMDGPU_NONE; 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; } Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp (revision 343217) @@ -1,584 +1,612 @@ //===- 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; 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; + uint32_t getThunkSectionSpacing() 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; + NoneRel = R_ARM_NONE; 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; + TrapInstr = {0xd4, 0xd4, 0xd4, 0xd4}; 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 { // The ABIFloatType is used by loaders to detect the floating point calling // convention. uint32_t ABIFloatType = 0; if (Config->ARMVFPArgs == ARMVFPArgKind::Base || Config->ARMVFPArgs == ARMVFPArgKind::Default) ABIFloatType = EF_ARM_ABI_FLOAT_SOFT; else if (Config->ARMVFPArgs == ARMVFPArgKind::VFP) ABIFloatType = EF_ARM_ABI_FLOAT_HARD; // 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 | ABIFloatType; } 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; + case R_ARM_V4BX: + // V4BX is just a marker to indicate there's a "bx rN" instruction at the + // given address. It can be used to implement a special linker mode which + // rewrites ARMv4T inputs to ARMv4. Since we support only ARMv4 input and + // not ARMv4 output, we can just ignore it. + return R_HINT; default: return R_ABS; } } RelType ARM::getDynRel(RelType Type) const { if ((Type == R_ARM_ABS32) || (Type == R_ARM_TARGET1 && !Config->Target1Rel)) return R_ARM_ABS32; return R_ARM_NONE; } void ARM::writeGotPlt(uint8_t *Buf, const Symbol &) const { - write32le(Buf, InX::Plt->getVA()); + write32le(Buf, In.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; + uint64_t GotPlt = In.GotPlt->getVA(); + uint64_t L1 = In.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; + uint64_t Offset = In.GotPlt->getVA() - In.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); + memcpy(Buf + 16, TrapInstr.data(), 4); // Pad to 32-byte boundary + memcpy(Buf + 20, TrapInstr.data(), 4); + memcpy(Buf + 24, TrapInstr.data(), 4); + memcpy(Buf + 28, TrapInstr.data(), 4); } 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 + memcpy(Buf + 12, TrapInstr.data(), 4); // 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; } +uint32_t ARM::getThunkSectionSpacing() const { + // The placing of pre-created ThunkSections is controlled by the value + // ThunkSectionSpacing returned by getThunkSectionSpacing(). 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 ARMv7. 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. + + // On Arm the ThunkSectionSpacing depends on the range of the Thumb Branch + // range. On earlier Architectures such as ARMv4, ARMv5 and ARMv6 (except + // ARMv6T2) the range is +/- 4MiB. + + return (Config->ARMJ1J2BranchEncoding) ? 0x1000000 - 0x30000 + : 0x400000 - 0x7500; +} + 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; + Range = Config->ARMJ1J2BranchEncoding ? 0x1000000 : 0x400000; 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(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(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(Loc, Val, 26, Type); write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff)); break; case R_ARM_THM_JUMP11: 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(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); + if (!Config->ARMJ1J2BranchEncoding) { + // Older Arm architectures do not support R_ARM_THM_JUMP24 and have + // different encoding rules and range due to J1 and J2 always being 1. + checkInt(Loc, Val, 23, Type); + write16le(Loc, + 0xf000 | // opcode + ((Val >> 12) & 0x07ff)); // imm11 + write16le(Loc + 2, + (read16le(Loc + 2) & 0xd000) | // opcode + 0x2800 | // J1 == J2 == 1 + ((Val >> 1) & 0x07ff)); // imm11 + break; + } // 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(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(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(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: + if (!Config->ARMJ1J2BranchEncoding) { + // Older Arm architectures do not support R_ARM_THM_JUMP24 and have + // different encoding rules and range due to J1 and J2 always being 1. + uint16_t Hi = read16le(Buf); + uint16_t Lo = read16le(Buf + 2); + return SignExtend64<22>(((Hi & 0x7ff) << 12) | // imm11 + ((Lo & 0x7ff) << 1)); // imm11:0 + break; + } + LLVM_FALLTHROUGH; 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; } Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/AVR.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/AVR.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/AVR.cpp (revision 343217) @@ -1,74 +1,77 @@ //===- AVR.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // AVR is a Harvard-architecture 8-bit micrcontroller designed for small // baremetal programs. All AVR-family processors have 32 8-bit registers. // The tiniest AVR has 32 byte RAM and 1 KiB program memory, and the largest // one supports up to 2^24 data address space and 2^22 code address space. // // Since it is a baremetal programming, there's usually no loader to load // ELF files on AVRs. You are expected to link your program against address // 0 and pull out a .text section from the result using objcopy, so that you // can write the linked code to on-chip flush memory. You can do that with // the following commands: // // ld.lld -Ttext=0 -o foo foo.o // objcopy -O binary --only-section=.text foo output.bin // // Note that the current AVR support is very preliminary so you can't // link any useful program yet, though. // //===----------------------------------------------------------------------===// #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 AVR final : public TargetInfo { public: + AVR(); 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 + +AVR::AVR() { NoneRel = R_AVR_NONE; } RelExpr AVR::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { return R_ABS; } void AVR::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_AVR_CALL: { uint16_t Hi = Val >> 17; uint16_t Lo = Val >> 1; write16le(Loc, read16le(Loc) | ((Hi >> 1) << 4) | (Hi & 1)); write16le(Loc + 2, Lo); break; } default: error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type)); } } TargetInfo *elf::getAVRTargetInfo() { static AVR Target; return &Target; } Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/Hexagon.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/Hexagon.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/Hexagon.cpp (revision 343217) @@ -1,103 +1,292 @@ //===-- 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 "SyntheticSections.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: + Hexagon(); 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; + 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 -// Support V60 only at the moment. -uint32_t Hexagon::calcEFlags() const { return 0x60; } +Hexagon::Hexagon() { + PltRel = R_HEX_JMP_SLOT; + RelativeRel = R_HEX_RELATIVE; + GotRel = R_HEX_GLOB_DAT; + GotEntrySize = 4; + // The zero'th GOT entry is reserved for the address of _DYNAMIC. The + // next 3 are reserved for the dynamic loader. + GotPltHeaderEntriesNum = 4; + GotPltEntrySize = 4; + PltEntrySize = 16; + PltHeaderSize = 32; + + // Hexagon Linux uses 64K pages by default. + DefaultMaxPageSize = 0x10000; + NoneRel = R_HEX_NONE; +} + +uint32_t Hexagon::calcEFlags() const { + assert(!ObjectFiles.empty()); + + // The architecture revision must always be equal to or greater than + // greatest revision in the list of inputs. + uint32_t Ret = 0; + for (InputFile *F : ObjectFiles) { + uint32_t EFlags = cast>(F)->getObj().getHeader()->e_flags; + if (EFlags > Ret) + Ret = EFlags; + } + return Ret; +} + 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_B9_PCREL: + case R_HEX_B9_PCREL_X: + case R_HEX_B13_PCREL: case R_HEX_B15_PCREL: case R_HEX_B15_PCREL_X: + case R_HEX_6_PCREL_X: + case R_HEX_32_PCREL: + return R_PC; case R_HEX_B22_PCREL: + case R_HEX_PLT_B22_PCREL: case R_HEX_B22_PCREL_X: case R_HEX_B32_PCREL_X: - return R_PC; + return R_PLT_PC; + case R_HEX_GOT_11_X: + case R_HEX_GOT_16_X: + case R_HEX_GOT_32_6_X: + return R_HEXAGON_GOT; default: return R_ABS; } } +static uint32_t findMaskR6(uint32_t Insn) { + // There are (arguably too) many relocation masks for the DSP's + // R_HEX_6_X type. The table below is used to select the correct mask + // for the given instruction. + struct InstructionMask { + uint32_t CmpMask; + uint32_t RelocMask; + }; + + static const InstructionMask R6[] = { + {0x38000000, 0x0000201f}, {0x39000000, 0x0000201f}, + {0x3e000000, 0x00001f80}, {0x3f000000, 0x00001f80}, + {0x40000000, 0x000020f8}, {0x41000000, 0x000007e0}, + {0x42000000, 0x000020f8}, {0x43000000, 0x000007e0}, + {0x44000000, 0x000020f8}, {0x45000000, 0x000007e0}, + {0x46000000, 0x000020f8}, {0x47000000, 0x000007e0}, + {0x6a000000, 0x00001f80}, {0x7c000000, 0x001f2000}, + {0x9a000000, 0x00000f60}, {0x9b000000, 0x00000f60}, + {0x9c000000, 0x00000f60}, {0x9d000000, 0x00000f60}, + {0x9f000000, 0x001f0100}, {0xab000000, 0x0000003f}, + {0xad000000, 0x0000003f}, {0xaf000000, 0x00030078}, + {0xd7000000, 0x006020e0}, {0xd8000000, 0x006020e0}, + {0xdb000000, 0x006020e0}, {0xdf000000, 0x006020e0}}; + + // Duplex forms have a fixed mask and parse bits 15:14 are always + // zero. Non-duplex insns will always have at least one bit set in the + // parse field. + if ((0xC000 & Insn) == 0x0) + return 0x03f00000; + + for (InstructionMask I : R6) + if ((0xff000000 & Insn) == I.CmpMask) + return I.RelocMask; + + error("unrecognized instruction for R_HEX_6 relocation: 0x" + + utohexstr(Insn)); + return 0; +} + +static uint32_t findMaskR8(uint32_t Insn) { + if ((0xff000000 & Insn) == 0xde000000) + return 0x00e020e8; + if ((0xff000000 & Insn) == 0x3c000000) + return 0x0000207f; + return 0x00001fe0; +} + +static uint32_t findMaskR11(uint32_t Insn) { + if ((0xff000000 & Insn) == 0xa1000000) + return 0x060020ff; + return 0x06003fe0; +} + +static uint32_t findMaskR16(uint32_t Insn) { + if ((0xff000000 & Insn) == 0x48000000) + return 0x061f20ff; + if ((0xff000000 & Insn) == 0x49000000) + return 0x061f3fe0; + if ((0xff000000 & Insn) == 0x78000000) + return 0x00df3fe0; + if ((0xff000000 & Insn) == 0xb0000000) + return 0x0fe03fe0; + + error("unrecognized instruction for R_HEX_16_X relocation: 0x" + + utohexstr(Insn)); + return 0; +} + 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_6_PCREL_X: + case R_HEX_6_X: + or32le(Loc, applyMask(findMaskR6(read32le(Loc)), Val)); + break; + case R_HEX_8_X: + or32le(Loc, applyMask(findMaskR8(read32le(Loc)), Val)); + break; + case R_HEX_9_X: + or32le(Loc, applyMask(0x00003fe0, Val & 0x3f)); + break; + case R_HEX_10_X: + or32le(Loc, applyMask(0x00203fe0, Val & 0x3f)); + break; + case R_HEX_11_X: + case R_HEX_GOT_11_X: + or32le(Loc, applyMask(findMaskR11(read32le(Loc)), Val & 0x3f)); + break; case R_HEX_12_X: or32le(Loc, applyMask(0x000007e0, Val)); break; + case R_HEX_16_X: // These relocs only have 6 effective bits. + case R_HEX_GOT_16_X: + or32le(Loc, applyMask(findMaskR16(read32le(Loc)), Val & 0x3f)); + break; + case R_HEX_32: + case R_HEX_32_PCREL: + or32le(Loc, Val); + break; case R_HEX_32_6_X: + case R_HEX_GOT_32_6_X: or32le(Loc, applyMask(0x0fff3fff, Val >> 6)); break; + case R_HEX_B9_PCREL: + or32le(Loc, applyMask(0x003000fe, Val >> 2)); + break; + case R_HEX_B9_PCREL_X: + or32le(Loc, applyMask(0x003000fe, Val & 0x3f)); + break; + case R_HEX_B13_PCREL: + or32le(Loc, applyMask(0x00202ffe, Val >> 2)); + 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: + case R_HEX_PLT_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; + case R_HEX_HI16: + or32le(Loc, applyMask(0x00c03fff, Val >> 16)); + break; + case R_HEX_LO16: + or32le(Loc, applyMask(0x00c03fff, Val)); + break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type)); break; } +} + +void Hexagon::writePltHeader(uint8_t *Buf) const { + const uint8_t PltData[] = { + 0x00, 0x40, 0x00, 0x00, // { immext (#0) + 0x1c, 0xc0, 0x49, 0x6a, // r28 = add (pc, ##GOT0@PCREL) } # @GOT0 + 0x0e, 0x42, 0x9c, 0xe2, // { r14 -= add (r28, #16) # offset of GOTn + 0x4f, 0x40, 0x9c, 0x91, // r15 = memw (r28 + #8) # object ID at GOT2 + 0x3c, 0xc0, 0x9c, 0x91, // r28 = memw (r28 + #4) }# dynamic link at GOT1 + 0x0e, 0x42, 0x0e, 0x8c, // { r14 = asr (r14, #2) # index of PLTn + 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 } # call dynamic linker + 0x0c, 0xdb, 0x00, 0x54, // trap0(#0xdb) # bring plt0 into 16byte alignment + }; + memcpy(Buf, PltData, sizeof(PltData)); + + // Offset from PLT0 to the GOT. + uint64_t Off = In.GotPlt->getVA() - In.Plt->getVA(); + relocateOne(Buf, R_HEX_B32_PCREL_X, Off); + relocateOne(Buf + 4, R_HEX_6_PCREL_X, Off); +} + +void Hexagon::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Inst[] = { + 0x00, 0x40, 0x00, 0x00, // { immext (#0) + 0x0e, 0xc0, 0x49, 0x6a, // r14 = add (pc, ##GOTn@PCREL) } + 0x1c, 0xc0, 0x8e, 0x91, // r28 = memw (r14) + 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 + }; + memcpy(Buf, Inst, sizeof(Inst)); + + relocateOne(Buf, R_HEX_B32_PCREL_X, GotPltEntryAddr - PltEntryAddr); + relocateOne(Buf + 4, R_HEX_6_PCREL_X, GotPltEntryAddr - PltEntryAddr); } TargetInfo *elf::getHexagonTargetInfo() { static Hexagon Target; return &Target; } Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/MSP430.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/MSP430.cpp (nonexistent) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/MSP430.cpp (revision 343217) @@ -0,0 +1,94 @@ +//===- MSP430.cpp ---------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// The MSP430 is a 16-bit microcontroller RISC architecture. The instruction set +// has only 27 core instructions orthogonally augmented with a variety +// of addressing modes for source and destination operands. Entire address space +// of MSP430 is 64KB (the extended MSP430X architecture is not considered here). +// A typical MSP430 MCU has several kilobytes of RAM and ROM, plenty +// of peripherals and is generally optimized for a low power consumption. +// +//===----------------------------------------------------------------------===// + +#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 MSP430 final : public TargetInfo { +public: + MSP430(); + 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 + +MSP430::MSP430() { + // mov.b #0, r3 + TrapInstr = {0x43, 0x43, 0x43, 0x43}; +} + +RelExpr MSP430::getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const { + switch (Type) { + case R_MSP430_10_PCREL: + case R_MSP430_16_PCREL: + case R_MSP430_16_PCREL_BYTE: + case R_MSP430_2X_PCREL: + case R_MSP430_RL_PCREL: + case R_MSP430_SYM_DIFF: + return R_PC; + default: + return R_ABS; + } +} + +void MSP430::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { + case R_MSP430_8: + checkIntUInt(Loc, Val, 8, Type); + *Loc = Val; + break; + case R_MSP430_16: + case R_MSP430_16_PCREL: + case R_MSP430_16_BYTE: + case R_MSP430_16_PCREL_BYTE: + checkIntUInt(Loc, Val, 16, Type); + write16le(Loc, Val); + break; + case R_MSP430_32: + checkIntUInt(Loc, Val, 32, Type); + write32le(Loc, Val); + break; + case R_MSP430_10_PCREL: { + int16_t Offset = ((int16_t)Val >> 1) - 1; + checkInt(Loc, Offset, 10, Type); + write16le(Loc, (read16le(Loc) & 0xFC00) | (Offset & 0x3FF)); + break; + } + default: + error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type)); + } +} + +TargetInfo *elf::getMSP430TargetInfo() { + static MSP430 Target; + return &Target; +} Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp (revision 343217) @@ -1,673 +1,676 @@ //===- 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; 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; + NoneRel = R_MIPS_NONE; PltRel = R_MIPS_JUMP_SLOT; NeedsThunks = true; - TrapInstr = 0xefefefef; + // Set `sigrie 1` as a trap instruction. + write32(TrapInstr.data(), 0x04170001); + 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: // 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_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_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: 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 RelType MIPS::getDynRel(RelType Type) const { 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(); + uint64_t VA = In.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 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 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]); 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(); + uint64_t GotPlt = In.GotPlt->getVA(); + uint64_t Plt = In.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(); + uint64_t GotPlt = In.GotPlt->getVA(); 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) 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); 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; } 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: 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) { writeValue(Loc, Val + 0x8000, 16, 16); } else { checkInt(Loc, Val, 16, Type); writeValue(Loc, Val, 16, 0); } break; case R_MICROMIPS_GOT16: if (Config->Relocatable) { writeShuffleValue(Loc, Val + 0x8000, 16, 16); } else { 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(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: writeValue(Loc, Val, 16, 0); break; case R_MICROMIPS_GPREL16: case R_MICROMIPS_TLS_GD: case R_MICROMIPS_TLS_LDM: checkInt(Loc, Val, 16, Type); writeShuffleValue(Loc, Val, 16, 0); break; case R_MICROMIPS_CALL16: case R_MICROMIPS_CALL_LO16: case R_MICROMIPS_LO16: case R_MICROMIPS_TLS_DTPREL_LO16: case R_MICROMIPS_TLS_GOTTPREL: case R_MICROMIPS_TLS_TPREL_LO16: writeShuffleValue(Loc, Val, 16, 0); break; case R_MICROMIPS_GPREL7_S2: 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: 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: writeShuffleValue(Loc, Val + 0x8000, 16, 16); break; case R_MIPS_HIGHER: writeValue(Loc, Val + 0x80008000, 16, 32); break; case R_MIPS_HIGHEST: writeValue(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(Loc, Val, 4, Type); checkInt(Loc, Val, 18, Type); writeValue(Loc, Val, 16, 2); break; case R_MIPS_PC19_S2: checkAlignment(Loc, Val, 4, Type); checkInt(Loc, Val, 21, Type); writeValue(Loc, Val, 19, 2); break; case R_MIPS_PC21_S2: checkAlignment(Loc, Val, 4, Type); checkInt(Loc, Val, 23, Type); writeValue(Loc, Val, 21, 2); break; case R_MIPS_PC26_S2: checkAlignment(Loc, Val, 4, Type); checkInt(Loc, Val, 28, Type); writeValue(Loc, Val, 26, 2); break; case R_MIPS_PC32: writeValue(Loc, Val, 32, 0); break; case R_MICROMIPS_26_S1: case R_MICROMIPS_PC26_S1: checkInt(Loc, Val, 27, Type); writeShuffleValue(Loc, Val, 26, 1); break; case R_MICROMIPS_PC7_S1: checkInt(Loc, Val, 8, Type); writeMicroRelocation16(Loc, Val, 7, 1); break; case R_MICROMIPS_PC10_S1: checkInt(Loc, Val, 11, Type); writeMicroRelocation16(Loc, Val, 10, 1); break; case R_MICROMIPS_PC16_S1: checkInt(Loc, Val, 17, Type); writeShuffleValue(Loc, Val, 16, 1); break; case R_MICROMIPS_PC18_S3: checkInt(Loc, Val, 21, Type); writeShuffleValue(Loc, Val, 18, 3); break; case R_MICROMIPS_PC19_S2: checkInt(Loc, Val, 21, Type); writeShuffleValue(Loc, Val, 19, 2); break; case R_MICROMIPS_PC21_S1: checkInt(Loc, Val, 22, Type); writeShuffleValue(Loc, Val, 21, 1); break; case R_MICROMIPS_PC23_S2: 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; } // Return true if the symbol is a PIC function. template bool elf::isMipsPIC(const Defined *Sym) { if (!Sym->isFunc()) return false; 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 *); Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp (revision 343217) @@ -1,76 +1,81 @@ //===- 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(); 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() { + NoneRel = R_PPC_NONE; GotBaseSymOff = 0x8000; GotBaseSymInGotPlt = false; } RelExpr PPC::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { + case R_PPC_REL14: 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_REL14: + write32be(Loc, read32be(Loc) | (Val & 0xFFFC)); 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; } Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp (revision 343217) @@ -1,532 +1,931 @@ //===- 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; +// The instruction encoding of bits 21-30 from the ISA for the Xform and Dform +// instructions that can be used as part of the initial exec TLS sequence. +enum XFormOpcd { + LBZX = 87, + LHZX = 279, + LWZX = 23, + LDX = 21, + STBX = 215, + STHX = 407, + STWX = 151, + STDX = 149, + ADD = 266, +}; + +enum DFormOpcd { + LBZ = 34, + LBZU = 35, + LHZ = 40, + LHZU = 41, + LHAU = 43, + LWZ = 32, + LWZU = 33, + LFSU = 49, + LD = 58, + LFDU = 51, + STB = 38, + STBU = 39, + STH = 44, + STHU = 45, + STW = 36, + STWU = 37, + STFSU = 53, + STFDU = 55, + STD = 62, + ADDI = 14 +}; + 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(); + uint64_t TocVA = In.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; } +unsigned elf::getPPC64GlobalEntryToLocalEntryOffset(uint8_t StOther) { + // The offset is encoded into the 3 most significant bits of the st_other + // field, with some special values described in section 3.4.1 of the ABI: + // 0 --> Zero offset between the GEP and LEP, and the function does NOT use + // the TOC pointer (r2). r2 will hold the same value on returning from + // the function as it did on entering the function. + // 1 --> Zero offset between the GEP and LEP, and r2 should be treated as a + // caller-saved register for all callers. + // 2-6 --> The binary logarithm of the offset eg: + // 2 --> 2^2 = 4 bytes --> 1 instruction. + // 6 --> 2^6 = 64 bytes --> 16 instructions. + // 7 --> Reserved. + uint8_t GepToLep = (StOther >> 5) & 7; + if (GepToLep < 2) + return 0; + + // The value encoded in the st_other bits is the + // log-base-2(offset). + if (GepToLep < 7) + return 1 << GepToLep; + + error("reserved value of 7 in the 3 most-significant-bits of st_other"); + return 0; +} + 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; + bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) 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; + void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + + bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End, + uint8_t StOther) 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 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; } +// Extracts the 'PO' field of an instruction encoding. +static uint8_t getPrimaryOpCode(uint32_t Encoding) { return (Encoding >> 26); } + +static bool isDQFormInstruction(uint32_t Encoding) { + switch (getPrimaryOpCode(Encoding)) { + default: + return false; + case 56: + // The only instruction with a primary opcode of 56 is `lq`. + return true; + case 61: + // There are both DS and DQ instruction forms with this primary opcode. + // Namely `lxv` and `stxv` are the DQ-forms that use it. + // The DS 'XO' bits being set to 01 is restricted to DQ form. + return (Encoding & 3) == 0x1; + } +} + +static bool isInstructionUpdateForm(uint32_t Encoding) { + switch (getPrimaryOpCode(Encoding)) { + default: + return false; + case LBZU: + case LHAU: + case LHZU: + case LWZU: + case LFSU: + case LFDU: + case STBU: + case STHU: + case STWU: + case STFSU: + case STFDU: + return true; + // LWA has the same opcode as LD, and the DS bits is what differentiates + // between LD/LDU/LWA + case LD: + case STD: + return (Encoding & 3) == 1; + } +} + +// There are a number of places when we either want to read or write an +// instruction when handling a half16 relocation type. On big-endian the buffer +// pointer is pointing into the middle of the word we want to extract, and on +// little-endian it is pointing to the start of the word. These 2 helpers are to +// simplify reading and writing in that context. +static void writeInstrFromHalf16(uint8_t *Loc, uint32_t Instr) { + write32(Loc - (Config->EKind == ELF64BEKind ? 2 : 0), Instr); +} + +static uint32_t readInstrFromHalf16(const uint8_t *Loc) { + return read32(Loc - (Config->EKind == ELF64BEKind ? 2 : 0)); +} + PPC64::PPC64() { GotRel = R_PPC64_GLOB_DAT; + NoneRel = R_PPC64_NONE; PltRel = R_PPC64_JMP_SLOT; RelativeRel = R_PPC64_RELATIVE; IRelativeRel = R_PPC64_IRELATIVE; GotEntrySize = 8; PltEntrySize = 4; GotPltEntrySize = 8; 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; + NeedsMoreStackNonSplit = false; + // 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; + write32(TrapInstr.data(), 0x7fe00008); } 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 + writeInstrFromHalf16(Loc, 0x60000000); // nop break; + case R_PPC64_GOT_TLSGD16: case R_PPC64_GOT_TLSGD16_LO: - write32(Loc - EndianOffset, 0x3c6d0000); // addis r3, r13 + writeInstrFromHalf16(Loc, 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); + // Since we are relocating a half16 type relocation and Loc + 4 points to + // the start of an instruction we need to advance the buffer by an extra + // 2 bytes on BE. + relocateOne(Loc + 4 + (Config->EKind == ELF64BEKind ? 2 : 0), + 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 + writeInstrFromHalf16(Loc, 0x60000000); // nop break; case R_PPC64_GOT_TLSLD16_LO: - write32(Loc - EndianOffset, 0x3c6d0000); // addis r3, r13, 0 + writeInstrFromHalf16(Loc, 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"); } } +static unsigned getDFormOp(unsigned SecondaryOp) { + switch (SecondaryOp) { + case LBZX: + return LBZ; + case LHZX: + return LHZ; + case LWZX: + return LWZ; + case LDX: + return LD; + case STBX: + return STB; + case STHX: + return STH; + case STWX: + return STW; + case STDX: + return STD; + case ADD: + return ADDI; + default: + error("unrecognized instruction for IE to LE R_PPC64_TLS"); + return 0; + } +} + +void PPC64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { + // The initial exec code sequence for a global `x` will look like: + // Instruction Relocation Symbol + // addis r9, r2, x@got@tprel@ha R_PPC64_GOT_TPREL16_HA x + // ld r9, x@got@tprel@l(r9) R_PPC64_GOT_TPREL16_LO_DS x + // add r9, r9, x@tls R_PPC64_TLS x + + // Relaxing to local exec entails converting: + // addis r9, r2, x@got@tprel@ha into nop + // ld r9, x@got@tprel@l(r9) into addis r9, r13, x@tprel@ha + // add r9, r9, x@tls into addi r9, r9, x@tprel@l + + // x@tls R_PPC64_TLS is a relocation which does not compute anything, + // it is replaced with r13 (thread pointer). + + // The add instruction in the initial exec sequence has multiple variations + // that need to be handled. If we are building an address it will use an add + // instruction, if we are accessing memory it will use any of the X-form + // indexed load or store instructions. + + unsigned Offset = (Config->EKind == ELF64BEKind) ? 2 : 0; + switch (Type) { + case R_PPC64_GOT_TPREL16_HA: + write32(Loc - Offset, 0x60000000); // nop + break; + case R_PPC64_GOT_TPREL16_LO_DS: + case R_PPC64_GOT_TPREL16_DS: { + uint32_t RegNo = read32(Loc - Offset) & 0x03E00000; // bits 6-10 + write32(Loc - Offset, 0x3C0D0000 | RegNo); // addis RegNo, r13 + relocateOne(Loc, R_PPC64_TPREL16_HA, Val); + break; + } + case R_PPC64_TLS: { + uint32_t PrimaryOp = getPrimaryOpCode(read32(Loc)); + if (PrimaryOp != 31) + error("unrecognized instruction for IE to LE R_PPC64_TLS"); + uint32_t SecondaryOp = (read32(Loc) & 0x000007FE) >> 1; // bits 21-30 + uint32_t DFormOp = getDFormOp(SecondaryOp); + write32(Loc, ((DFormOp << 26) | (read32(Loc) & 0x03FFFFFF))); + relocateOne(Loc + Offset, R_PPC64_TPREL16_LO, Val); + break; + } + default: + llvm_unreachable("unknown relocation for IE to LE"); + break; + } +} + RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { + case R_PPC64_GOT16: + case R_PPC64_GOT16_DS: + case R_PPC64_GOT16_HA: + case R_PPC64_GOT16_HI: + case R_PPC64_GOT16_LO: + case R_PPC64_GOT16_LO_DS: + return R_GOT_OFF; 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_REL14: case R_PPC64_REL24: 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; + return R_TLSIE_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); + int64_t GotPltOffset = In.GotPlt->getVA() - (In.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 { - int32_t Offset = PltHeaderSize + Index * PltEntrySize; - // bl __glink_PLTresolve - write32(Buf, 0x48000000 | ((-Offset) & 0x03FFFFFc)); + int32_t Offset = PltHeaderSize + Index * PltEntrySize; + // bl __glink_PLTresolve + write32(Buf, 0x48000000 | ((-Offset) & 0x03FFFFFc)); } static std::pair toAddr16Rel(RelType Type, uint64_t Val) { // 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_GOT16: case R_PPC64_GOT_TLSGD16: case R_PPC64_GOT_TLSLD16: case R_PPC64_TOC16: return {R_PPC64_ADDR16, TocBiasedVal}; + case R_PPC64_GOT16_DS: case R_PPC64_TOC16_DS: case R_PPC64_GOT_TPREL16_DS: case R_PPC64_GOT_DTPREL16_DS: return {R_PPC64_ADDR16_DS, TocBiasedVal}; + case R_PPC64_GOT16_HA: 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, TocBiasedVal}; + case R_PPC64_GOT16_HI: 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, TocBiasedVal}; + case R_PPC64_GOT16_LO: case R_PPC64_GOT_TLSGD16_LO: case R_PPC64_GOT_TLSLD16_LO: case R_PPC64_TOC16_LO: return {R_PPC64_ADDR16_LO, TocBiasedVal}; + case R_PPC64_GOT16_LO_DS: case R_PPC64_TOC16_LO_DS: 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}; } } +static bool isTocOptType(RelType Type) { + switch (Type) { + case R_PPC64_GOT16_HA: + case R_PPC64_GOT16_LO_DS: + case R_PPC64_TOC16_HA: + case R_PPC64_TOC16_LO_DS: + case R_PPC64_TOC16_LO: + return true; + default: + return false; + } +} + 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. + // We need to save the original relocation type to use in diagnostics, and + // use the original type to determine if we should toc-optimize the + // instructions being relocated. + RelType OriginalType = Type; + bool ShouldTocOptimize = isTocOptType(Type); + // For dynamic thread pointer relative, toc-relative, and got-indirect + // relocations, proceed in terms of the corresponding ADDR16 relocation type. std::tie(Type, Val) = toAddr16Rel(Type, Val); switch (Type) { case R_PPC64_ADDR14: { checkAlignment(Loc, Val, 4, Type); // Preserve the AA/LK bits in the branch instruction uint8_t AALK = Loc[3]; write16(Loc + 2, (AALK & 3) | (Val & 0xfffc)); break; } case R_PPC64_ADDR16: case R_PPC64_TPREL16: - checkInt(Loc, Val, 16, Type); + checkInt(Loc, Val, 16, OriginalType); write16(Loc, Val); break; case R_PPC64_ADDR16_DS: - case R_PPC64_TPREL16_DS: - checkInt(Loc, Val, 16, Type); - write16(Loc, (read16(Loc) & 3) | (Val & ~3)); - break; + case R_PPC64_TPREL16_DS: { + checkInt(Loc, Val, 16, OriginalType); + // DQ-form instructions use bits 28-31 as part of the instruction encoding + // DS-form instructions only use bits 30-31. + uint16_t Mask = isDQFormInstruction(readInstrFromHalf16(Loc)) ? 0xF : 0x3; + checkAlignment(Loc, lo(Val), Mask + 1, OriginalType); + write16(Loc, (read16(Loc) & Mask) | lo(Val)); + } break; case R_PPC64_ADDR16_HA: case R_PPC64_REL16_HA: case R_PPC64_TPREL16_HA: - write16(Loc, ha(Val)); + if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0) + writeInstrFromHalf16(Loc, 0x60000000); + else + write16(Loc, ha(Val)); break; case R_PPC64_ADDR16_HI: case R_PPC64_REL16_HI: case R_PPC64_TPREL16_HI: write16(Loc, hi(Val)); break; case R_PPC64_ADDR16_HIGHER: case R_PPC64_TPREL16_HIGHER: write16(Loc, higher(Val)); break; case R_PPC64_ADDR16_HIGHERA: case R_PPC64_TPREL16_HIGHERA: write16(Loc, highera(Val)); break; case R_PPC64_ADDR16_HIGHEST: case R_PPC64_TPREL16_HIGHEST: write16(Loc, highest(Val)); break; case R_PPC64_ADDR16_HIGHESTA: case R_PPC64_TPREL16_HIGHESTA: write16(Loc, highesta(Val)); break; case R_PPC64_ADDR16_LO: case R_PPC64_REL16_LO: case R_PPC64_TPREL16_LO: + // When the high-adjusted part of a toc relocation evalutes to 0, it is + // changed into a nop. The lo part then needs to be updated to use the + // toc-pointer register r2, as the base register. + if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0) { + uint32_t Instr = readInstrFromHalf16(Loc); + if (isInstructionUpdateForm(Instr)) + error(getErrorLocation(Loc) + + "can't toc-optimize an update instruction: 0x" + + utohexstr(Instr)); + Instr = (Instr & 0xFFE00000) | 0x00020000; + writeInstrFromHalf16(Loc, Instr); + } write16(Loc, lo(Val)); break; case R_PPC64_ADDR16_LO_DS: - case R_PPC64_TPREL16_LO_DS: - write16(Loc, (read16(Loc) & 3) | (lo(Val) & ~3)); - break; + case R_PPC64_TPREL16_LO_DS: { + // DQ-form instructions use bits 28-31 as part of the instruction encoding + // DS-form instructions only use bits 30-31. + uint32_t Inst = readInstrFromHalf16(Loc); + uint16_t Mask = isDQFormInstruction(Inst) ? 0xF : 0x3; + checkAlignment(Loc, lo(Val), Mask + 1, OriginalType); + if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0) { + // When the high-adjusted part of a toc relocation evalutes to 0, it is + // changed into a nop. The lo part then needs to be updated to use the toc + // pointer register r2, as the base register. + if (isInstructionUpdateForm(Inst)) + error(getErrorLocation(Loc) + + "Can't toc-optimize an update instruction: 0x" + + Twine::utohexstr(Inst)); + Inst = (Inst & 0xFFE0000F) | 0x00020000; + writeInstrFromHalf16(Loc, Inst); + } + write16(Loc, (read16(Loc) & Mask) | lo(Val)); + } break; case R_PPC64_ADDR32: case R_PPC64_REL32: checkInt(Loc, Val, 32, Type); write32(Loc, Val); break; case R_PPC64_ADDR64: case R_PPC64_REL64: case R_PPC64_TOC: write64(Loc, Val); break; + case R_PPC64_REL14: { + uint32_t Mask = 0x0000FFFC; + checkInt(Loc, Val, 16, Type); + checkAlignment(Loc, Val, 4, Type); + write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask)); + break; + } case R_PPC64_REL24: { uint32_t Mask = 0x03FFFFFC; - checkInt(Loc, Val, 24, Type); + checkInt(Loc, Val, 26, Type); + checkAlignment(Loc, Val, 4, 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(); + if (Type != R_PPC64_REL14 && Type != R_PPC64_REL24) + return false; + + // If a function is in the Plt it needs to be called with a call-stub. + if (S.isInPlt()) + return true; + + // If a symbol is a weak undefined and we are compiling an executable + // it doesn't need a range-extending thunk since it can't be called. + if (S.isUndefWeak() && !Config->Shared) + return false; + + // If the offset exceeds the range of the branch type then it will need + // a range-extending thunk. + return !inBranchRange(Type, BranchAddr, S.getVA()); } +bool PPC64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { + int64_t Offset = Dst - Src; + if (Type == R_PPC64_REL14) + return isInt<16>(Offset); + if (Type == R_PPC64_REL24) + return isInt<26>(Offset); + llvm_unreachable("unsupported relocation type used in branch"); +} + 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); + uint32_t InputRegister = (readInstrFromHalf16(Loc) & (0x1f << 16)); + writeInstrFromHalf16(Loc, 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"); } +} + +// The prologue for a split-stack function is expected to look roughly +// like this: +// .Lglobal_entry_point: +// # TOC pointer initalization. +// ... +// .Llocal_entry_point: +// # load the __private_ss member of the threads tcbhead. +// ld r0,-0x7000-64(r13) +// # subtract the functions stack size from the stack pointer. +// addis r12, r1, ha(-stack-frame size) +// addi r12, r12, l(-stack-frame size) +// # compare needed to actual and branch to allocate_more_stack if more +// # space is needed, otherwise fallthrough to 'normal' function body. +// cmpld cr7,r12,r0 +// blt- cr7, .Lallocate_more_stack +// +// -) The allocate_more_stack block might be placed after the split-stack +// prologue and the `blt-` replaced with a `bge+ .Lnormal_func_body` +// instead. +// -) If either the addis or addi is not needed due to the stack size being +// smaller then 32K or a multiple of 64K they will be replaced with a nop, +// but there will always be 2 instructions the linker can overwrite for the +// adjusted stack size. +// +// The linkers job here is to increase the stack size used in the addis/addi +// pair by split-stack-size-adjust. +// addis r12, r1, ha(-stack-frame size - split-stack-adjust-size) +// addi r12, r12, l(-stack-frame size - split-stack-adjust-size) +bool PPC64::adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End, + uint8_t StOther) const { + // If the caller has a global entry point adjust the buffer past it. The start + // of the split-stack prologue will be at the local entry point. + Loc += getPPC64GlobalEntryToLocalEntryOffset(StOther); + + // At the very least we expect to see a load of some split-stack data from the + // tcb, and 2 instructions that calculate the ending stack address this + // function will require. If there is not enough room for at least 3 + // instructions it can't be a split-stack prologue. + if (Loc + 12 >= End) + return false; + + // First instruction must be `ld r0, -0x7000-64(r13)` + if (read32(Loc) != 0xe80d8fc0) + return false; + + int16_t HiImm = 0; + int16_t LoImm = 0; + // First instruction can be either an addis if the frame size is larger then + // 32K, or an addi if the size is less then 32K. + int32_t FirstInstr = read32(Loc + 4); + if (getPrimaryOpCode(FirstInstr) == 15) { + HiImm = FirstInstr & 0xFFFF; + } else if (getPrimaryOpCode(FirstInstr) == 14) { + LoImm = FirstInstr & 0xFFFF; + } else { + return false; + } + + // Second instruction is either an addi or a nop. If the first instruction was + // an addi then LoImm is set and the second instruction must be a nop. + uint32_t SecondInstr = read32(Loc + 8); + if (!LoImm && getPrimaryOpCode(SecondInstr) == 14) { + LoImm = SecondInstr & 0xFFFF; + } else if (SecondInstr != 0x60000000) { + return false; + } + + // The register operands of the first instruction should be the stack-pointer + // (r1) as the input (RA) and r12 as the output (RT). If the second + // instruction is not a nop, then it should use r12 as both input and output. + auto CheckRegOperands = [](uint32_t Instr, uint8_t ExpectedRT, + uint8_t ExpectedRA) { + return ((Instr & 0x3E00000) >> 21 == ExpectedRT) && + ((Instr & 0x1F0000) >> 16 == ExpectedRA); + }; + if (!CheckRegOperands(FirstInstr, 12, 1)) + return false; + if (SecondInstr != 0x60000000 && !CheckRegOperands(SecondInstr, 12, 12)) + return false; + + int32_t StackFrameSize = (HiImm * 65536) + LoImm; + // Check that the adjusted size doesn't overflow what we can represent with 2 + // instructions. + if (StackFrameSize < Config->SplitStackAdjustSize + INT32_MIN) { + error(getErrorLocation(Loc) + "split-stack prologue adjustment overflows"); + return false; + } + + int32_t AdjustedStackFrameSize = + StackFrameSize - Config->SplitStackAdjustSize; + + LoImm = AdjustedStackFrameSize & 0xFFFF; + HiImm = (AdjustedStackFrameSize + 0x8000) >> 16; + if (HiImm) { + write32(Loc + 4, 0x3D810000 | (uint16_t)HiImm); + // If the low immediate is zero the second instruction will be a nop. + SecondInstr = LoImm ? 0x398C0000 | (uint16_t)LoImm : 0x60000000; + write32(Loc + 8, SecondInstr); + } else { + // addi r12, r1, imm + write32(Loc + 4, (0x39810000) | (uint16_t)LoImm); + write32(Loc + 8, 0x60000000); + } + + return true; } TargetInfo *elf::getPPC64TargetInfo() { static PPC64 Target; return &Target; } Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/RISCV.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/RISCV.cpp (nonexistent) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/RISCV.cpp (revision 343217) @@ -0,0 +1,279 @@ +//===- RISCV.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 "Target.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 RISCV final : public TargetInfo { +public: + RISCV(); + 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; +}; + +} // end anonymous namespace + +RISCV::RISCV() { NoneRel = R_RISCV_NONE; } + +static uint32_t getEFlags(InputFile *F) { + if (Config->Is64) + return cast>(F)->getObj().getHeader()->e_flags; + return cast>(F)->getObj().getHeader()->e_flags; +} + +uint32_t RISCV::calcEFlags() const { + assert(!ObjectFiles.empty()); + + uint32_t Target = getEFlags(ObjectFiles.front()); + + for (InputFile *F : ObjectFiles) { + uint32_t EFlags = getEFlags(F); + if (EFlags & EF_RISCV_RVC) + Target |= EF_RISCV_RVC; + + if ((EFlags & EF_RISCV_FLOAT_ABI) != (Target & EF_RISCV_FLOAT_ABI)) + error(toString(F) + + ": cannot link object files with different floating-point ABI"); + + if ((EFlags & EF_RISCV_RVE) != (Target & EF_RISCV_RVE)) + error(toString(F) + + ": cannot link object files with different EF_RISCV_RVE"); + } + + return Target; +} + +RelExpr RISCV::getRelExpr(const RelType Type, const Symbol &S, + const uint8_t *Loc) const { + switch (Type) { + case R_RISCV_JAL: + case R_RISCV_BRANCH: + case R_RISCV_CALL: + case R_RISCV_PCREL_HI20: + case R_RISCV_RVC_BRANCH: + case R_RISCV_RVC_JUMP: + case R_RISCV_32_PCREL: + return R_PC; + case R_RISCV_PCREL_LO12_I: + case R_RISCV_PCREL_LO12_S: + return R_RISCV_PC_INDIRECT; + case R_RISCV_RELAX: + case R_RISCV_ALIGN: + return R_HINT; + default: + return R_ABS; + } +} + +// Extract bits V[Begin:End], where range is inclusive, and Begin must be < 63. +static uint32_t extractBits(uint64_t V, uint32_t Begin, uint32_t End) { + return (V & ((1ULL << (Begin + 1)) - 1)) >> End; +} + +void RISCV::relocateOne(uint8_t *Loc, const RelType Type, + const uint64_t Val) const { + switch (Type) { + case R_RISCV_32: + write32le(Loc, Val); + return; + case R_RISCV_64: + write64le(Loc, Val); + return; + + case R_RISCV_RVC_BRANCH: { + checkInt(Loc, static_cast(Val) >> 1, 8, Type); + checkAlignment(Loc, Val, 2, Type); + uint16_t Insn = read16le(Loc) & 0xE383; + uint16_t Imm8 = extractBits(Val, 8, 8) << 12; + uint16_t Imm4_3 = extractBits(Val, 4, 3) << 10; + uint16_t Imm7_6 = extractBits(Val, 7, 6) << 5; + uint16_t Imm2_1 = extractBits(Val, 2, 1) << 3; + uint16_t Imm5 = extractBits(Val, 5, 5) << 2; + Insn |= Imm8 | Imm4_3 | Imm7_6 | Imm2_1 | Imm5; + + write16le(Loc, Insn); + return; + } + + case R_RISCV_RVC_JUMP: { + checkInt(Loc, static_cast(Val) >> 1, 11, Type); + checkAlignment(Loc, Val, 2, Type); + uint16_t Insn = read16le(Loc) & 0xE003; + uint16_t Imm11 = extractBits(Val, 11, 11) << 12; + uint16_t Imm4 = extractBits(Val, 4, 4) << 11; + uint16_t Imm9_8 = extractBits(Val, 9, 8) << 9; + uint16_t Imm10 = extractBits(Val, 10, 10) << 8; + uint16_t Imm6 = extractBits(Val, 6, 6) << 7; + uint16_t Imm7 = extractBits(Val, 7, 7) << 6; + uint16_t Imm3_1 = extractBits(Val, 3, 1) << 3; + uint16_t Imm5 = extractBits(Val, 5, 5) << 2; + Insn |= Imm11 | Imm4 | Imm9_8 | Imm10 | Imm6 | Imm7 | Imm3_1 | Imm5; + + write16le(Loc, Insn); + return; + } + + case R_RISCV_RVC_LUI: { + int32_t Imm = ((Val + 0x800) >> 12); + checkUInt(Loc, Imm, 6, Type); + if (Imm == 0) { // `c.lui rd, 0` is illegal, convert to `c.li rd, 0` + write16le(Loc, (read16le(Loc) & 0x0F83) | 0x4000); + } else { + uint16_t Imm17 = extractBits(Val + 0x800, 17, 17) << 12; + uint16_t Imm16_12 = extractBits(Val + 0x800, 16, 12) << 2; + write16le(Loc, (read16le(Loc) & 0xEF83) | Imm17 | Imm16_12); + } + return; + } + + case R_RISCV_JAL: { + checkInt(Loc, static_cast(Val) >> 1, 20, Type); + checkAlignment(Loc, Val, 2, Type); + + uint32_t Insn = read32le(Loc) & 0xFFF; + uint32_t Imm20 = extractBits(Val, 20, 20) << 31; + uint32_t Imm10_1 = extractBits(Val, 10, 1) << 21; + uint32_t Imm11 = extractBits(Val, 11, 11) << 20; + uint32_t Imm19_12 = extractBits(Val, 19, 12) << 12; + Insn |= Imm20 | Imm10_1 | Imm11 | Imm19_12; + + write32le(Loc, Insn); + return; + } + + case R_RISCV_BRANCH: { + checkInt(Loc, static_cast(Val) >> 1, 12, Type); + checkAlignment(Loc, Val, 2, Type); + + uint32_t Insn = read32le(Loc) & 0x1FFF07F; + uint32_t Imm12 = extractBits(Val, 12, 12) << 31; + uint32_t Imm10_5 = extractBits(Val, 10, 5) << 25; + uint32_t Imm4_1 = extractBits(Val, 4, 1) << 8; + uint32_t Imm11 = extractBits(Val, 11, 11) << 7; + Insn |= Imm12 | Imm10_5 | Imm4_1 | Imm11; + + write32le(Loc, Insn); + return; + } + + // auipc + jalr pair + case R_RISCV_CALL: { + checkInt(Loc, Val, 32, Type); + if (isInt<32>(Val)) { + relocateOne(Loc, R_RISCV_PCREL_HI20, Val); + relocateOne(Loc + 4, R_RISCV_PCREL_LO12_I, Val); + } + return; + } + + case R_RISCV_PCREL_HI20: + case R_RISCV_HI20: { + checkInt(Loc, Val, 32, Type); + uint32_t Hi = Val + 0x800; + write32le(Loc, (read32le(Loc) & 0xFFF) | (Hi & 0xFFFFF000)); + return; + } + + case R_RISCV_PCREL_LO12_I: + case R_RISCV_LO12_I: { + checkInt(Loc, Val, 32, Type); + uint32_t Hi = Val + 0x800; + uint32_t Lo = Val - (Hi & 0xFFFFF000); + write32le(Loc, (read32le(Loc) & 0xFFFFF) | ((Lo & 0xFFF) << 20)); + return; + } + + case R_RISCV_PCREL_LO12_S: + case R_RISCV_LO12_S: { + checkInt(Loc, Val, 32, Type); + uint32_t Hi = Val + 0x800; + uint32_t Lo = Val - (Hi & 0xFFFFF000); + uint32_t Imm11_5 = extractBits(Lo, 11, 5) << 25; + uint32_t Imm4_0 = extractBits(Lo, 4, 0) << 7; + write32le(Loc, (read32le(Loc) & 0x1FFF07F) | Imm11_5 | Imm4_0); + return; + } + + case R_RISCV_ADD8: + *Loc += Val; + return; + case R_RISCV_ADD16: + write16le(Loc, read16le(Loc) + Val); + return; + case R_RISCV_ADD32: + write32le(Loc, read32le(Loc) + Val); + return; + case R_RISCV_ADD64: + write64le(Loc, read64le(Loc) + Val); + return; + case R_RISCV_SUB6: + *Loc = (*Loc & 0xc0) | (((*Loc & 0x3f) - Val) & 0x3f); + return; + case R_RISCV_SUB8: + *Loc -= Val; + return; + case R_RISCV_SUB16: + write16le(Loc, read16le(Loc) - Val); + return; + case R_RISCV_SUB32: + write32le(Loc, read32le(Loc) - Val); + return; + case R_RISCV_SUB64: + write64le(Loc, read64le(Loc) - Val); + return; + case R_RISCV_SET6: + *Loc = (*Loc & 0xc0) | (Val & 0x3f); + return; + case R_RISCV_SET8: + *Loc = Val; + return; + case R_RISCV_SET16: + write16le(Loc, Val); + return; + case R_RISCV_SET32: + case R_RISCV_32_PCREL: + write32le(Loc, Val); + return; + + case R_RISCV_ALIGN: + case R_RISCV_RELAX: + return; // Ignored (for now) + case R_RISCV_NONE: + return; // Do nothing + + // These are handled by the dynamic linker + case R_RISCV_RELATIVE: + case R_RISCV_COPY: + case R_RISCV_JUMP_SLOT: + // GP-relative relocations are only produced after relaxation, which + // we don't support for now + case R_RISCV_GPREL_I: + case R_RISCV_GPREL_S: + default: + error(getErrorLocation(Loc) + + "unimplemented relocation: " + toString(Type)); + return; + } +} + +TargetInfo *elf::getRISCVTargetInfo() { + static RISCV Target; + return &Target; +} Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/SPARCV9.cpp (revision 343217) @@ -1,148 +1,149 @@ //===- 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; + NoneRel = R_SPARC_NONE; 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(Loc, Val, 32, Type); write32be(Loc, Val); break; case R_SPARC_DISP32: // V-disp32 checkInt(Loc, Val, 32, Type); write32be(Loc, Val); break; case R_SPARC_WDISP30: case R_SPARC_WPLT30: // V-disp30 checkInt(Loc, Val, 32, Type); write32be(Loc, (read32be(Loc) & ~0x3fffffff) | ((Val >> 2) & 0x3fffffff)); break; case R_SPARC_22: // V-imm22 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(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 = 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; } Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/X86.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/X86.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/X86.cpp (revision 343217) @@ -1,553 +1,554 @@ //===- 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() { CopyRel = R_386_COPY; GotRel = R_386_GLOB_DAT; + NoneRel = R_386_NONE; 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 + TrapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3 // Align to the non-PAE large page size (known as a superpage or huge page). // FreeBSD automatically promotes large, superpage-aligned allocations. DefaultImageBase = 0x400000; } 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_GOT_FROM_END; case R_386_TLS_LDM: 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()); + write32le(Buf, In.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; + uint32_t Ebx = In.Got->getVA() + In.Got->getSize(); + uint32_t GotPlt = In.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(); + uint32_t GotPlt = In.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(); + uint32_t Ebx = In.Got->getVA() + In.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, -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. checkIntUInt(Loc, Val, 8, Type); *Loc = Val; break; case R_386_PC8: checkInt(Loc, Val, 8, Type); *Loc = Val; break; case R_386_16: 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(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(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; + uint32_t Ebx = In.Got->getVA() + In.Got->getSize(); + uint32_t GotPlt = In.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 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding }; memcpy(Buf, Insn, sizeof(Insn)); - uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); + uint32_t Ebx = In.Got->getVA() + In.Got->getSize(); unsigned Off = getPltEntryOffset(Index); write32le(Buf + 3, GotPltEntryAddr - Ebx); write32le(Buf + 8, -Off - 12 + 32); write32le(Buf + 13, -Off - 17 + 18); write32le(Buf + 18, RelOff); 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 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, Insn, sizeof(Insn)); - uint32_t GotPlt = InX::GotPlt->getVA(); + uint32_t GotPlt = In.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 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, -Off - 11 + 32); write32le(Buf + 12, -Off - 16 + 17); write32le(Buf + 17, RelOff); 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; } Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp (revision 343217) @@ -1,650 +1,656 @@ //===- 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; 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; + bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End, + uint8_t StOther) const override; private: void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, uint8_t ModRm) const; }; } // namespace template X86_64::X86_64() { CopyRel = R_X86_64_COPY; GotRel = R_X86_64_GLOB_DAT; + NoneRel = R_X86_64_NONE; 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 + TrapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 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()); + write64le(Buf, In.Dynamic->getVA()); } template void X86_64::writeGotPlt(uint8_t *Buf, const Symbol &S) const { // See comments in X86::writeGotPlt. 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(); + uint64_t GotPlt = In.GotPlt->getVA(); + uint64_t Plt = In.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, -getPltEntryOffset(Index) - 16); } 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(Loc, Val, 8, Type); *Loc = Val; break; case R_X86_64_16: checkUInt(Loc, Val, 16, Type); write16le(Loc, Val); break; case R_X86_64_32: 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(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 { + uint8_t *End, + uint8_t StOther) const { + if (Loc + 8 >= End) + return false; + // 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) { + if (memcmp(Loc, "\x64\x48\x3b\x24\x25", 5) == 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); + // Adjust "lea X(%rsp),%rYY" to lea "(X - 0x4000)(%rsp),%rYY" where rYY could + // be r10 or r11. The lea instruction feeds a subsequent compare which checks + // if there is X available stack space. Making X larger effectively reserves + // that much additional space. The stack grows downward so subtract the value. + if (memcmp(Loc, "\x4c\x8d\x94\x24", 4) == 0 || + memcmp(Loc, "\x4c\x8d\x9c\x24", 4) == 0) { + // The offset bytes are encoded four bytes after the start of the + // instruction. + write32le(Loc + 4, read32le(Loc + 4) - 0x4000); 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 { + uint8_t *End, + uint8_t StOther) 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 { 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(); + uint64_t GotPlt = In.GotPlt->getVA(); + uint64_t Plt = In.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 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1b: int3; padding }; memcpy(Buf, Insn, sizeof(Insn)); - uint64_t Off = TargetInfo::getPltEntryOffset(Index); + uint64_t Off = 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 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding }; memcpy(Buf, Insn, sizeof(Insn)); write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7); - write32le(Buf + 8, -TargetInfo::getPltEntryOffset(Index) - 12); + write32le(Buf + 8, -getPltEntryOffset(Index) - 12); } 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(); } Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/CMakeLists.txt =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/CMakeLists.txt (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/CMakeLists.txt (revision 343217) @@ -1,66 +1,68 @@ 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/MSP430.cpp Arch/PPC.cpp Arch/PPC64.cpp + Arch/RISCV.cpp Arch/SPARCV9.cpp Arch/X86.cpp Arch/X86_64.cpp CallGraphSort.cpp + DWARF.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 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} ) Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/CallGraphSort.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/CallGraphSort.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/CallGraphSort.cpp (revision 343217) @@ -1,249 +1,240 @@ //===- 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; - } + Cluster(int Sec, size_t S) : Sections{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; + Edge BestPred = {-1, 0}; }; 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 +typedef std::pair + SectionPair; + // 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; + MapVector &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) { + for (std::pair &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}); + // Remember the best edge. + Cluster &ToC = Clusters[To]; + if (ToC.BestPred.From == -1 || ToC.BestPred.Weight < Weight) { + ToC.BestPred.From = From; + ToC.BestPred.Weight = 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; + return NewDensity < A.getDensity() / MAX_DENSITY_DEGRADATION; } 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]; + for (size_t I = 0; I < Clusters.size(); ++I) { + SortedSecs[I] = I; + SecToCluster[I] = &Clusters[I]; } 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) + // Don't consider merging if the edge is unlikely. + if (C.BestPred.From == -1 || C.BestPred.Weight * 10 <= C.InitialWeight) continue; - Cluster *PredC = SecToCluster[BestPred]; + Cluster *PredC = SecToCluster[C.BestPred.From]; 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; + 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(); } Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/Config.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/Config.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/Config.h (revision 343217) @@ -1,286 +1,294 @@ //===- 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 }; +enum class UnresolvedPolicy { ReportError, Warn, Ignore }; // 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 }; // For tracking ARM Float Argument PCS enum class ARMVFPArgKind { Default, Base, VFP, ToolChain }; 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 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; bool ARMHasBlx = false; bool ARMHasMovtMovw = false; bool ARMJ1J2BranchEncoding = false; bool AsNeeded = false; bool Bsymbolic; bool BsymbolicFunctions; + bool CallGraphProfileSort; bool CheckSections; bool CompressDebugSections; bool Cref; bool DefineCommon; bool Demangle = true; bool DisableVerify; bool EhFrameHdr; + bool EmitLLVM; bool EmitRelocs; bool EnableNewDtags; bool ExecuteOnly; bool ExportDynamic; bool FixCortexA53Errata843419; + bool FormatBinary = false; bool GcSections; bool GdbIndex; bool GnuHash = false; bool GnuUnique; bool HasDynamicList = false; bool HasDynSymTab; bool IgnoreDataAddressEquality; bool IgnoreFunctionAddressEquality; bool LTODebugPassManager; bool LTONewPassManager; bool MergeArmExidx; bool MipsN32Abi = false; 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 ThinLTOEmitImportsFiles; bool ThinLTOIndexOnly; + bool TocOptimize; bool UndefinedVersion; bool UseAndroidRelrTags = false; bool WarnBackrefs; bool WarnCommon; + bool WarnIfuncTextrel; bool WarnMissingEntry; bool WarnSymbolOrdering; bool WriteAddends; bool ZCombreloc; bool ZCopyreloc; bool ZExecstack; + bool ZGlobal; bool ZHazardplt; bool ZIfuncnoplt; bool ZInitfirst; bool ZInterpose; bool ZKeepTextSectionPrefix; + bool ZNodefaultlib; bool ZNodelete; bool ZNodlopen; bool ZNow; bool ZOrigin; bool ZRelro; bool ZRodynamic; bool ZText; bool ZRetpolineplt; bool ZWxneeded; DiscardPolicy Discard; ICFLevel ICF; OrphanHandlingPolicy OrphanHandling; SortSectionPolicy SortSection; StripPolicy Strip; UnresolvedPolicy UnresolvedSymbols; Target2Policy Target2; ARMVFPArgKind ARMVFPArgs = ARMVFPArgKind::Default; 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; + int32_t SplitStackAdjustSize; // 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 Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/DWARF.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/DWARF.cpp (nonexistent) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/DWARF.cpp (revision 343217) @@ -0,0 +1,109 @@ +//===- DWARF.cpp ----------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// The -gdb-index option instructs the linker to emit a .gdb_index section. +// The section contains information to make gdb startup faster. +// The format of the section is described at +// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html. +// +//===----------------------------------------------------------------------===// + +#include "DWARF.h" +#include "Symbols.h" +#include "Target.h" +#include "lld/Common/Memory.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" +#include "llvm/Object/ELFObjectFile.h" + +using namespace llvm; +using namespace llvm::object; +using namespace lld; +using namespace lld::elf; + +template LLDDwarfObj::LLDDwarfObj(ObjFile *Obj) { + for (InputSectionBase *Sec : Obj->getSections()) { + if (!Sec) + continue; + + if (LLDDWARFSection *M = + StringSwitch(Sec->Name) + .Case(".debug_addr", &AddrSection) + .Case(".debug_gnu_pubnames", &GnuPubNamesSection) + .Case(".debug_gnu_pubtypes", &GnuPubTypesSection) + .Case(".debug_info", &InfoSection) + .Case(".debug_ranges", &RangeSection) + .Case(".debug_rnglists", &RngListsSection) + .Case(".debug_line", &LineSection) + .Default(nullptr)) { + M->Data = toStringRef(Sec->data()); + M->Sec = Sec; + continue; + } + + if (Sec->Name == ".debug_abbrev") + AbbrevSection = toStringRef(Sec->data()); + else if (Sec->Name == ".debug_str") + StrSection = toStringRef(Sec->data()); + else if (Sec->Name == ".debug_line_str") + LineStringSection = toStringRef(Sec->data()); + } +} + +// Find if there is a relocation at Pos in Sec. The code is a bit +// more complicated than usual because we need to pass a section index +// to llvm since it has no idea about InputSection. +template +template +Optional +LLDDwarfObj::findAux(const InputSectionBase &Sec, uint64_t Pos, + ArrayRef Rels) const { + auto It = std::lower_bound( + Rels.begin(), Rels.end(), Pos, + [](const RelTy &A, uint64_t B) { return A.r_offset < B; }); + if (It == Rels.end() || It->r_offset != Pos) + return None; + const RelTy &Rel = *It; + + const ObjFile *File = Sec.getFile(); + uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL); + const typename ELFT::Sym &Sym = File->getELFSyms()[SymIndex]; + uint32_t SecIndex = File->getSectionIndex(Sym); + + // Broken debug info can point to a non-Defined symbol. + auto *DR = dyn_cast(&File->getRelocTargetSym(Rel)); + if (!DR) { + RelType Type = Rel.getType(Config->IsMips64EL); + if (Type != Target->NoneRel) + error(toString(File) + ": relocation " + lld::toString(Type) + " at 0x" + + llvm::utohexstr(Rel.r_offset) + " has unsupported target"); + return None; + } + uint64_t Val = DR->Value + getAddend(Rel); + + // FIXME: We should be consistent about always adding the file + // offset or not. + if (DR->Section->Flags & ELF::SHF_ALLOC) + Val += cast(DR->Section)->getOffsetInFile(); + + return RelocAddrEntry{SecIndex, Val}; +} + +template +Optional LLDDwarfObj::find(const llvm::DWARFSection &S, + uint64_t Pos) const { + auto &Sec = static_cast(S); + if (Sec.Sec->AreRelocsRela) + return findAux(*Sec.Sec, Pos, Sec.Sec->template relas()); + return findAux(*Sec.Sec, Pos, Sec.Sec->template rels()); +} + +template class elf::LLDDwarfObj; +template class elf::LLDDwarfObj; +template class elf::LLDDwarfObj; +template class elf::LLDDwarfObj; Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/DWARF.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/DWARF.h (nonexistent) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/DWARF.h (revision 343217) @@ -0,0 +1,93 @@ +//===- DWARF.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_DWARF_H +#define LLD_ELF_DWARF_H + +#include "InputFiles.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/Object/ELF.h" + +namespace lld { +namespace elf { + +class InputSection; + +struct LLDDWARFSection final : public llvm::DWARFSection { + InputSectionBase *Sec = nullptr; +}; + +template class LLDDwarfObj final : public llvm::DWARFObject { +public: + explicit LLDDwarfObj(ObjFile *Obj); + + void forEachInfoSections( + llvm::function_ref F) const override { + F(InfoSection); + } + + const llvm::DWARFSection &getRangeSection() const override { + return RangeSection; + } + + const llvm::DWARFSection &getRnglistsSection() const override { + return RngListsSection; + } + + const llvm::DWARFSection &getLineSection() const override { + return LineSection; + } + + const llvm::DWARFSection &getAddrSection() const override { + return AddrSection; + } + + const llvm::DWARFSection &getGnuPubNamesSection() const override { + return GnuPubNamesSection; + } + + const llvm::DWARFSection &getGnuPubTypesSection() const override { + return GnuPubTypesSection; + } + + StringRef getFileName() const override { return ""; } + StringRef getAbbrevSection() const override { return AbbrevSection; } + StringRef getStringSection() const override { return StrSection; } + StringRef getLineStringSection() const override { return LineStringSection; } + + bool isLittleEndian() const override { + return ELFT::TargetEndianness == llvm::support::little; + } + + llvm::Optional find(const llvm::DWARFSection &Sec, + uint64_t Pos) const override; + +private: + template + llvm::Optional findAux(const InputSectionBase &Sec, + uint64_t Pos, + ArrayRef Rels) const; + + LLDDWARFSection GnuPubNamesSection; + LLDDWARFSection GnuPubTypesSection; + LLDDWARFSection InfoSection; + LLDDWARFSection RangeSection; + LLDDWARFSection RngListsSection; + LLDDWARFSection LineSection; + LLDDWARFSection AddrSection; + StringRef AbbrevSection; + StringRef StrSection; + StringRef LineStringSection; +}; + +} // namespace elf +} // namespace lld + +#endif Index: projects/clang800-import/contrib/llvm/tools/lld/ELF/Driver.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/ELF/Driver.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/ELF/Driver.cpp (revision 343217) @@ -1,1521 +1,1650 @@ //===- 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 "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 llvm::support; using namespace lld; using namespace lld::elf; Configuration *elf::Config; LinkerDriver *elf::Driver; static void setConfigs(opt::InputArgList &Args); bool elf::link(ArrayRef Args, bool CanExitEarly, raw_ostream &Error) { - errorHandler().LogName = sys::path::filename(Args[0]); + errorHandler().LogName = args::getFilenameWithoutExe(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(); + + Tar = nullptr; + memset(&In, 0, sizeof(In)); + Config->ProgName = Args[0]; 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 (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", "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("elf32lriscv", {ELF32LEKind, EM_RISCV}) .Case("elf32ppc", {ELF32BEKind, EM_PPC}) .Case("elf64btsmip", {ELF64BEKind, EM_MIPS}) .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS}) + .Case("elf64lriscv", {ELF64LEKind, EM_RISCV}) .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) { + if (Config->FormatBinary) { 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) { + if (Config->Static || 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; 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() { InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmPrinters(); InitializeAllAsmParsers(); } // Some command line options or some combinations of them are not allowed. // This function checks for such errors. -static void checkOptions(opt::InputArgList &Args) { +static void checkOptions() { // 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."); + 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."); + error("--fix-cortex-a53-843419 is only supported on AArch64 targets"); + if (Config->TocOptimize && Config->EMachine != EM_PPC64) + error("--toc-optimize is only supported on the PowerPC64 target"); + 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->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"); } if (Config->ExecuteOnly) { if (Config->EMachine != EM_AARCH64) error("-execute-only is only supported on AArch64 targets"); if (Config->SingleRoRx && !Script->HasSectionsCommand) error("-execute-only and -no-rosegment cannot 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; } 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) { +static bool isKnownZFlag(StringRef S) { return S == "combreloc" || S == "copyreloc" || S == "defs" || - S == "execstack" || S == "hazardplt" || S == "ifunc-noplt" || + S == "execstack" || S == "global" || S == "hazardplt" || + S == "ifunc-noplt" || S == "initfirst" || S == "interpose" || S == "keep-text-section-prefix" || S == "lazy" || S == "muldefs" || - S == "nocombreloc" || S == "nocopyreloc" || S == "nodelete" || - S == "nodlopen" || S == "noexecstack" || + S == "nocombreloc" || S == "nocopyreloc" || S == "nodefaultlib" || + 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())) + if (!isKnownZFlag(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(); 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; - 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 = std::move(*ErrOrWriter); 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())); + error("--reproduce: " + toString(ErrOrWriter.takeError())); } } readConfigs(Args); checkZOptions(Args); + + // 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; + initLLVM(); createFiles(Args); if (errorCount()) return; inferMachineType(); setConfigs(Args); - checkOptions(Args); + checkOptions(); 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; - if (S.startswith("elf")) - return false; + StringRef S = Args.getLastArgValue(OPT_oformat, "elf"); + if (S == "binary") + return true; + if (!S.startswith("elf")) 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= .. role:: none .. role:: partial .. role:: good =============== Windows support =============== LLD supports Windows operating system. When invoked as ``lld-link.exe`` or with ``-flavor link``, the driver for Windows operating system is used to parse command line options, and it drives further linking processes. LLD accepts almost all command line options that the linker shipped with Microsoft Visual C++ (link.exe) supports. -The current status is that LLD can link itself on Windows x86/x64 -using Visual C++ 2013 as the compiler. +The current status is that LLD is used to link production builds of large +real-world binaries such as Firefox and Chromium. Development status ================== Driver :good:`Mostly done`. Some exotic command line options that are not usually used for application develompent, such as ``/DRIVER``, are not supported. Linking against DLL :good:`Done`. LLD can read import libraries needed to link against DLL. Both export-by-name and export-by-ordinal are supported. Linking against static library :good:`Done`. The format of static library (.lib) on Windows is actually the same as on Unix (.a). LLD can read it. Creating DLL :good:`Done`. LLD creates a DLL if ``/DLL`` option is given. Exported functions can be specified either via command line (``/EXPORT``) or via module-definition file (.def). Both export-by-name and export-by-ordinal are supported. Windows resource files support :good:`Done`. If an ``.res`` file is given, LLD converts the file to a COFF file using LLVM's Object library. Safe Structured Exception Handler (SEH) :good:`Done` for both x86 and x64. Module-definition file :partial:`Partially done`. LLD currently recognizes these directives: ``EXPORTS``, ``HEAPSIZE``, ``STACKSIZE``, ``NAME``, and ``VERSION``. Debug info :good:`Done`. LLD can emit PDBs that are at parity with those generated by link.exe. However, LLD does not support /DEBUG:FASTLINK. Downloading LLD =============== The Windows version of LLD is included in the `pre-built binaries of LLVM's releases `_ and in the `LLVM Snapshot Builds `_. Building LLD ============ Using Visual Studio IDE/MSBuild ------------------------------- 1. Check out LLVM and LLD from the LLVM SVN repository (or Git mirror), #. run ``cmake -G "Visual Studio 12" `` from VS command prompt, #. open LLVM.sln with Visual Studio, and #. build ``lld`` target in ``lld executables`` folder Alternatively, you can use msbuild if you don't like to work in an IDE:: msbuild LLVM.sln /m /target:"lld executables\lld" MSBuild.exe had been shipped as a component of the .NET framework, but since 2013 it's part of Visual Studio. You can find it at "C:\\Program Files (x86)\\msbuild". You can build LLD as a 64 bit application. To do that, open VS2013 x64 command prompt and run cmake for "Visual Studio 12 Win64" target. Using Ninja ----------- 1. Check out LLVM and LLD from the LLVM SVN repository (or Git mirror), #. run ``cmake -G ninja `` from VS command prompt, #. run ``ninja lld`` Index: projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/Args.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/Args.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/Args.h (revision 343217) @@ -1,35 +1,38 @@ //===- Args.h ---------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_ARGS_H #define LLD_ARGS_H #include "lld/Common/LLVM.h" #include "llvm/Support/MemoryBuffer.h" #include namespace llvm { namespace opt { class InputArgList; } } // namespace llvm namespace lld { namespace args { int getInteger(llvm::opt::InputArgList &Args, unsigned Key, int Default); std::vector getStrings(llvm::opt::InputArgList &Args, int Id); uint64_t getZOptionValue(llvm::opt::InputArgList &Args, int Id, StringRef Key, uint64_t Default); std::vector getLines(MemoryBufferRef MB); + +StringRef getFilenameWithoutExe(StringRef Path); + } // namespace args } // namespace lld #endif Index: projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/ErrorHandler.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/ErrorHandler.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/ErrorHandler.h (revision 343217) @@ -1,160 +1,160 @@ //===- ErrorHandler.h -------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // We designed lld's error handlers with the following goals in mind: // // - Errors can occur at any place where we handle user input, but we don't // want them to affect the normal execution path too much. Ideally, // handling errors should be as simple as reporting them and exit (but // without actually doing exit). // // In particular, the design to wrap all functions that could fail with // ErrorOr is rejected because otherwise we would have to wrap a large // number of functions in lld with ErrorOr. With that approach, if some // function F can fail, not only F but all functions that transitively call // F have to be wrapped with ErrorOr. That seemed too much. // // - Finding only one error at a time is not sufficient. We want to find as // many errors as possible with one execution of the linker. That means the // linker needs to keep running after a first error and give up at some // checkpoint (beyond which it would find cascading, false errors caused by // the previous errors). // // - We want a simple interface to report errors. Unlike Clang, the data we // handle is compiled binary, so we don't need an error reporting mechanism // that's as sophisticated as the one that Clang has. // // The current lld's error handling mechanism is simple: // // - When you find an error, report it using error() and continue as far as // you can. An internal error counter is incremented by one every time you // call error(). // // A common idiom to handle an error is calling error() and then returning // a reasonable default value. For example, if your function handles a // user-supplied alignment value, and if you find an invalid alignment // (e.g. 17 which is not 2^n), you may report it using error() and continue // as if it were alignment 1 (which is the simplest reasonable value). // // Note that you should not continue with an invalid value; that breaks the // internal consistency. You need to maintain all variables have some sane // value even after an error occurred. So, when you have to continue with // some value, always use a dummy value. // // - Find a reasonable checkpoint at where you want to stop the linker, and // add code to return from the function if errorCount() > 0. In most cases, // a checkpoint already exists, so you don't need to do anything for this. // // This interface satisfies all the goals that we mentioned above. // // You should never call fatal() except for reporting a corrupted input file. // fatal() immediately terminates the linker, so the function is not desirable // if you are using lld as a subroutine in other program, and with that you // can find only one error at a time. // // warn() doesn't do anything but printing out a given message. // // It is not recommended to use llvm::outs() or llvm::errs() directly in lld // because they are not thread-safe. The functions declared in this file are // thread-safe. // //===----------------------------------------------------------------------===// #ifndef LLD_COMMON_ERRORHANDLER_H #define LLD_COMMON_ERRORHANDLER_H #include "lld/Common/LLVM.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileOutputBuffer.h" namespace llvm { class DiagnosticInfo; } namespace lld { class ErrorHandler { public: uint64_t ErrorCount = 0; uint64_t ErrorLimit = 20; StringRef ErrorLimitExceededMsg = "too many errors emitted, stopping now"; StringRef LogName = "lld"; llvm::raw_ostream *ErrorOS = &llvm::errs(); bool ColorDiagnostics = llvm::errs().has_colors(); bool ExitEarly = true; bool FatalWarnings = false; bool Verbose = false; void error(const Twine &Msg); LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); void log(const Twine &Msg); void message(const Twine &Msg); void warn(const Twine &Msg); std::unique_ptr OutputBuffer; private: void print(StringRef S, raw_ostream::Colors C); }; /// Returns the default error handler. ErrorHandler &errorHandler(); inline void error(const Twine &Msg) { errorHandler().error(Msg); } inline LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg) { errorHandler().fatal(Msg); } inline void log(const Twine &Msg) { errorHandler().log(Msg); } inline void message(const Twine &Msg) { errorHandler().message(Msg); } inline void warn(const Twine &Msg) { errorHandler().warn(Msg); } inline uint64_t errorCount() { return errorHandler().ErrorCount; } LLVM_ATTRIBUTE_NORETURN void exitLld(int Val); void diagnosticHandler(const llvm::DiagnosticInfo &DI); void checkError(Error E); // check functions are convenient functions to strip errors // from error-or-value objects. template T check(ErrorOr E) { if (auto EC = E.getError()) fatal(EC.message()); return std::move(*E); } template T check(Expected E) { if (!E) fatal(llvm::toString(E.takeError())); return std::move(*E); } template T check2(ErrorOr E, llvm::function_ref Prefix) { if (auto EC = E.getError()) fatal(Prefix() + ": " + EC.message()); return std::move(*E); } template T check2(Expected E, llvm::function_ref Prefix) { if (!E) fatal(Prefix() + ": " + toString(E.takeError())); return std::move(*E); } inline std::string toString(const Twine &S) { return S.str(); } // To evaluate the second argument lazily, we use C macro. -#define CHECK(E, S) check2(E, [&] { return toString(S); }) +#define CHECK(E, S) check2((E), [&] { return toString(S); }) } // namespace lld #endif Index: projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/LLVM.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/LLVM.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/LLVM.h (revision 343217) @@ -1,83 +1,99 @@ //===--- LLVM.h - Import various common LLVM datatypes ----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file forward declares and imports various common LLVM datatypes that // lld wants to use unqualified. // //===----------------------------------------------------------------------===// #ifndef LLD_COMMON_LLVM_H #define LLD_COMMON_LLVM_H // This should be the only #include, force #includes of all the others on // clients. #include "llvm/ADT/Hashing.h" #include "llvm/Support/Casting.h" #include namespace llvm { - // ADT's. - class Error; - class StringRef; - class Twine; - class MemoryBuffer; - class MemoryBufferRef; - template class ArrayRef; - template class SmallString; - template class SmallVector; - template class SmallVectorImpl; +// ADT's. +class raw_ostream; +class Error; +class StringRef; +class Twine; +class MemoryBuffer; +class MemoryBufferRef; +template class ArrayRef; +template class SmallString; +template class SmallVector; +template class ErrorOr; +template class Expected; - template - struct SaveAndRestore; +namespace object { +class WasmObjectFile; +struct WasmSection; +struct WasmSegment; +class WasmSymbol; +} // namespace object - template - class ErrorOr; +namespace wasm { +struct WasmEvent; +struct WasmEventType; +struct WasmFunction; +struct WasmGlobal; +struct WasmGlobalType; +struct WasmRelocation; +struct WasmSignature; +} // namespace wasm +} // namespace llvm - template - class Expected; - - class raw_ostream; - // TODO: DenseMap, ... -} - namespace lld { - // Casting operators. - using llvm::isa; - using llvm::cast; - using llvm::dyn_cast; - using llvm::dyn_cast_or_null; - using llvm::cast_or_null; +// Casting operators. +using llvm::cast; +using llvm::cast_or_null; +using llvm::dyn_cast; +using llvm::dyn_cast_or_null; +using llvm::isa; - // ADT's. - using llvm::Error; - using llvm::StringRef; - using llvm::Twine; - using llvm::MemoryBuffer; - using llvm::MemoryBufferRef; - using llvm::ArrayRef; - using llvm::SmallString; - using llvm::SmallVector; - using llvm::SmallVectorImpl; - using llvm::SaveAndRestore; - using llvm::ErrorOr; - using llvm::Expected; +// ADT's. +using llvm::ArrayRef; +using llvm::Error; +using llvm::ErrorOr; +using llvm::Expected; +using llvm::MemoryBuffer; +using llvm::MemoryBufferRef; +using llvm::raw_ostream; +using llvm::SmallString; +using llvm::SmallVector; +using llvm::StringRef; +using llvm::Twine; - using llvm::raw_ostream; +using llvm::object::WasmObjectFile; +using llvm::object::WasmSection; +using llvm::object::WasmSegment; +using llvm::object::WasmSymbol; +using llvm::wasm::WasmEvent; +using llvm::wasm::WasmEventType; +using llvm::wasm::WasmFunction; +using llvm::wasm::WasmGlobal; +using llvm::wasm::WasmGlobalType; +using llvm::wasm::WasmRelocation; +using llvm::wasm::WasmSignature; } // end namespace lld. namespace std { template <> struct hash { public: size_t operator()(const llvm::StringRef &s) const { return llvm::hash_value(s); } }; -} +} // namespace std #endif Index: projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/Strings.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/Strings.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/Strings.h (revision 343217) @@ -1,49 +1,46 @@ //===- 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_STRINGS_H #define LLD_STRINGS_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/GlobPattern.h" #include #include namespace lld { // Returns a demangled C++ symbol name. If Name is not a mangled // name, it returns Optional::None. llvm::Optional demangleItanium(llvm::StringRef Name); llvm::Optional demangleMSVC(llvm::StringRef S); std::vector parseHex(llvm::StringRef S); bool isValidCIdentifier(llvm::StringRef S); // Write the contents of the a buffer to a file void saveBuffer(llvm::StringRef Buffer, const llvm::Twine &Path); // This class represents multiple glob patterns. class StringMatcher { public: StringMatcher() = default; explicit StringMatcher(llvm::ArrayRef Pat); bool match(llvm::StringRef S) const; private: std::vector Patterns; }; -inline llvm::ArrayRef toArrayRef(llvm::StringRef S) { - return {reinterpret_cast(S.data()), S.size()}; -} } // namespace lld #endif Index: projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/TargetOptionsCommandFlags.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/TargetOptionsCommandFlags.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/TargetOptionsCommandFlags.h (revision 343217) @@ -1,22 +1,23 @@ //===-- TargetOptionsCommandFlags.h ----------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Helper to create TargetOptions from command line flags. // //===----------------------------------------------------------------------===// #include "llvm/ADT/Optional.h" #include "llvm/Support/CodeGen.h" #include "llvm/Target/TargetOptions.h" namespace lld { llvm::TargetOptions InitTargetOptionsFromCodeGenFlags(); llvm::Optional GetCodeModelFromCMModel(); std::string GetCPUStr(); +std::vector GetMAttrs(); } Index: projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/Threads.h =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/Threads.h (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/include/lld/Common/Threads.h (revision 343217) @@ -1,86 +1,86 @@ //===- Threads.h ------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // LLD supports threads to distribute workloads to multiple cores. Using // multicore is most effective when more than one core are idle. At the // last step of a build, it is often the case that a linker is the only // active process on a computer. So, we are naturally interested in using // threads wisely to reduce latency to deliver results to users. // // That said, we don't want to do "too clever" things using threads. // Complex multi-threaded algorithms are sometimes extremely hard to // reason about and can easily mess up the entire design. // // Fortunately, when a linker links large programs (when the link time is // most critical), it spends most of the time to work on massive number of // small pieces of data of the same kind, and there are opportunities for // large parallelism there. Here are examples: // // - We have hundreds of thousands of input sections that need to be // copied to a result file at the last step of link. Once we fix a file // layout, each section can be copied to its destination and its // relocations can be applied independently. // // - We have tens of millions of small strings when constructing a // mergeable string section. // // For the cases such as the former, we can just use parallelForEach // instead of std::for_each (or a plain for loop). Because tasks are // completely independent from each other, we can run them in parallel // without any coordination between them. That's very easy to understand // and reason about. // // For the cases such as the latter, we can use parallel algorithms to // deal with massive data. We have to write code for a tailored algorithm // for each problem, but the complexity of multi-threading is isolated in // a single pass and doesn't affect the linker's overall design. // // The above approach seems to be working fairly well. As an example, when // linking Chromium (output size 1.6 GB), using 4 cores reduces latency to // 75% compared to single core (from 12.66 seconds to 9.55 seconds) on my // Ivy Bridge Xeon 2.8 GHz machine. Using 40 cores reduces it to 63% (from // 12.66 seconds to 7.95 seconds). Because of the Amdahl's law, the // speedup is not linear, but as you add more cores, it gets faster. // // On a final note, if you are trying to optimize, keep the axiom "don't // guess, measure!" in mind. Some important passes of the linker are not // that slow. For example, resolving all symbols is not a very heavy pass, // although it would be very hard to parallelize it. You want to first // identify a slow pass and then optimize it. // //===----------------------------------------------------------------------===// #ifndef LLD_COMMON_THREADS_H #define LLD_COMMON_THREADS_H #include "llvm/Support/Parallel.h" #include namespace lld { extern bool ThreadsEnabled; template void parallelForEach(R &&Range, FuncTy Fn) { if (ThreadsEnabled) for_each(llvm::parallel::par, std::begin(Range), std::end(Range), Fn); else for_each(llvm::parallel::seq, std::begin(Range), std::end(Range), Fn); } inline void parallelForEachN(size_t Begin, size_t End, - std::function Fn) { + llvm::function_ref Fn) { if (ThreadsEnabled) for_each_n(llvm::parallel::par, Begin, End, Fn); else for_each_n(llvm::parallel::seq, Begin, End, Fn); } } // namespace lld #endif Index: projects/clang800-import/contrib/llvm/tools/lld/include/lld/Core/TODO.txt =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/include/lld/Core/TODO.txt (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/include/lld/Core/TODO.txt (nonexistent) @@ -1,14 +0,0 @@ -include/lld/Core -~~~~~~~~~~~~~~~~ - -* The yaml reader/writer interfaces should be changed to return - an explanatory string if there is an error. The existing error_code - abstraction only works for returning low level OS errors. It does not - work for describing formatting issues. - -* We need to add more attributes to File. In particular, we need cpu - and OS information (like target triples). We should also provide explicit - support for `LLVM IR module flags metadata`__. - -.. __: http://llvm.org/docs/LangRef.html#module_flags -.. _Clang: http://clang.llvm.org/docs/InternalsManual.html#Diagnostics Property changes on: projects/clang800-import/contrib/llvm/tools/lld/include/lld/Core/TODO.txt ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: projects/clang800-import/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp (revision 343217) @@ -1,1227 +1,1230 @@ //===- lib/Driver/DarwinLdDriver.cpp --------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// /// Concrete instance of the Driver for darwin's ld. /// //===----------------------------------------------------------------------===// #include "lld/Common/Args.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/LLVM.h" #include "lld/Core/ArchiveLibraryFile.h" #include "lld/Core/Error.h" #include "lld/Core/File.h" #include "lld/Core/Instrumentation.h" #include "lld/Core/LinkingContext.h" #include "lld/Core/Node.h" #include "lld/Core/PassManager.h" #include "lld/Core/Resolver.h" #include "lld/Core/SharedLibraryFile.h" #include "lld/Core/Simple.h" #include "lld/ReaderWriter/MachOLinkingContext.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/Format.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include #include #include using namespace lld; namespace { // Create enum with OPT_xxx values for each option in DarwinLdOptions.td enum { OPT_INVALID = 0, #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ HELP, META, VALUES) \ OPT_##ID, #include "DarwinLdOptions.inc" #undef OPTION }; // Create prefix string literals used in DarwinLdOptions.td #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; #include "DarwinLdOptions.inc" #undef PREFIX // Create table mapping all options defined in DarwinLdOptions.td static const llvm::opt::OptTable::Info InfoTable[] = { #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ HELPTEXT, METAVAR, VALUES) \ {PREFIX, NAME, HELPTEXT, \ METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ PARAM, FLAGS, OPT_##GROUP, \ OPT_##ALIAS, ALIASARGS, VALUES}, #include "DarwinLdOptions.inc" #undef OPTION }; // Create OptTable class for parsing actual command line arguments class DarwinLdOptTable : public llvm::opt::OptTable { public: DarwinLdOptTable() : OptTable(InfoTable) {} }; static std::vector> makeErrorFile(StringRef path, std::error_code ec) { std::vector> result; result.push_back(llvm::make_unique(path, ec)); return result; } static std::vector> parseMemberFiles(std::unique_ptr file) { std::vector> members; if (auto *archive = dyn_cast(file.get())) { if (std::error_code ec = archive->parseAllMembers(members)) return makeErrorFile(file->path(), ec); } else { members.push_back(std::move(file)); } return members; } std::vector> loadFile(MachOLinkingContext &ctx, StringRef path, bool wholeArchive, bool upwardDylib) { if (ctx.logInputFiles()) message(path); ErrorOr> mbOrErr = ctx.getMemoryBuffer(path); if (std::error_code ec = mbOrErr.getError()) return makeErrorFile(path, ec); ErrorOr> fileOrErr = ctx.registry().loadFile(std::move(mbOrErr.get())); if (std::error_code ec = fileOrErr.getError()) return makeErrorFile(path, ec); std::unique_ptr &file = fileOrErr.get(); // If file is a dylib, inform LinkingContext about it. if (SharedLibraryFile *shl = dyn_cast(file.get())) { if (std::error_code ec = shl->parse()) return makeErrorFile(path, ec); ctx.registerDylib(reinterpret_cast(shl), upwardDylib); } if (wholeArchive) return parseMemberFiles(std::move(file)); std::vector> files; files.push_back(std::move(file)); return files; } } // end anonymous namespace // Test may be running on Windows. Canonicalize the path // separator to '/' to get consistent outputs for tests. static std::string canonicalizePath(StringRef path) { char sep = llvm::sys::path::get_separator().front(); if (sep != '/') { std::string fixedPath = path; std::replace(fixedPath.begin(), fixedPath.end(), sep, '/'); return fixedPath; } else { return path; } } static void addFile(StringRef path, MachOLinkingContext &ctx, bool loadWholeArchive, bool upwardDylib) { std::vector> files = loadFile(ctx, path, loadWholeArchive, upwardDylib); for (std::unique_ptr &file : files) ctx.getNodes().push_back(llvm::make_unique(std::move(file))); } // Export lists are one symbol per line. Blank lines are ignored. // Trailing comments start with #. static std::error_code parseExportsList(StringRef exportFilePath, MachOLinkingContext &ctx) { // Map in export list file. ErrorOr> mb = MemoryBuffer::getFileOrSTDIN(exportFilePath); if (std::error_code ec = mb.getError()) return ec; ctx.addInputFileDependency(exportFilePath); StringRef buffer = mb->get()->getBuffer(); while (!buffer.empty()) { // Split off each line in the file. std::pair lineAndRest = buffer.split('\n'); StringRef line = lineAndRest.first; // Ignore trailing # comments. std::pair symAndComment = line.split('#'); StringRef sym = symAndComment.first.trim(); if (!sym.empty()) ctx.addExportSymbol(sym); buffer = lineAndRest.second; } return std::error_code(); } /// Order files are one symbol per line. Blank lines are ignored. /// Trailing comments start with #. Symbol names can be prefixed with an /// architecture name and/or .o leaf name. Examples: /// _foo /// bar.o:_bar /// libfrob.a(bar.o):_bar /// x86_64:_foo64 static std::error_code parseOrderFile(StringRef orderFilePath, MachOLinkingContext &ctx) { // Map in order file. ErrorOr> mb = MemoryBuffer::getFileOrSTDIN(orderFilePath); if (std::error_code ec = mb.getError()) return ec; ctx.addInputFileDependency(orderFilePath); StringRef buffer = mb->get()->getBuffer(); while (!buffer.empty()) { // Split off each line in the file. std::pair lineAndRest = buffer.split('\n'); StringRef line = lineAndRest.first; buffer = lineAndRest.second; // Ignore trailing # comments. std::pair symAndComment = line.split('#'); if (symAndComment.first.empty()) continue; StringRef sym = symAndComment.first.trim(); if (sym.empty()) continue; // Check for prefix. StringRef prefix; std::pair prefixAndSym = sym.split(':'); if (!prefixAndSym.second.empty()) { sym = prefixAndSym.second; prefix = prefixAndSym.first; if (!prefix.endswith(".o") && !prefix.endswith(".o)")) { // If arch name prefix does not match arch being linked, ignore symbol. if (!ctx.archName().equals(prefix)) continue; prefix = ""; } } else sym = prefixAndSym.first; if (!sym.empty()) { ctx.appendOrderedSymbol(sym, prefix); //llvm::errs() << sym << ", prefix=" << prefix << "\n"; } } return std::error_code(); } // // There are two variants of the -filelist option: // // -filelist // In this variant, the path is to a text file which contains one file path // per line. There are no comments or trimming of whitespace. // // -fileList , // In this variant, the path is to a text file which contains a partial path // per line. The prefix is prepended to each partial path. // static llvm::Error loadFileList(StringRef fileListPath, MachOLinkingContext &ctx, bool forceLoad) { // If there is a comma, split off . std::pair opt = fileListPath.split(','); StringRef filePath = opt.first; StringRef dirName = opt.second; ctx.addInputFileDependency(filePath); // Map in file list file. ErrorOr> mb = MemoryBuffer::getFileOrSTDIN(filePath); if (std::error_code ec = mb.getError()) return llvm::errorCodeToError(ec); StringRef buffer = mb->get()->getBuffer(); while (!buffer.empty()) { // Split off each line in the file. std::pair lineAndRest = buffer.split('\n'); StringRef line = lineAndRest.first; StringRef path; if (!dirName.empty()) { // If there is a then prepend dir to each line. SmallString<256> fullPath; fullPath.assign(dirName); llvm::sys::path::append(fullPath, Twine(line)); path = ctx.copy(fullPath.str()); } else { // No use whole line as input file path. path = ctx.copy(line); } if (!ctx.pathExists(path)) { return llvm::make_error(Twine("File not found '") + path + "'"); } if (ctx.testingFileUsage()) { message("Found filelist entry " + canonicalizePath(path)); } addFile(path, ctx, forceLoad, false); buffer = lineAndRest.second; } return llvm::Error::success(); } /// Parse number assuming it is base 16, but allow 0x prefix. static bool parseNumberBase16(StringRef numStr, uint64_t &baseAddress) { if (numStr.startswith_lower("0x")) numStr = numStr.drop_front(2); return numStr.getAsInteger(16, baseAddress); } static void parseLLVMOptions(const LinkingContext &ctx) { // Honor -mllvm if (!ctx.llvmOptions().empty()) { unsigned numArgs = ctx.llvmOptions().size(); auto **args = new const char *[numArgs + 2]; args[0] = "lld (LLVM option parsing)"; for (unsigned i = 0; i != numArgs; ++i) args[i + 1] = ctx.llvmOptions()[i]; args[numArgs + 1] = nullptr; llvm::cl::ParseCommandLineOptions(numArgs + 1, args); } } namespace lld { namespace mach_o { bool parse(llvm::ArrayRef args, MachOLinkingContext &ctx) { // Parse command line options using DarwinLdOptions.td DarwinLdOptTable table; unsigned missingIndex; unsigned missingCount; llvm::opt::InputArgList parsedArgs = table.ParseArgs(args.slice(1), missingIndex, missingCount); if (missingCount) { error("missing arg value for '" + Twine(parsedArgs.getArgString(missingIndex)) + "' expected " + Twine(missingCount) + " argument(s)."); return false; } for (auto unknownArg : parsedArgs.filtered(OPT_UNKNOWN)) { warn("ignoring unknown argument: " + Twine(unknownArg->getAsString(parsedArgs))); } errorHandler().Verbose = parsedArgs.hasArg(OPT_v); errorHandler().ErrorLimit = args::getInteger(parsedArgs, OPT_error_limit, 20); // Figure out output kind ( -dylib, -r, -bundle, -preload, or -static ) llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE; bool isStaticExecutable = false; if (llvm::opt::Arg *kind = parsedArgs.getLastArg( OPT_dylib, OPT_relocatable, OPT_bundle, OPT_static, OPT_preload)) { switch (kind->getOption().getID()) { case OPT_dylib: fileType = llvm::MachO::MH_DYLIB; break; case OPT_relocatable: fileType = llvm::MachO::MH_OBJECT; break; case OPT_bundle: fileType = llvm::MachO::MH_BUNDLE; break; case OPT_static: fileType = llvm::MachO::MH_EXECUTE; isStaticExecutable = true; break; case OPT_preload: fileType = llvm::MachO::MH_PRELOAD; break; } } // Handle -arch xxx MachOLinkingContext::Arch arch = MachOLinkingContext::arch_unknown; if (llvm::opt::Arg *archStr = parsedArgs.getLastArg(OPT_arch)) { arch = MachOLinkingContext::archFromName(archStr->getValue()); if (arch == MachOLinkingContext::arch_unknown) { error("unknown arch named '" + Twine(archStr->getValue()) + "'"); return false; } } // If no -arch specified, scan input files to find first non-fat .o file. if (arch == MachOLinkingContext::arch_unknown) { for (auto &inFile : parsedArgs.filtered(OPT_INPUT)) { // This is expensive because it opens and maps the file. But that is // ok because no -arch is rare. if (MachOLinkingContext::isThinObjectFile(inFile->getValue(), arch)) break; } if (arch == MachOLinkingContext::arch_unknown && !parsedArgs.getLastArg(OPT_test_file_usage)) { // If no -arch and no options at all, print usage message. - if (parsedArgs.size() == 0) - table.PrintHelp(llvm::outs(), args[0], "LLVM Linker", false); - else + if (parsedArgs.size() == 0) { + table.PrintHelp(llvm::outs(), + (std::string(args[0]) + " [options] file...").c_str(), + "LLVM Linker", false); + } else { error("-arch not specified and could not be inferred"); + } return false; } } // Handle -macosx_version_min or -ios_version_min MachOLinkingContext::OS os = MachOLinkingContext::OS::unknown; uint32_t minOSVersion = 0; if (llvm::opt::Arg *minOS = parsedArgs.getLastArg(OPT_macosx_version_min, OPT_ios_version_min, OPT_ios_simulator_version_min)) { switch (minOS->getOption().getID()) { case OPT_macosx_version_min: os = MachOLinkingContext::OS::macOSX; if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), minOSVersion)) { error("malformed macosx_version_min value"); return false; } break; case OPT_ios_version_min: os = MachOLinkingContext::OS::iOS; if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), minOSVersion)) { error("malformed ios_version_min value"); return false; } break; case OPT_ios_simulator_version_min: os = MachOLinkingContext::OS::iOS_simulator; if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), minOSVersion)) { error("malformed ios_simulator_version_min value"); return false; } break; } } else { // No min-os version on command line, check environment variables } // Handle export_dynamic // FIXME: Should we warn when this applies to something other than a static // executable or dylib? Those are the only cases where this has an effect. // Note, this has to come before ctx.configure() so that we get the correct // value for _globalsAreDeadStripRoots. bool exportDynamicSymbols = parsedArgs.hasArg(OPT_export_dynamic); // Now that there's enough information parsed in, let the linking context // set up default values. ctx.configure(fileType, arch, os, minOSVersion, exportDynamicSymbols); // Handle -e xxx if (llvm::opt::Arg *entry = parsedArgs.getLastArg(OPT_entry)) ctx.setEntrySymbolName(entry->getValue()); // Handle -o xxx if (llvm::opt::Arg *outpath = parsedArgs.getLastArg(OPT_output)) ctx.setOutputPath(outpath->getValue()); else ctx.setOutputPath("a.out"); // Handle -image_base XXX and -seg1addr XXXX if (llvm::opt::Arg *imageBase = parsedArgs.getLastArg(OPT_image_base)) { uint64_t baseAddress; if (parseNumberBase16(imageBase->getValue(), baseAddress)) { error("image_base expects a hex number"); return false; } else if (baseAddress < ctx.pageZeroSize()) { error("image_base overlaps with __PAGEZERO"); return false; } else if (baseAddress % ctx.pageSize()) { error("image_base must be a multiple of page size (0x" + llvm::utohexstr(ctx.pageSize()) + ")"); return false; } ctx.setBaseAddress(baseAddress); } // Handle -dead_strip if (parsedArgs.getLastArg(OPT_dead_strip)) ctx.setDeadStripping(true); bool globalWholeArchive = false; // Handle -all_load if (parsedArgs.getLastArg(OPT_all_load)) globalWholeArchive = true; // Handle -install_name if (llvm::opt::Arg *installName = parsedArgs.getLastArg(OPT_install_name)) ctx.setInstallName(installName->getValue()); else ctx.setInstallName(ctx.outputPath()); // Handle -mark_dead_strippable_dylib if (parsedArgs.getLastArg(OPT_mark_dead_strippable_dylib)) ctx.setDeadStrippableDylib(true); // Handle -compatibility_version and -current_version if (llvm::opt::Arg *vers = parsedArgs.getLastArg(OPT_compatibility_version)) { if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) { error("-compatibility_version can only be used with -dylib"); return false; } uint32_t parsedVers; if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) { error("-compatibility_version value is malformed"); return false; } ctx.setCompatibilityVersion(parsedVers); } if (llvm::opt::Arg *vers = parsedArgs.getLastArg(OPT_current_version)) { if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) { error("-current_version can only be used with -dylib"); return false; } uint32_t parsedVers; if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) { error("-current_version value is malformed"); return false; } ctx.setCurrentVersion(parsedVers); } // Handle -bundle_loader if (llvm::opt::Arg *loader = parsedArgs.getLastArg(OPT_bundle_loader)) ctx.setBundleLoader(loader->getValue()); // Handle -sectalign segname sectname align for (auto &alignArg : parsedArgs.filtered(OPT_sectalign)) { const char* segName = alignArg->getValue(0); const char* sectName = alignArg->getValue(1); const char* alignStr = alignArg->getValue(2); if ((alignStr[0] == '0') && (alignStr[1] == 'x')) alignStr += 2; unsigned long long alignValue; if (llvm::getAsUnsignedInteger(alignStr, 16, alignValue)) { error("-sectalign alignment value '" + Twine(alignStr) + "' not a valid number"); return false; } uint16_t align = 1 << llvm::countTrailingZeros(alignValue); if (!llvm::isPowerOf2_64(alignValue)) { std::string Msg; llvm::raw_string_ostream OS(Msg); OS << "alignment for '-sectalign " << segName << " " << sectName << llvm::format(" 0x%llX", alignValue) << "' is not a power of two, using " << llvm::format("0x%08X", align); OS.flush(); warn(Msg); } ctx.addSectionAlignment(segName, sectName, align); } // Handle -mllvm for (auto &llvmArg : parsedArgs.filtered(OPT_mllvm)) { ctx.appendLLVMOption(llvmArg->getValue()); } // Handle -print_atoms if (parsedArgs.getLastArg(OPT_print_atoms)) ctx.setPrintAtoms(); // Handle -t (trace) option. if (parsedArgs.getLastArg(OPT_t)) ctx.setLogInputFiles(true); // Handle -demangle option. if (parsedArgs.getLastArg(OPT_demangle)) ctx.setDemangleSymbols(true); // Handle -keep_private_externs if (parsedArgs.getLastArg(OPT_keep_private_externs)) { ctx.setKeepPrivateExterns(true); if (ctx.outputMachOType() != llvm::MachO::MH_OBJECT) warn("-keep_private_externs only used in -r mode"); } // Handle -dependency_info used by Xcode. if (llvm::opt::Arg *depInfo = parsedArgs.getLastArg(OPT_dependency_info)) if (std::error_code ec = ctx.createDependencyFile(depInfo->getValue())) warn(ec.message() + ", processing '-dependency_info " + depInfo->getValue()); // In -test_file_usage mode, we'll be given an explicit list of paths that // exist. We'll also be expected to print out information about how we located // libraries and so on that the user specified, but not to actually do any // linking. if (parsedArgs.getLastArg(OPT_test_file_usage)) { ctx.setTestingFileUsage(); // With paths existing by fiat, linking is not going to end well. ctx.setDoNothing(true); // Only bother looking for an existence override if we're going to use it. for (auto existingPath : parsedArgs.filtered(OPT_path_exists)) { ctx.addExistingPathForDebug(existingPath->getValue()); } } // Register possible input file parsers. if (!ctx.doNothing()) { ctx.registry().addSupportMachOObjects(ctx); ctx.registry().addSupportArchives(ctx.logInputFiles()); ctx.registry().addSupportYamlFiles(); } // Now construct the set of library search directories, following ld64's // baroque set of accumulated hacks. Mostly, the algorithm constructs // { syslibroots } x { libpaths } // // Unfortunately, there are numerous exceptions: // 1. Only absolute paths get modified by syslibroot options. // 2. If there is just 1 -syslibroot, system paths not found in it are // skipped. // 3. If the last -syslibroot is "/", all of them are ignored entirely. // 4. If { syslibroots } x path == {}, the original path is kept. std::vector sysLibRoots; for (auto syslibRoot : parsedArgs.filtered(OPT_syslibroot)) { sysLibRoots.push_back(syslibRoot->getValue()); } if (!sysLibRoots.empty()) { // Ignore all if last -syslibroot is "/". if (sysLibRoots.back() != "/") ctx.setSysLibRoots(sysLibRoots); } // Paths specified with -L come first, and are not considered system paths for // the case where there is precisely 1 -syslibroot. for (auto libPath : parsedArgs.filtered(OPT_L)) { ctx.addModifiedSearchDir(libPath->getValue()); } // Process -F directories (where to look for frameworks). for (auto fwPath : parsedArgs.filtered(OPT_F)) { ctx.addFrameworkSearchDir(fwPath->getValue()); } // -Z suppresses the standard search paths. if (!parsedArgs.hasArg(OPT_Z)) { ctx.addModifiedSearchDir("/usr/lib", true); ctx.addModifiedSearchDir("/usr/local/lib", true); ctx.addFrameworkSearchDir("/Library/Frameworks", true); ctx.addFrameworkSearchDir("/System/Library/Frameworks", true); } // Now that we've constructed the final set of search paths, print out those // search paths in verbose mode. if (errorHandler().Verbose) { message("Library search paths:"); for (auto path : ctx.searchDirs()) { message(" " + path); } message("Framework search paths:"); for (auto path : ctx.frameworkDirs()) { message(" " + path); } } // Handle -exported_symbols_list for (auto expFile : parsedArgs.filtered(OPT_exported_symbols_list)) { if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) { error("-exported_symbols_list cannot be combined with " "-unexported_symbol[s_list]"); return false; } ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList); if (std::error_code ec = parseExportsList(expFile->getValue(), ctx)) { error(ec.message() + ", processing '-exported_symbols_list " + expFile->getValue()); return false; } } // Handle -exported_symbol for (auto symbol : parsedArgs.filtered(OPT_exported_symbol)) { if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) { error("-exported_symbol cannot be combined with " "-unexported_symbol[s_list]"); return false; } ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList); ctx.addExportSymbol(symbol->getValue()); } // Handle -unexported_symbols_list for (auto expFile : parsedArgs.filtered(OPT_unexported_symbols_list)) { if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) { error("-unexported_symbols_list cannot be combined with " "-exported_symbol[s_list]"); return false; } ctx.setExportMode(MachOLinkingContext::ExportMode::blackList); if (std::error_code ec = parseExportsList(expFile->getValue(), ctx)) { error(ec.message() + ", processing '-unexported_symbols_list " + expFile->getValue()); return false; } } // Handle -unexported_symbol for (auto symbol : parsedArgs.filtered(OPT_unexported_symbol)) { if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) { error("-unexported_symbol cannot be combined with " "-exported_symbol[s_list]"); return false; } ctx.setExportMode(MachOLinkingContext::ExportMode::blackList); ctx.addExportSymbol(symbol->getValue()); } // Handle obosolete -multi_module and -single_module if (llvm::opt::Arg *mod = parsedArgs.getLastArg(OPT_multi_module, OPT_single_module)) { if (mod->getOption().getID() == OPT_multi_module) warn("-multi_module is obsolete and being ignored"); else if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) warn("-single_module being ignored. It is only for use when producing a " "dylib"); } // Handle obsolete ObjC options: -objc_gc_compaction, -objc_gc, -objc_gc_only if (parsedArgs.getLastArg(OPT_objc_gc_compaction)) { error("-objc_gc_compaction is not supported"); return false; } if (parsedArgs.getLastArg(OPT_objc_gc)) { error("-objc_gc is not supported"); return false; } if (parsedArgs.getLastArg(OPT_objc_gc_only)) { error("-objc_gc_only is not supported"); return false; } // Handle -pie or -no_pie if (llvm::opt::Arg *pie = parsedArgs.getLastArg(OPT_pie, OPT_no_pie)) { switch (ctx.outputMachOType()) { case llvm::MachO::MH_EXECUTE: switch (ctx.os()) { case MachOLinkingContext::OS::macOSX: if ((minOSVersion < 0x000A0500) && (pie->getOption().getID() == OPT_pie)) { error("-pie can only be used when targeting Mac OS X 10.5 or later"); return false; } break; case MachOLinkingContext::OS::iOS: if ((minOSVersion < 0x00040200) && (pie->getOption().getID() == OPT_pie)) { error("-pie can only be used when targeting iOS 4.2 or later"); return false; } break; case MachOLinkingContext::OS::iOS_simulator: if (pie->getOption().getID() == OPT_no_pie) { error("iOS simulator programs must be built PIE"); return false; } break; case MachOLinkingContext::OS::unknown: break; } ctx.setPIE(pie->getOption().getID() == OPT_pie); break; case llvm::MachO::MH_PRELOAD: break; case llvm::MachO::MH_DYLIB: case llvm::MachO::MH_BUNDLE: warn(pie->getSpelling() + " being ignored. It is only used when linking main executables"); break; default: error(pie->getSpelling() + " can only used when linking main executables"); return false; } } // Handle -version_load_command or -no_version_load_command { bool flagOn = false; bool flagOff = false; if (auto *arg = parsedArgs.getLastArg(OPT_version_load_command, OPT_no_version_load_command)) { flagOn = arg->getOption().getID() == OPT_version_load_command; flagOff = arg->getOption().getID() == OPT_no_version_load_command; } // default to adding version load command for dynamic code, // static code must opt-in switch (ctx.outputMachOType()) { case llvm::MachO::MH_OBJECT: ctx.setGenerateVersionLoadCommand(false); break; case llvm::MachO::MH_EXECUTE: // dynamic executables default to generating a version load command, // while static exectuables only generate it if required. if (isStaticExecutable) { if (flagOn) ctx.setGenerateVersionLoadCommand(true); } else { if (!flagOff) ctx.setGenerateVersionLoadCommand(true); } break; case llvm::MachO::MH_PRELOAD: case llvm::MachO::MH_KEXT_BUNDLE: if (flagOn) ctx.setGenerateVersionLoadCommand(true); break; case llvm::MachO::MH_DYLINKER: case llvm::MachO::MH_DYLIB: case llvm::MachO::MH_BUNDLE: if (!flagOff) ctx.setGenerateVersionLoadCommand(true); break; case llvm::MachO::MH_FVMLIB: case llvm::MachO::MH_DYLDLINK: case llvm::MachO::MH_DYLIB_STUB: case llvm::MachO::MH_DSYM: // We don't generate load commands for these file types, even if // forced on. break; } } // Handle -function_starts or -no_function_starts { bool flagOn = false; bool flagOff = false; if (auto *arg = parsedArgs.getLastArg(OPT_function_starts, OPT_no_function_starts)) { flagOn = arg->getOption().getID() == OPT_function_starts; flagOff = arg->getOption().getID() == OPT_no_function_starts; } // default to adding functions start for dynamic code, static code must // opt-in switch (ctx.outputMachOType()) { case llvm::MachO::MH_OBJECT: ctx.setGenerateFunctionStartsLoadCommand(false); break; case llvm::MachO::MH_EXECUTE: // dynamic executables default to generating a version load command, // while static exectuables only generate it if required. if (isStaticExecutable) { if (flagOn) ctx.setGenerateFunctionStartsLoadCommand(true); } else { if (!flagOff) ctx.setGenerateFunctionStartsLoadCommand(true); } break; case llvm::MachO::MH_PRELOAD: case llvm::MachO::MH_KEXT_BUNDLE: if (flagOn) ctx.setGenerateFunctionStartsLoadCommand(true); break; case llvm::MachO::MH_DYLINKER: case llvm::MachO::MH_DYLIB: case llvm::MachO::MH_BUNDLE: if (!flagOff) ctx.setGenerateFunctionStartsLoadCommand(true); break; case llvm::MachO::MH_FVMLIB: case llvm::MachO::MH_DYLDLINK: case llvm::MachO::MH_DYLIB_STUB: case llvm::MachO::MH_DSYM: // We don't generate load commands for these file types, even if // forced on. break; } } // Handle -data_in_code_info or -no_data_in_code_info { bool flagOn = false; bool flagOff = false; if (auto *arg = parsedArgs.getLastArg(OPT_data_in_code_info, OPT_no_data_in_code_info)) { flagOn = arg->getOption().getID() == OPT_data_in_code_info; flagOff = arg->getOption().getID() == OPT_no_data_in_code_info; } // default to adding data in code for dynamic code, static code must // opt-in switch (ctx.outputMachOType()) { case llvm::MachO::MH_OBJECT: if (!flagOff) ctx.setGenerateDataInCodeLoadCommand(true); break; case llvm::MachO::MH_EXECUTE: // dynamic executables default to generating a version load command, // while static exectuables only generate it if required. if (isStaticExecutable) { if (flagOn) ctx.setGenerateDataInCodeLoadCommand(true); } else { if (!flagOff) ctx.setGenerateDataInCodeLoadCommand(true); } break; case llvm::MachO::MH_PRELOAD: case llvm::MachO::MH_KEXT_BUNDLE: if (flagOn) ctx.setGenerateDataInCodeLoadCommand(true); break; case llvm::MachO::MH_DYLINKER: case llvm::MachO::MH_DYLIB: case llvm::MachO::MH_BUNDLE: if (!flagOff) ctx.setGenerateDataInCodeLoadCommand(true); break; case llvm::MachO::MH_FVMLIB: case llvm::MachO::MH_DYLDLINK: case llvm::MachO::MH_DYLIB_STUB: case llvm::MachO::MH_DSYM: // We don't generate load commands for these file types, even if // forced on. break; } } // Handle sdk_version if (llvm::opt::Arg *arg = parsedArgs.getLastArg(OPT_sdk_version)) { uint32_t sdkVersion = 0; if (MachOLinkingContext::parsePackedVersion(arg->getValue(), sdkVersion)) { error("malformed sdkVersion value"); return false; } ctx.setSdkVersion(sdkVersion); } else if (ctx.generateVersionLoadCommand()) { // If we don't have an sdk version, but were going to emit a load command // with min_version, then we need to give an warning as we have no sdk // version to put in that command. // FIXME: We need to decide whether to make this an error. warn("-sdk_version is required when emitting min version load command. " "Setting sdk version to match provided min version"); ctx.setSdkVersion(ctx.osMinVersion()); } // Handle source_version if (llvm::opt::Arg *arg = parsedArgs.getLastArg(OPT_source_version)) { uint64_t version = 0; if (MachOLinkingContext::parsePackedVersion(arg->getValue(), version)) { error("malformed source_version value"); return false; } ctx.setSourceVersion(version); } // Handle stack_size if (llvm::opt::Arg *stackSize = parsedArgs.getLastArg(OPT_stack_size)) { uint64_t stackSizeVal; if (parseNumberBase16(stackSize->getValue(), stackSizeVal)) { error("stack_size expects a hex number"); return false; } if ((stackSizeVal % ctx.pageSize()) != 0) { error("stack_size must be a multiple of page size (0x" + llvm::utohexstr(ctx.pageSize()) + ")"); return false; } ctx.setStackSize(stackSizeVal); } // Handle debug info handling options: -S if (parsedArgs.hasArg(OPT_S)) ctx.setDebugInfoMode(MachOLinkingContext::DebugInfoMode::noDebugMap); // Handle -order_file for (auto orderFile : parsedArgs.filtered(OPT_order_file)) { if (std::error_code ec = parseOrderFile(orderFile->getValue(), ctx)) { error(ec.message() + ", processing '-order_file " + orderFile->getValue() + "'"); return false; } } // Handle -flat_namespace. if (llvm::opt::Arg *ns = parsedArgs.getLastArg(OPT_flat_namespace, OPT_twolevel_namespace)) { if (ns->getOption().getID() == OPT_flat_namespace) ctx.setUseFlatNamespace(true); } // Handle -undefined if (llvm::opt::Arg *undef = parsedArgs.getLastArg(OPT_undefined)) { MachOLinkingContext::UndefinedMode UndefMode; if (StringRef(undef->getValue()).equals("error")) UndefMode = MachOLinkingContext::UndefinedMode::error; else if (StringRef(undef->getValue()).equals("warning")) UndefMode = MachOLinkingContext::UndefinedMode::warning; else if (StringRef(undef->getValue()).equals("suppress")) UndefMode = MachOLinkingContext::UndefinedMode::suppress; else if (StringRef(undef->getValue()).equals("dynamic_lookup")) UndefMode = MachOLinkingContext::UndefinedMode::dynamicLookup; else { error("invalid option to -undefined [ warning | error | suppress | " "dynamic_lookup ]"); return false; } if (ctx.useFlatNamespace()) { // If we're using -flat_namespace then 'warning', 'suppress' and // 'dynamic_lookup' are all equivalent, so map them to 'suppress'. if (UndefMode != MachOLinkingContext::UndefinedMode::error) UndefMode = MachOLinkingContext::UndefinedMode::suppress; } else { // If we're using -twolevel_namespace then 'warning' and 'suppress' are // illegal. Emit a diagnostic if they've been (mis)used. if (UndefMode == MachOLinkingContext::UndefinedMode::warning || UndefMode == MachOLinkingContext::UndefinedMode::suppress) { error("can't use -undefined warning or suppress with " "-twolevel_namespace"); return false; } } ctx.setUndefinedMode(UndefMode); } // Handle -no_objc_category_merging. if (parsedArgs.getLastArg(OPT_no_objc_category_merging)) ctx.setMergeObjCCategories(false); // Handle -rpath if (parsedArgs.hasArg(OPT_rpath)) { switch (ctx.outputMachOType()) { case llvm::MachO::MH_EXECUTE: case llvm::MachO::MH_DYLIB: case llvm::MachO::MH_BUNDLE: if (!ctx.minOS("10.5", "2.0")) { if (ctx.os() == MachOLinkingContext::OS::macOSX) error("-rpath can only be used when targeting OS X 10.5 or later"); else error("-rpath can only be used when targeting iOS 2.0 or later"); return false; } break; default: error("-rpath can only be used when creating a dynamic final linked " "image"); return false; } for (auto rPath : parsedArgs.filtered(OPT_rpath)) { ctx.addRpath(rPath->getValue()); } } // Parse the LLVM options before we process files in case the file handling // makes use of things like LLVM_DEBUG(). parseLLVMOptions(ctx); // Handle input files and sectcreate. for (auto &arg : parsedArgs) { bool upward; llvm::Optional resolvedPath; switch (arg->getOption().getID()) { default: continue; case OPT_INPUT: addFile(arg->getValue(), ctx, globalWholeArchive, false); break; case OPT_upward_library: addFile(arg->getValue(), ctx, false, true); break; case OPT_force_load: addFile(arg->getValue(), ctx, true, false); break; case OPT_l: case OPT_upward_l: upward = (arg->getOption().getID() == OPT_upward_l); resolvedPath = ctx.searchLibrary(arg->getValue()); if (!resolvedPath) { error("Unable to find library for " + arg->getSpelling() + arg->getValue()); return false; } else if (ctx.testingFileUsage()) { message(Twine("Found ") + (upward ? "upward " : " ") + "library " + canonicalizePath(resolvedPath.getValue())); } addFile(resolvedPath.getValue(), ctx, globalWholeArchive, upward); break; case OPT_framework: case OPT_upward_framework: upward = (arg->getOption().getID() == OPT_upward_framework); resolvedPath = ctx.findPathForFramework(arg->getValue()); if (!resolvedPath) { error("Unable to find framework for " + arg->getSpelling() + " " + arg->getValue()); return false; } else if (ctx.testingFileUsage()) { message(Twine("Found ") + (upward ? "upward " : " ") + "framework " + canonicalizePath(resolvedPath.getValue())); } addFile(resolvedPath.getValue(), ctx, globalWholeArchive, upward); break; case OPT_filelist: if (auto ec = loadFileList(arg->getValue(), ctx, globalWholeArchive)) { handleAllErrors(std::move(ec), [&](const llvm::ErrorInfoBase &EI) { error(EI.message() + ", processing '-filelist " + arg->getValue()); }); return false; } break; case OPT_sectcreate: { const char* seg = arg->getValue(0); const char* sect = arg->getValue(1); const char* fileName = arg->getValue(2); ErrorOr> contentOrErr = MemoryBuffer::getFile(fileName); if (!contentOrErr) { error("can't open -sectcreate file " + Twine(fileName)); return false; } ctx.addSectCreateSection(seg, sect, std::move(*contentOrErr)); } break; } } if (ctx.getNodes().empty()) { error("No input files"); return false; } // Validate the combination of options used. return ctx.validate(); } static void createFiles(MachOLinkingContext &ctx, bool Implicit) { std::vector> Files; if (Implicit) ctx.createImplicitFiles(Files); else ctx.createInternalFiles(Files); for (auto i = Files.rbegin(), e = Files.rend(); i != e; ++i) { auto &members = ctx.getNodes(); members.insert(members.begin(), llvm::make_unique(std::move(*i))); } } /// This is where the link is actually performed. bool link(llvm::ArrayRef args, bool CanExitEarly, raw_ostream &Error) { - errorHandler().LogName = llvm::sys::path::filename(args[0]); + errorHandler().LogName = args::getFilenameWithoutExe(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(); MachOLinkingContext ctx; if (!parse(args, ctx)) return false; if (ctx.doNothing()) return true; if (ctx.getNodes().empty()) return false; for (std::unique_ptr &ie : ctx.getNodes()) if (FileNode *node = dyn_cast(ie.get())) node->getFile()->parse(); createFiles(ctx, false /* Implicit */); // Give target a chance to add files createFiles(ctx, true /* Implicit */); // Give target a chance to postprocess input files. // Mach-O uses this chance to move all object files before library files. ctx.finalizeInputFiles(); // Do core linking. ScopedTask resolveTask(getDefaultDomain(), "Resolve"); Resolver resolver(ctx); if (!resolver.resolve()) return false; SimpleFile *merged = nullptr; { std::unique_ptr mergedFile = resolver.resultFile(); merged = mergedFile.get(); auto &members = ctx.getNodes(); members.insert(members.begin(), llvm::make_unique(std::move(mergedFile))); } resolveTask.end(); // Run passes on linked atoms. ScopedTask passTask(getDefaultDomain(), "Passes"); PassManager pm; ctx.addPasses(pm); if (auto ec = pm.runOnFile(*merged)) { // FIXME: This should be passed to logAllUnhandledErrors but it needs // to be passed a Twine instead of a string. *errorHandler().ErrorOS << "Failed to run passes on file '" << ctx.outputPath() << "': "; logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS, std::string()); return false; } passTask.end(); // Give linked atoms to Writer to generate output file. ScopedTask writeTask(getDefaultDomain(), "Write"); if (auto ec = ctx.writeFile(*merged)) { // FIXME: This should be passed to logAllUnhandledErrors but it needs // to be passed a Twine instead of a string. *errorHandler().ErrorOS << "Failed to write file '" << ctx.outputPath() << "': "; logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS, std::string()); return false; } // Call exit() if we can to avoid calling destructors. if (CanExitEarly) exitLld(errorCount() ? 1 : 0); return true; } } // end namespace mach_o } // end namespace lld Index: projects/clang800-import/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp (revision 343217) @@ -1,865 +1,866 @@ //===- lib/FileFormat/MachO/ArchHandler_x86_64.cpp ------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "ArchHandler.h" #include "Atoms.h" #include "MachONormalizedFileBinaryUtils.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" using namespace llvm::MachO; using namespace lld::mach_o::normalized; namespace lld { namespace mach_o { using llvm::support::ulittle32_t; using llvm::support::ulittle64_t; using llvm::support::little32_t; using llvm::support::little64_t; class ArchHandler_x86_64 : public ArchHandler { public: ArchHandler_x86_64() = default; ~ArchHandler_x86_64() override = default; const Registry::KindStrings *kindStrings() override { return _sKindStrings; } Reference::KindArch kindArch() override { return Reference::KindArch::x86_64; } /// Used by GOTPass to locate GOT References bool isGOTAccess(const Reference &ref, bool &canBypassGOT) override { if (ref.kindNamespace() != Reference::KindNamespace::mach_o) return false; assert(ref.kindArch() == Reference::KindArch::x86_64); switch (ref.kindValue()) { case ripRel32GotLoad: canBypassGOT = true; return true; case ripRel32Got: canBypassGOT = false; return true; case imageOffsetGot: canBypassGOT = false; return true; default: return false; } } bool isTLVAccess(const Reference &ref) const override { assert(ref.kindNamespace() == Reference::KindNamespace::mach_o); assert(ref.kindArch() == Reference::KindArch::x86_64); return ref.kindValue() == ripRel32Tlv; } void updateReferenceToTLV(const Reference *ref) override { assert(ref->kindNamespace() == Reference::KindNamespace::mach_o); assert(ref->kindArch() == Reference::KindArch::x86_64); assert(ref->kindValue() == ripRel32Tlv); const_cast(ref)->setKindValue(ripRel32); } /// Used by GOTPass to update GOT References void updateReferenceToGOT(const Reference *ref, bool targetNowGOT) override { assert(ref->kindNamespace() == Reference::KindNamespace::mach_o); assert(ref->kindArch() == Reference::KindArch::x86_64); switch (ref->kindValue()) { case ripRel32Got: assert(targetNowGOT && "target must be GOT"); + LLVM_FALLTHROUGH; case ripRel32GotLoad: const_cast(ref) ->setKindValue(targetNowGOT ? ripRel32 : ripRel32GotLoadNowLea); break; case imageOffsetGot: const_cast(ref)->setKindValue(imageOffset); break; default: llvm_unreachable("unknown GOT reference kind"); } } bool needsCompactUnwind() override { return true; } Reference::KindValue imageOffsetKind() override { return imageOffset; } Reference::KindValue imageOffsetKindIndirect() override { return imageOffsetGot; } Reference::KindValue unwindRefToPersonalityFunctionKind() override { return ripRel32Got; } Reference::KindValue unwindRefToCIEKind() override { return negDelta32; } Reference::KindValue unwindRefToFunctionKind() override{ return unwindFDEToFunction; } Reference::KindValue lazyImmediateLocationKind() override { return lazyImmediateLocation; } Reference::KindValue unwindRefToEhFrameKind() override { return unwindInfoToEhFrame; } Reference::KindValue pointerKind() override { return pointer64; } uint32_t dwarfCompactUnwindType() override { return 0x04000000U; } const StubInfo &stubInfo() override { return _sStubInfo; } bool isNonCallBranch(const Reference &) override { return false; } bool isCallSite(const Reference &) override; bool isPointer(const Reference &) override; bool isPairedReloc(const normalized::Relocation &) override; llvm::Error getReferenceInfo(const normalized::Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress, bool swap, FindAtomBySectionAndAddress atomFromAddress, FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, const lld::Atom **target, Reference::Addend *addend) override; llvm::Error getPairReferenceInfo(const normalized::Relocation &reloc1, const normalized::Relocation &reloc2, const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress, bool swap, bool scatterable, FindAtomBySectionAndAddress atomFromAddress, FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, const lld::Atom **target, Reference::Addend *addend) override; bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) override { return (atom->contentType() == DefinedAtom::typeCString); } void generateAtomContent(const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress, FindAddressForAtom findSectionAddress, uint64_t imageBase, llvm::MutableArrayRef atomContentBuffer) override; void appendSectionRelocations(const DefinedAtom &atom, uint64_t atomSectionOffset, const Reference &ref, FindSymbolIndexForAtom symbolIndexForAtom, FindSectionIndexForAtom sectionIndexForAtom, FindAddressForAtom addressForAtom, normalized::Relocations &relocs) override; private: static const Registry::KindStrings _sKindStrings[]; static const StubInfo _sStubInfo; enum X86_64Kind: Reference::KindValue { invalid, /// for error condition // Kinds found in mach-o .o files: branch32, /// ex: call _foo ripRel32, /// ex: movq _foo(%rip), %rax ripRel32Minus1, /// ex: movb $0x12, _foo(%rip) ripRel32Minus2, /// ex: movw $0x1234, _foo(%rip) ripRel32Minus4, /// ex: movl $0x12345678, _foo(%rip) ripRel32Anon, /// ex: movq L1(%rip), %rax ripRel32Minus1Anon, /// ex: movb $0x12, L1(%rip) ripRel32Minus2Anon, /// ex: movw $0x1234, L1(%rip) ripRel32Minus4Anon, /// ex: movw $0x12345678, L1(%rip) ripRel32GotLoad, /// ex: movq _foo@GOTPCREL(%rip), %rax ripRel32Got, /// ex: pushq _foo@GOTPCREL(%rip) ripRel32Tlv, /// ex: movq _foo@TLVP(%rip), %rdi pointer64, /// ex: .quad _foo pointer64Anon, /// ex: .quad L1 delta64, /// ex: .quad _foo - . delta32, /// ex: .long _foo - . delta64Anon, /// ex: .quad L1 - . delta32Anon, /// ex: .long L1 - . negDelta64, /// ex: .quad . - _foo negDelta32, /// ex: .long . - _foo // Kinds introduced by Passes: ripRel32GotLoadNowLea, /// Target of GOT load is in linkage unit so /// "movq _foo@GOTPCREL(%rip), %rax" can be changed /// to "leaq _foo(%rip), %rax lazyPointer, /// Location contains a lazy pointer. lazyImmediateLocation, /// Location contains immediate value used in stub. imageOffset, /// Location contains offset of atom in final image imageOffsetGot, /// Location contains offset of GOT entry for atom in /// final image (typically personality function). unwindFDEToFunction, /// Nearly delta64, but cannot be rematerialized in /// relocatable object (yay for implicit contracts!). unwindInfoToEhFrame, /// Fix low 24 bits of compact unwind encoding to /// refer to __eh_frame entry. tlvInitSectionOffset /// Location contains offset tlv init-value atom /// within the __thread_data section. }; Reference::KindValue kindFromReloc(const normalized::Relocation &reloc); void applyFixupFinal(const Reference &ref, uint8_t *location, uint64_t fixupAddress, uint64_t targetAddress, uint64_t inAtomAddress, uint64_t imageBaseAddress, FindAddressForAtom findSectionAddress); void applyFixupRelocatable(const Reference &ref, uint8_t *location, uint64_t fixupAddress, uint64_t targetAddress, uint64_t inAtomAddress); }; const Registry::KindStrings ArchHandler_x86_64::_sKindStrings[] = { LLD_KIND_STRING_ENTRY(invalid), LLD_KIND_STRING_ENTRY(branch32), LLD_KIND_STRING_ENTRY(ripRel32), LLD_KIND_STRING_ENTRY(ripRel32Minus1), LLD_KIND_STRING_ENTRY(ripRel32Minus2), LLD_KIND_STRING_ENTRY(ripRel32Minus4), LLD_KIND_STRING_ENTRY(ripRel32Anon), LLD_KIND_STRING_ENTRY(ripRel32Minus1Anon), LLD_KIND_STRING_ENTRY(ripRel32Minus2Anon), LLD_KIND_STRING_ENTRY(ripRel32Minus4Anon), LLD_KIND_STRING_ENTRY(ripRel32GotLoad), LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea), LLD_KIND_STRING_ENTRY(ripRel32Got), LLD_KIND_STRING_ENTRY(ripRel32Tlv), LLD_KIND_STRING_ENTRY(lazyPointer), LLD_KIND_STRING_ENTRY(lazyImmediateLocation), LLD_KIND_STRING_ENTRY(pointer64), LLD_KIND_STRING_ENTRY(pointer64Anon), LLD_KIND_STRING_ENTRY(delta32), LLD_KIND_STRING_ENTRY(delta64), LLD_KIND_STRING_ENTRY(delta32Anon), LLD_KIND_STRING_ENTRY(delta64Anon), LLD_KIND_STRING_ENTRY(negDelta64), LLD_KIND_STRING_ENTRY(negDelta32), LLD_KIND_STRING_ENTRY(imageOffset), LLD_KIND_STRING_ENTRY(imageOffsetGot), LLD_KIND_STRING_ENTRY(unwindFDEToFunction), LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame), LLD_KIND_STRING_ENTRY(tlvInitSectionOffset), LLD_KIND_STRING_END }; const ArchHandler::StubInfo ArchHandler_x86_64::_sStubInfo = { "dyld_stub_binder", // Lazy pointer references { Reference::KindArch::x86_64, pointer64, 0, 0 }, { Reference::KindArch::x86_64, lazyPointer, 0, 0 }, // GOT pointer to dyld_stub_binder { Reference::KindArch::x86_64, pointer64, 0, 0 }, // x86_64 code alignment 2^1 1, // Stub size and code 6, { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }, // jmp *lazyPointer { Reference::KindArch::x86_64, ripRel32, 2, 0 }, { false, 0, 0, 0 }, // Stub Helper size and code 10, { 0x68, 0x00, 0x00, 0x00, 0x00, // pushq $lazy-info-offset 0xE9, 0x00, 0x00, 0x00, 0x00 }, // jmp helperhelper { Reference::KindArch::x86_64, lazyImmediateLocation, 1, 0 }, { Reference::KindArch::x86_64, branch32, 6, 0 }, // Stub helper image cache content type DefinedAtom::typeNonLazyPointer, // Stub Helper-Common size and code 16, // Stub helper alignment 2, { 0x4C, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00, // leaq cache(%rip),%r11 0x41, 0x53, // push %r11 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *binder(%rip) 0x90 }, // nop { Reference::KindArch::x86_64, ripRel32, 3, 0 }, { false, 0, 0, 0 }, { Reference::KindArch::x86_64, ripRel32, 11, 0 }, { false, 0, 0, 0 } }; bool ArchHandler_x86_64::isCallSite(const Reference &ref) { if (ref.kindNamespace() != Reference::KindNamespace::mach_o) return false; assert(ref.kindArch() == Reference::KindArch::x86_64); return (ref.kindValue() == branch32); } bool ArchHandler_x86_64::isPointer(const Reference &ref) { if (ref.kindNamespace() != Reference::KindNamespace::mach_o) return false; assert(ref.kindArch() == Reference::KindArch::x86_64); Reference::KindValue kind = ref.kindValue(); return (kind == pointer64 || kind == pointer64Anon); } bool ArchHandler_x86_64::isPairedReloc(const Relocation &reloc) { return (reloc.type == X86_64_RELOC_SUBTRACTOR); } Reference::KindValue ArchHandler_x86_64::kindFromReloc(const Relocation &reloc) { switch(relocPattern(reloc)) { case X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4: return branch32; case X86_64_RELOC_SIGNED | rPcRel | rExtern | rLength4: return ripRel32; case X86_64_RELOC_SIGNED | rPcRel | rLength4: return ripRel32Anon; case X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4: return ripRel32Minus1; case X86_64_RELOC_SIGNED_1 | rPcRel | rLength4: return ripRel32Minus1Anon; case X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4: return ripRel32Minus2; case X86_64_RELOC_SIGNED_2 | rPcRel | rLength4: return ripRel32Minus2Anon; case X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4: return ripRel32Minus4; case X86_64_RELOC_SIGNED_4 | rPcRel | rLength4: return ripRel32Minus4Anon; case X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4: return ripRel32GotLoad; case X86_64_RELOC_GOT | rPcRel | rExtern | rLength4: return ripRel32Got; case X86_64_RELOC_TLV | rPcRel | rExtern | rLength4: return ripRel32Tlv; case X86_64_RELOC_UNSIGNED | rExtern | rLength8: return pointer64; case X86_64_RELOC_UNSIGNED | rLength8: return pointer64Anon; default: return invalid; } } llvm::Error ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress, bool swap, FindAtomBySectionAndAddress atomFromAddress, FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, const lld::Atom **target, Reference::Addend *addend) { *kind = kindFromReloc(reloc); if (*kind == invalid) return llvm::make_error("unknown type"); const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; uint64_t targetAddress; switch (*kind) { case branch32: case ripRel32: if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = *(const little32_t *)fixupContent; return llvm::Error::success(); case ripRel32Minus1: if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = (int32_t)*(const little32_t *)fixupContent + 1; return llvm::Error::success(); case ripRel32Minus2: if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = (int32_t)*(const little32_t *)fixupContent + 2; return llvm::Error::success(); case ripRel32Minus4: if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = (int32_t)*(const little32_t *)fixupContent + 4; return llvm::Error::success(); case ripRel32Anon: targetAddress = fixupAddress + 4 + *(const little32_t *)fixupContent; return atomFromAddress(reloc.symbol, targetAddress, target, addend); case ripRel32Minus1Anon: targetAddress = fixupAddress + 5 + *(const little32_t *)fixupContent; return atomFromAddress(reloc.symbol, targetAddress, target, addend); case ripRel32Minus2Anon: targetAddress = fixupAddress + 6 + *(const little32_t *)fixupContent; return atomFromAddress(reloc.symbol, targetAddress, target, addend); case ripRel32Minus4Anon: targetAddress = fixupAddress + 8 + *(const little32_t *)fixupContent; return atomFromAddress(reloc.symbol, targetAddress, target, addend); case ripRel32GotLoad: case ripRel32Got: case ripRel32Tlv: if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; *addend = *(const little32_t *)fixupContent; return llvm::Error::success(); case tlvInitSectionOffset: case pointer64: if (auto ec = atomFromSymbolIndex(reloc.symbol, target)) return ec; // If this is the 3rd pointer of a tlv-thunk (i.e. the pointer to the TLV's // initial value) we need to handle it specially. if (inAtom->contentType() == DefinedAtom::typeThunkTLV && offsetInAtom == 16) { *kind = tlvInitSectionOffset; assert(*addend == 0 && "TLV-init has non-zero addend?"); } else *addend = *(const little64_t *)fixupContent; return llvm::Error::success(); case pointer64Anon: targetAddress = *(const little64_t *)fixupContent; return atomFromAddress(reloc.symbol, targetAddress, target, addend); default: llvm_unreachable("bad reloc kind"); } } llvm::Error ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1, const normalized::Relocation &reloc2, const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress, bool swap, bool scatterable, FindAtomBySectionAndAddress atomFromAddress, FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind, const lld::Atom **target, Reference::Addend *addend) { const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom]; uint64_t targetAddress; const lld::Atom *fromTarget; if (auto ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget)) return ec; switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) { case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 | X86_64_RELOC_UNSIGNED | rExtern | rLength8): { if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) return ec; uint64_t encodedAddend = (int64_t)*(const little64_t *)fixupContent; if (inAtom == fromTarget) { if (inAtom->contentType() == DefinedAtom::typeCFI) *kind = unwindFDEToFunction; else *kind = delta64; *addend = encodedAddend + offsetInAtom; } else if (inAtom == *target) { *kind = negDelta64; *addend = encodedAddend - offsetInAtom; *target = fromTarget; } else return llvm::make_error("Invalid pointer diff"); return llvm::Error::success(); } case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 | X86_64_RELOC_UNSIGNED | rExtern | rLength4): { if (auto ec = atomFromSymbolIndex(reloc2.symbol, target)) return ec; uint32_t encodedAddend = (int32_t)*(const little32_t *)fixupContent; if (inAtom == fromTarget) { *kind = delta32; *addend = encodedAddend + offsetInAtom; } else if (inAtom == *target) { *kind = negDelta32; *addend = encodedAddend - offsetInAtom; *target = fromTarget; } else return llvm::make_error("Invalid pointer diff"); return llvm::Error::success(); } case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 | X86_64_RELOC_UNSIGNED | rLength8): if (fromTarget != inAtom) return llvm::make_error("pointer diff not in base atom"); *kind = delta64Anon; targetAddress = offsetInAtom + (int64_t)*(const little64_t *)fixupContent; return atomFromAddress(reloc2.symbol, targetAddress, target, addend); case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 | X86_64_RELOC_UNSIGNED | rLength4): if (fromTarget != inAtom) return llvm::make_error("pointer diff not in base atom"); *kind = delta32Anon; targetAddress = offsetInAtom + (int32_t)*(const little32_t *)fixupContent; return atomFromAddress(reloc2.symbol, targetAddress, target, addend); default: return llvm::make_error("unknown pair"); } } void ArchHandler_x86_64::generateAtomContent( const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress, FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress, llvm::MutableArrayRef atomContentBuffer) { // Copy raw bytes. std::copy(atom.rawContent().begin(), atom.rawContent().end(), atomContentBuffer.begin()); // Apply fix-ups. for (const Reference *ref : atom) { uint32_t offset = ref->offsetInAtom(); const Atom *target = ref->target(); uint64_t targetAddress = 0; if (isa(target)) targetAddress = findAddress(*target); uint64_t atomAddress = findAddress(atom); uint64_t fixupAddress = atomAddress + offset; if (relocatable) { applyFixupRelocatable(*ref, &atomContentBuffer[offset], fixupAddress, targetAddress, atomAddress); } else { applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress, targetAddress, atomAddress, imageBaseAddress, findSectionAddress); } } } void ArchHandler_x86_64::applyFixupFinal( const Reference &ref, uint8_t *loc, uint64_t fixupAddress, uint64_t targetAddress, uint64_t inAtomAddress, uint64_t imageBaseAddress, FindAddressForAtom findSectionAddress) { if (ref.kindNamespace() != Reference::KindNamespace::mach_o) return; assert(ref.kindArch() == Reference::KindArch::x86_64); ulittle32_t *loc32 = reinterpret_cast(loc); ulittle64_t *loc64 = reinterpret_cast(loc); switch (static_cast(ref.kindValue())) { case branch32: case ripRel32: case ripRel32Anon: case ripRel32Got: case ripRel32GotLoad: case ripRel32Tlv: *loc32 = targetAddress - (fixupAddress + 4) + ref.addend(); return; case pointer64: case pointer64Anon: *loc64 = targetAddress + ref.addend(); return; case tlvInitSectionOffset: *loc64 = targetAddress - findSectionAddress(*ref.target()) + ref.addend(); return; case ripRel32Minus1: case ripRel32Minus1Anon: *loc32 = targetAddress - (fixupAddress + 5) + ref.addend(); return; case ripRel32Minus2: case ripRel32Minus2Anon: *loc32 = targetAddress - (fixupAddress + 6) + ref.addend(); return; case ripRel32Minus4: case ripRel32Minus4Anon: *loc32 = targetAddress - (fixupAddress + 8) + ref.addend(); return; case delta32: case delta32Anon: *loc32 = targetAddress - fixupAddress + ref.addend(); return; case delta64: case delta64Anon: case unwindFDEToFunction: *loc64 = targetAddress - fixupAddress + ref.addend(); return; case ripRel32GotLoadNowLea: // Change MOVQ to LEA assert(loc[-2] == 0x8B); loc[-2] = 0x8D; *loc32 = targetAddress - (fixupAddress + 4) + ref.addend(); return; case negDelta64: *loc64 = fixupAddress - targetAddress + ref.addend(); return; case negDelta32: *loc32 = fixupAddress - targetAddress + ref.addend(); return; case lazyPointer: // Do nothing return; case lazyImmediateLocation: *loc32 = ref.addend(); return; case imageOffset: case imageOffsetGot: *loc32 = (targetAddress - imageBaseAddress) + ref.addend(); return; case unwindInfoToEhFrame: { uint64_t val = targetAddress - findSectionAddress(*ref.target()) + ref.addend(); assert(val < 0xffffffU && "offset in __eh_frame too large"); *loc32 = (*loc32 & 0xff000000U) | val; return; } case invalid: // Fall into llvm_unreachable(). break; } llvm_unreachable("invalid x86_64 Reference Kind"); } void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref, uint8_t *loc, uint64_t fixupAddress, uint64_t targetAddress, uint64_t inAtomAddress) { if (ref.kindNamespace() != Reference::KindNamespace::mach_o) return; assert(ref.kindArch() == Reference::KindArch::x86_64); ulittle32_t *loc32 = reinterpret_cast(loc); ulittle64_t *loc64 = reinterpret_cast(loc); switch (static_cast(ref.kindValue())) { case branch32: case ripRel32: case ripRel32Got: case ripRel32GotLoad: case ripRel32Tlv: *loc32 = ref.addend(); return; case ripRel32Anon: *loc32 = (targetAddress - (fixupAddress + 4)) + ref.addend(); return; case tlvInitSectionOffset: case pointer64: *loc64 = ref.addend(); return; case pointer64Anon: *loc64 = targetAddress + ref.addend(); return; case ripRel32Minus1: *loc32 = ref.addend() - 1; return; case ripRel32Minus1Anon: *loc32 = (targetAddress - (fixupAddress + 5)) + ref.addend(); return; case ripRel32Minus2: *loc32 = ref.addend() - 2; return; case ripRel32Minus2Anon: *loc32 = (targetAddress - (fixupAddress + 6)) + ref.addend(); return; case ripRel32Minus4: *loc32 = ref.addend() - 4; return; case ripRel32Minus4Anon: *loc32 = (targetAddress - (fixupAddress + 8)) + ref.addend(); return; case delta32: *loc32 = ref.addend() + inAtomAddress - fixupAddress; return; case delta32Anon: // The value we write here should be the delta to the target // after taking in to account the difference from the fixup back to the // last defined label // ie, if we have: // _base: ... // Lfixup: .quad Ltarget - . // ... // Ltarget: // // Then we want to encode the value (Ltarget + addend) - (LFixup - _base) *loc32 = (targetAddress + ref.addend()) - (fixupAddress - inAtomAddress); return; case delta64: *loc64 = ref.addend() + inAtomAddress - fixupAddress; return; case delta64Anon: // The value we write here should be the delta to the target // after taking in to account the difference from the fixup back to the // last defined label // ie, if we have: // _base: ... // Lfixup: .quad Ltarget - . // ... // Ltarget: // // Then we want to encode the value (Ltarget + addend) - (LFixup - _base) *loc64 = (targetAddress + ref.addend()) - (fixupAddress - inAtomAddress); return; case negDelta64: *loc64 = ref.addend() + fixupAddress - inAtomAddress; return; case negDelta32: *loc32 = ref.addend() + fixupAddress - inAtomAddress; return; case ripRel32GotLoadNowLea: llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run"); return; case lazyPointer: case lazyImmediateLocation: llvm_unreachable("lazy reference kind implies Stubs pass was run"); return; case imageOffset: case imageOffsetGot: case unwindInfoToEhFrame: llvm_unreachable("fixup implies __unwind_info"); return; case unwindFDEToFunction: // Do nothing for now return; case invalid: // Fall into llvm_unreachable(). break; } llvm_unreachable("unknown x86_64 Reference Kind"); } void ArchHandler_x86_64::appendSectionRelocations( const DefinedAtom &atom, uint64_t atomSectionOffset, const Reference &ref, FindSymbolIndexForAtom symbolIndexForAtom, FindSectionIndexForAtom sectionIndexForAtom, FindAddressForAtom addressForAtom, normalized::Relocations &relocs) { if (ref.kindNamespace() != Reference::KindNamespace::mach_o) return; assert(ref.kindArch() == Reference::KindArch::x86_64); uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom(); switch (static_cast(ref.kindValue())) { case branch32: appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4); return; case ripRel32: appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, X86_64_RELOC_SIGNED | rPcRel | rExtern | rLength4 ); return; case ripRel32Anon: appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, X86_64_RELOC_SIGNED | rPcRel | rLength4 ); return; case ripRel32Got: appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, X86_64_RELOC_GOT | rPcRel | rExtern | rLength4 ); return; case ripRel32GotLoad: appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4 ); return; case ripRel32Tlv: appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, X86_64_RELOC_TLV | rPcRel | rExtern | rLength4 ); return; case tlvInitSectionOffset: case pointer64: appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, X86_64_RELOC_UNSIGNED | rExtern | rLength8); return; case pointer64Anon: appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, X86_64_RELOC_UNSIGNED | rLength8); return; case ripRel32Minus1: appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4 ); return; case ripRel32Minus1Anon: appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, X86_64_RELOC_SIGNED_1 | rPcRel | rLength4 ); return; case ripRel32Minus2: appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4 ); return; case ripRel32Minus2Anon: appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, X86_64_RELOC_SIGNED_2 | rPcRel | rLength4 ); return; case ripRel32Minus4: appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4 ); return; case ripRel32Minus4Anon: appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, X86_64_RELOC_SIGNED_4 | rPcRel | rLength4 ); return; case delta32: appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 ); appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, X86_64_RELOC_UNSIGNED | rExtern | rLength4 ); return; case delta32Anon: appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 ); appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, X86_64_RELOC_UNSIGNED | rLength4 ); return; case delta64: appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 ); appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, X86_64_RELOC_UNSIGNED | rExtern | rLength8 ); return; case delta64Anon: appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 ); appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0, X86_64_RELOC_UNSIGNED | rLength8 ); return; case unwindFDEToFunction: case unwindInfoToEhFrame: return; case negDelta32: appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, X86_64_RELOC_SUBTRACTOR | rExtern | rLength4 ); appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, X86_64_RELOC_UNSIGNED | rExtern | rLength4 ); return; case negDelta64: appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0, X86_64_RELOC_SUBTRACTOR | rExtern | rLength8 ); appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0, X86_64_RELOC_UNSIGNED | rExtern | rLength8 ); return; case ripRel32GotLoadNowLea: llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run"); return; case lazyPointer: case lazyImmediateLocation: llvm_unreachable("lazy reference kind implies Stubs pass was run"); return; case imageOffset: case imageOffsetGot: llvm_unreachable("__unwind_info references should have been resolved"); return; case invalid: // Fall into llvm_unreachable(). break; } llvm_unreachable("unknown x86_64 Reference Kind"); } std::unique_ptr ArchHandler::create_x86_64() { return std::unique_ptr(new ArchHandler_x86_64()); } } // namespace mach_o } // namespace lld Index: projects/clang800-import/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp (revision 343217) @@ -1,1100 +1,1101 @@ //===- lib/ReaderWriter/MachO/MachOLinkingContext.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/ReaderWriter/MachOLinkingContext.h" #include "ArchHandler.h" #include "File.h" #include "FlatNamespaceFile.h" #include "MachONormalizedFile.h" #include "MachOPasses.h" #include "SectCreateFile.h" #include "lld/Common/Driver.h" #include "lld/Core/ArchiveLibraryFile.h" #include "lld/Core/PassManager.h" #include "lld/Core/Reader.h" #include "lld/Core/Writer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/Demangle/Demangle.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Host.h" #include "llvm/Support/Path.h" #include using lld::mach_o::ArchHandler; using lld::mach_o::MachOFile; using lld::mach_o::MachODylibFile; using namespace llvm::MachO; namespace lld { bool MachOLinkingContext::parsePackedVersion(StringRef str, uint32_t &result) { result = 0; if (str.empty()) return false; SmallVector parts; llvm::SplitString(str, parts, "."); unsigned long long num; if (llvm::getAsUnsignedInteger(parts[0], 10, num)) return true; if (num > 65535) return true; result = num << 16; if (parts.size() > 1) { if (llvm::getAsUnsignedInteger(parts[1], 10, num)) return true; if (num > 255) return true; result |= (num << 8); } if (parts.size() > 2) { if (llvm::getAsUnsignedInteger(parts[2], 10, num)) return true; if (num > 255) return true; result |= num; } return false; } bool MachOLinkingContext::parsePackedVersion(StringRef str, uint64_t &result) { result = 0; if (str.empty()) return false; SmallVector parts; llvm::SplitString(str, parts, "."); unsigned long long num; if (llvm::getAsUnsignedInteger(parts[0], 10, num)) return true; if (num > 0xFFFFFF) return true; result = num << 40; unsigned Shift = 30; for (StringRef str : llvm::makeArrayRef(parts).slice(1)) { if (llvm::getAsUnsignedInteger(str, 10, num)) return true; if (num > 0x3FF) return true; result |= (num << Shift); Shift -= 10; } return false; } MachOLinkingContext::ArchInfo MachOLinkingContext::_s_archInfos[] = { { "x86_64", arch_x86_64, true, CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL }, { "i386", arch_x86, true, CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL }, { "ppc", arch_ppc, false, CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL }, { "armv6", arch_armv6, true, CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6 }, { "armv7", arch_armv7, true, CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7 }, { "armv7s", arch_armv7s, true, CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S }, { "arm64", arch_arm64, true, CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL }, { "", arch_unknown,false, 0, 0 } }; MachOLinkingContext::Arch MachOLinkingContext::archFromCpuType(uint32_t cputype, uint32_t cpusubtype) { for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) { if ((info->cputype == cputype) && (info->cpusubtype == cpusubtype)) return info->arch; } return arch_unknown; } MachOLinkingContext::Arch MachOLinkingContext::archFromName(StringRef archName) { for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) { if (info->archName.equals(archName)) return info->arch; } return arch_unknown; } StringRef MachOLinkingContext::nameFromArch(Arch arch) { for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) { if (info->arch == arch) return info->archName; } return ""; } uint32_t MachOLinkingContext::cpuTypeFromArch(Arch arch) { assert(arch != arch_unknown); for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) { if (info->arch == arch) return info->cputype; } llvm_unreachable("Unknown arch type"); } uint32_t MachOLinkingContext::cpuSubtypeFromArch(Arch arch) { assert(arch != arch_unknown); for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) { if (info->arch == arch) return info->cpusubtype; } llvm_unreachable("Unknown arch type"); } bool MachOLinkingContext::isThinObjectFile(StringRef path, Arch &arch) { return mach_o::normalized::isThinObjectFile(path, arch); } bool MachOLinkingContext::sliceFromFatFile(MemoryBufferRef mb, uint32_t &offset, uint32_t &size) { return mach_o::normalized::sliceFromFatFile(mb, _arch, offset, size); } MachOLinkingContext::MachOLinkingContext() {} MachOLinkingContext::~MachOLinkingContext() { // Atoms are allocated on BumpPtrAllocator's on File's. // As we transfer atoms from one file to another, we need to clear all of the // atoms before we remove any of the BumpPtrAllocator's. auto &nodes = getNodes(); for (unsigned i = 0, e = nodes.size(); i != e; ++i) { FileNode *node = dyn_cast(nodes[i].get()); if (!node) continue; File *file = node->getFile(); file->clearAtoms(); } } void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os, uint32_t minOSVersion, bool exportDynamicSymbols) { _outputMachOType = type; _arch = arch; _os = os; _osMinVersion = minOSVersion; // If min OS not specified on command line, use reasonable defaults. // Note that we only do sensible defaults when emitting something other than // object and preload. if (_outputMachOType != llvm::MachO::MH_OBJECT && _outputMachOType != llvm::MachO::MH_PRELOAD) { if (minOSVersion == 0) { switch (_arch) { case arch_x86_64: case arch_x86: parsePackedVersion("10.8", _osMinVersion); _os = MachOLinkingContext::OS::macOSX; break; case arch_armv6: case arch_armv7: case arch_armv7s: case arch_arm64: parsePackedVersion("7.0", _osMinVersion); _os = MachOLinkingContext::OS::iOS; break; default: break; } } } switch (_outputMachOType) { case llvm::MachO::MH_EXECUTE: // If targeting newer OS, use _main if (minOS("10.8", "6.0")) { _entrySymbolName = "_main"; } else { // If targeting older OS, use start (in crt1.o) _entrySymbolName = "start"; } // __PAGEZERO defaults to 4GB on 64-bit (except for PP64 which lld does not // support) and 4KB on 32-bit. if (is64Bit(_arch)) { _pageZeroSize = 0x100000000; } else { _pageZeroSize = 0x1000; } // Initial base address is __PAGEZERO size. _baseAddress = _pageZeroSize; // Make PIE by default when targetting newer OSs. switch (os) { case OS::macOSX: if (minOSVersion >= 0x000A0700) // MacOSX 10.7 _pie = true; break; case OS::iOS: if (minOSVersion >= 0x00040300) // iOS 4.3 _pie = true; break; case OS::iOS_simulator: _pie = true; break; case OS::unknown: break; } setGlobalsAreDeadStripRoots(exportDynamicSymbols); break; case llvm::MachO::MH_DYLIB: setGlobalsAreDeadStripRoots(exportDynamicSymbols); break; case llvm::MachO::MH_BUNDLE: break; case llvm::MachO::MH_OBJECT: _printRemainingUndefines = false; _allowRemainingUndefines = true; + break; default: break; } // Set default segment page sizes based on arch. if (arch == arch_arm64) _pageSize = 4*4096; } uint32_t MachOLinkingContext::getCPUType() const { return cpuTypeFromArch(_arch); } uint32_t MachOLinkingContext::getCPUSubType() const { return cpuSubtypeFromArch(_arch); } bool MachOLinkingContext::is64Bit(Arch arch) { for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) { if (info->arch == arch) { return (info->cputype & CPU_ARCH_ABI64); } } // unknown archs are not 64-bit. return false; } bool MachOLinkingContext::isHostEndian(Arch arch) { assert(arch != arch_unknown); for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) { if (info->arch == arch) { return (info->littleEndian == llvm::sys::IsLittleEndianHost); } } llvm_unreachable("Unknown arch type"); } bool MachOLinkingContext::isBigEndian(Arch arch) { assert(arch != arch_unknown); for (ArchInfo *info = _s_archInfos; !info->archName.empty(); ++info) { if (info->arch == arch) { return ! info->littleEndian; } } llvm_unreachable("Unknown arch type"); } bool MachOLinkingContext::is64Bit() const { return is64Bit(_arch); } bool MachOLinkingContext::outputTypeHasEntry() const { switch (_outputMachOType) { case MH_EXECUTE: case MH_DYLINKER: case MH_PRELOAD: return true; default: return false; } } bool MachOLinkingContext::needsStubsPass() const { switch (_outputMachOType) { case MH_EXECUTE: return !_outputMachOTypeStatic; case MH_DYLIB: case MH_BUNDLE: return true; default: return false; } } bool MachOLinkingContext::needsGOTPass() const { // GOT pass not used in -r mode. if (_outputMachOType == MH_OBJECT) return false; // Only some arches use GOT pass. switch (_arch) { case arch_x86_64: case arch_arm64: return true; default: return false; } } bool MachOLinkingContext::needsCompactUnwindPass() const { switch (_outputMachOType) { case MH_EXECUTE: case MH_DYLIB: case MH_BUNDLE: return archHandler().needsCompactUnwind(); default: return false; } } bool MachOLinkingContext::needsObjCPass() const { // ObjC pass is only needed if any of the inputs were ObjC. return _objcConstraint != objc_unknown; } bool MachOLinkingContext::needsShimPass() const { // Shim pass only used in final executables. if (_outputMachOType == MH_OBJECT) return false; // Only 32-bit arm arches use Shim pass. switch (_arch) { case arch_armv6: case arch_armv7: case arch_armv7s: return true; default: return false; } } bool MachOLinkingContext::needsTLVPass() const { switch (_outputMachOType) { case MH_BUNDLE: case MH_EXECUTE: case MH_DYLIB: return true; default: return false; } } StringRef MachOLinkingContext::binderSymbolName() const { return archHandler().stubInfo().binderSymbolName; } bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const { uint32_t parsedVersion; switch (_os) { case OS::macOSX: if (parsePackedVersion(mac, parsedVersion)) return false; return _osMinVersion >= parsedVersion; case OS::iOS: case OS::iOS_simulator: if (parsePackedVersion(iOS, parsedVersion)) return false; return _osMinVersion >= parsedVersion; case OS::unknown: // If we don't know the target, then assume that we don't meet the min OS. // This matches the ld64 behaviour return false; } llvm_unreachable("invalid OS enum"); } bool MachOLinkingContext::addEntryPointLoadCommand() const { if ((_outputMachOType == MH_EXECUTE) && !_outputMachOTypeStatic) { return minOS("10.8", "6.0"); } return false; } bool MachOLinkingContext::addUnixThreadLoadCommand() const { switch (_outputMachOType) { case MH_EXECUTE: if (_outputMachOTypeStatic) return true; else return !minOS("10.8", "6.0"); break; case MH_DYLINKER: case MH_PRELOAD: return true; default: return false; } } bool MachOLinkingContext::pathExists(StringRef path) const { if (!_testingFileUsage) return llvm::sys::fs::exists(path.str()); // Otherwise, we're in test mode: only files explicitly provided on the // command-line exist. std::string key = path.str(); std::replace(key.begin(), key.end(), '\\', '/'); return _existingPaths.find(key) != _existingPaths.end(); } bool MachOLinkingContext::fileExists(StringRef path) const { bool found = pathExists(path); // Log search misses. if (!found) addInputFileNotFound(path); // When testing, file is never opened, so logging is done here. if (_testingFileUsage && found) addInputFileDependency(path); return found; } void MachOLinkingContext::setSysLibRoots(const StringRefVector &paths) { _syslibRoots = paths; } void MachOLinkingContext::addRpath(StringRef rpath) { _rpaths.push_back(rpath); } void MachOLinkingContext::addModifiedSearchDir(StringRef libPath, bool isSystemPath) { bool addedModifiedPath = false; // -syslibroot only applies to absolute paths. if (libPath.startswith("/")) { for (auto syslibRoot : _syslibRoots) { SmallString<256> path(syslibRoot); llvm::sys::path::append(path, libPath); if (pathExists(path)) { _searchDirs.push_back(path.str().copy(_allocator)); addedModifiedPath = true; } } } if (addedModifiedPath) return; // Finally, if only one -syslibroot is given, system paths which aren't in it // get suppressed. if (_syslibRoots.size() != 1 || !isSystemPath) { if (pathExists(libPath)) { _searchDirs.push_back(libPath); } } } void MachOLinkingContext::addFrameworkSearchDir(StringRef fwPath, bool isSystemPath) { bool pathAdded = false; // -syslibroot only used with to absolute framework search paths. if (fwPath.startswith("/")) { for (auto syslibRoot : _syslibRoots) { SmallString<256> path(syslibRoot); llvm::sys::path::append(path, fwPath); if (pathExists(path)) { _frameworkDirs.push_back(path.str().copy(_allocator)); pathAdded = true; } } } // If fwPath found in any -syslibroot, then done. if (pathAdded) return; // If only one -syslibroot, system paths not in that SDK are suppressed. if (isSystemPath && (_syslibRoots.size() == 1)) return; // Only use raw fwPath if that directory exists. if (pathExists(fwPath)) _frameworkDirs.push_back(fwPath); } llvm::Optional MachOLinkingContext::searchDirForLibrary(StringRef path, StringRef libName) const { SmallString<256> fullPath; if (libName.endswith(".o")) { // A request ending in .o is special: just search for the file directly. fullPath.assign(path); llvm::sys::path::append(fullPath, libName); if (fileExists(fullPath)) return fullPath.str().copy(_allocator); return llvm::None; } // Search for dynamic library fullPath.assign(path); llvm::sys::path::append(fullPath, Twine("lib") + libName + ".dylib"); if (fileExists(fullPath)) return fullPath.str().copy(_allocator); // If not, try for a static library fullPath.assign(path); llvm::sys::path::append(fullPath, Twine("lib") + libName + ".a"); if (fileExists(fullPath)) return fullPath.str().copy(_allocator); return llvm::None; } llvm::Optional MachOLinkingContext::searchLibrary(StringRef libName) const { SmallString<256> path; for (StringRef dir : searchDirs()) { llvm::Optional searchDir = searchDirForLibrary(dir, libName); if (searchDir) return searchDir; } return llvm::None; } llvm::Optional MachOLinkingContext::findPathForFramework(StringRef fwName) const{ SmallString<256> fullPath; for (StringRef dir : frameworkDirs()) { fullPath.assign(dir); llvm::sys::path::append(fullPath, Twine(fwName) + ".framework", fwName); if (fileExists(fullPath)) return fullPath.str().copy(_allocator); } return llvm::None; } bool MachOLinkingContext::validateImpl() { // TODO: if -arch not specified, look at arch of first .o file. if (_currentVersion && _outputMachOType != MH_DYLIB) { error("-current_version can only be used with dylibs"); return false; } if (_compatibilityVersion && _outputMachOType != MH_DYLIB) { error("-compatibility_version can only be used with dylibs"); return false; } if (_deadStrippableDylib && _outputMachOType != MH_DYLIB) { error("-mark_dead_strippable_dylib can only be used with dylibs"); return false; } if (!_bundleLoader.empty() && outputMachOType() != MH_BUNDLE) { error("-bundle_loader can only be used with Mach-O bundles"); return false; } // If -exported_symbols_list used, all exported symbols must be defined. if (_exportMode == ExportMode::whiteList) { for (const auto &symbol : _exportedSymbols) addInitialUndefinedSymbol(symbol.getKey()); } // If -dead_strip, set up initial live symbols. if (deadStrip()) { // Entry point is live. if (outputTypeHasEntry()) addDeadStripRoot(entrySymbolName()); // Lazy binding helper is live. if (needsStubsPass()) addDeadStripRoot(binderSymbolName()); // If using -exported_symbols_list, make all exported symbols live. if (_exportMode == ExportMode::whiteList) { setGlobalsAreDeadStripRoots(false); for (const auto &symbol : _exportedSymbols) addDeadStripRoot(symbol.getKey()); } } addOutputFileDependency(outputPath()); return true; } void MachOLinkingContext::addPasses(PassManager &pm) { // objc pass should be before layout pass. Otherwise test cases may contain // no atoms which confuses the layout pass. if (needsObjCPass()) mach_o::addObjCPass(pm, *this); mach_o::addLayoutPass(pm, *this); if (needsStubsPass()) mach_o::addStubsPass(pm, *this); if (needsCompactUnwindPass()) mach_o::addCompactUnwindPass(pm, *this); if (needsGOTPass()) mach_o::addGOTPass(pm, *this); if (needsTLVPass()) mach_o::addTLVPass(pm, *this); if (needsShimPass()) mach_o::addShimPass(pm, *this); // Shim pass must run after stubs pass. } Writer &MachOLinkingContext::writer() const { if (!_writer) _writer = createWriterMachO(*this); return *_writer; } ErrorOr> MachOLinkingContext::getMemoryBuffer(StringRef path) { addInputFileDependency(path); ErrorOr> mbOrErr = MemoryBuffer::getFileOrSTDIN(path); if (std::error_code ec = mbOrErr.getError()) return ec; std::unique_ptr mb = std::move(mbOrErr.get()); // If buffer contains a fat file, find required arch in fat buffer // and switch buffer to point to just that required slice. uint32_t offset; uint32_t size; if (sliceFromFatFile(mb->getMemBufferRef(), offset, size)) return MemoryBuffer::getFileSlice(path, size, offset); return std::move(mb); } MachODylibFile* MachOLinkingContext::loadIndirectDylib(StringRef path) { ErrorOr> mbOrErr = getMemoryBuffer(path); if (mbOrErr.getError()) return nullptr; ErrorOr> fileOrErr = registry().loadFile(std::move(mbOrErr.get())); if (!fileOrErr) return nullptr; std::unique_ptr &file = fileOrErr.get(); file->parse(); MachODylibFile *result = reinterpret_cast(file.get()); // Node object now owned by _indirectDylibs vector. _indirectDylibs.push_back(std::move(file)); return result; } MachODylibFile* MachOLinkingContext::findIndirectDylib(StringRef path) { // See if already loaded. auto pos = _pathToDylibMap.find(path); if (pos != _pathToDylibMap.end()) return pos->second; // Search -L paths if of the form "libXXX.dylib" std::pair split = path.rsplit('/'); StringRef leafName = split.second; if (leafName.startswith("lib") && leafName.endswith(".dylib")) { // FIXME: Need to enhance searchLibrary() to only look for .dylib auto libPath = searchLibrary(leafName); if (libPath) return loadIndirectDylib(libPath.getValue()); } // Try full path with sysroot. for (StringRef sysPath : _syslibRoots) { SmallString<256> fullPath; fullPath.assign(sysPath); llvm::sys::path::append(fullPath, path); if (pathExists(fullPath)) return loadIndirectDylib(fullPath); } // Try full path. if (pathExists(path)) { return loadIndirectDylib(path); } return nullptr; } uint32_t MachOLinkingContext::dylibCurrentVersion(StringRef installName) const { auto pos = _pathToDylibMap.find(installName); if (pos != _pathToDylibMap.end()) return pos->second->currentVersion(); else return 0x10000; // 1.0 } uint32_t MachOLinkingContext::dylibCompatVersion(StringRef installName) const { auto pos = _pathToDylibMap.find(installName); if (pos != _pathToDylibMap.end()) return pos->second->compatVersion(); else return 0x10000; // 1.0 } void MachOLinkingContext::createImplicitFiles( std::vector > &result) { // Add indirect dylibs by asking each linked dylib to add its indirects. // Iterate until no more dylibs get loaded. size_t dylibCount = 0; while (dylibCount != _allDylibs.size()) { dylibCount = _allDylibs.size(); for (MachODylibFile *dylib : _allDylibs) { dylib->loadReExportedDylibs([this] (StringRef path) -> MachODylibFile* { return findIndirectDylib(path); }); } } // Let writer add output type specific extras. writer().createImplicitFiles(result); // If undefinedMode is != error, add a FlatNamespaceFile instance. This will // provide a SharedLibraryAtom for symbols that aren't defined elsewhere. if (undefinedMode() != UndefinedMode::error) { result.emplace_back(new mach_o::FlatNamespaceFile(*this)); _flatNamespaceFile = result.back().get(); } } void MachOLinkingContext::registerDylib(MachODylibFile *dylib, bool upward) const { std::lock_guard lock(_dylibsMutex); if (std::find(_allDylibs.begin(), _allDylibs.end(), dylib) == _allDylibs.end()) _allDylibs.push_back(dylib); _pathToDylibMap[dylib->installName()] = dylib; // If path is different than install name, register path too. if (!dylib->path().equals(dylib->installName())) _pathToDylibMap[dylib->path()] = dylib; if (upward) _upwardDylibs.insert(dylib); } bool MachOLinkingContext::isUpwardDylib(StringRef installName) const { for (MachODylibFile *dylib : _upwardDylibs) { if (dylib->installName().equals(installName)) return true; } return false; } ArchHandler &MachOLinkingContext::archHandler() const { if (!_archHandler) _archHandler = ArchHandler::create(_arch); return *_archHandler; } void MachOLinkingContext::addSectionAlignment(StringRef seg, StringRef sect, uint16_t align) { SectionAlign entry = { seg, sect, align }; _sectAligns.push_back(entry); } void MachOLinkingContext::addSectCreateSection( StringRef seg, StringRef sect, std::unique_ptr content) { if (!_sectCreateFile) { auto sectCreateFile = llvm::make_unique(); _sectCreateFile = sectCreateFile.get(); getNodes().push_back(llvm::make_unique(std::move(sectCreateFile))); } assert(_sectCreateFile && "sectcreate file does not exist."); _sectCreateFile->addSection(seg, sect, std::move(content)); } bool MachOLinkingContext::sectionAligned(StringRef seg, StringRef sect, uint16_t &align) const { for (const SectionAlign &entry : _sectAligns) { if (seg.equals(entry.segmentName) && sect.equals(entry.sectionName)) { align = entry.align; return true; } } return false; } void MachOLinkingContext::addExportSymbol(StringRef sym) { // Support old crufty export lists with bogus entries. if (sym.endswith(".eh") || sym.startswith(".objc_category_name_")) { llvm::errs() << "warning: ignoring " << sym << " in export list\n"; return; } // Only i386 MacOSX uses old ABI, so don't change those. if ((_os != OS::macOSX) || (_arch != arch_x86)) { // ObjC has two differnent ABIs. Be nice and allow one export list work for // both ABIs by renaming symbols. if (sym.startswith(".objc_class_name_")) { std::string abi2className("_OBJC_CLASS_$_"); abi2className += sym.substr(17); _exportedSymbols.insert(copy(abi2className)); std::string abi2metaclassName("_OBJC_METACLASS_$_"); abi2metaclassName += sym.substr(17); _exportedSymbols.insert(copy(abi2metaclassName)); return; } } // FIXME: Support wildcards. _exportedSymbols.insert(sym); } bool MachOLinkingContext::exportSymbolNamed(StringRef sym) const { switch (_exportMode) { case ExportMode::globals: llvm_unreachable("exportSymbolNamed() should not be called in this mode"); break; case ExportMode::whiteList: return _exportedSymbols.count(sym); case ExportMode::blackList: return !_exportedSymbols.count(sym); } llvm_unreachable("_exportMode unknown enum value"); } std::string MachOLinkingContext::demangle(StringRef symbolName) const { // Only try to demangle symbols if -demangle on command line if (!demangleSymbols()) return symbolName; // Only try to demangle symbols that look like C++ symbols if (!symbolName.startswith("__Z")) return symbolName; SmallString<256> symBuff; StringRef nullTermSym = Twine(symbolName).toNullTerminatedStringRef(symBuff); // Mach-O has extra leading underscore that needs to be removed. const char *cstr = nullTermSym.data() + 1; int status; char *demangled = llvm::itaniumDemangle(cstr, nullptr, nullptr, &status); if (demangled) { std::string result(demangled); // __cxa_demangle() always uses a malloc'ed buffer to return the result. free(demangled); return result; } return symbolName; } static void addDependencyInfoHelper(llvm::raw_fd_ostream *DepInfo, char Opcode, StringRef Path) { if (!DepInfo) return; *DepInfo << Opcode; *DepInfo << Path; *DepInfo << '\0'; } std::error_code MachOLinkingContext::createDependencyFile(StringRef path) { std::error_code ec; _dependencyInfo = std::unique_ptr(new llvm::raw_fd_ostream(path, ec, llvm::sys::fs::F_None)); if (ec) { _dependencyInfo.reset(); return ec; } addDependencyInfoHelper(_dependencyInfo.get(), 0x00, "lld" /*FIXME*/); return std::error_code(); } void MachOLinkingContext::addInputFileDependency(StringRef path) const { addDependencyInfoHelper(_dependencyInfo.get(), 0x10, path); } void MachOLinkingContext::addInputFileNotFound(StringRef path) const { addDependencyInfoHelper(_dependencyInfo.get(), 0x11, path); } void MachOLinkingContext::addOutputFileDependency(StringRef path) const { addDependencyInfoHelper(_dependencyInfo.get(), 0x40, path); } void MachOLinkingContext::appendOrderedSymbol(StringRef symbol, StringRef filename) { // To support sorting static functions which may have the same name in // multiple .o files, _orderFiles maps the symbol name to a vector // of OrderFileNode each of which can specify a file prefix. OrderFileNode info; if (!filename.empty()) info.fileFilter = copy(filename); info.order = _orderFileEntries++; _orderFiles[symbol].push_back(info); } bool MachOLinkingContext::findOrderOrdinal(const std::vector &nodes, const DefinedAtom *atom, unsigned &ordinal) { const File *objFile = &atom->file(); assert(objFile); StringRef objName = objFile->path(); std::pair dirAndLeaf = objName.rsplit('/'); if (!dirAndLeaf.second.empty()) objName = dirAndLeaf.second; for (const OrderFileNode &info : nodes) { if (info.fileFilter.empty()) { // Have unprefixed symbol name in order file that matches this atom. ordinal = info.order; return true; } if (info.fileFilter.equals(objName)) { // Have prefixed symbol name in order file that matches atom's path. ordinal = info.order; return true; } } return false; } bool MachOLinkingContext::customAtomOrderer(const DefinedAtom *left, const DefinedAtom *right, bool &leftBeforeRight) const { // No custom sorting if no order file entries. if (!_orderFileEntries) return false; // Order files can only order named atoms. StringRef leftName = left->name(); StringRef rightName = right->name(); if (leftName.empty() || rightName.empty()) return false; // If neither is in order file list, no custom sorter. auto leftPos = _orderFiles.find(leftName); auto rightPos = _orderFiles.find(rightName); bool leftIsOrdered = (leftPos != _orderFiles.end()); bool rightIsOrdered = (rightPos != _orderFiles.end()); if (!leftIsOrdered && !rightIsOrdered) return false; // There could be multiple symbols with same name but different file prefixes. unsigned leftOrder; unsigned rightOrder; bool foundLeft = leftIsOrdered && findOrderOrdinal(leftPos->getValue(), left, leftOrder); bool foundRight = rightIsOrdered && findOrderOrdinal(rightPos->getValue(), right, rightOrder); if (!foundLeft && !foundRight) return false; // If only one is in order file list, ordered one goes first. if (foundLeft != foundRight) leftBeforeRight = foundLeft; else leftBeforeRight = (leftOrder < rightOrder); return true; } static bool isLibrary(const std::unique_ptr &elem) { if (FileNode *node = dyn_cast(const_cast(elem.get()))) { File *file = node->getFile(); return isa(file) || isa(file); } return false; } // The darwin linker processes input files in two phases. The first phase // links in all object (.o) files in command line order. The second phase // links in libraries in command line order. // In this function we reorder the input files so that all the object files // comes before any library file. We also make a group for the library files // so that the Resolver will reiterate over the libraries as long as we find // new undefines from libraries. void MachOLinkingContext::finalizeInputFiles() { std::vector> &elements = getNodes(); std::stable_sort(elements.begin(), elements.end(), [](const std::unique_ptr &a, const std::unique_ptr &b) { return !isLibrary(a) && isLibrary(b); }); size_t numLibs = std::count_if(elements.begin(), elements.end(), isLibrary); elements.push_back(llvm::make_unique(numLibs)); } llvm::Error MachOLinkingContext::handleLoadedFile(File &file) { auto *machoFile = dyn_cast(&file); if (!machoFile) return llvm::Error::success(); // Check that the arch of the context matches that of the file. // Also set the arch of the context if it didn't have one. if (_arch == arch_unknown) { _arch = machoFile->arch(); } else if (machoFile->arch() != arch_unknown && machoFile->arch() != _arch) { // Archs are different. return llvm::make_error(file.path() + Twine(" cannot be linked due to incompatible architecture")); } // Check that the OS of the context matches that of the file. // Also set the OS of the context if it didn't have one. if (_os == OS::unknown) { _os = machoFile->OS(); } else if (machoFile->OS() != OS::unknown && machoFile->OS() != _os) { // OSes are different. return llvm::make_error(file.path() + Twine(" cannot be linked due to incompatible operating systems")); } // Check that if the objc info exists, that it is compatible with the target // OS. switch (machoFile->objcConstraint()) { case objc_unknown: // The file is not compiled with objc, so skip the checks. break; case objc_gc_only: case objc_supports_gc: llvm_unreachable("GC support should already have thrown an error"); case objc_retainReleaseForSimulator: // The file is built with simulator objc, so make sure that the context // is also building with simulator support. if (_os != OS::iOS_simulator) return llvm::make_error(file.path() + Twine(" cannot be linked. It contains ObjC built for the simulator" " while we are linking a non-simulator target")); assert((_objcConstraint == objc_unknown || _objcConstraint == objc_retainReleaseForSimulator) && "Must be linking with retain/release for the simulator"); _objcConstraint = objc_retainReleaseForSimulator; break; case objc_retainRelease: // The file is built without simulator objc, so make sure that the // context is also building without simulator support. if (_os == OS::iOS_simulator) return llvm::make_error(file.path() + Twine(" cannot be linked. It contains ObjC built for a non-simulator" " target while we are linking a simulator target")); assert((_objcConstraint == objc_unknown || _objcConstraint == objc_retainRelease) && "Must be linking with retain/release for a non-simulator target"); _objcConstraint = objc_retainRelease; break; } // Check that the swift version of the context matches that of the file. // Also set the swift version of the context if it didn't have one. if (!_swiftVersion) { _swiftVersion = machoFile->swiftVersion(); } else if (machoFile->swiftVersion() && machoFile->swiftVersion() != _swiftVersion) { // Swift versions are different. return llvm::make_error("different swift versions"); } return llvm::Error::success(); } } // end namespace lld Index: projects/clang800-import/contrib/llvm/tools/lld/tools/lld/lld.cpp =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld/tools/lld/lld.cpp (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld/tools/lld/lld.cpp (revision 343217) @@ -1,148 +1,148 @@ //===- tools/lld/lld.cpp - Linker Driver Dispatcher -----------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains the main function of the lld executable. The main // function is a thin wrapper which dispatches to the platform specific // driver. // // lld is a single executable that contains four different linkers for ELF, // COFF, WebAssembly and Mach-O. The main function dispatches according to // argv[0] (i.e. command name). The most common name for each target is shown // below: // // - ld.lld: ELF (Unix) // - ld64: Mach-O (macOS) // - lld-link: COFF (Windows) // - ld-wasm: WebAssembly // // lld can be invoked as "lld" along with "-flavor" option. This is for // backward compatibility and not recommended. // //===----------------------------------------------------------------------===// #include "lld/Common/Driver.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/Path.h" #include using namespace lld; using namespace llvm; using namespace llvm::sys; enum Flavor { Invalid, Gnu, // -flavor gnu WinLink, // -flavor link Darwin, // -flavor darwin Wasm, // -flavor wasm }; LLVM_ATTRIBUTE_NORETURN static void die(const Twine &S) { errs() << S << "\n"; exit(1); } static Flavor getFlavor(StringRef S) { return StringSwitch(S) .CasesLower("ld", "ld.lld", "gnu", Gnu) .CasesLower("wasm", "ld-wasm", Wasm) .CaseLower("link", WinLink) .CasesLower("ld64", "ld64.lld", "darwin", Darwin) .Default(Invalid); } static bool isPETarget(const std::vector &V) { for (auto It = V.begin(); It + 1 != V.end(); ++It) { if (StringRef(*It) != "-m") continue; StringRef S = *(It + 1); return S == "i386pe" || S == "i386pep" || S == "thumb2pe" || S == "arm64pe"; } return false; } static Flavor parseProgname(StringRef Progname) { #if __APPLE__ // Use Darwin driver for "ld" on Darwin. if (Progname == "ld") return Darwin; #endif #if LLVM_ON_UNIX // Use GNU driver for "ld" on other Unix-like system. if (Progname == "ld") return Gnu; #endif // Progname may be something like "lld-gnu". Parse it. SmallVector V; Progname.split(V, "-"); for (StringRef S : V) if (Flavor F = getFlavor(S)) return F; return Invalid; } static Flavor parseFlavor(std::vector &V) { // Parse -flavor option. if (V.size() > 1 && V[1] == StringRef("-flavor")) { if (V.size() <= 2) die("missing arg value for '-flavor'"); Flavor F = getFlavor(V[2]); if (F == Invalid) die("Unknown flavor: " + StringRef(V[2])); V.erase(V.begin() + 1, V.begin() + 3); return F; } // Deduct the flavor from argv[0]. StringRef Arg0 = path::filename(V[0]); if (Arg0.endswith_lower(".exe")) Arg0 = Arg0.drop_back(4); return parseProgname(Arg0); } // If this function returns true, lld calls _exit() so that it quickly // exits without invoking destructors of globally allocated objects. // // We don't want to do that if we are running tests though, because // doing that breaks leak sanitizer. So, lit sets this environment variable, // and we use it to detect whether we are running tests or not. static bool canExitEarly() { return StringRef(getenv("LLD_IN_TEST")) != "1"; } /// Universal linker main(). This linker emulates the gnu, darwin, or /// windows linker based on the argv[0] or -flavor option. int main(int Argc, const char **Argv) { InitLLVM X(Argc, Argv); std::vector Args(Argv, Argv + Argc); #ifdef __FreeBSD__ return !elf::link(Args, true); #else switch (parseFlavor(Args)) { case Gnu: if (isPETarget(Args)) return !mingw::link(Args); return !elf::link(Args, canExitEarly()); case WinLink: return !coff::link(Args, canExitEarly()); case Darwin: return !mach_o::link(Args, canExitEarly()); case Wasm: return !wasm::link(Args, canExitEarly()); default: die("lld is a generic driver.\n" - "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-lld" + "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld" " (WebAssembly) instead"); } #endif } Index: projects/clang800-import/contrib/llvm/tools/lld =================================================================== --- projects/clang800-import/contrib/llvm/tools/lld (revision 343216) +++ projects/clang800-import/contrib/llvm/tools/lld (revision 343217) Property changes on: projects/clang800-import/contrib/llvm/tools/lld ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /vendor/lld/dist:r337311-343214