Index: vendor/lld/dist/COFF/Chunks.cpp =================================================================== --- vendor/lld/dist/COFF/Chunks.cpp (revision 320381) +++ vendor/lld/dist/COFF/Chunks.cpp (revision 320382) @@ -1,391 +1,410 @@ //===- Chunks.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Chunks.h" #include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "llvm/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(ObjectFile *F, const coff_section *H) : Chunk(SectionKind), Repl(this), Header(H), File(F), Relocs(File->getCOFFObj()->getRelocations(Header)), NumRelocs(std::distance(Relocs.begin(), Relocs.end())) { // Initialize SectionName. File->getCOFFObj()->getSectionName(Header, SectionName); Align = Header->getAlignment(); - // Only COMDAT sections are subject of dead-stripping. - Live = !isCOMDAT(); + // Chunks may be discarded during comdat merging. + Discarded = false; + + // If linker GC is disabled, every chunk starts out alive. If linker GC is + // enabled, treat non-comdat sections as roots. Generally optimized object + // files will be built with -ffunction-sections or /Gy, so most things worth + // stripping will be in a comdat. + Live = !Config->DoGC || !isCOMDAT(); } static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); } static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); } static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); } static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); } +static void applySecRel(const SectionChunk *Sec, uint8_t *Off, Defined *Sym) { + // Don't apply section relative relocations to absolute symbols in codeview + // debug info sections. MSVC does not treat such relocations as fatal errors, + // and they can be found in the standard library for linker-provided symbols + // like __guard_fids_table and __safe_se_handler_table. + if (!(isa(Sym) && Sec->isCodeView())) + add32(Off, Sym->getSecrel()); +} + void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const { uint64_t S = Sym->getRVA(); switch (Type) { case IMAGE_REL_AMD64_ADDR32: add32(Off, S + Config->ImageBase); break; case IMAGE_REL_AMD64_ADDR64: add64(Off, S + Config->ImageBase); break; case IMAGE_REL_AMD64_ADDR32NB: add32(Off, S); break; case IMAGE_REL_AMD64_REL32: add32(Off, S - P - 4); break; case IMAGE_REL_AMD64_REL32_1: add32(Off, S - P - 5); break; case IMAGE_REL_AMD64_REL32_2: add32(Off, S - P - 6); break; case IMAGE_REL_AMD64_REL32_3: add32(Off, S - P - 7); break; case IMAGE_REL_AMD64_REL32_4: add32(Off, S - P - 8); break; case IMAGE_REL_AMD64_REL32_5: add32(Off, S - P - 9); break; case IMAGE_REL_AMD64_SECTION: add16(Off, Sym->getSectionIndex()); break; - case IMAGE_REL_AMD64_SECREL: add32(Off, Sym->getSecrel()); break; + case IMAGE_REL_AMD64_SECREL: applySecRel(this, Off, Sym); break; default: fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); } } void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const { uint64_t S = Sym->getRVA(); switch (Type) { case IMAGE_REL_I386_ABSOLUTE: break; case IMAGE_REL_I386_DIR32: add32(Off, S + Config->ImageBase); break; case IMAGE_REL_I386_DIR32NB: add32(Off, S); break; case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break; case IMAGE_REL_I386_SECTION: add16(Off, Sym->getSectionIndex()); break; - case IMAGE_REL_I386_SECREL: add32(Off, Sym->getSecrel()); break; + case IMAGE_REL_I386_SECREL: applySecRel(this, Off, Sym); break; default: fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); } } static void applyMOV(uint8_t *Off, uint16_t V) { write16le(Off, (read16le(Off) & 0xfbf0) | ((V & 0x800) >> 1) | ((V >> 12) & 0xf)); write16le(Off + 2, (read16le(Off + 2) & 0x8f00) | ((V & 0x700) << 4) | (V & 0xff)); } static uint16_t readMOV(uint8_t *Off) { uint16_t Opcode1 = read16le(Off); uint16_t Opcode2 = read16le(Off + 2); uint16_t Imm = (Opcode2 & 0x00ff) | ((Opcode2 >> 4) & 0x0700); Imm |= ((Opcode1 << 1) & 0x0800) | ((Opcode1 & 0x000f) << 12); return Imm; } static void applyMOV32T(uint8_t *Off, uint32_t V) { uint16_t ImmW = readMOV(Off); // read MOVW operand uint16_t ImmT = readMOV(Off + 4); // read MOVT operand uint32_t Imm = ImmW | (ImmT << 16); V += Imm; // add the immediate offset applyMOV(Off, V); // set MOVW operand applyMOV(Off + 4, V >> 16); // set MOVT operand } static void applyBranch20T(uint8_t *Off, int32_t V) { uint32_t S = V < 0 ? 1 : 0; uint32_t J1 = (V >> 19) & 1; uint32_t J2 = (V >> 18) & 1; or16(Off, (S << 10) | ((V >> 12) & 0x3f)); or16(Off + 2, (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); } static void applyBranch24T(uint8_t *Off, int32_t V) { if (!isInt<25>(V)) fatal("relocation out of range"); uint32_t S = V < 0 ? 1 : 0; uint32_t J1 = ((~V >> 23) & 1) ^ S; uint32_t J2 = ((~V >> 22) & 1) ^ S; or16(Off, (S << 10) | ((V >> 12) & 0x3ff)); // Clear out the J1 and J2 bits which may be set. write16le(Off + 2, (read16le(Off + 2) & 0xd000) | (J1 << 13) | (J2 << 11) | ((V >> 1) & 0x7ff)); } void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const { uint64_t S = Sym->getRVA(); // Pointer to thumb code must have the LSB set. if (Sym->isExecutable()) S |= 1; switch (Type) { case IMAGE_REL_ARM_ADDR32: add32(Off, S + Config->ImageBase); break; case IMAGE_REL_ARM_ADDR32NB: add32(Off, S); break; case IMAGE_REL_ARM_MOV32T: applyMOV32T(Off, S + Config->ImageBase); break; case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, S - P - 4); break; case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, S - P - 4); break; case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, S - P - 4); break; - case IMAGE_REL_ARM_SECREL: add32(Off, Sym->getSecrel()); break; + case IMAGE_REL_ARM_SECREL: applySecRel(this, Off, Sym); break; default: fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); } } void SectionChunk::writeTo(uint8_t *Buf) const { if (!hasData()) return; // Copy section contents from source object file to output file. ArrayRef A = getContents(); memcpy(Buf + OutputSectionOff, A.data(), A.size()); // Apply relocations. for (const coff_relocation &Rel : Relocs) { uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress; SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex); Defined *Sym = cast(Body); uint64_t P = RVA + Rel.VirtualAddress; switch (Config->Machine) { case AMD64: applyRelX64(Off, Rel.Type, Sym, P); break; case I386: applyRelX86(Off, Rel.Type, Sym, P); break; case ARMNT: applyRelARM(Off, Rel.Type, Sym, P); break; default: llvm_unreachable("unknown machine type"); } } } void SectionChunk::addAssociative(SectionChunk *Child) { AssocChildren.push_back(Child); } static uint8_t getBaserelType(const coff_relocation &Rel) { switch (Config->Machine) { case AMD64: if (Rel.Type == IMAGE_REL_AMD64_ADDR64) return IMAGE_REL_BASED_DIR64; return IMAGE_REL_BASED_ABSOLUTE; case I386: if (Rel.Type == IMAGE_REL_I386_DIR32) return IMAGE_REL_BASED_HIGHLOW; return IMAGE_REL_BASED_ABSOLUTE; case ARMNT: if (Rel.Type == IMAGE_REL_ARM_ADDR32) return IMAGE_REL_BASED_HIGHLOW; if (Rel.Type == IMAGE_REL_ARM_MOV32T) return IMAGE_REL_BASED_ARM_MOV32T; return IMAGE_REL_BASED_ABSOLUTE; default: llvm_unreachable("unknown machine type"); } } // Windows-specific. // Collect all locations that contain absolute addresses, which need to be // fixed by the loader if load-time relocation is needed. // Only called when base relocation is enabled. void SectionChunk::getBaserels(std::vector *Res) { for (const coff_relocation &Rel : Relocs) { uint8_t Ty = getBaserelType(Rel); if (Ty == IMAGE_REL_BASED_ABSOLUTE) continue; SymbolBody *Body = File->getSymbolBody(Rel.SymbolTableIndex); if (isa(Body)) continue; Res->emplace_back(RVA + Rel.VirtualAddress, Ty); } } bool SectionChunk::hasData() const { return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA); } uint32_t SectionChunk::getPermissions() const { return Header->Characteristics & PermMask; } bool SectionChunk::isCOMDAT() const { return Header->Characteristics & IMAGE_SCN_LNK_COMDAT; } void SectionChunk::printDiscardedMessage() const { // Removed by dead-stripping. If it's removed by ICF, ICF already // printed out the name, so don't repeat that here. - if (Sym && this == Repl) - message("Discarded " + Sym->getName()); + if (Sym && this == Repl) { + if (Discarded) + message("Discarded comdat symbol " + Sym->getName()); + else if (!Live) + 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) { Other->Repl = Repl; Other->Live = false; } CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) { // Common symbols are aligned on natural boundaries up to 32 bytes. // This is what MSVC link.exe does. Align = std::min(uint64_t(32), PowerOf2Ceil(Sym.getValue())); } uint32_t CommonChunk::getPermissions() const { return IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; } void StringChunk::writeTo(uint8_t *Buf) const { memcpy(Buf + OutputSectionOff, Str.data(), Str.size()); } ImportThunkChunkX64::ImportThunkChunkX64(Defined *S) : ImpSymbol(S) { // Intel Optimization Manual says that all branch targets // should be 16-byte aligned. MSVC linker does this too. Align = 16; } void ImportThunkChunkX64::writeTo(uint8_t *Buf) const { memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86)); // The first two bytes is a JMP instruction. Fill its operand. write32le(Buf + OutputSectionOff + 2, ImpSymbol->getRVA() - RVA - getSize()); } void ImportThunkChunkX86::getBaserels(std::vector *Res) { Res->emplace_back(getRVA() + 2); } void ImportThunkChunkX86::writeTo(uint8_t *Buf) const { memcpy(Buf + OutputSectionOff, ImportThunkX86, sizeof(ImportThunkX86)); // The first two bytes is a JMP instruction. Fill its operand. write32le(Buf + OutputSectionOff + 2, ImpSymbol->getRVA() + Config->ImageBase); } void ImportThunkChunkARM::getBaserels(std::vector *Res) { Res->emplace_back(getRVA(), IMAGE_REL_BASED_ARM_MOV32T); } void ImportThunkChunkARM::writeTo(uint8_t *Buf) const { memcpy(Buf + OutputSectionOff, ImportThunkARM, sizeof(ImportThunkARM)); // Fix mov.w and mov.t operands. applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase); } void LocalImportChunk::getBaserels(std::vector *Res) { Res->emplace_back(getRVA()); } size_t LocalImportChunk::getSize() const { return Config->is64() ? 8 : 4; } void LocalImportChunk::writeTo(uint8_t *Buf) const { if (Config->is64()) { write64le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); } else { write32le(Buf + OutputSectionOff, Sym->getRVA() + Config->ImageBase); } } void SEHTableChunk::writeTo(uint8_t *Buf) const { ulittle32_t *Begin = reinterpret_cast(Buf + OutputSectionOff); size_t Cnt = 0; for (Defined *D : Syms) Begin[Cnt++] = D->getRVA(); std::sort(Begin, Begin + Cnt); } // Windows-specific. This class represents a block in .reloc section. // 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: return IMAGE_REL_BASED_DIR64; case I386: return IMAGE_REL_BASED_HIGHLOW; default: llvm_unreachable("unknown machine type"); } } } // namespace coff } // namespace lld Index: vendor/lld/dist/COFF/Chunks.h =================================================================== --- vendor/lld/dist/COFF/Chunks.h (revision 320381) +++ vendor/lld/dist/COFF/Chunks.h (revision 320382) @@ -1,331 +1,351 @@ //===- Chunks.h -------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_COFF_CHUNKS_H #define LLD_COFF_CHUNKS_H #include "Config.h" #include "InputFiles.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Object/COFF.h" #include #include namespace lld { namespace coff { using llvm::COFF::ImportDirectoryTableEntry; using llvm::object::COFFSymbolRef; using llvm::object::SectionRef; using llvm::object::coff_relocation; using llvm::object::coff_section; class Baserel; class Defined; class DefinedImportData; class DefinedRegular; class ObjectFile; class OutputSection; class SymbolBody; // Mask for section types (code, data, bss, disacardable, etc.) // and permissions (writable, readable or executable). const uint32_t PermMask = 0xFF0000F0; // A Chunk represents a chunk of data that will occupy space in the // output (if the resolver chose that). It may or may not be backed by // a section of an input file. It could be linker-created data, or // doesn't even have actual data (if common or bss). class Chunk { public: enum Kind { SectionKind, OtherKind }; Kind kind() const { return ChunkKind; } virtual ~Chunk() = default; // Returns the size of this chunk (even if this is a common or BSS.) virtual size_t getSize() const = 0; // Write this chunk to a mmap'ed file, assuming Buf is pointing to // beginning of the file. Because this function may use RVA values // of other chunks for relocations, you need to set them properly // before calling this function. virtual void writeTo(uint8_t *Buf) const {} // The writer sets and uses the addresses. uint64_t getRVA() const { return RVA; } uint32_t getAlign() const { return Align; } void setRVA(uint64_t V) { RVA = V; } - void setOutputSectionOff(uint64_t V) { OutputSectionOff = V; } // Returns true if this has non-zero data. BSS chunks return // false. If false is returned, the space occupied by this chunk // will be filled with zeros. virtual bool hasData() const { return true; } // Returns readable/writable/executable bits. virtual uint32_t getPermissions() const { return 0; } // Returns the section name if this is a section chunk. // It is illegal to call this function on non-section chunks. virtual StringRef getSectionName() const { llvm_unreachable("unimplemented getSectionName"); } // An output section has pointers to chunks in the section, and each // chunk has a back pointer to an output section. void setOutputSection(OutputSection *O) { Out = O; } OutputSection *getOutputSection() { return Out; } // Windows-specific. // Collect all locations that contain absolute addresses for base relocations. virtual void getBaserels(std::vector *Res) {} // Returns a human-readable name of this chunk. Chunks are unnamed chunks of // bytes, so this is used only for logging or debugging. virtual StringRef getDebugName() { return ""; } protected: Chunk(Kind K = OtherKind) : ChunkKind(K) {} const Kind ChunkKind; + // The alignment of this chunk. The writer uses the value. + uint32_t Align = 1; + // The RVA of this chunk in the output. The writer sets a value. uint64_t RVA = 0; +public: // The offset from beginning of the output section. The writer sets a value. uint64_t OutputSectionOff = 0; +protected: // The output section for this chunk. OutputSection *Out = nullptr; - - // The alignment of this chunk. The writer uses the value. - uint32_t Align = 1; }; // A chunk corresponding a section of an input file. class SectionChunk : public Chunk { // Identical COMDAT Folding feature accesses section internal data. friend class ICF; public: class symbol_iterator : public llvm::iterator_adaptor_base< symbol_iterator, const coff_relocation *, std::random_access_iterator_tag, SymbolBody *> { friend SectionChunk; ObjectFile *File; symbol_iterator(ObjectFile *File, const coff_relocation *I) : symbol_iterator::iterator_adaptor_base(I), File(File) {} public: symbol_iterator() = default; SymbolBody *operator*() const { return File->getSymbolBody(I->SymbolTableIndex); } }; SectionChunk(ObjectFile *File, const coff_section *Header); static bool classof(const Chunk *C) { return C->kind() == SectionKind; } size_t getSize() const override { return Header->SizeOfRawData; } ArrayRef getContents() const; void writeTo(uint8_t *Buf) const override; bool hasData() const override; uint32_t getPermissions() const override; StringRef getSectionName() const override { return SectionName; } void getBaserels(std::vector *Res) override; bool isCOMDAT() const; void applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const; void applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const; void applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const; // Called if the garbage collector decides to not include this chunk // in a final output. It's supposed to print out a log message to stdout. void printDiscardedMessage() const; // Adds COMDAT associative sections to this COMDAT section. A chunk // and its children are treated as a group by the garbage collector. void addAssociative(SectionChunk *Child); StringRef getDebugName() override; void setSymbol(DefinedRegular *S) { if (!Sym) Sym = S; } + // Returns true if the chunk was not dropped by GC or COMDAT deduplication. + bool isLive() { return Live && !Discarded; } + // Used by the garbage collector. - bool isLive() { return !Config->DoGC || Live; } void markLive() { + assert(Config->DoGC && "should only mark things live from GC"); assert(!isLive() && "Cannot mark an already live section!"); Live = true; } + // Returns true if this chunk was dropped by COMDAT deduplication. + bool isDiscarded() const { return Discarded; } + + // Used by the SymbolTable when discarding unused comdat sections. This is + // redundant when GC is enabled, as all comdat sections will start out dead. + void markDiscarded() { Discarded = 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$"); + } + // Allow iteration over the bodies of this chunk's relocated symbols. llvm::iterator_range symbols() const { return llvm::make_range(symbol_iterator(File, Relocs.begin()), symbol_iterator(File, Relocs.end())); } // Allow iteration over the associated child chunks for this section. ArrayRef children() const { return AssocChildren; } // A pointer pointing to a replacement for this chunk. // Initially it points to "this" object. If this chunk is merged // with other chunk by ICF, it points to another chunk, // and this chunk is considrered as dead. SectionChunk *Repl; // The CRC of the contents as described in the COFF spec 4.5.5. // Auxiliary Format 5: Section Definitions. Used for ICF. uint32_t Checksum = 0; const coff_section *Header; // The file that this chunk was created from. ObjectFile *File; private: StringRef SectionName; std::vector AssocChildren; llvm::iterator_range Relocs; size_t NumRelocs; + + // True if this chunk was discarded because it was a duplicate comdat section. + bool Discarded; // Used by the garbage collector. bool Live; // Used for ICF (Identical COMDAT Folding) void replace(SectionChunk *Other); uint32_t Class[2] = {0, 0}; // Sym points to a section symbol if this is a COMDAT chunk. DefinedRegular *Sym = nullptr; }; // A chunk for common symbols. Common chunks don't have actual data. class CommonChunk : public Chunk { public: CommonChunk(const COFFSymbolRef Sym); size_t getSize() const override { return Sym.getValue(); } bool hasData() const override { return false; } uint32_t getPermissions() const override; StringRef getSectionName() const override { return ".bss"; } private: const COFFSymbolRef Sym; }; // A chunk for linker-created strings. class StringChunk : public Chunk { public: explicit StringChunk(StringRef S) : Str(S) {} size_t getSize() const override { return Str.size() + 1; } void writeTo(uint8_t *Buf) const override; private: StringRef Str; }; static const uint8_t ImportThunkX86[] = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // JMP *0x0 }; static const uint8_t ImportThunkARM[] = { 0x40, 0xf2, 0x00, 0x0c, // mov.w ip, #0 0xc0, 0xf2, 0x00, 0x0c, // mov.t ip, #0 0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip] }; // Windows-specific. // A chunk for DLL import jump table entry. In a final output, it's // contents will be a JMP instruction to some __imp_ symbol. class ImportThunkChunkX64 : public Chunk { public: explicit ImportThunkChunkX64(Defined *S); size_t getSize() const override { return sizeof(ImportThunkX86); } void writeTo(uint8_t *Buf) const override; private: Defined *ImpSymbol; }; class ImportThunkChunkX86 : public Chunk { public: explicit ImportThunkChunkX86(Defined *S) : ImpSymbol(S) {} size_t getSize() const override { return sizeof(ImportThunkX86); } void getBaserels(std::vector *Res) override; void writeTo(uint8_t *Buf) const override; private: Defined *ImpSymbol; }; class ImportThunkChunkARM : public Chunk { public: explicit ImportThunkChunkARM(Defined *S) : ImpSymbol(S) {} size_t getSize() const override { return sizeof(ImportThunkARM); } void getBaserels(std::vector *Res) override; void writeTo(uint8_t *Buf) const override; private: Defined *ImpSymbol; }; // Windows-specific. // See comments for DefinedLocalImport class. class LocalImportChunk : public Chunk { public: explicit LocalImportChunk(Defined *S) : Sym(S) {} size_t getSize() const override; void getBaserels(std::vector *Res) override; void writeTo(uint8_t *Buf) const override; private: Defined *Sym; }; // Windows-specific. // A chunk for SEH table which contains RVAs of safe exception handler // functions. x86-only. class SEHTableChunk : public Chunk { public: explicit SEHTableChunk(std::set S) : Syms(std::move(S)) {} size_t getSize() const override { return Syms.size() * 4; } void writeTo(uint8_t *Buf) const override; private: std::set Syms; }; // Windows-specific. // This class represents a block in .reloc section. // See the PE/COFF spec 5.6 for details. class BaserelChunk : public Chunk { public: BaserelChunk(uint32_t Page, Baserel *Begin, Baserel *End); size_t getSize() const override { return Data.size(); } void writeTo(uint8_t *Buf) const override; private: std::vector Data; }; class Baserel { public: Baserel(uint32_t V, uint8_t Ty) : RVA(V), Type(Ty) {} explicit Baserel(uint32_t V) : Baserel(V, getDefaultType()) {} uint8_t getDefaultType(); uint32_t RVA; uint8_t Type; }; } // namespace coff } // namespace lld #endif Index: vendor/lld/dist/COFF/Config.h =================================================================== --- vendor/lld/dist/COFF/Config.h (revision 320381) +++ vendor/lld/dist/COFF/Config.h (revision 320382) @@ -1,174 +1,171 @@ //===- Config.h -------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_COFF_CONFIG_H #define LLD_COFF_CONFIG_H #include "llvm/ADT/StringRef.h" #include "llvm/Object/COFF.h" #include #include #include #include namespace lld { namespace coff { using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN; using llvm::COFF::WindowsSubsystem; using llvm::StringRef; class DefinedAbsolute; class DefinedRelative; class StringChunk; struct Symbol; class SymbolBody; // Short aliases. static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64; static const auto ARMNT = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT; static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386; // Represents an /export option. struct Export { StringRef Name; // N in /export:N or /export:E=N StringRef ExtName; // E in /export:E=N SymbolBody *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 }; // Global configuration. struct Configuration { enum ManifestKind { SideBySide, Embed, No }; bool is64() { return Machine == AMD64; } llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN; bool Verbose = false; WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN; SymbolBody *Entry = nullptr; bool NoEntry = false; std::string OutputFile; bool ColorDiagnostics; bool DoGC = true; bool DoICF = true; uint64_t ErrorLimit = 20; bool Relocatable = true; bool Force = false; bool Debug = false; bool WriteSymtab = true; unsigned DebugTypes = static_cast(DebugType::None); llvm::SmallString<128> PDBPath; // Symbols in this set are considered as live by the garbage collector. std::set GCRoot; std::set NoDefaultLibs; bool NoDefaultLibAll = false; // True if we are creating a DLL. bool DLL = false; StringRef Implib; std::vector Exports; std::set DelayLoads; std::map DLLOrder; SymbolBody *DelayLoadHelper = nullptr; bool SaveTemps = false; // Used for SafeSEH. Symbol *SEHTable = nullptr; Symbol *SEHCount = nullptr; // Used for /opt:lldlto=N unsigned LTOOptLevel = 2; // Used for /opt:lldltojobs=N unsigned LTOJobs = 0; // Used for /opt:lldltopartitions=N unsigned LTOPartitions = 1; // 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 = SideBySide; int ManifestID = 1; StringRef ManifestDependency; bool ManifestUAC = true; std::vector ManifestInput; StringRef ManifestLevel = "'asInvoker'"; StringRef ManifestUIAccess = "'false'"; StringRef ManifestFile; // Used for /failifmismatch. std::map MustMatch; // Used for /alternatename. std::map AlternateNames; // Used for /lldmap. std::string MapFile; uint64_t ImageBase = -1; uint64_t StackReserve = 1024 * 1024; uint64_t StackCommit = 4096; uint64_t HeapReserve = 1024 * 1024; uint64_t HeapCommit = 4096; uint32_t MajorImageVersion = 0; uint32_t MinorImageVersion = 0; uint32_t MajorOSVersion = 6; uint32_t MinorOSVersion = 0; bool DynamicBase = true; bool NxCompat = true; bool AllowIsolation = true; bool TerminalServerAware = true; bool LargeAddressAware = false; bool HighEntropyVA = false; bool AppContainer = false; - - // This is for debugging. - bool DumpPdb = false; }; extern Configuration *Config; } // namespace coff } // namespace lld #endif Index: vendor/lld/dist/COFF/Driver.cpp =================================================================== --- vendor/lld/dist/COFF/Driver.cpp (revision 320381) +++ vendor/lld/dist/COFF/Driver.cpp (revision 320382) @@ -1,1141 +1,1144 @@ //===- Driver.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Driver.h" #include "Config.h" #include "Error.h" #include "InputFiles.h" #include "Memory.h" #include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" #include "lld/Driver/Driver.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/BinaryFormat/Magic.h" #include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/COFFImportFile.h" #include "llvm/Object/COFFModuleDefinition.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ToolDrivers/llvm-lib/LibDriver.h" #include #include #include using namespace llvm; using namespace llvm::object; using namespace llvm::COFF; using llvm::sys::Process; namespace lld { namespace coff { Configuration *Config; LinkerDriver *Driver; BumpPtrAllocator BAlloc; StringSaver Saver{BAlloc}; std::vector SpecificAllocBase::Instances; bool link(ArrayRef Args, raw_ostream &Diag) { ErrorCount = 0; ErrorOS = &Diag; Argv0 = Args[0]; Config = make(); Config->ColorDiagnostics = (ErrorOS == &llvm::errs() && Process::StandardErrHasColors()); Driver = make(); Driver->link(Args); return !ErrorCount; } // Drop directory components and replace extension with ".exe" or ".dll". static std::string getOutputPath(StringRef Path) { auto P = Path.find_last_of("\\/"); StringRef S = (P == StringRef::npos) ? Path : Path.substr(P + 1); const char* E = Config->DLL ? ".dll" : ".exe"; return (S.substr(0, S.rfind('.')) + E).str(); } // ErrorOr is not default constructible, so it cannot be used as the type // parameter of a future. // FIXME: We could open the file in createFutureForFile and avoid needing to // return an error here, but for the moment that would cost us a file descriptor // (a limited resource on Windows) for the duration that the future is pending. typedef std::pair, std::error_code> MBErrPair; // Create a std::future that opens and maps a file using the best strategy for // the host platform. static std::future createFutureForFile(std::string Path) { #if LLVM_ON_WIN32 // 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); if (!MBOrErr) return MBErrPair{nullptr, MBOrErr.getError()}; return MBErrPair{std::move(*MBOrErr), std::error_code()}; }); } MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr MB) { MemoryBufferRef MBRef = *MB; make>(std::move(MB)); // take ownership if (Driver->Tar) Driver->Tar->append(relativeToRoot(MBRef.getBufferIdentifier()), MBRef.getBuffer()); return MBRef; } void LinkerDriver::addBuffer(std::unique_ptr MB) { MemoryBufferRef MBRef = takeBuffer(std::move(MB)); // File type is detected by contents, not by file extension. file_magic Magic = identify_magic(MBRef.getBuffer()); if (Magic == file_magic::windows_resource) { Resources.push_back(MBRef); return; } FilePaths.push_back(MBRef.getBufferIdentifier()); if (Magic == file_magic::archive) return Symtab.addFile(make(MBRef)); if (Magic == file_magic::bitcode) return Symtab.addFile(make(MBRef)); if (Magic == file_magic::coff_cl_gl_object) error(MBRef.getBufferIdentifier() + ": is not a native COFF file. " "Recompile without /GL"); else Symtab.addFile(make(MBRef)); } void LinkerDriver::enqueuePath(StringRef Path) { 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)); }); } 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(MBOrErr.second, "could not get the buffer for the member defining " + SymName); Driver->addArchiveBuffer(takeBuffer(std::move(MBOrErr.first)), SymName, ParentName); }); } static bool isDecorated(StringRef Sym) { return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?"); } // Parses .drectve section contents and returns a list of files // specified by /defaultlib. void LinkerDriver::parseDirectives(StringRef S) { opt::InputArgList Args = Parser.parse(S); for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_alternatename: parseAlternateName(Arg->getValue()); break; case OPT_defaultlib: if (Optional Path = findLib(Arg->getValue())) enqueuePath(*Path); break; case OPT_export: { Export E = parseExport(Arg->getValue()); E.Directives = true; Config->Exports.push_back(E); break; } case OPT_failifmismatch: checkFailIfMismatch(Arg->getValue()); break; case OPT_incl: addUndefined(Arg->getValue()); break; case OPT_merge: parseMerge(Arg->getValue()); break; case OPT_nodefaultlib: Config->NoDefaultLibs.insert(doFindLib(Arg->getValue())); break; case OPT_section: parseSection(Arg->getValue()); break; case OPT_editandcontinue: case OPT_fastfail: case OPT_guardsym: 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.find('.') != StringRef::npos); 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; } // Resolves a file path. This never returns the same path // (in that case, it returns None). Optional LinkerDriver::findFile(StringRef Filename) { StringRef Path = doFindFile(Filename); bool Seen = !VisitedFiles.insert(Path.lower()).second; if (Seen) return None; return Path; } // Find library file from search path. StringRef LinkerDriver::doFindLib(StringRef Filename) { // Add ".lib" to Filename if that has no file extension. bool HasExt = (Filename.find('.') != StringRef::npos); if (!HasExt) Filename = Saver.save(Filename + ".lib"); return doFindFile(Filename); } // Resolves a library path. /nodefaultlib options are taken into // consideration. This never returns the same path (in that case, // it returns None). Optional LinkerDriver::findLib(StringRef Filename) { if (Config->NoDefaultLibAll) return None; if (!VisitedLibs.insert(Filename.lower()).second) return None; StringRef Path = doFindLib(Filename); if (Config->NoDefaultLibs.count(Path)) return None; if (!VisitedFiles.insert(Path.lower()).second) return None; 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); } } SymbolBody *LinkerDriver::addUndefined(StringRef Name) { SymbolBody *B = Symtab.addUndefined(Name); Config->GCRoot.insert(B); return B; } // Symbol names are mangled by appending "_" prefix on x86. StringRef LinkerDriver::mangle(StringRef Sym) { assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN); if (Config->Machine == I386) return Saver.save("_" + Sym); return Sym; } // Windows specific -- find default entry point name. StringRef LinkerDriver::findDefaultEntry() { // User-defined main functions and their corresponding entry points. static const char *Entries[][2] = { {"main", "mainCRTStartup"}, {"wmain", "wmainCRTStartup"}, {"WinMain", "WinMainCRTStartup"}, {"wWinMain", "wWinMainCRTStartup"}, }; for (auto E : Entries) { StringRef Entry = Symtab.findMangle(mangle(E[0])); if (!Entry.empty() && !isa(Symtab.find(Entry)->body())) return mangle(E[1]); } return ""; } WindowsSubsystem LinkerDriver::inferSubsystem() { if (Config->DLL) return IMAGE_SUBSYSTEM_WINDOWS_GUI; if (Symtab.findUnderscore("main") || Symtab.findUnderscore("wmain")) return IMAGE_SUBSYSTEM_WINDOWS_CUI; if (Symtab.findUnderscore("WinMain") || Symtab.findUnderscore("wWinMain")) return IMAGE_SUBSYSTEM_WINDOWS_GUI; return IMAGE_SUBSYSTEM_UNKNOWN; } static uint64_t getDefaultImageBase() { if (Config->is64()) return Config->DLL ? 0x180000000 : 0x140000000; return Config->DLL ? 0x10000000 : 0x400000; } 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: break; default: OS << toString(Arg) << "\n"; } } for (StringRef Path : SearchPaths) { std::string RelPath = relativeToRoot(Path); OS << "/libpath:" << quote(RelPath) << "\n"; } for (StringRef Path : FilePaths) OS << quote(relativeToRoot(Path)) << "\n"; return Data.str(); } static unsigned getDefaultDebugType(const opt::InputArgList &Args) { unsigned DebugTypes = static_cast(DebugType::CV); if (Args.hasArg(OPT_driver)) DebugTypes |= static_cast(DebugType::PData); if (Args.hasArg(OPT_profile)) DebugTypes |= static_cast(DebugType::Fixup); return DebugTypes; } static unsigned parseDebugType(StringRef Arg) { SmallVector Types; Arg.split(Types, ',', /*KeepEmpty=*/false); unsigned DebugTypes = static_cast(DebugType::None); for (StringRef Type : Types) DebugTypes |= StringSwitch(Type.lower()) .Case("cv", static_cast(DebugType::CV)) .Case("pdata", static_cast(DebugType::PData)) .Case("fixup", static_cast(DebugType::Fixup)) .Default(0); return DebugTypes; } static std::string getMapFile(const opt::InputArgList &Args) { auto *Arg = Args.getLastArg(OPT_lldmap, OPT_lldmap_file); if (!Arg) return ""; if (Arg->getOption().getID() == OPT_lldmap_file) return Arg->getValue(); assert(Arg->getOption().getID() == OPT_lldmap); StringRef OutFile = Config->OutputFile; return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str(); } static std::string getImplibPath() { if (!Config->Implib.empty()) return Config->Implib; SmallString<128> Out = StringRef(Config->OutputFile); sys::path::replace_extension(Out, ".lib"); return Out.str(); } static void createImportLibrary() { std::vector Exports; for (Export &E1 : Config->Exports) { COFFShortExport E2; // Use SymbolName, which will have any stdcall or fastcall qualifiers. E2.Name = 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); } std::string DLLName = sys::path::filename(Config->OutputFile); std::string Path = getImplibPath(); writeImportLibrary(DLLName, Path, Exports, Config->Machine); } 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)); if (Config->OutputFile.empty()) Config->OutputFile = Saver.save(M.OutputFile); 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; E2.Name = Saver.save(E1.Name); if (E1.isWeak()) 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); } } 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; } // A helper function for filterBitcodeFiles. static bool needsRebuilding(MemoryBufferRef MB) { // The MSVC linker doesn't support thin archives, so if it's a thin // archive, we always need to rebuild it. std::unique_ptr File = check(Archive::create(MB), "Failed to read " + MB.getBufferIdentifier()); if (File->isThin()) return true; // Returns true if the archive contains at least one bitcode file. for (MemoryBufferRef Member : getArchiveMembers(File.get())) if (identify_magic(Member.getBuffer()) == file_magic::bitcode) return true; return false; } // Opens a given path as an archive file and removes bitcode files // from them if exists. This function is to appease the MSVC linker as // their linker doesn't like archive files containing non-native // object files. // // If a given archive doesn't contain bitcode files, the archive path // is returned as-is. Otherwise, a new temporary file is created and // its path is returned. static Optional filterBitcodeFiles(StringRef Path, std::vector &TemporaryFiles) { std::unique_ptr MB = check( MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); MemoryBufferRef MBRef = MB->getMemBufferRef(); file_magic Magic = identify_magic(MBRef.getBuffer()); if (Magic == file_magic::bitcode) return None; if (Magic != file_magic::archive) return Path.str(); if (!needsRebuilding(MBRef)) return Path.str(); std::unique_ptr File = check(Archive::create(MBRef), MBRef.getBufferIdentifier() + ": failed to parse archive"); std::vector New; for (MemoryBufferRef Member : getArchiveMembers(File.get())) if (identify_magic(Member.getBuffer()) != file_magic::bitcode) New.emplace_back(Member); if (New.empty()) return None; log("Creating a temporary archive for " + Path + " to remove bitcode files"); SmallString<128> S; if (auto EC = sys::fs::createTemporaryFile("lld-" + sys::path::stem(Path), ".lib", S)) fatal(EC, "cannot create a temporary file"); std::string Temp = S.str(); TemporaryFiles.push_back(Temp); std::pair Ret = llvm::writeArchive(Temp, New, /*WriteSymtab=*/true, Archive::Kind::K_GNU, /*Deterministics=*/true, /*Thin=*/false); if (Ret.second) error("failed to create a new archive " + S.str() + ": " + Ret.first); 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 (const auto *O : Symtab.ObjectFiles) { if (O->ParentName.empty()) continue; SmallString<128> S; int Fd; if (auto EC = sys::fs::createTemporaryFile( "lld-" + sys::path::filename(O->ParentName), ".obj", Fd, S)) fatal(EC, "cannot create a temporary file"); raw_fd_ostream OS(Fd, /*shouldClose*/ true); OS << O->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 ObjectFiles = Symtab.compileBitcodeFiles(); runMSVCLinker(Rsp, ObjectFiles); for (StringRef Path : Temps) sys::fs::remove(Path); } void LinkerDriver::enqueueTask(std::function Task) { TaskQueue.push_back(std::move(Task)); } bool LinkerDriver::run() { bool DidWork = !TaskQueue.empty(); while (!TaskQueue.empty()) { TaskQueue.front()(); TaskQueue.pop_front(); } return DidWork; } void LinkerDriver::link(ArrayRef ArgsArr) { // If the first command line argument is "/lib", link.exe acts like lib.exe. // We call our own implementation of lib.exe that understands bitcode files. if (ArgsArr.size() > 1 && StringRef(ArgsArr[1]).equals_lower("/lib")) { if (llvm::libDriverMain(ArgsArr.slice(1)) != 0) fatal("lib failed"); return; } // Needed for LTO. InitializeAllTargetInfos(); InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmParsers(); InitializeAllAsmPrinters(); InitializeAllDisassemblers(); // Parse command line options. opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1)); // 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); Config->ErrorLimit = N; } // Handle /help if (Args.hasArg(OPT_help)) { printHelp(ArgsArr[0]); return; } 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.hasArgNoClaim(OPT_INPUT)) { if (Args.hasArgNoClaim(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 /out if (auto *Arg = Args.getLastArg(OPT_out)) Config->OutputFile = Arg->getValue(); // Handle /verbose if (Args.hasArg(OPT_verbose)) Config->Verbose = true; // Handle /force or /force:unresolved if (Args.hasArg(OPT_force) || Args.hasArg(OPT_force_unresolved)) Config->Force = true; // Handle /debug if (Args.hasArg(OPT_debug)) { Config->Debug = true; Config->DebugTypes = Args.hasArg(OPT_debugtype) ? parseDebugType(Args.getLastArg(OPT_debugtype)->getValue()) : getDefaultDebugType(Args); } // Create a dummy PDB file to satisfy build sytem rules. if (auto *Arg = Args.getLastArg(OPT_pdb)) Config->PDBPath = 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 /fixed if (Args.hasArg(OPT_fixed)) { if (Args.hasArg(OPT_dynamicbase)) { error("/fixed must not be specified with /dynamicbase"); } else { Config->Relocatable = false; Config->DynamicBase = false; } } if (Args.hasArg(OPT_appcontainer)) Config->AppContainer = true; // Handle /machine if (auto *Arg = Args.getLastArg(OPT_machine)) Config->Machine = getMachineType(Arg->getValue()); // Handle /nodefaultlib: for (auto *Arg : Args.filtered(OPT_nodefaultlib)) Config->NoDefaultLibs.insert(doFindLib(Arg->getValue())); // Handle /nodefaultlib if (Args.hasArg(OPT_nodefaultlib_all)) Config->NoDefaultLibAll = true; // Handle /base if (auto *Arg = Args.getLastArg(OPT_base)) parseNumbers(Arg->getValue(), &Config->ImageBase); // Handle /stack if (auto *Arg = Args.getLastArg(OPT_stack)) parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit); // Handle /heap if (auto *Arg = Args.getLastArg(OPT_heap)) parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit); // Handle /version if (auto *Arg = Args.getLastArg(OPT_version)) parseVersion(Arg->getValue(), &Config->MajorImageVersion, &Config->MinorImageVersion); // Handle /subsystem if (auto *Arg = Args.getLastArg(OPT_subsystem)) parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion, &Config->MinorOSVersion); // Handle /alternatename for (auto *Arg : Args.filtered(OPT_alternatename)) parseAlternateName(Arg->getValue()); // Handle /include for (auto *Arg : Args.filtered(OPT_incl)) addUndefined(Arg->getValue()); // Handle /implib if (auto *Arg = Args.getLastArg(OPT_implib)) Config->Implib = Arg->getValue(); // Handle /opt for (auto *Arg : Args.filtered(OPT_opt)) { std::string Str = StringRef(Arg->getValue()).lower(); SmallVector Vec; StringRef(Str).split(Vec, ','); for (StringRef S : Vec) { if (S == "noref") { Config->DoGC = false; Config->DoICF = false; continue; } if (S == "icf" || StringRef(S).startswith("icf=")) { Config->DoICF = true; continue; } if (S == "noicf") { Config->DoICF = false; continue; } if (StringRef(S).startswith("lldlto=")) { StringRef OptLevel = StringRef(S).substr(7); if (OptLevel.getAsInteger(10, Config->LTOOptLevel) || Config->LTOOptLevel > 3) error("/opt:lldlto: invalid optimization level: " + OptLevel); continue; } if (StringRef(S).startswith("lldltojobs=")) { StringRef Jobs = StringRef(S).substr(11); if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0) error("/opt:lldltojobs: invalid job count: " + Jobs); continue; } if (StringRef(S).startswith("lldltopartitions=")) { StringRef N = StringRef(S).substr(17); if (N.getAsInteger(10, Config->LTOPartitions) || Config->LTOPartitions == 0) error("/opt:lldltopartitions: invalid partition count: " + N); continue; } if (S != "ref" && S != "lbr" && S != "nolbr") error("/opt: unknown option: " + S); } } // Handle /lldsavetemps if (Args.hasArg(OPT_lldsavetemps)) Config->SaveTemps = true; // Handle /failifmismatch for (auto *Arg : Args.filtered(OPT_failifmismatch)) checkFailIfMismatch(Arg->getValue()); // Handle /merge for (auto *Arg : Args.filtered(OPT_merge)) parseMerge(Arg->getValue()); // Handle /section for (auto *Arg : Args.filtered(OPT_section)) parseSection(Arg->getValue()); // Handle /manifest if (auto *Arg = Args.getLastArg(OPT_manifest_colon)) parseManifest(Arg->getValue()); // Handle /manifestuac if (auto *Arg = Args.getLastArg(OPT_manifestuac)) parseManifestUAC(Arg->getValue()); // Handle /manifestdependency if (auto *Arg = Args.getLastArg(OPT_manifestdependency)) Config->ManifestDependency = Arg->getValue(); // Handle /manifestfile if (auto *Arg = Args.getLastArg(OPT_manifestfile)) Config->ManifestFile = Arg->getValue(); // Handle /manifestinput for (auto *Arg : Args.filtered(OPT_manifestinput)) Config->ManifestInput.push_back(Arg->getValue()); // Handle miscellaneous boolean flags. if (Args.hasArg(OPT_allowisolation_no)) Config->AllowIsolation = false; if (Args.hasArg(OPT_dynamicbase_no)) Config->DynamicBase = false; if (Args.hasArg(OPT_nxcompat_no)) Config->NxCompat = false; if (Args.hasArg(OPT_tsaware_no)) Config->TerminalServerAware = false; if (Args.hasArg(OPT_nosymtab)) Config->WriteSymtab = false; - Config->DumpPdb = Args.hasArg(OPT_dumppdb); Config->MapFile = getMapFile(Args); if (ErrorCount) return; // Create a list of input files. Files can be given as arguments // for /defaultlib option. std::vector MBs; for (auto *Arg : Args.filtered(OPT_INPUT)) if (Optional Path = findFile(Arg->getValue())) enqueuePath(*Path); for (auto *Arg : Args.filtered(OPT_defaultlib)) if (Optional Path = findLib(Arg->getValue())) enqueuePath(*Path); // Windows specific -- Create a resource file containing a manifest file. if (Config->Manifest == Configuration::Embed) addBuffer(createManifestRes()); // Read all input files given via the command line. run(); // We should have inferred a machine type by now from the input files, but if // not we assume x64. if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { warn("/machine is not specified. x64 is assumed"); Config->Machine = AMD64; } - // Windows specific -- Input files can be Windows resource files (.res files). - // We invoke cvtres.exe to convert resource files to a regular COFF file - // then link the result file normally. + // 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()) addBuffer(convertResToCOFF(Resources)); if (Tar) Tar->append("response.txt", createResponseFile(Args, FilePaths, ArrayRef(SearchPaths).slice(1))); // Handle /largeaddressaware if (Config->is64() || Args.hasArg(OPT_largeaddressaware)) Config->LargeAddressAware = true; // Handle /highentropyva if (Config->is64() && !Args.hasArg(OPT_highentropyva_no)) Config->HighEntropyVA = true; // Handle /entry and /dll if (auto *Arg = Args.getLastArg(OPT_entry)) { Config->Entry = addUndefined(mangle(Arg->getValue())); } else if (Args.hasArg(OPT_dll) && !Config->NoEntry) { StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12" : "_DllMainCRTStartup"; Config->Entry = addUndefined(S); } else if (!Config->NoEntry) { // Windows specific -- If entry point name is not given, we need to // infer that from user-defined entry name. StringRef S = findDefaultEntry(); if (S.empty()) fatal("entry point must be defined"); Config->Entry = addUndefined(S); log("Entry name inferred: " + S); } // Handle /export for (auto *Arg : Args.filtered(OPT_export)) { Export E = parseExport(Arg->getValue()); if (Config->Machine == I386) { if (!isDecorated(E.Name)) E.Name = Saver.save("_" + E.Name); if (!E.ExtName.empty() && !isDecorated(E.ExtName)) E.ExtName = Saver.save("_" + E.ExtName); } Config->Exports.push_back(E); } // Handle /def if (auto *Arg = Args.getLastArg(OPT_deffile)) { // parseModuleDefs mutates Config object. parseModuleDefs(Arg->getValue()); } // Handle generation of import library from a def file. if (!Args.hasArgNoClaim(OPT_INPUT)) { fixupExports(); createImportLibrary(); exit(0); } // Handle /delayload for (auto *Arg : Args.filtered(OPT_delayload)) { Config->DelayLoads.insert(StringRef(Arg->getValue()).lower()); if (Config->Machine == I386) { Config->DelayLoadHelper = addUndefined("___delayLoadHelper2@8"); } else { Config->DelayLoadHelper = addUndefined("__delayLoadHelper2"); } } // Set default image name if neither /out or /def set it. if (Config->OutputFile.empty()) { Config->OutputFile = getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue()); } // Put the PDB next to the image if no /pdb flag was passed. if (Config->Debug && Config->PDBPath.empty()) { Config->PDBPath = Config->OutputFile; sys::path::replace_extension(Config->PDBPath, ".pdb"); } // Disable PDB generation if the user requested it. if (Args.hasArg(OPT_nopdb)) Config->PDBPath = ""; // Set default image base if /base is not given. if (Config->ImageBase == uint64_t(-1)) Config->ImageBase = getDefaultImageBase(); - Symtab.addRelative(mangle("__ImageBase"), 0); + Symtab.addSynthetic(mangle("__ImageBase"), nullptr); if (Config->Machine == I386) { - Config->SEHTable = Symtab.addRelative("___safe_se_handler_table", 0); - Config->SEHCount = Symtab.addAbsolute("___safe_se_handler_count", 0); + Symtab.addAbsolute("___safe_se_handler_table", 0); + Symtab.addAbsolute("___safe_se_handler_count", 0); } // We do not support /guard:cf (control flow protection) yet. // Define CFG symbols anyway so that we can link MSVC 2015 CRT. - Symtab.addAbsolute(mangle("__guard_fids_table"), 0); Symtab.addAbsolute(mangle("__guard_fids_count"), 0); + Symtab.addAbsolute(mangle("__guard_fids_table"), 0); Symtab.addAbsolute(mangle("__guard_flags"), 0x100); + 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); // 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->body())) if (!U->WeakAlias) U->WeakAlias = Symtab.addUndefined(To); } // Windows specific -- if __load_config_used can be resolved, resolve it. if (Symtab.findUnderscore("_load_config_used")) addUndefined(mangle("_load_config_used")); } 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); exit(0); } // Do LTO by compiling bitcode input files to a set of native COFF files then // link those files. Symtab.addCombinedLTOObjects(); run(); // Make sure we have resolved all symbols. Symtab.reportRemainingUndefines(); // Windows specific -- if no /subsystem is given, we need to infer // that from entry point name. if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) { Config->Subsystem = inferSubsystem(); if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) fatal("subsystem must be defined"); } // Handle /safeseh. if (Args.hasArg(OPT_safeseh)) { for (ObjectFile *File : Symtab.ObjectFiles) if (!File->SEHCompat) error("/safeseh: " + File->getName() + " is not compatible with SEH"); if (ErrorCount) return; } // 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(); assignExportOrdinals(); } // Windows specific -- Create a side-by-side manifest file. if (Config->Manifest == Configuration::SideBySide) createSideBySideManifest(); // Identify unreferenced COMDAT sections. if (Config->DoGC) markLive(Symtab.getChunks()); // Identify identical COMDAT sections to merge them. if (Config->DoICF) doICF(Symtab.getChunks()); // Write the result. writeResult(&Symtab); // Call exit to avoid calling destructors. exit(0); } } // namespace coff } // namespace lld Index: vendor/lld/dist/COFF/Driver.h =================================================================== --- vendor/lld/dist/COFF/Driver.h (revision 320381) +++ vendor/lld/dist/COFF/Driver.h (revision 320382) @@ -1,189 +1,189 @@ //===- 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/Core/LLVM.h" #include "lld/Core/Reproduce.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFF.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.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 InputFile; // Implemented in MarkLive.cpp. void markLive(const std::vector &Chunks); // Implemented in ICF.cpp. void doICF(const std::vector &Chunks); class ArgParser { public: // Parses command line options. llvm::opt::InputArgList parse(llvm::ArrayRef Args); // Concatenate LINK environment varirable and given arguments and parse them. llvm::opt::InputArgList parseLINK(std::vector Args); // Tokenizes a given string and then parses as command line options. llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); } private: std::vector tokenize(StringRef S); std::vector replaceResponseFiles(std::vector); }; class LinkerDriver { public: LinkerDriver() { coff::Symtab = &Symtab; } 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); private: ArgParser Parser; SymbolTable Symtab; std::unique_ptr Tar; // for /linkrepro // Opens a file. Path has to be resolved already. MemoryBufferRef openFile(StringRef Path); // Searches a file from search paths. Optional findFile(StringRef Filename); Optional findLib(StringRef Filename); StringRef doFindFile(StringRef Filename); StringRef doFindLib(StringRef Filename); // Parses LIB environment which contains a list of search paths. void addLibSearchPaths(); // Library search path. The first element is always "" (current directory). std::vector SearchPaths; std::set VisitedFiles; std::set VisitedLibs; SymbolBody *addUndefined(StringRef Sym); StringRef mangle(StringRef Sym); // Windows specific -- "main" is not the only main function in Windows. // You can choose one from these four -- {w,}{WinMain,main}. // There are four different entry point functions for them, // {w,}{WinMain,main}CRTStartup, respectively. The linker needs to // choose the right one depending on which "main" function is defined. // This function looks up the symbol table and resolve corresponding // entry point name. StringRef findDefaultEntry(); WindowsSubsystem inferSubsystem(); void invokeMSVC(llvm::opt::InputArgList &Args); MemoryBufferRef takeBuffer(std::unique_ptr MB); void addBuffer(std::unique_ptr MB); void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName, StringRef ParentName); void enqueuePath(StringRef Path); void enqueueTask(std::function Task); bool run(); std::list> TaskQueue; std::vector FilePaths; std::vector Resources; }; // Functions below this line are defined in DriverUtils.cpp. void printHelp(const char *Argv0); // For /machine option. MachineTypes getMachineType(StringRef Arg); StringRef machineToStr(MachineTypes MT); // Parses a string in the form of "[,]". void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr); // Parses a string in the form of "[.]". // Minor's default value is 0. void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor); // Parses a string in the form of "[,[.]]". void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, uint32_t *Minor); void parseAlternateName(StringRef); void parseMerge(StringRef); void parseSection(StringRef); // Parses a string in the form of "EMBED[,=]|NO". void parseManifest(StringRef Arg); // Parses a string in the form of "level=|uiAccess=" void parseManifestUAC(StringRef Arg); // Create a resource file containing a manifest XML. std::unique_ptr createManifestRes(); void createSideBySideManifest(); // Used for dllexported symbols. Export parseExport(StringRef Arg); void fixupExports(); void assignExportOrdinals(); // Parses a string in the form of "key=value" and check // if value matches previous values for the key. // This feature used in the directive section to reject // incompatible objects. void checkFailIfMismatch(StringRef Arg); // Convert Windows resource files (.res files) to a .obj file // using cvtres.exe. std::unique_ptr convertResToCOFF(const std::vector &MBs); void 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) OPT_##ID, +#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: vendor/lld/dist/COFF/DriverUtils.cpp =================================================================== --- vendor/lld/dist/COFF/DriverUtils.cpp (revision 320381) +++ vendor/lld/dist/COFF/DriverUtils.cpp (revision 320382) @@ -1,737 +1,729 @@ //===- DriverUtils.cpp ----------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains utility functions for the driver. Because there // are so many small functions, we created this separate file to make // Driver.cpp less cluttered. // //===----------------------------------------------------------------------===// #include "Config.h" #include "Driver.h" #include "Error.h" #include "Memory.h" #include "Symbols.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 using namespace llvm::COFF; using namespace llvm; using llvm::cl::ExpandResponseFiles; using llvm::cl::TokenizeWindowsCommandLine; 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(EC, "unable to find " + Prog + " in PATH: "); StringRef Exe = Saver.save(*ExeOrErr); Args.insert(Args.begin(), Exe); std::vector Vec; for (StringRef S : Args) Vec.push_back(S.data()); Vec.push_back(nullptr); if (sys::ExecuteAndWait(Args[0], Vec.data()) != 0) 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) .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 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); } // 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); 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 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); } } -// Quote each line with "". Existing double-quote is converted -// to two double-quotes. -static void quoteAndPrint(raw_ostream &Out, StringRef S) { - while (!S.empty()) { - StringRef Line; - std::tie(Line, S) = S.split("\n"); - if (Line.empty()) - continue; - Out << '\"'; - for (int I = 0, E = Line.size(); I != E; ++I) { - if (Line[I] == '\"') { - Out << "\"\""; - } else { - Out << Line[I]; - } - } - Out << "\"\n"; - } -} - // 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(EC, "cannot create a temporary file"); Path = S.str(); if (!Contents.empty()) { std::error_code EC; raw_fd_ostream OS(Path, EC, sys::fs::F_None); if (EC) fatal(EC, "failed to open " + Path); 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; }; } // Create the default manifest file as a temporary file. TemporaryFile createDefaultXml() { // Create a temporary file. TemporaryFile File("defaultxml", "manifest"); // Open the temporary file for writing. std::error_code EC; raw_fd_ostream OS(File.Path, EC, sys::fs::F_Text); if (EC) fatal(EC, "failed to open " + File.Path); // Emit the XML. Note that we do *not* verify that the XML attributes are // syntactically correct. This is intentional for link.exe compatibility. OS << "\n" << "\n"; if (Config->ManifestUAC) { OS << " \n" << " \n" << " \n" << " \n" << " \n" << " \n" << " \n"; if (!Config->ManifestDependency.empty()) { OS << " \n" << " \n" << " ManifestDependency << " />\n" << " \n" << " \n"; } } OS << "\n"; OS.close(); return File; } static std::string readFile(StringRef Path) { std::unique_ptr MB = check(MemoryBuffer::getFile(Path), "could not open " + Path); return MB->getBuffer(); } static std::string createManifestXml() { // Create the default manifest file. TemporaryFile File1 = createDefaultXml(); if (Config->ManifestInput.empty()) return readFile(File1.Path); // If manifest files are supplied by the user using /MANIFESTINPUT // option, we need to merge them with the default manifest. TemporaryFile File2("user", "manifest"); Executor E("mt.exe"); E.add("/manifest"); E.add(File1.Path); for (StringRef Filename : Config->ManifestInput) { E.add("/manifest"); E.add(Filename); } E.add("/nologo"); E.add("/out:" + StringRef(File2.Path)); E.run(); return readFile(File2.Path); } +static std::unique_ptr +createMemoryBufferForManifestRes(size_t ManifestSize) { + size_t ResSize = alignTo(object::WIN_RES_MAGIC_SIZE + + object::WIN_RES_NULL_ENTRY_SIZE + + sizeof(object::WinResHeaderPrefix) + + sizeof(object::WinResIDs) + + sizeof(object::WinResHeaderSuffix) + + ManifestSize, + object::WIN_RES_DATA_ALIGNMENT); + return MemoryBuffer::getNewMemBuffer(ResSize); +} + +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() { - // Create a temporary file for the resource script file. - TemporaryFile RCFile("manifest", "rc"); + std::string Manifest = createManifestXml(); - // Open the temporary file for writing. - std::error_code EC; - raw_fd_ostream Out(RCFile.Path, EC, sys::fs::F_Text); - if (EC) - fatal(EC, "failed to open " + RCFile.Path); + std::unique_ptr Res = + createMemoryBufferForManifestRes(Manifest.size()); - // Write resource script to the RC file. - Out << "#define LANG_ENGLISH 9\n" - << "#define SUBLANG_DEFAULT 1\n" - << "#define APP_MANIFEST " << Config->ManifestID << "\n" - << "#define RT_MANIFEST 24\n" - << "LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT\n" - << "APP_MANIFEST RT_MANIFEST {\n"; - quoteAndPrint(Out, createManifestXml()); - Out << "}\n"; - Out.close(); + char *Buf = const_cast(Res->getBufferStart()); + writeResFileHeader(Buf); + writeResEntryHeader(Buf, Manifest.size()); - // Create output resource file. - TemporaryFile ResFile("output-resource", "res"); - - Executor E("rc.exe"); - E.add("/fo"); - E.add(ResFile.Path); - E.add("/nologo"); - E.add(RCFile.Path); - E.run(); - return ResFile.getMemoryBuffer(); + // Copy the manifest data into the .res file. + std::copy(Manifest.begin(), Manifest.end(), Buf); + return 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(EC, "failed to create manifest"); 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.find('=') != StringRef::npos) { StringRef X, Y; std::tie(X, Y) = E.Name.split("="); // If "=.". if (Y.find(".") != StringRef::npos) { E.Name = X; E.ForwardTo = Y; return E; } E.ExtName = X; E.Name = Y; if (E.Name.empty()) goto err; } // If "=[,@ordinal[,NONAME]][,DATA][,PRIVATE]" while (!Rest.empty()) { StringRef Tok; std::tie(Tok, Rest) = Rest.split(","); if (Tok.equals_lower("noname")) { if (E.Ordinal == 0) goto err; E.Noname = true; continue; } if (Tok.equals_lower("data")) { E.Data = true; continue; } if (Tok.equals_lower("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; return Sym.startswith("_") ? Sym.substr(1) : Sym; } // Performs error checking on all /export arguments. // It also sets ordinals. void fixupExports() { // Symbol ordinals must be unique. std::set Ords; for (Export &E : Config->Exports) { if (E.Ordinal == 0) continue; if (!Ords.insert(E.Ordinal).second) fatal("duplicate export ordinal: " + E.Name); } for (Export &E : Config->Exports) { SymbolBody *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); } } // Uniquefy by name. std::map Map; std::vector V; for (Export &E : Config->Exports) { auto Pair = Map.insert(std::make_pair(E.ExportName, &E)); bool Inserted = Pair.second; if (Inserted) { V.push_back(E); continue; } Export *Existing = Pair.first->second; if (E == *Existing || E.Name != Existing->Name) continue; 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 // using cvtres.exe. std::unique_ptr convertResToCOFF(const std::vector &MBs) { - // Create an output file path. - TemporaryFile File("resource-file", "obj"); + object::WindowsResourceParser Parser; - // Execute cvtres.exe. - Executor E("cvtres.exe"); - E.add("/machine:" + machineToStr(Config->Machine)); - E.add("/readonly"); - E.add("/nologo"); - E.add("/out:" + Twine(File.Path)); - - // We must create new files because the memory buffers we have may have no - // underlying file still existing on the disk. - // It happens if it was created from a TemporaryFile, which usually delete - // the file just after creating the MemoryBuffer. - std::vector ResFiles; - ResFiles.reserve(MBs.size()); for (MemoryBufferRef MB : MBs) { - // We store the temporary file in a vector to avoid deletion - // before running cvtres - ResFiles.emplace_back("resource-file", "res"); - TemporaryFile& ResFile = ResFiles.back(); - // Write the content of the resource in a temporary file - std::error_code EC; - raw_fd_ostream OS(ResFile.Path, EC, sys::fs::F_None); - if (EC) - fatal(EC, "failed to open " + ResFile.Path); - OS << MB.getBuffer(); - OS.close(); - - E.add(ResFile.Path); + 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(EC, "failed to parse .res file"); } - E.run(); - return File.getMemoryBuffer(); + Expected> E = + llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser); + if (!E) + fatal(errorToErrorCode(E.takeError()), "failed to write .res to COFF"); + return std::move(E.get()); } // 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, X6, X7, X8, X9, X10) \ - { \ - X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, X8, X7, \ - OPT_##GROUP, OPT_##ALIAS, X6 \ - }, +#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 }; class COFFOptTable : public llvm::opt::OptTable { public: COFFOptTable() : OptTable(infoTable, true) {} }; // Parses a given list of options. opt::InputArgList ArgParser::parse(ArrayRef ArgsArr) { // First, replace respnose files (@-style options). std::vector Argv = replaceResponseFiles(ArgsArr); // Make InputArgList from string vectors. COFFOptTable Table; unsigned MissingIndex; unsigned MissingCount; opt::InputArgList Args = Table.ParseArgs(Argv, MissingIndex, MissingCount); // Print the real command line if response files are expanded. if (Args.hasArg(OPT_verbose) && ArgsArr.size() != Argv.size()) { std::string Msg = "Command line:"; for (const char *S : Argv) Msg += " " + std::string(S); message(Msg); } if (MissingCount) fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); for (auto *Arg : Args.filtered(OPT_UNKNOWN)) warn("ignoring unknown argument: " + Arg->getSpelling()); return Args; } // 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 Args) { // Concatenate LINK env and command line arguments, and then parse them. if (Optional S = Process::GetEnv("LINK")) { std::vector V = tokenize(*S); Args.insert(Args.begin(), V.begin(), V.end()); } if (Optional S = Process::GetEnv("_LINK_")) { std::vector V = tokenize(*S); Args.insert(Args.begin(), V.begin(), V.end()); } return parse(Args); } std::vector ArgParser::tokenize(StringRef S) { SmallVector Tokens; cl::TokenizeWindowsCommandLine(S, Saver, Tokens); return std::vector(Tokens.begin(), Tokens.end()); } // Creates a new command line by replacing options starting with '@' // character. '@' is replaced by the file's contents. std::vector ArgParser::replaceResponseFiles(std::vector Argv) { SmallVector Tokens(Argv.data(), Argv.data() + Argv.size()); ExpandResponseFiles(Saver, TokenizeWindowsCommandLine, Tokens); return std::vector(Tokens.begin(), Tokens.end()); } void printHelp(const char *Argv0) { COFFOptTable Table; Table.PrintHelp(outs(), Argv0, "LLVM Linker", false); } } // namespace coff } // namespace lld Index: vendor/lld/dist/COFF/InputFiles.cpp =================================================================== --- vendor/lld/dist/COFF/InputFiles.cpp (revision 320381) +++ vendor/lld/dist/COFF/InputFiles.cpp (revision 320382) @@ -1,405 +1,409 @@ //===- 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 "Error.h" #include "Memory.h" #include "SymbolTable.h" #include "Symbols.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/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 { /// 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, SymbolBody *Source, SymbolBody *Target) { if (auto *U = dyn_cast(Source)) { if (U->WeakAlias && U->WeakAlias != Target) Symtab->reportDuplicate(Source->symbol(), 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), toString(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()); } void ObjectFile::parse() { // Parse a memory buffer as a COFF file. std::unique_ptr Bin = check(createBinary(MB), toString(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(); initializeSEH(); } void ObjectFile::initializeChunks() { uint32_t NumSections = COFFObj->getNumberOfSections(); Chunks.reserve(NumSections); SparseChunks.resize(NumSections + 1); for (uint32_t I = 1; I < NumSections + 1; ++I) { const coff_section *Sec; StringRef Name; if (auto EC = COFFObj->getSection(I, Sec)) fatal(EC, "getSection failed: #" + Twine(I)); if (auto EC = COFFObj->getSectionName(Sec, Name)) fatal(EC, "getSectionName failed: #" + Twine(I)); if (Name == ".sxdata") { SXData = Sec; continue; } if (Name == ".drectve") { ArrayRef Data; COFFObj->getSectionContents(Sec, Data); Directives = std::string((const char *)Data.data(), Data.size()); continue; } // Object files may have DWARF debug info or MS CodeView debug info // (or both). // // DWARF sections don't need any special handling from the perspective // of the linker; they are just a data section containing relocations. // We can just link them to complete debug info. // // CodeView needs a linker support. We need to interpret and debug // info, and then write it to a separate .pdb file. // Ignore debug info unless /debug is given. if (!Config->Debug && Name.startswith(".debug")) continue; - // CodeView sections are stored to a different vector because they are - // not linked in the regular manner. - if (Name == ".debug" || Name.startswith(".debug$")) { - DebugChunks.push_back(make(this, Sec)); - continue; - } - if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) continue; auto *C = make(this, Sec); - Chunks.push_back(C); + + // 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 + Chunks.push_back(C); + SparseChunks[I] = C; } } void ObjectFile::initializeSymbols() { uint32_t NumSymbols = COFFObj->getNumberOfSymbols(); SymbolBodies.reserve(NumSymbols); SparseSymbolBodies.resize(NumSymbols); SmallVector, 8> WeakAliases; int32_t LastSectionNumber = 0; for (uint32_t I = 0; I < NumSymbols; ++I) { // Get a COFFSymbolRef object. ErrorOr SymOrErr = COFFObj->getSymbol(I); if (!SymOrErr) fatal(SymOrErr.getError(), "broken object file: " + toString(this)); COFFSymbolRef Sym = *SymOrErr; const void *AuxP = nullptr; if (Sym.getNumberOfAuxSymbols()) AuxP = COFFObj->getSymbol(I + 1)->getRawPtr(); bool IsFirst = (LastSectionNumber != Sym.getSectionNumber()); SymbolBody *Body = nullptr; if (Sym.isUndefined()) { Body = createUndefined(Sym); } else if (Sym.isWeakExternal()) { Body = createUndefined(Sym); uint32_t TagIndex = static_cast(AuxP)->TagIndex; WeakAliases.emplace_back(Body, TagIndex); } else { Body = createDefined(Sym, AuxP, IsFirst); } if (Body) { SymbolBodies.push_back(Body); SparseSymbolBodies[I] = Body; } I += Sym.getNumberOfAuxSymbols(); LastSectionNumber = Sym.getSectionNumber(); } for (auto &KV : WeakAliases) { SymbolBody *Sym = KV.first; uint32_t Idx = KV.second; checkAndSetWeakAlias(Symtab, this, Sym, SparseSymbolBodies[Idx]); } } SymbolBody *ObjectFile::createUndefined(COFFSymbolRef Sym) { StringRef Name; COFFObj->getSymbolName(Sym, Name); return Symtab->addUndefined(Name, this, Sym.isWeakExternal())->body(); } SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, bool IsFirst) { StringRef Name; if (Sym.isCommon()) { auto *C = make(Sym); Chunks.push_back(C); COFFObj->getSymbolName(Sym, Name); Symbol *S = Symtab->addCommon(this, Name, Sym.getValue(), Sym.getGeneric(), C); return S->body(); } if (Sym.isAbsolute()) { COFFObj->getSymbolName(Sym, Name); // Skip special symbols. if (Name == "@comp.id") return nullptr; // COFF spec 5.10.1. The .sxdata section. if (Name == "@feat.00") { if (Sym.getValue() & 1) SEHCompat = true; return nullptr; } if (Sym.isExternal()) return Symtab->addAbsolute(Name, Sym)->body(); else return make(Name, Sym); } int32_t SectionNumber = Sym.getSectionNumber(); if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG) return nullptr; // Reserved sections numbers don't have contents. if (llvm::COFF::isReservedSectionNumber(SectionNumber)) fatal("broken object file: " + toString(this)); // This symbol references a section which is not present in the section // header. if ((uint32_t)SectionNumber >= SparseChunks.size()) fatal("broken object file: " + toString(this)); // Nothing else to do without a section chunk. auto *SC = cast_or_null(SparseChunks[SectionNumber]); if (!SC) return nullptr; // Handle section definitions if (IsFirst && AuxP) { auto *Aux = reinterpret_cast(AuxP); if (Aux->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) if (auto *ParentSC = cast_or_null( - SparseChunks[Aux->getNumber(Sym.isBigObj())])) + SparseChunks[Aux->getNumber(Sym.isBigObj())])) { ParentSC->addAssociative(SC); + // If we already discarded the parent, discard the child. + if (ParentSC->isDiscarded()) + SC->markDiscarded(); + } SC->Checksum = Aux->CheckSum; } DefinedRegular *B; if (Sym.isExternal()) { COFFObj->getSymbolName(Sym, Name); Symbol *S = Symtab->addRegular(this, Name, SC->isCOMDAT(), Sym.getGeneric(), SC); B = cast(S->body()); } else B = make(this, /*Name*/ "", SC->isCOMDAT(), /*IsExternal*/ false, Sym.getGeneric(), SC); if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP) SC->setSymbol(B); return B; } void ObjectFile::initializeSEH() { if (!SEHCompat || !SXData) return; ArrayRef A; COFFObj->getSectionContents(SXData, A); if (A.size() % 4 != 0) fatal(".sxdata must be an array of symbol table indices"); auto *I = reinterpret_cast(A.data()); auto *E = reinterpret_cast(A.data() + A.size()); for (; I != E; ++I) SEHandlers.insert(SparseSymbolBodies[*I]); } MachineTypes ObjectFile::getMachineType() { if (COFFObj) return static_cast(COFFObj->getMachine()); return IMAGE_FILE_MACHINE_UNKNOWN; } StringRef ltrim1(StringRef S, const char *Chars) { if (!S.empty() && strchr(Chars, S[0])) return S.substr(1); return S; } void ImportFile::parse() { const char *Buf = MB.getBufferStart(); const char *End = MB.getBufferEnd(); const auto *Hdr = reinterpret_cast(Buf); // Check if the total size is valid. if ((size_t)(End - Buf) != (sizeof(*Hdr) + Hdr->SizeOfData)) 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 = cast( Symtab->addImportData(ImpName, this)->body()); if (Hdr->getType() == llvm::COFF::IMPORT_CONST) ConstSym = cast(Symtab->addImportData(Name, this)->body()); // If type is function, we need to create a thunk which jump to an // address pointed by the __imp_ symbol. (This allows you to call // DLL functions just like regular non-DLL functions.) if (Hdr->getType() != llvm::COFF::IMPORT_CODE) return; ThunkSym = cast( Symtab->addImportThunk(Name, ImpSym, Hdr->Machine)->body()); } void BitcodeFile::parse() { Obj = check(lto::InputFile::create(MemoryBufferRef( MB.getBuffer(), Saver.save(ParentName + MB.getBufferIdentifier())))); for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) { StringRef SymName = Saver.save(ObjSym.getName()); 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(); SymbolBody *Alias = Symtab->addUndefined(Saver.save(Fallback)); checkAndSetWeakAlias(Symtab, this, Sym->body(), Alias); } else { bool IsCOMDAT = ObjSym.getComdatIndex() != -1; Sym = Symtab->addRegular(this, SymName, IsCOMDAT); } SymbolBodies.push_back(Sym->body()); } 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; default: return IMAGE_FILE_MACHINE_UNKNOWN; } } } // namespace coff } // namespace lld // Returns the last element of a path, which is supposed to be a filename. static StringRef getBasename(StringRef Path) { size_t Pos = Path.find_last_of("\\/"); if (Pos == StringRef::npos) return Path; return Path.substr(Pos + 1); } // Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)". std::string lld::toString(coff::InputFile *File) { if (!File) return "(internal)"; if (File->ParentName.empty()) return File->getName().lower(); std::string Res = (getBasename(File->ParentName) + "(" + getBasename(File->getName()) + ")") .str(); return StringRef(Res).lower(); } Index: vendor/lld/dist/COFF/Options.td =================================================================== --- vendor/lld/dist/COFF/Options.td (revision 320381) +++ vendor/lld/dist/COFF/Options.td (revision 320382) @@ -1,140 +1,139 @@ include "llvm/Option/OptParser.td" // link.exe accepts options starting with either a dash or a slash. // Flag that takes no arguments. class F : Flag<["/", "-", "-?"], name>; // Flag that takes one argument after ":". class P : Joined<["/", "-", "-?"], name#":">, HelpText; // Boolean flag suffixed by ":no". multiclass B { def "" : F; def _no : F, HelpText; } def align : P<"align", "Section alignment">; def alternatename : P<"alternatename", "Define weak alias">; def base : P<"base", "Base address of the program">; def defaultlib : P<"defaultlib", "Add the library to the list of input files">; def delayload : P<"delayload", "Delay loaded DLL name">; def entry : P<"entry", "Name of entry point symbol">; def 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 heap : P<"heap", "Size of the heap">; def implib : P<"implib", "Import library name">; def libpath : P<"libpath", "Additional library search path">; def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">; 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 out : P<"out", "Path to file to write output">; def pdb : P<"pdb", "PDB file path">; def section : P<"section", "Specify section attributes">; def stack : P<"stack", "Size of the stack">; def stub : P<"stub", "Specify DOS stub file">; def subsystem : P<"subsystem", "Specify subsystem">; def version : P<"version", "Specify a version number in the PE header">; def disallowlib : Joined<["/", "-", "-?"], "disallowlib:">, Alias; def manifest : F<"manifest">; def manifest_colon : P<"manifest", "Create manifest file">; def manifestuac : P<"manifestuac", "User access control">; def manifestfile : P<"manifestfile", "Manifest file path">; def manifestdependency : P<"manifestdependency", "Attributes for in manifest file">; def manifestinput : P<"manifestinput", "Specify manifest file">; // We cannot use multiclass P because class name "incl" is different // from its command line option name. We do this because "include" is // a reserved keyword in tablegen. def incl : Joined<["/", "-"], "include:">, HelpText<"Force symbol to be added to symbol table as undefined one">; // "def" is also a keyword. def deffile : Joined<["/", "-"], "def:">, HelpText<"Use module-definition file">; def debug : F<"debug">, HelpText<"Embed a symbol table in the image">; def debugtype : P<"debugtype", "Debug Info Options">; def dll : F<"dll">, HelpText<"Create a DLL">; def driver : P<"driver", "Generate a Windows NT Kernel Mode Driver">; def nodefaultlib_all : F<"nodefaultlib">; def noentry : F<"noentry">; def profile : F<"profile">; def swaprun_cd : F<"swaprun:cd">; def swaprun_net : F<"swaprun:net">; def verbose : F<"verbose">; def force : F<"force">, HelpText<"Allow undefined symbols when creating executables">; def force_unresolved : F<"force:unresolved">; defm allowbind: B<"allowbind", "Disable DLL binding">; defm allowisolation : B<"allowisolation", "Set NO_ISOLATION bit">; defm appcontainer : B<"appcontainer", "Image can only be run in an app container">; defm dynamicbase : B<"dynamicbase", "Disable address space layout randomization">; defm fixed : B<"fixed", "Enable base relocations">; defm highentropyva : B<"highentropyva", "Set HIGH_ENTROPY_VA bit">; defm largeaddressaware : B<"largeaddressaware", "Disable large addresses">; defm nxcompat : B<"nxcompat", "Disable data execution provention">; defm safeseh : B<"safeseh", "Produce an image with Safe Exception Handler">; defm tsaware : B<"tsaware", "Create non-Terminal Server aware executable">; def help : F<"help">; def help_q : Flag<["/?", "-?"], "">, Alias; // LLD extensions def nopdb : F<"nopdb">, HelpText<"Disable PDB generation for DWARF users">; def nosymtab : F<"nosymtab">; def msvclto : F<"msvclto">; // Flags for debugging -def dumppdb : Joined<["/", "-"], "dumppdb">; def lldmap : F<"lldmap">; def lldmap_file : Joined<["/", "-"], "lldmap:">; //============================================================================== // The flags below do nothing. They are defined only for link.exe compatibility. //============================================================================== class QF : Joined<["/", "-", "-?"], name#":">; multiclass QB { def "" : F; def _no : F; } def functionpadmin : F<"functionpadmin">; def ignoreidl : F<"ignoreidl">; def incremental : F<"incremental">; def no_incremental : F<"incremental:no">; def nologo : F<"nologo">; def throwingnew : F<"throwingnew">; def editandcontinue : F<"editandcontinue">; def fastfail : F<"fastfail">; def delay : QF<"delay">; def errorreport : QF<"errorreport">; def idlout : QF<"idlout">; def ignore : QF<"ignore">; def maxilksize : QF<"maxilksize">; def pdbaltpath : QF<"pdbaltpath">; def tlbid : QF<"tlbid">; def tlbout : QF<"tlbout">; def verbose_all : QF<"verbose">; def guardsym : QF<"guardsym">; defm wx : QB<"wx">; Index: vendor/lld/dist/COFF/PDB.cpp =================================================================== --- vendor/lld/dist/COFF/PDB.cpp (revision 320381) +++ vendor/lld/dist/COFF/PDB.cpp (revision 320382) @@ -1,245 +1,380 @@ //===- PDB.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "PDB.h" #include "Chunks.h" #include "Config.h" #include "Error.h" #include "SymbolTable.h" #include "Symbols.h" #include "llvm/DebugInfo/CodeView/CVDebugRecord.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" +#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" -#include "llvm/DebugInfo/CodeView/SymbolDumper.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" #include "llvm/Object/COFF.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/Endian.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" #include using namespace lld; using namespace lld::coff; using namespace llvm; using namespace llvm::codeview; -using namespace llvm::support; -using namespace llvm::support::endian; using llvm::object::coff_section; static ExitOnError ExitOnErr; // Returns a list of all SectionChunks. static void addSectionContribs(SymbolTable *Symtab, pdb::DbiStreamBuilder &DbiBuilder) { for (Chunk *C : Symtab->getChunks()) if (auto *SC = dyn_cast(C)) DbiBuilder.addSectionContrib(SC->File->ModuleDBI, SC->Header); } static SectionChunk *findByName(std::vector &Sections, StringRef Name) { for (SectionChunk *C : Sections) if (C->getSectionName() == Name) return C; return nullptr; } -static ArrayRef getDebugSection(ObjectFile *File, StringRef SecName) { - SectionChunk *Sec = findByName(File->getDebugChunks(), SecName); - if (!Sec) - return {}; - +static ArrayRef consumeDebugMagic(ArrayRef Data, + StringRef SecName) { // First 4 bytes are section magic. - ArrayRef Data = Sec->getContents(); if (Data.size() < 4) fatal(SecName + " too short"); - if (read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC) + if (support::endian::read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC) fatal(SecName + " has an invalid magic"); return Data.slice(4); } +static ArrayRef getDebugSection(ObjectFile *File, StringRef SecName) { + if (SectionChunk *Sec = findByName(File->getDebugChunks(), SecName)) + return consumeDebugMagic(Sec->getContents(), SecName); + return {}; +} + static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder, - codeview::TypeTableBuilder &TypeTable) { + TypeTableBuilder &TypeTable) { // Start the TPI or IPI stream header. TpiBuilder.setVersionHeader(pdb::PdbTpiV80); // Flatten the in memory type table. TypeTable.ForEachRecord([&](TypeIndex TI, ArrayRef Rec) { // FIXME: Hash types. TpiBuilder.addTypeRecord(Rec, None); }); } +static void mergeDebugT(ObjectFile *File, + TypeTableBuilder &IDTable, + TypeTableBuilder &TypeTable, + SmallVectorImpl &TypeIndexMap, + pdb::PDBTypeServerHandler &Handler) { + ArrayRef Data = getDebugSection(File, ".debug$T"); + if (Data.empty()) + return; + + BinaryByteStream Stream(Data, support::little); + CVTypeArray Types; + BinaryStreamReader Reader(Stream); + Handler.addSearchPath(sys::path::parent_path(File->getName())); + if (auto EC = Reader.readArray(Types, Reader.getLength())) + fatal(EC, "Reader::readArray failed"); + if (auto Err = mergeTypeAndIdRecords(IDTable, TypeTable, + TypeIndexMap, &Handler, Types)) + fatal(Err, "codeview::mergeTypeStreams failed"); +} + +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 bool remapTypesInSymbolRecord(ObjectFile *File, + MutableArrayRef Contents, + ArrayRef TypeIndexMap, + ArrayRef TypeRefs) { + for (const TiReference &Ref : TypeRefs) { + unsigned ByteSize = Ref.Count * sizeof(TypeIndex); + if (Contents.size() < Ref.Offset + ByteSize) { + log("ignoring short symbol record"); + return false; + } + MutableArrayRef TIs( + reinterpret_cast(Contents.data() + Ref.Offset), Ref.Count); + for (TypeIndex &TI : TIs) + if (!remapTypeIndex(TI, TypeIndexMap)) { + log("ignoring symbol record in " + File->getName() + + " with bad type index 0x" + utohexstr(TI.getIndex())); + return false; + } + } + return true; +} + +/// MSVC translates S_PROC_ID_END to S_END. +uint16_t canonicalizeSymbolKind(SymbolKind Kind) { + if (Kind == SymbolKind::S_PROC_ID_END) + return SymbolKind::S_END; + return Kind; +} + +/// Copy the symbol record. In a PDB, symbol records must be 4 byte aligned. +/// The object file may not be aligned. +static MutableArrayRef copySymbolForPdb(const CVSymbol &Sym, + BumpPtrAllocator &Alloc) { + size_t Size = alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb)); + assert(Size >= 4 && "record too short"); + assert(Size <= MaxRecordLength && "record too long"); + void *Mem = Alloc.Allocate(Size, 4); + + // Copy the symbol record and zero out any padding bytes. + MutableArrayRef NewData(reinterpret_cast(Mem), Size); + memcpy(NewData.data(), Sym.data().data(), Sym.length()); + memset(NewData.data() + Sym.length(), 0, Size - Sym.length()); + + // Update the record prefix length. It should point to the beginning of the + // next record. MSVC does some canonicalization of the record kind, so we do + // that as well. + auto *Prefix = reinterpret_cast(Mem); + Prefix->RecordKind = canonicalizeSymbolKind(Sym.kind()); + Prefix->RecordLen = Size - 2; + return NewData; +} + +static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File, + ArrayRef TypeIndexMap, + BinaryStreamRef SymData) { + // FIXME: Improve error recovery by warning and skipping records when + // possible. + CVSymbolArray Syms; + BinaryStreamReader Reader(SymData); + ExitOnErr(Reader.readArray(Syms, Reader.getLength())); + for (const CVSymbol &Sym : Syms) { + // Discover type index references in the record. Skip it if we don't know + // where they are. + SmallVector TypeRefs; + if (!discoverTypeIndices(Sym, TypeRefs)) { + log("ignoring unknown symbol record with kind 0x" + utohexstr(Sym.kind())); + continue; + } + + // Copy the symbol record so we can mutate it. + MutableArrayRef NewData = copySymbolForPdb(Sym, Alloc); + + // Re-map all the type index references. + MutableArrayRef Contents = + NewData.drop_front(sizeof(RecordPrefix)); + if (!remapTypesInSymbolRecord(File, Contents, TypeIndexMap, TypeRefs)) + continue; + + // FIXME: Fill in "Parent" and "End" fields by maintaining a stack of + // scopes. + + // Add the symbol to the module. + File->ModuleDBI->addSymbol(CVSymbol(Sym.kind(), NewData)); + } +} + +// Allocate memory for a .debug$S section and relocate it. +static ArrayRef relocateDebugChunk(BumpPtrAllocator &Alloc, + SectionChunk *DebugChunk) { + uint8_t *Buffer = Alloc.Allocate(DebugChunk->getSize()); + assert(DebugChunk->OutputSectionOff == 0 && + "debug sections should not be in output sections"); + DebugChunk->writeTo(Buffer); + return consumeDebugMagic(makeArrayRef(Buffer, DebugChunk->getSize()), + ".debug$S"); +} + // Add all object files to the PDB. Merge .debug$T sections into IpiData and // TpiData. -static void addObjectsToPDB(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder, - codeview::TypeTableBuilder &TypeTable, - codeview::TypeTableBuilder &IDTable) { +static void addObjectsToPDB(BumpPtrAllocator &Alloc, SymbolTable *Symtab, + pdb::PDBFileBuilder &Builder, + TypeTableBuilder &TypeTable, + TypeTableBuilder &IDTable) { // Follow type servers. If the same type server is encountered more than // once for this instance of `PDBTypeServerHandler` (for example if many // object files reference the same TypeServer), the types from the // TypeServer will only be visited once. pdb::PDBTypeServerHandler Handler; + // PDBs use a single global string table for filenames in the file checksum + // table. + auto PDBStrTab = std::make_shared(); + // Visit all .debug$T sections to add them to Builder. for (ObjectFile *File : Symtab->ObjectFiles) { // 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); StringRef Name = InArchive ? File->getName() : StringRef(Path); File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name)); File->ModuleDBI->setObjFileName(Path); - // FIXME: Walk the .debug$S sections and add them. Do things like recording - // source files. + // 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. + SmallVector TypeIndexMap; + mergeDebugT(File, IDTable, TypeTable, TypeIndexMap, Handler); - ArrayRef Data = getDebugSection(File, ".debug$T"); - if (Data.empty()) - continue; + // Now do all line info. + for (SectionChunk *DebugChunk : File->getDebugChunks()) { + if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S") + continue; - BinaryByteStream Stream(Data, support::little); - codeview::CVTypeArray Types; - BinaryStreamReader Reader(Stream); - SmallVector SourceToDest; - Handler.addSearchPath(llvm::sys::path::parent_path(File->getName())); - if (auto EC = Reader.readArray(Types, Reader.getLength())) - fatal(EC, "Reader::readArray failed"); - if (auto Err = codeview::mergeTypeAndIdRecords( - IDTable, TypeTable, SourceToDest, &Handler, Types)) - fatal(Err, "codeview::mergeTypeStreams failed"); + ArrayRef RelocatedDebugContents = + relocateDebugChunk(Alloc, DebugChunk); + if (RelocatedDebugContents.empty()) + continue; + + DebugSubsectionArray Subsections; + BinaryStreamReader Reader(RelocatedDebugContents, support::little); + ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size())); + + DebugStringTableSubsectionRef CVStrTab; + DebugChecksumsSubsectionRef Checksums; + for (const DebugSubsectionRecord &SS : Subsections) { + switch (SS.kind()) { + case DebugSubsectionKind::StringTable: + ExitOnErr(CVStrTab.initialize(SS.getRecordData())); + break; + case DebugSubsectionKind::FileChecksums: + 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: + mergeSymbolRecords(Alloc, File, TypeIndexMap, SS.getRecordData()); + break; + default: + // FIXME: Process the rest of the subsections. + break; + } + } + + if (Checksums.valid()) { + // Make a new file checksum table that refers to offsets in the PDB-wide + // string table. Generally the string table subsection appears after the + // checksum table, so we have to do this after looping over all the + // subsections. + if (!CVStrTab.valid()) + fatal(".debug$S sections must have both a string table subsection " + "and a checksum subsection table or neither"); + auto NewChecksums = + make_unique(*PDBStrTab); + for (FileChecksumEntry &FC : Checksums) { + StringRef FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); + ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile( + *File->ModuleDBI, FileName)); + NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum); + } + File->ModuleDBI->addDebugSubsection(std::move(NewChecksums)); + } + } } + Builder.getStringTableBuilder().setStrings(*PDBStrTab); + // Construct TPI stream contents. addTypeInfo(Builder.getTpiBuilder(), TypeTable); // Construct IPI stream contents. addTypeInfo(Builder.getIpiBuilder(), IDTable); } -static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) { - ListScope LS(W, "DebugT"); - ArrayRef Data = getDebugSection(File, ".debug$T"); - if (Data.empty()) - return; - - LazyRandomTypeCollection Types(Data, 100); - TypeDumpVisitor TDV(Types, &W, false); - // Use a default implementation that does not follow type servers and instead - // just dumps the contents of the TypeServer2 record. - if (auto EC = codeview::visitTypeStream(Types, TDV)) - fatal(EC, "CVTypeDumper::dump failed"); -} - -static void dumpDebugS(ScopedPrinter &W, ObjectFile *File) { - ListScope LS(W, "DebugS"); - ArrayRef Data = getDebugSection(File, ".debug$S"); - if (Data.empty()) - return; - - BinaryByteStream Stream(Data, llvm::support::little); - CVSymbolArray Symbols; - BinaryStreamReader Reader(Stream); - if (auto EC = Reader.readArray(Symbols, Reader.getLength())) - fatal(EC, "StreamReader.readArray failed"); - - TypeDatabase TDB(0); - CVSymbolDumper SymbolDumper(W, TDB, CodeViewContainer::ObjectFile, nullptr, - false); - if (auto EC = SymbolDumper.dump(Symbols)) - fatal(EC, "CVSymbolDumper::dump failed"); -} - -// Dump CodeView debug info. This is for debugging. -static void dumpCodeView(SymbolTable *Symtab) { - ScopedPrinter W(outs()); - - for (ObjectFile *File : Symtab->ObjectFiles) { - dumpDebugT(W, File); - dumpDebugS(W, File); - } -} - // Creates a PDB file. void coff::createPDB(StringRef Path, SymbolTable *Symtab, ArrayRef SectionTable, const llvm::codeview::DebugInfo *DI) { - if (Config->DumpPdb) - dumpCodeView(Symtab); - BumpPtrAllocator Alloc; pdb::PDBFileBuilder Builder(Alloc); ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize // Create streams in MSF for predefined streams, namely // PDB, TPI, DBI and IPI. for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I) ExitOnErr(Builder.getMsfBuilder().addStream(0)); // Add an Info stream. auto &InfoBuilder = Builder.getInfoBuilder(); InfoBuilder.setAge(DI ? DI->PDB70.Age : 0); pdb::PDB_UniqueId uuid{}; if (DI) memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid)); InfoBuilder.setGuid(uuid); // Should be the current time, but set 0 for reproducibilty. InfoBuilder.setSignature(0); InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70); // Add an empty DPI stream. pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); DbiBuilder.setVersionHeader(pdb::PdbDbiV110); - codeview::TypeTableBuilder TypeTable(BAlloc); - codeview::TypeTableBuilder IDTable(BAlloc); - addObjectsToPDB(Symtab, Builder, TypeTable, IDTable); + TypeTableBuilder TypeTable(BAlloc); + TypeTableBuilder IDTable(BAlloc); + addObjectsToPDB(Alloc, Symtab, Builder, TypeTable, IDTable); // Add Section Contributions. addSectionContribs(Symtab, DbiBuilder); // Add Section Map stream. ArrayRef Sections = { (const object::coff_section *)SectionTable.data(), SectionTable.size() / sizeof(object::coff_section)}; std::vector SectionMap = pdb::DbiStreamBuilder::createSectionMap(Sections); DbiBuilder.setSectionMap(SectionMap); ExitOnErr(DbiBuilder.addModuleInfo("* Linker *")); // Add COFF section header stream. ExitOnErr( DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable)); // Write to a file. ExitOnErr(Builder.commit(Path)); } Index: vendor/lld/dist/COFF/Strings.cpp =================================================================== --- vendor/lld/dist/COFF/Strings.cpp (revision 320381) +++ vendor/lld/dist/COFF/Strings.cpp (revision 320382) @@ -1,30 +1,35 @@ //===- Strings.cpp -------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Strings.h" +#include #if defined(_MSC_VER) #include #include #pragma comment(lib, "dbghelp.lib") #endif using namespace lld; using namespace lld::coff; using namespace llvm; Optional coff::demangle(StringRef S) { #if defined(_MSC_VER) + // UnDecorateSymbolName is not thread-safe, so we need a mutex. + static std::mutex Mu; + std::lock_guard Lock(Mu); + char Buf[4096]; if (S.startswith("?")) if (size_t Len = UnDecorateSymbolName(S.str().c_str(), Buf, sizeof(Buf), 0)) return std::string(Buf, Len); #endif return None; } Index: vendor/lld/dist/COFF/SymbolTable.cpp =================================================================== --- vendor/lld/dist/COFF/SymbolTable.cpp (revision 320381) +++ vendor/lld/dist/COFF/SymbolTable.cpp (revision 320382) @@ -1,369 +1,375 @@ //===- 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 "Error.h" #include "LTO.h" #include "Memory.h" #include "Symbols.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 { enum SymbolPreference { SP_EXISTING = -1, SP_CONFLICT = 0, SP_NEW = 1, }; /// Checks if an existing symbol S should be kept or replaced by a new symbol. /// Returns SP_EXISTING when S should be kept, SP_NEW when the new symbol /// should be kept, and SP_CONFLICT if no valid resolution exists. static SymbolPreference compareDefined(Symbol *S, bool WasInserted, bool NewIsCOMDAT) { // If the symbol wasn't previously known, the new symbol wins by default. if (WasInserted || !isa(S->body())) return SP_NEW; // If the existing symbol is a DefinedRegular, both it and the new symbol // must be comdats. In that case, we have no reason to prefer one symbol // over the other, and we keep the existing one. If one of the symbols // is not a comdat, we report a conflict. if (auto *R = dyn_cast(S->body())) { if (NewIsCOMDAT && R->isCOMDAT()) return SP_EXISTING; else return SP_CONFLICT; } // Existing symbol is not a DefinedRegular; new symbol wins. return SP_NEW; } SymbolTable *Symtab; void SymbolTable::addFile(InputFile *File) { log("Reading " + toString(File)); File->parse(); MachineTypes MT = File->getMachineType(); if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { Config->Machine = MT; } else if (MT != IMAGE_FILE_MACHINE_UNKNOWN && Config->Machine != MT) { fatal(toString(File) + ": machine type " + machineToStr(MT) + " conflicts with " + machineToStr(Config->Machine)); } if (auto *F = dyn_cast(File)) { ObjectFiles.push_back(F); } else if (auto *F = dyn_cast(File)) { BitcodeFiles.push_back(F); } else if (auto *F = dyn_cast(File)) { ImportFiles.push_back(F); } StringRef S = File->getDirectives(); if (S.empty()) return; log("Directives: " + toString(File) + ": " + S); Driver->parseDirectives(S); } void SymbolTable::reportRemainingUndefines() { SmallPtrSet Undefs; for (auto &I : Symtab) { Symbol *Sym = I.second; auto *Undef = dyn_cast(Sym->body()); 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 resolve weak aliases by replacing the alias's SymbolBody with the // target's SymbolBody. This causes all SymbolBody pointers referring to // the old symbol to instead refer to the new symbol. However, we can't // just blindly copy sizeof(Symbol::Body) bytes from D to Sym->Body // because D may be an internal symbol, and internal symbols are stored as // "unparented" SymbolBodies. 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->Body.buffer, D, sizeof(DefinedRegular)); else if (isa(D)) memcpy(Sym->Body.buffer, D, sizeof(DefinedAbsolute)); else // No other internal symbols are possible. Sym->Body = D->symbol()->Body; 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->body())) { auto *D = cast(Imp->body()); replaceBody(Sym, Name, D); LocalImportChunks.push_back( cast(Sym->body())->getChunk()); continue; } } // Remaining undefined symbols are not fatal if /force is specified. // They are replaced with dummy defined symbols. if (Config->Force) replaceBody(Sym, Name, 0); Undefs.insert(Sym->body()); } if (Undefs.empty()) return; for (SymbolBody *B : Config->GCRoot) if (Undefs.count(B)) warn(": undefined symbol: " + B->getName()); for (ObjectFile *File : ObjectFiles) for (SymbolBody *Sym : File->getSymbols()) if (Undefs.count(Sym)) warn(toString(File) + ": undefined symbol: " + Sym->getName()); if (!Config->Force) fatal("link failed"); } std::pair SymbolTable::insert(StringRef Name) { Symbol *&Sym = Symtab[CachedHashStringRef(Name)]; if (Sym) return {Sym, false}; Sym = make(); Sym->IsUsedInRegularObj = false; Sym->PendingArchiveLoad = false; return {Sym, true}; } Symbol *SymbolTable::addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); if (!F || !isa(F)) S->IsUsedInRegularObj = true; if (WasInserted || (isa(S->body()) && IsWeakAlias)) { replaceBody(S, Name); return S; } if (auto *L = dyn_cast(S->body())) { 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) { replaceBody(S, F, Sym); return; } auto *U = dyn_cast(S->body()); 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->body()) + " in " + toString(Existing->body()->getFile()) + " and in " + (NewFile ? toString(NewFile) : "(internal)")); } Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N); S->IsUsedInRegularObj = true; if (WasInserted || isa(S->body()) || isa(S->body())) replaceBody(S, N, Sym); else if (!isa(S->body())) reportDuplicate(S, nullptr); return S; } Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N); S->IsUsedInRegularObj = true; if (WasInserted || isa(S->body()) || isa(S->body())) replaceBody(S, N, VA); else if (!isa(S->body())) reportDuplicate(S, nullptr); return S; } -Symbol *SymbolTable::addRelative(StringRef N, uint64_t VA) { +Symbol *SymbolTable::addSynthetic(StringRef N, Chunk *C) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N); S->IsUsedInRegularObj = true; if (WasInserted || isa(S->body()) || isa(S->body())) - replaceBody(S, N, VA); + replaceBody(S, N, C); else if (!isa(S->body())) reportDuplicate(S, nullptr); return S; } Symbol *SymbolTable::addRegular(InputFile *F, StringRef N, bool IsCOMDAT, const coff_symbol_generic *Sym, SectionChunk *C) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N); if (!isa(F)) S->IsUsedInRegularObj = true; SymbolPreference SP = compareDefined(S, WasInserted, IsCOMDAT); if (SP == SP_CONFLICT) { reportDuplicate(S, F); } else if (SP == SP_NEW) { replaceBody(S, F, N, IsCOMDAT, /*IsExternal*/ true, Sym, C); + } else if (SP == SP_EXISTING && IsCOMDAT && C) { + C->markDiscarded(); + // Discard associative chunks that we've parsed so far. No need to recurse + // because an associative section cannot have children. + for (SectionChunk *Child : C->children()) + Child->markDiscarded(); } return S; } Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size, const coff_symbol_generic *Sym, CommonChunk *C) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N); if (!isa(F)) S->IsUsedInRegularObj = true; if (WasInserted || !isa(S->body())) replaceBody(S, F, N, Size, Sym, C); else if (auto *DC = dyn_cast(S->body())) if (Size > DC->getSize()) replaceBody(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); S->IsUsedInRegularObj = true; if (WasInserted || isa(S->body()) || isa(S->body())) replaceBody(S, N, F); else if (!isa(S->body())) reportDuplicate(S, nullptr); return S; } Symbol *SymbolTable::addImportThunk(StringRef Name, DefinedImportData *ID, uint16_t Machine) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); S->IsUsedInRegularObj = true; if (WasInserted || isa(S->body()) || isa(S->body())) replaceBody(S, Name, ID, Machine); else if (!isa(S->body())) reportDuplicate(S, nullptr); return S; } std::vector SymbolTable::getChunks() { std::vector Res; for (ObjectFile *File : ObjectFiles) { std::vector &V = File->getChunks(); Res.insert(Res.end(), V.begin(), V.end()); } return Res; } Symbol *SymbolTable::find(StringRef Name) { auto It = Symtab.find(CachedHashStringRef(Name)); if (It == Symtab.end()) return nullptr; return It->second; } Symbol *SymbolTable::findUnderscore(StringRef Name) { if (Config->Machine == I386) return find(("_" + Name).str()); return find(Name); } StringRef SymbolTable::findByPrefix(StringRef Prefix) { for (auto Pair : Symtab) { 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->body())) return Name; if (Config->Machine != I386) return findByPrefix(("?" + Name + "@@Y").str()); if (!Name.startswith("_")) return ""; // Search for x86 C function. StringRef S = findByPrefix((Name + "@").str()); if (!S.empty()) return S; // Search for x86 C++ non-member function. return findByPrefix(("?" + Name.substr(1) + "@@Y").str()); } void SymbolTable::mangleMaybe(SymbolBody *B) { auto *U = dyn_cast(B); if (!U || U->WeakAlias) return; StringRef Alias = findMangle(U->getName()); if (!Alias.empty()) U->WeakAlias = addUndefined(Alias); } SymbolBody *SymbolTable::addUndefined(StringRef Name) { return addUndefined(Name, nullptr, false)->body(); } std::vector SymbolTable::compileBitcodeFiles() { LTO.reset(new BitcodeCompiler); for (BitcodeFile *F : BitcodeFiles) LTO->add(*F); return LTO->compile(); } void SymbolTable::addCombinedLTOObjects() { if (BitcodeFiles.empty()) return; for (StringRef Object : compileBitcodeFiles()) { auto *Obj = make(MemoryBufferRef(Object, "lto.tmp")); Obj->parse(); ObjectFiles.push_back(Obj); } } } // namespace coff } // namespace lld Index: vendor/lld/dist/COFF/SymbolTable.h =================================================================== --- vendor/lld/dist/COFF/SymbolTable.h (revision 320381) +++ vendor/lld/dist/COFF/SymbolTable.h (revision 320382) @@ -1,124 +1,124 @@ //===- 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 SymbolBody; struct Symbol; // SymbolTable is a bucket of all known symbols, including defined, // undefined, or lazy symbols (the last one is symbols in archive // files whose archive members are not yet loaded). // // We put all symbols of all files to a SymbolTable, and the // SymbolTable selects the "best" symbols if there are name // conflicts. For example, obviously, a defined symbol is better than // an undefined symbol. Or, if there's a conflict between a lazy and a // undefined, it'll read an archive member to read a real definition // to replace the lazy symbol. The logic is implemented in the // add*() functions, which are called by input files as they are parsed. // There is one add* function per symbol type. class SymbolTable { public: void addFile(InputFile *File); // Try to resolve any undefined symbols and update the symbol table // accordingly, then print an error message for any remaining undefined // symbols. void reportRemainingUndefines(); // Returns a list of chunks of selected symbols. std::vector getChunks(); // Returns a symbol for a given name. Returns a nullptr if not found. Symbol *find(StringRef Name); Symbol *findUnderscore(StringRef Name); // Occasionally we have to resolve an undefined symbol to its // mangled symbol. This function tries to find a mangled name // for U from the symbol table, and if found, set the symbol as // a weak alias for U. void mangleMaybe(SymbolBody *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(); // The writer needs to handle DLL import libraries specially in // order to create the import descriptor table. std::vector ImportFiles; // The writer needs to infer the machine type from the object files. std::vector ObjectFiles; // Creates an Undefined symbol for a given name. SymbolBody *addUndefined(StringRef Name); - Symbol *addRelative(StringRef N, uint64_t VA); + 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, bool IsCOMDAT, const llvm::object::coff_symbol_generic *S = nullptr, SectionChunk *C = 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; private: std::pair insert(StringRef Name); StringRef findByPrefix(StringRef Prefix); llvm::DenseMap Symtab; std::vector BitcodeFiles; std::unique_ptr LTO; }; extern SymbolTable *Symtab; } // namespace coff } // namespace lld #endif Index: vendor/lld/dist/COFF/Symbols.cpp =================================================================== --- vendor/lld/dist/COFF/Symbols.cpp (revision 320381) +++ vendor/lld/dist/COFF/Symbols.cpp (revision 320382) @@ -1,86 +1,88 @@ //===- 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 "Error.h" #include "InputFiles.h" #include "Memory.h" #include "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::SymbolBody &B) { if (Optional S = coff::demangle(B.getName())) return ("\"" + *S + "\" (" + B.getName() + ")").str(); return B.getName(); } namespace lld { namespace coff { StringRef SymbolBody::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 *SymbolBody::getFile() { if (auto *Sym = dyn_cast(this)) return Sym->File; if (auto *Sym = dyn_cast(this)) return Sym->File; return nullptr; } COFFSymbolRef DefinedCOFF::getCOFFSymbol() { size_t SymSize = cast(File)->getCOFFObj()->getSymbolTableEntrySize(); if (SymSize == sizeof(coff_symbol16)) return COFFSymbolRef(reinterpret_cast(Sym)); assert(SymSize == sizeof(coff_symbol32)); return COFFSymbolRef(reinterpret_cast(Sym)); } +uint16_t DefinedAbsolute::OutputSectionIndex = 0; + static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) { if (Machine == AMD64) return make(S); if (Machine == I386) 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 (SymbolBody *A = WeakAlias; A; A = cast(A)->WeakAlias) if (auto *D = dyn_cast(A)) return D; return nullptr; } } // namespace coff } // namespace lld Index: vendor/lld/dist/COFF/Symbols.h =================================================================== --- vendor/lld/dist/COFF/Symbols.h (revision 320381) +++ vendor/lld/dist/COFF/Symbols.h (revision 320382) @@ -1,419 +1,428 @@ //===- 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 "Memory.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFF.h" #include #include #include namespace lld { namespace coff { using llvm::object::Archive; using llvm::object::COFFSymbolRef; using llvm::object::coff_import_header; using llvm::object::coff_symbol_generic; class ArchiveFile; class InputFile; class ObjectFile; struct Symbol; class SymbolTable; // The base class for real symbol classes. class SymbolBody { public: enum Kind { // The order of these is significant. We start with the regular defined // symbols as those are the most prevelant and the zero tag is the cheapest // to set. Among the defined kinds, the lower the kind is preferred over // the higher kind when testing wether one symbol should take precedence // over another. DefinedRegularKind = 0, DefinedCommonKind, DefinedLocalImportKind, DefinedImportThunkKind, DefinedImportDataKind, DefinedAbsoluteKind, - DefinedRelativeKind, + DefinedSyntheticKind, UndefinedKind, LazyKind, LastDefinedCOFFKind = DefinedCommonKind, - LastDefinedKind = DefinedRelativeKind, + LastDefinedKind = DefinedSyntheticKind, }; Kind kind() const { return static_cast(SymbolKind); } // Returns true if this is an external symbol. bool isExternal() { return IsExternal; } // Returns the symbol name. StringRef getName(); // Returns the file from which this symbol was created. InputFile *getFile(); Symbol *symbol(); const Symbol *symbol() const { return const_cast(this)->symbol(); } protected: friend SymbolTable; explicit SymbolBody(Kind K, StringRef N = "") : SymbolKind(K), IsExternal(true), IsCOMDAT(false), WrittenToSymtab(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; protected: StringRef Name; }; // The base class for any defined symbols, including absolute symbols, // etc. class Defined : public SymbolBody { public: Defined(Kind K, StringRef N) : SymbolBody(K, N) {} static bool classof(const SymbolBody *S) { return S->kind() <= LastDefinedKind; } // Returns the RVA (relative virtual address) of this symbol. The // writer sets and uses RVAs. uint64_t getRVA(); // Returns the RVA relative to the beginning of the output section. // Used to implement SECREL relocation type. - uint64_t getSecrel(); + uint32_t getSecrel(); // Returns the output section index. // Used to implement SECTION relocation type. - uint64_t getSectionIndex(); + uint16_t getSectionIndex(); // Returns true if this symbol points to an executable (e.g. .text) section. // Used to implement ARM relocations. bool isExecutable(); }; // Symbols defined via a COFF object file 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 SymbolBody; public: DefinedCOFF(Kind K, InputFile *F, StringRef N, const coff_symbol_generic *S) : Defined(K, N), File(F), Sym(S) {} static bool classof(const SymbolBody *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 SymbolBody *S) { return S->kind() == DefinedRegularKind; } uint64_t getRVA() { return (*Data)->getRVA() + Sym->Value; } bool isCOMDAT() { return IsCOMDAT; } SectionChunk *getChunk() { return *Data; } uint32_t getValue() { return Sym->Value; } + uint32_t getSecrel(); private: 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 SymbolBody *S) { return S->kind() == DefinedCommonKind; } uint64_t getRVA() { return Data->getRVA(); } + uint32_t getSecrel() { return Data->OutputSectionOff; } + uint16_t getSectionIndex(); 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 SymbolBody *S) { return S->kind() == DefinedAbsoluteKind; } uint64_t getRVA() { return VA - Config->ImageBase; } void setVA(uint64_t V) { VA = V; } + // The sentinel absolute symbol section index. Section index relocations + // against absolute symbols resolve to this 16 bit number, and it is the + // largest valid section index plus one. This is written by the Writer. + static uint16_t OutputSectionIndex; + private: uint64_t VA; }; -// This is a kind of absolute symbol but relative to the image base. -// Unlike absolute symbols, relocations referring this kind of symbols -// are subject of the base relocation. This type is used rarely -- -// mainly for __ImageBase. -class DefinedRelative : public Defined { +// This symbol is used for linker-synthesized symbols like __ImageBase and +// __safe_se_handler_table. +class DefinedSynthetic : public Defined { public: - explicit DefinedRelative(StringRef Name, uint64_t V = 0) - : Defined(DefinedRelativeKind, Name), RVA(V) {} + explicit DefinedSynthetic(StringRef Name, Chunk *C) + : Defined(DefinedSyntheticKind, Name), C(C) {} static bool classof(const SymbolBody *S) { - return S->kind() == DefinedRelativeKind; + return S->kind() == DefinedSyntheticKind; } - uint64_t getRVA() { return RVA; } - void setRVA(uint64_t V) { RVA = V; } + // A null chunk indicates that this is __ImageBase. Otherwise, this is some + // other synthesized chunk, like SEHTableChunk. + uint32_t getRVA() const { return C ? C->getRVA() : 0; } + uint32_t getSecrel() const { return C ? C->OutputSectionOff : 0; } + Chunk *getChunk() const { return C; } private: - uint64_t RVA; + 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 SymbolBody { public: Lazy(ArchiveFile *F, const Archive::Symbol S) : SymbolBody(LazyKind, S.getName()), File(F), Sym(S) {} static bool classof(const SymbolBody *S) { return S->kind() == LazyKind; } ArchiveFile *File; private: friend SymbolTable; private: const Archive::Symbol Sym; }; // Undefined symbols. class Undefined : public SymbolBody { public: explicit Undefined(StringRef N) : SymbolBody(UndefinedKind, N) {} static bool classof(const SymbolBody *S) { return S->kind() == UndefinedKind; } // An undefined symbol can have a fallback symbol which gives an // undefined symbol a second chance if it would remain undefined. // If it remains undefined, it'll be replaced with whatever the // Alias pointer points to. SymbolBody *WeakAlias = nullptr; // If this symbol is external weak, try to resolve it to a defined // symbol by searching the chain of fallback symbols. Returns the symbol if // successful, otherwise returns null. Defined *getWeakAlias(); }; // Windows-specific classes. // This class represents a symbol imported from a DLL. This has two // names for internal use and external use. The former is used for // name resolution, and the latter is used for the import descriptor // table in an output. The former has "__imp_" prefix. class DefinedImportData : public Defined { public: DefinedImportData(StringRef N, ImportFile *F) : Defined(DefinedImportDataKind, N), File(F) { } static bool classof(const SymbolBody *S) { return S->kind() == DefinedImportDataKind; } uint64_t getRVA() { return File->Location->getRVA(); } StringRef getDLLName() { return File->DLLName; } StringRef getExternalName() { return File->ExternalName; } void setLocation(Chunk *AddressTable) { File->Location = AddressTable; } 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 SymbolBody *S) { return S->kind() == DefinedImportThunkKind; } uint64_t getRVA() { return Data->getRVA(); } Chunk *getChunk() { return Data; } DefinedImportData *WrappedSym; private: Chunk *Data; }; // If you have a symbol "__imp_foo" in your object file, a symbol name // "foo" becomes automatically available as a pointer to "__imp_foo". // This class is for such automatically-created symbols. // Yes, this is an odd feature. We didn't intend to implement that. // This is here just for compatibility with MSVC. class DefinedLocalImport : public Defined { public: DefinedLocalImport(StringRef N, Defined *S) : Defined(DefinedLocalImportKind, N), Data(make(S)) {} static bool classof(const SymbolBody *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 DefinedRelativeKind: - 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"); } // A real symbol object, SymbolBody, is usually stored within a Symbol. There's // always one Symbol for each symbol name. The resolver updates the SymbolBody // stored in the Body field of this object as it resolves symbols. Symbol also // holds computed properties of symbol names. struct Symbol { // 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; // This field is used to store the Symbol's SymbolBody. This instantiation of // AlignedCharArrayUnion gives us a struct with a char array field that is // large and aligned enough to store any derived class of SymbolBody. llvm::AlignedCharArrayUnion< - DefinedRegular, DefinedCommon, DefinedAbsolute, DefinedRelative, Lazy, + DefinedRegular, DefinedCommon, DefinedAbsolute, DefinedSynthetic, Lazy, Undefined, DefinedImportData, DefinedImportThunk, DefinedLocalImport> Body; SymbolBody *body() { return reinterpret_cast(Body.buffer); } const SymbolBody *body() const { return const_cast(this)->body(); } }; template void replaceBody(Symbol *S, ArgT &&... Arg) { static_assert(sizeof(T) <= sizeof(S->Body), "Body too small"); static_assert(alignof(T) <= alignof(decltype(S->Body)), "Body not aligned enough"); assert(static_cast(static_cast(nullptr)) == nullptr && "Not a SymbolBody"); new (S->Body.buffer) T(std::forward(Arg)...); } inline Symbol *SymbolBody::symbol() { assert(isExternal()); return reinterpret_cast(reinterpret_cast(this) - offsetof(Symbol, Body)); } } // namespace coff std::string toString(coff::SymbolBody &B); } // namespace lld #endif Index: vendor/lld/dist/COFF/Writer.cpp =================================================================== --- vendor/lld/dist/COFF/Writer.cpp (revision 320381) +++ vendor/lld/dist/COFF/Writer.cpp (revision 320382) @@ -1,894 +1,950 @@ //===- 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 "Error.h" #include "InputFiles.h" #include "MapFile.h" #include "Memory.h" #include "PDB.h" #include "SymbolTable.h" #include "Symbols.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Parallel.h" #include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include using namespace llvm; using namespace llvm::COFF; using namespace llvm::object; using namespace llvm::support; using namespace llvm::support::endian; using namespace lld; using namespace lld::coff; static const int SectorSize = 512; static const int DOSStubSize = 64; static const int NumberfOfDataDirectory = 16; namespace { class DebugDirectoryChunk : public Chunk { public: DebugDirectoryChunk(const std::vector &R) : Records(R) {} size_t getSize() const override { return Records.size() * sizeof(debug_directory); } void writeTo(uint8_t *B) const override { auto *D = reinterpret_cast(B + OutputSectionOff); for (const Chunk *Record : Records) { D->Characteristics = 0; D->TimeDateStamp = 0; D->MajorVersion = 0; D->MinorVersion = 0; D->Type = COFF::IMAGE_DEBUG_TYPE_CODEVIEW; D->SizeOfData = Record->getSize(); D->AddressOfRawData = Record->getRVA(); // TODO(compnerd) get the file offset D->PointerToRawData = 0; ++D; } } private: const std::vector &Records; }; class CVDebugRecordChunk : public Chunk { size_t getSize() const override { return sizeof(codeview::DebugInfo) + Config->PDBPath.size() + 1; } void writeTo(uint8_t *B) const override { // Save off the DebugInfo entry to backfill the file signature (build id) // in Writer::writeBuildId DI = reinterpret_cast(B + OutputSectionOff); DI->Signature.CVSignature = OMF::Signature::PDB70; // variable sized field (PDB Path) auto *P = reinterpret_cast(B + OutputSectionOff + sizeof(*DI)); if (!Config->PDBPath.empty()) memcpy(P, Config->PDBPath.data(), Config->PDBPath.size()); P[Config->PDBPath.size()] = '\0'; } public: mutable codeview::DebugInfo *DI = nullptr; }; // The writer writes a SymbolTable result to a file. class Writer { public: Writer(SymbolTable *T) : Symtab(T) {} void run(); private: void createSections(); void createMiscChunks(); void createImportTables(); void createExportTable(); void assignAddresses(); void removeEmptySections(); void createSymbolAndStringTable(); void openFile(StringRef OutputPath); template void writeHeader(); void fixSafeSEHSymbols(); void setSectionPermissions(); void writeSections(); void sortExceptionTable(); void writeBuildId(); void applyRelocations(); llvm::Optional createSymbol(Defined *D); size_t addEntryToStringTable(StringRef Str); OutputSection *findSection(StringRef Name); OutputSection *createSection(StringRef Name); void addBaserels(OutputSection *Dest); void addBaserelBlocks(OutputSection *Dest, std::vector &V); uint32_t getSizeOfInitializedData(); std::map> binImports(); SymbolTable *Symtab; std::unique_ptr Buffer; std::vector OutputSections; std::vector Strtab; std::vector OutputSymtab; IdataContents Idata; DelayLoadContents DelayIdata; EdataContents Edata; SEHTableChunk *SEHTable = nullptr; Chunk *DebugDirectory = nullptr; std::vector DebugRecords; CVDebugRecordChunk *BuildId = nullptr; ArrayRef SectionTable; uint64_t FileSize; uint32_t PointerToSymbolTable = 0; uint64_t SizeOfImage; uint64_t SizeOfHeaders; }; } // anonymous namespace namespace lld { namespace coff { void writeResult(SymbolTable *T) { Writer(T).run(); } void OutputSection::setRVA(uint64_t RVA) { Header.VirtualAddress = RVA; for (Chunk *C : Chunks) C->setRVA(C->getRVA() + RVA); } void OutputSection::setFileOffset(uint64_t Off) { // If a section has no actual data (i.e. BSS section), we want to // set 0 to its PointerToRawData. Otherwise the output is rejected // by the loader. if (Header.SizeOfRawData == 0) return; Header.PointerToRawData = Off; } void OutputSection::addChunk(Chunk *C) { Chunks.push_back(C); C->setOutputSection(this); uint64_t Off = Header.VirtualSize; Off = alignTo(Off, C->getAlign()); C->setRVA(Off); - C->setOutputSectionOff(Off); + C->OutputSectionOff = Off; Off += C->getSize(); Header.VirtualSize = Off; if (C->hasData()) Header.SizeOfRawData = alignTo(Off, SectorSize); } void OutputSection::addPermissions(uint32_t C) { Header.Characteristics |= C & PermMask; } void OutputSection::setPermissions(uint32_t C) { Header.Characteristics = C & PermMask; } // Write the section header to a given buffer. void OutputSection::writeHeaderTo(uint8_t *Buf) { auto *Hdr = reinterpret_cast(Buf); *Hdr = Header; if (StringTableOff) { // If name is too long, write offset into the string table as a name. sprintf(Hdr->Name, "/%d", StringTableOff); } else { assert(!Config->Debug || Name.size() <= COFF::NameSize); strncpy(Hdr->Name, Name.data(), std::min(Name.size(), (size_t)COFF::NameSize)); } } -uint64_t Defined::getSecrel() { - if (auto *D = dyn_cast(this)) - return getRVA() - D->getChunk()->getOutputSection()->getRVA(); - fatal("SECREL relocation points to a non-regular symbol"); +uint32_t Defined::getSecrel() { + assert(this); + switch (kind()) { + case DefinedRegularKind: + return cast(this)->getSecrel(); + case DefinedCommonKind: + return cast(this)->getSecrel(); + case DefinedSyntheticKind: + return cast(this)->getSecrel(); + default: + break; + } + fatal("SECREL relocation points to a non-regular symbol: " + toString(*this)); } -uint64_t Defined::getSectionIndex() { +uint32_t DefinedRegular::getSecrel() { + assert(getChunk()->isLive() && "relocation against discarded section"); + uint64_t Diff = getRVA() - getChunk()->getOutputSection()->getRVA(); + assert(Diff < UINT32_MAX && "section offset too large"); + return (uint32_t)Diff; +} + +uint16_t Defined::getSectionIndex() { if (auto *D = dyn_cast(this)) return D->getChunk()->getOutputSection()->SectionIndex; - fatal("SECTION relocation points to a non-regular symbol"); + if (isa(this)) + return DefinedAbsolute::OutputSectionIndex; + if (auto *D = dyn_cast(this)) + return D->getSectionIndex(); + if (auto *D = dyn_cast(this)) { + if (!D->getChunk()) + return 0; + return D->getChunk()->getOutputSection()->SectionIndex; + } + fatal("SECTION relocation points to a non-regular symbol: " + + toString(*this)); } +uint16_t DefinedCommon::getSectionIndex() { + return Data->getOutputSection()->SectionIndex; +} + bool Defined::isExecutable() { const auto X = IMAGE_SCN_MEM_EXECUTE; if (auto *D = dyn_cast(this)) return D->getChunk()->getOutputSection()->getPermissions() & X; return isa(this); } } // namespace coff } // namespace lld // The main function of the writer. void Writer::run() { createSections(); createMiscChunks(); createImportTables(); createExportTable(); if (Config->Relocatable) createSection(".reloc"); assignAddresses(); removeEmptySections(); setSectionPermissions(); createSymbolAndStringTable(); openFile(Config->OutputFile); if (Config->is64()) { writeHeader(); } else { writeHeader(); } fixSafeSEHSymbols(); writeSections(); sortExceptionTable(); writeBuildId(); if (!Config->PDBPath.empty() && Config->Debug) { const llvm::codeview::DebugInfo *DI = nullptr; if (Config->DebugTypes & static_cast(coff::DebugType::CV)) DI = BuildId->DI; createPDB(Config->PDBPath, Symtab, SectionTable, DI); } writeMapFile(OutputSections); if (auto EC = Buffer->commit()) fatal(EC, "failed to write the output file"); } static StringRef getOutputSection(StringRef Name) { StringRef S = Name.split('$').first; auto It = Config->Merge.find(S); if (It == Config->Merge.end()) return S; return It->second; } // Create output section objects and add them to OutputSections. void Writer::createSections() { // First, bin chunks by name. std::map> Map; for (Chunk *C : Symtab->getChunks()) { auto *SC = dyn_cast(C); if (SC && !SC->isLive()) { if (Config->Verbose) SC->printDiscardedMessage(); continue; } Map[C->getSectionName()].push_back(C); } // Then create an OutputSection for each section. // '$' and all following characters in input section names are // discarded when determining output section. So, .text$foo // contributes to .text, for example. See PE/COFF spec 3.2. SmallDenseMap Sections; for (auto Pair : Map) { StringRef Name = getOutputSection(Pair.first); OutputSection *&Sec = Sections[Name]; if (!Sec) { Sec = make(Name); OutputSections.push_back(Sec); } std::vector &Chunks = Pair.second; for (Chunk *C : Chunks) { Sec->addChunk(C); Sec->addPermissions(C->getPermissions()); } } } void Writer::createMiscChunks() { OutputSection *RData = createSection(".rdata"); // Create thunks for locally-dllimported symbols. if (!Symtab->LocalImportChunks.empty()) { for (Chunk *C : Symtab->LocalImportChunks) RData->addChunk(C); } // Create Debug Information Chunks if (Config->Debug) { DebugDirectory = make(DebugRecords); // TODO(compnerd) create a coffgrp entry if DebugType::CV is not enabled if (Config->DebugTypes & static_cast(coff::DebugType::CV)) { auto *Chunk = make(); BuildId = Chunk; DebugRecords.push_back(Chunk); } RData->addChunk(DebugDirectory); for (Chunk *C : DebugRecords) RData->addChunk(C); } // Create SEH table. x86-only. if (Config->Machine != I386) return; std::set Handlers; for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) { if (!File->SEHCompat) return; - for (SymbolBody *B : File->SEHandlers) - Handlers.insert(cast(B)); + for (SymbolBody *B : File->SEHandlers) { + // Make sure the handler is still live. Assume all handlers are regular + // symbols. + auto *D = dyn_cast(B); + if (D && D->getChunk()->isLive()) + Handlers.insert(D); + } } - SEHTable = make(Handlers); - RData->addChunk(SEHTable); + if (!Handlers.empty()) { + SEHTable = make(Handlers); + RData->addChunk(SEHTable); + } } // Create .idata section for the DLL-imported symbol table. // The format of this section is inherently Windows-specific. // IdataContents class abstracted away the details for us, // so we just let it create chunks and add them to the section. void Writer::createImportTables() { if (Symtab->ImportFiles.empty()) return; // Initialize DLLOrder so that import entries are ordered in // the same order as in the command line. (That affects DLL // initialization order, and this ordering is MSVC-compatible.) for (ImportFile *File : Symtab->ImportFiles) { if (!File->Live) continue; std::string DLL = StringRef(File->DLLName).lower(); if (Config->DLLOrder.count(DLL) == 0) Config->DLLOrder[DLL] = Config->DLLOrder.size(); } OutputSection *Text = createSection(".text"); for (ImportFile *File : Symtab->ImportFiles) { if (!File->Live) continue; if (DefinedImportThunk *Thunk = File->ThunkSym) Text->addChunk(Thunk->getChunk()); if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) { if (!File->ThunkSym) fatal("cannot delay-load " + toString(File) + " due to import of data: " + toString(*File->ImpSym)); DelayIdata.add(File->ImpSym); } else { Idata.add(File->ImpSym); } } if (!Idata.empty()) { OutputSection *Sec = createSection(".idata"); for (Chunk *C : Idata.getChunks()) Sec->addChunk(C); } if (!DelayIdata.empty()) { Defined *Helper = cast(Config->DelayLoadHelper); DelayIdata.create(Helper); OutputSection *Sec = createSection(".didat"); for (Chunk *C : DelayIdata.getChunks()) Sec->addChunk(C); Sec = createSection(".data"); for (Chunk *C : DelayIdata.getDataChunks()) Sec->addChunk(C); Sec = createSection(".text"); for (Chunk *C : DelayIdata.getCodeChunks()) Sec->addChunk(C); } } void Writer::createExportTable() { if (Config->Exports.empty()) return; OutputSection *Sec = createSection(".edata"); for (Chunk *C : Edata.Chunks) Sec->addChunk(C); } // The Windows loader doesn't seem to like empty sections, // so we remove them if any. void Writer::removeEmptySections() { auto IsEmpty = [](OutputSection *S) { return S->getVirtualSize() == 0; }; OutputSections.erase( std::remove_if(OutputSections.begin(), OutputSections.end(), IsEmpty), OutputSections.end()); uint32_t Idx = 1; for (OutputSection *Sec : OutputSections) Sec->SectionIndex = Idx++; } size_t Writer::addEntryToStringTable(StringRef Str) { assert(Str.size() > COFF::NameSize); size_t OffsetOfEntry = Strtab.size() + 4; // +4 for the size field Strtab.insert(Strtab.end(), Str.begin(), Str.end()); Strtab.push_back('\0'); return OffsetOfEntry; } Optional Writer::createSymbol(Defined *Def) { // Relative symbols are unrepresentable in a COFF symbol table. - if (isa(Def)) + if (isa(Def)) return None; - if (auto *D = dyn_cast(Def)) - if (!D->getChunk()->isLive()) + if (auto *D = dyn_cast(Def)) { + // Don't write dead symbols or symbols in codeview sections to the symbol + // table. + if (!D->getChunk()->isLive() || D->getChunk()->isCodeView()) return None; + } if (auto *Sym = dyn_cast(Def)) if (!Sym->File->Live) return None; if (auto *Sym = dyn_cast(Def)) if (!Sym->WrappedSym->File->Live) return None; coff_symbol16 Sym; StringRef Name = Def->getName(); if (Name.size() > COFF::NameSize) { Sym.Name.Offset.Zeroes = 0; Sym.Name.Offset.Offset = addEntryToStringTable(Name); } else { memset(Sym.Name.ShortName, 0, COFF::NameSize); memcpy(Sym.Name.ShortName, Name.data(), Name.size()); } if (auto *D = dyn_cast(Def)) { COFFSymbolRef Ref = D->getCOFFSymbol(); Sym.Type = Ref.getType(); Sym.StorageClass = Ref.getStorageClass(); } else { Sym.Type = IMAGE_SYM_TYPE_NULL; Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; } Sym.NumberOfAuxSymbols = 0; switch (Def->kind()) { case SymbolBody::DefinedAbsoluteKind: Sym.Value = Def->getRVA(); Sym.SectionNumber = IMAGE_SYM_ABSOLUTE; break; default: { uint64_t RVA = Def->getRVA(); OutputSection *Sec = nullptr; for (OutputSection *S : OutputSections) { if (S->getRVA() > RVA) break; Sec = S; } Sym.Value = RVA - Sec->getRVA(); Sym.SectionNumber = Sec->SectionIndex; break; } } return Sym; } void Writer::createSymbolAndStringTable() { if (!Config->Debug || !Config->WriteSymtab) return; // Name field in the section table is 8 byte long. Longer names need // to be written to the string table. First, construct string table. for (OutputSection *Sec : OutputSections) { StringRef Name = Sec->getName(); if (Name.size() <= COFF::NameSize) continue; Sec->setStringTableOff(addEntryToStringTable(Name)); } for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) { for (SymbolBody *B : File->getSymbols()) { auto *D = dyn_cast(B); if (!D || D->WrittenToSymtab) continue; D->WrittenToSymtab = true; if (Optional Sym = createSymbol(D)) OutputSymtab.push_back(*Sym); } } OutputSection *LastSection = OutputSections.back(); // We position the symbol table to be adjacent to the end of the last section. uint64_t FileOff = LastSection->getFileOff() + alignTo(LastSection->getRawSize(), SectorSize); if (!OutputSymtab.empty()) { PointerToSymbolTable = FileOff; FileOff += OutputSymtab.size() * sizeof(coff_symbol16); } if (!Strtab.empty()) FileOff += Strtab.size() + 4; FileSize = alignTo(FileOff, SectorSize); } // Visits all sections to assign incremental, non-overlapping RVAs and // file offsets. void Writer::assignAddresses() { SizeOfHeaders = DOSStubSize + sizeof(PEMagic) + sizeof(coff_file_header) + sizeof(data_directory) * NumberfOfDataDirectory + sizeof(coff_section) * OutputSections.size(); SizeOfHeaders += Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); SizeOfHeaders = alignTo(SizeOfHeaders, SectorSize); uint64_t RVA = 0x1000; // The first page is kept unmapped. FileSize = SizeOfHeaders; // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because // the loader cannot handle holes. std::stable_partition( OutputSections.begin(), OutputSections.end(), [](OutputSection *S) { return (S->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0; }); for (OutputSection *Sec : OutputSections) { if (Sec->getName() == ".reloc") addBaserels(Sec); Sec->setRVA(RVA); Sec->setFileOffset(FileSize); RVA += alignTo(Sec->getVirtualSize(), PageSize); FileSize += alignTo(Sec->getRawSize(), SectorSize); } SizeOfImage = SizeOfHeaders + alignTo(RVA - 0x1000, PageSize); } template void Writer::writeHeader() { // Write DOS stub uint8_t *Buf = Buffer->getBufferStart(); auto *DOS = reinterpret_cast(Buf); Buf += DOSStubSize; DOS->Magic[0] = 'M'; DOS->Magic[1] = 'Z'; DOS->AddressOfRelocationTable = sizeof(dos_header); DOS->AddressOfNewExeHeader = DOSStubSize; // Write PE magic memcpy(Buf, PEMagic, sizeof(PEMagic)); Buf += sizeof(PEMagic); // Write COFF header auto *COFF = reinterpret_cast(Buf); Buf += sizeof(*COFF); COFF->Machine = Config->Machine; COFF->NumberOfSections = OutputSections.size(); COFF->Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE; if (Config->LargeAddressAware) COFF->Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; if (!Config->is64()) COFF->Characteristics |= IMAGE_FILE_32BIT_MACHINE; if (Config->DLL) COFF->Characteristics |= IMAGE_FILE_DLL; if (!Config->Relocatable) COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; COFF->SizeOfOptionalHeader = sizeof(PEHeaderTy) + sizeof(data_directory) * NumberfOfDataDirectory; // Write PE header auto *PE = reinterpret_cast(Buf); Buf += sizeof(*PE); PE->Magic = Config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32; + + // 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; // Import Descriptor Tables and Import Address Tables are merged // in our output. That's not compatible with the Binding feature // that is sort of prelinking. Setting this flag to make it clear // that our outputs are not for the Binding. PE->DLLCharacteristics = IMAGE_DLL_CHARACTERISTICS_NO_BIND; 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->NxCompat) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; if (!Config->AllowIsolation) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION; if (Config->TerminalServerAware) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE; PE->NumberOfRvaAndSize = NumberfOfDataDirectory; if (OutputSection *Text = findSection(".text")) { PE->BaseOfCode = Text->getRVA(); PE->SizeOfCode = Text->getRawSize(); } PE->SizeOfInitializedData = getSizeOfInitializedData(); // Write data directory auto *Dir = reinterpret_cast(Buf); Buf += sizeof(*Dir) * NumberfOfDataDirectory; if (OutputSection *Sec = findSection(".edata")) { Dir[EXPORT_TABLE].RelativeVirtualAddress = Sec->getRVA(); Dir[EXPORT_TABLE].Size = Sec->getVirtualSize(); } if (!Idata.empty()) { Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA(); Dir[IMPORT_TABLE].Size = Idata.getDirSize(); Dir[IAT].RelativeVirtualAddress = Idata.getIATRVA(); Dir[IAT].Size = Idata.getIATSize(); } if (OutputSection *Sec = findSection(".rsrc")) { Dir[RESOURCE_TABLE].RelativeVirtualAddress = Sec->getRVA(); Dir[RESOURCE_TABLE].Size = Sec->getVirtualSize(); } if (OutputSection *Sec = findSection(".pdata")) { Dir[EXCEPTION_TABLE].RelativeVirtualAddress = Sec->getRVA(); Dir[EXCEPTION_TABLE].Size = Sec->getVirtualSize(); } if (OutputSection *Sec = findSection(".reloc")) { Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = Sec->getRVA(); Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize(); } if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) { if (Defined *B = dyn_cast(Sym->body())) { Dir[TLS_TABLE].RelativeVirtualAddress = B->getRVA(); Dir[TLS_TABLE].Size = Config->is64() ? sizeof(object::coff_tls_directory64) : sizeof(object::coff_tls_directory32); } } if (Config->Debug) { Dir[DEBUG_DIRECTORY].RelativeVirtualAddress = DebugDirectory->getRVA(); Dir[DEBUG_DIRECTORY].Size = DebugDirectory->getSize(); } if (Symbol *Sym = Symtab->findUnderscore("_load_config_used")) { if (auto *B = dyn_cast(Sym->body())) { 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()) 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::fixSafeSEHSymbols() { if (!SEHTable) return; - if (auto *T = dyn_cast(Config->SEHTable->body())) - T->setRVA(SEHTable->getRVA()); - if (auto *C = dyn_cast(Config->SEHCount->body())) - C->setVA(SEHTable->getSize() / 4); + // Replace the absolute table symbol with a synthetic symbol pointing to the + // SEHTable chunk so that we can emit base relocations for it and resolve + // section relative relocations. + Symbol *T = Symtab->find("___safe_se_handler_table"); + Symbol *C = Symtab->find("___safe_se_handler_count"); + replaceBody(T, T->body()->getName(), SEHTable); + cast(C->body())->setVA(SEHTable->getSize() / 4); } // Handles /section options to allow users to overwrite // section attributes. void Writer::setSectionPermissions() { for (auto &P : Config->Section) { StringRef Name = P.first; uint32_t Perm = P.second; if (auto *Sec = findSection(Name)) Sec->setPermissions(Perm); } } // Write section contents to a mmap'ed file. void Writer::writeSections() { + // Record the section index that should be used when resolving a section + // relocation against an absolute symbol. + DefinedAbsolute::OutputSectionIndex = OutputSections.size() + 1; + uint8_t *Buf = Buffer->getBufferStart(); for (OutputSection *Sec : OutputSections) { uint8_t *SecBuf = Buf + Sec->getFileOff(); // Fill gaps between functions in .text with INT3 instructions // instead of leaving as NUL bytes (which can be interpreted as // ADD instructions). if (Sec->getPermissions() & IMAGE_SCN_CNT_CODE) memset(SecBuf, 0xCC, Sec->getRawSize()); for_each(parallel::par, Sec->getChunks().begin(), Sec->getChunks().end(), [&](Chunk *C) { C->writeTo(SecBuf); }); } } // Sort .pdata section contents according to PE/COFF spec 5.5. void Writer::sortExceptionTable() { OutputSection *Sec = findSection(".pdata"); if (!Sec) return; // We assume .pdata contains function table entries only. uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff(); uint8_t *End = Begin + Sec->getVirtualSize(); if (Config->Machine == AMD64) { struct Entry { ulittle32_t Begin, End, Unwind; }; sort(parallel::par, (Entry *)Begin, (Entry *)End, [](const Entry &A, const Entry &B) { return A.Begin < B.Begin; }); return; } if (Config->Machine == ARMNT) { struct Entry { ulittle32_t Begin, Unwind; }; 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"; } // Backfill the CVSignature in a PDB70 Debug Record. This backfilling allows us // to get reproducible builds. void Writer::writeBuildId() { // There is nothing to backfill if BuildId was not setup. if (BuildId == nullptr) return; assert(BuildId->DI->Signature.CVSignature == OMF::Signature::PDB70 && "only PDB 7.0 is supported"); assert(sizeof(BuildId->DI->PDB70.Signature) == 16 && "signature size mismatch"); // Compute an MD5 hash. ArrayRef Buf(Buffer->getBufferStart(), Buffer->getBufferEnd()); memcpy(BuildId->DI->PDB70.Signature, MD5::hash(Buf).data(), 16); // TODO(compnerd) track the Age BuildId->DI->PDB70.Age = 1; } OutputSection *Writer::findSection(StringRef Name) { for (OutputSection *Sec : OutputSections) if (Sec->getName() == Name) return Sec; return nullptr; } uint32_t Writer::getSizeOfInitializedData() { uint32_t Res = 0; for (OutputSection *S : OutputSections) if (S->getPermissions() & IMAGE_SCN_CNT_INITIALIZED_DATA) Res += S->getRawSize(); return Res; } // Returns an existing section or create a new one if not found. OutputSection *Writer::createSection(StringRef Name) { if (auto *Sec = findSection(Name)) return Sec; const auto DATA = IMAGE_SCN_CNT_INITIALIZED_DATA; const auto BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA; const auto CODE = IMAGE_SCN_CNT_CODE; const auto DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE; const auto R = IMAGE_SCN_MEM_READ; const auto W = IMAGE_SCN_MEM_WRITE; const auto X = IMAGE_SCN_MEM_EXECUTE; uint32_t Perms = StringSwitch(Name) .Case(".bss", BSS | R | W) .Case(".data", DATA | R | W) .Cases(".didat", ".edata", ".idata", ".rdata", DATA | R) .Case(".reloc", DATA | DISCARDABLE | R) .Case(".text", CODE | R | X) .Default(0); if (!Perms) llvm_unreachable("unknown section name"); auto Sec = make(Name); Sec->addPermissions(Perms); OutputSections.push_back(Sec); return Sec; } // Dest is .reloc section. Add contents to that section. void Writer::addBaserels(OutputSection *Dest) { std::vector V; for (OutputSection *Sec : OutputSections) { if (Sec == Dest) continue; // Collect all locations for base relocations. for (Chunk *C : Sec->getChunks()) C->getBaserels(&V); // Add the addresses to .reloc section. if (!V.empty()) addBaserelBlocks(Dest, V); V.clear(); } } // Add addresses to .reloc section. Note that addresses are grouped by page. void Writer::addBaserelBlocks(OutputSection *Dest, std::vector &V) { const uint32_t Mask = ~uint32_t(PageSize - 1); uint32_t Page = V[0].RVA & Mask; size_t I = 0, J = 1; for (size_t E = V.size(); J < E; ++J) { uint32_t P = V[J].RVA & Mask; if (P == Page) continue; Dest->addChunk(make(Page, &V[I], &V[0] + J)); I = J; Page = P; } if (I == J) return; Dest->addChunk(make(Page, &V[I], &V[0] + J)); } Index: vendor/lld/dist/ELF/Mips.cpp =================================================================== --- vendor/lld/dist/ELF/Mips.cpp (revision 320381) +++ vendor/lld/dist/ELF/Mips.cpp (nonexistent) @@ -1,369 +0,0 @@ -//===- Mips.cpp ----------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===---------------------------------------------------------------------===// -// -// This file contains a helper function for the Writer. -// -//===---------------------------------------------------------------------===// - -#include "Error.h" -#include "InputFiles.h" -#include "SymbolTable.h" -#include "Writer.h" - -#include "llvm/BinaryFormat/ELF.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/MipsABIFlags.h" - -using namespace llvm; -using namespace llvm::object; -using namespace llvm::ELF; - -using namespace lld; -using namespace lld::elf; - -namespace { -struct ArchTreeEdge { - uint32_t Child; - uint32_t Parent; -}; - -struct FileFlags { - StringRef Filename; - uint32_t Flags; -}; -} - -static StringRef getAbiName(uint32_t Flags) { - switch (Flags) { - case 0: - return "n64"; - case EF_MIPS_ABI2: - return "n32"; - case EF_MIPS_ABI_O32: - return "o32"; - case EF_MIPS_ABI_O64: - return "o64"; - case EF_MIPS_ABI_EABI32: - return "eabi32"; - case EF_MIPS_ABI_EABI64: - return "eabi64"; - default: - return "unknown"; - } -} - -static StringRef getNanName(bool IsNan2008) { - return IsNan2008 ? "2008" : "legacy"; -} - -static StringRef getFpName(bool IsFp64) { return IsFp64 ? "64" : "32"; } - -static void checkFlags(ArrayRef Files) { - uint32_t ABI = Files[0].Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); - bool Nan = Files[0].Flags & EF_MIPS_NAN2008; - bool Fp = Files[0].Flags & EF_MIPS_FP64; - - for (const FileFlags &F : Files.slice(1)) { - uint32_t ABI2 = F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); - if (ABI != ABI2) - error("target ABI '" + getAbiName(ABI) + "' is incompatible with '" + - getAbiName(ABI2) + "': " + F.Filename); - - bool Nan2 = F.Flags & EF_MIPS_NAN2008; - if (Nan != Nan2) - error("target -mnan=" + getNanName(Nan) + " is incompatible with -mnan=" + - getNanName(Nan2) + ": " + F.Filename); - - bool Fp2 = F.Flags & EF_MIPS_FP64; - if (Fp != Fp2) - error("target -mfp" + getFpName(Fp) + " is incompatible with -mfp" + - getFpName(Fp2) + ": " + F.Filename); - } -} - -static uint32_t getMiscFlags(ArrayRef Files) { - uint32_t Ret = 0; - for (const FileFlags &F : Files) - Ret |= F.Flags & - (EF_MIPS_ABI | EF_MIPS_ABI2 | EF_MIPS_ARCH_ASE | EF_MIPS_NOREORDER | - EF_MIPS_MICROMIPS | EF_MIPS_NAN2008 | EF_MIPS_32BITMODE); - return Ret; -} - -static uint32_t getPicFlags(ArrayRef Files) { - // Check PIC/non-PIC compatibility. - bool IsPic = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); - for (const FileFlags &F : Files.slice(1)) { - bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); - if (IsPic && !IsPic2) - warn("linking abicalls code with non-abicalls file: " + F.Filename); - if (!IsPic && IsPic2) - warn("linking non-abicalls code with abicalls file: " + F.Filename); - } - - // Compute the result PIC/non-PIC flag. - uint32_t Ret = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); - for (const FileFlags &F : Files.slice(1)) - Ret &= F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); - - // PIC code is inherently CPIC and may not set CPIC flag explicitly. - if (Ret & EF_MIPS_PIC) - Ret |= EF_MIPS_CPIC; - return Ret; -} - -static ArchTreeEdge ArchTree[] = { - // MIPS32R6 and MIPS64R6 are not compatible with other extensions - // MIPS64R2 extensions. - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, EF_MIPS_ARCH_64R2}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, EF_MIPS_ARCH_64R2}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, EF_MIPS_ARCH_64R2}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, EF_MIPS_ARCH_64R2}, - // MIPS64 extensions. - {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, EF_MIPS_ARCH_64}, - {EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, EF_MIPS_ARCH_64}, - {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64}, - // MIPS V extensions. - {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5}, - // R5000 extensions. - {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400}, - // MIPS IV extensions. - {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, EF_MIPS_ARCH_4}, - {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, EF_MIPS_ARCH_4}, - {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4}, - // VR4100 extensions. - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, - // MIPS III extensions. - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_4, EF_MIPS_ARCH_3}, - // MIPS32 extensions. - {EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32}, - // MIPS II extensions. - {EF_MIPS_ARCH_3, EF_MIPS_ARCH_2}, - {EF_MIPS_ARCH_32, EF_MIPS_ARCH_2}, - // MIPS I extensions. - {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, EF_MIPS_ARCH_1}, - {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1}, -}; - -static bool isArchMatched(uint32_t New, uint32_t Res) { - if (New == Res) - return true; - if (New == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, Res)) - return true; - if (New == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, Res)) - return true; - for (const auto &Edge : ArchTree) { - if (Res == Edge.Child) { - Res = Edge.Parent; - if (Res == New) - return true; - } - } - return false; -} - -static StringRef getMachName(uint32_t Flags) { - switch (Flags & EF_MIPS_MACH) { - case EF_MIPS_MACH_NONE: - return ""; - case EF_MIPS_MACH_3900: - return "r3900"; - case EF_MIPS_MACH_4010: - return "r4010"; - case EF_MIPS_MACH_4100: - return "r4100"; - case EF_MIPS_MACH_4650: - return "r4650"; - case EF_MIPS_MACH_4120: - return "r4120"; - case EF_MIPS_MACH_4111: - return "r4111"; - case EF_MIPS_MACH_5400: - return "vr5400"; - case EF_MIPS_MACH_5900: - return "vr5900"; - case EF_MIPS_MACH_5500: - return "vr5500"; - case EF_MIPS_MACH_9000: - return "rm9000"; - case EF_MIPS_MACH_LS2E: - return "loongson2e"; - case EF_MIPS_MACH_LS2F: - return "loongson2f"; - case EF_MIPS_MACH_LS3A: - return "loongson3a"; - case EF_MIPS_MACH_OCTEON: - return "octeon"; - case EF_MIPS_MACH_OCTEON2: - return "octeon2"; - case EF_MIPS_MACH_OCTEON3: - return "octeon3"; - case EF_MIPS_MACH_SB1: - return "sb1"; - case EF_MIPS_MACH_XLR: - return "xlr"; - default: - return "unknown machine"; - } -} - -static StringRef getArchName(uint32_t Flags) { - StringRef S = getMachName(Flags); - if (!S.empty()) - return S; - - switch (Flags & EF_MIPS_ARCH) { - case EF_MIPS_ARCH_1: - return "mips1"; - case EF_MIPS_ARCH_2: - return "mips2"; - case EF_MIPS_ARCH_3: - return "mips3"; - case EF_MIPS_ARCH_4: - return "mips4"; - case EF_MIPS_ARCH_5: - return "mips5"; - case EF_MIPS_ARCH_32: - return "mips32"; - case EF_MIPS_ARCH_64: - return "mips64"; - case EF_MIPS_ARCH_32R2: - return "mips32r2"; - case EF_MIPS_ARCH_64R2: - return "mips64r2"; - case EF_MIPS_ARCH_32R6: - return "mips32r6"; - case EF_MIPS_ARCH_64R6: - return "mips64r6"; - default: - return "unknown arch"; - } -} - -// There are (arguably too) many MIPS ISAs out there. Their relationships -// can be represented as a forest. If all input files have ISAs which -// reachable by repeated proceeding from the single child to the parent, -// these input files are compatible. In that case we need to return "highest" -// ISA. If there are incompatible input files, we show an error. -// For example, mips1 is a "parent" of mips2 and such files are compatible. -// Output file gets EF_MIPS_ARCH_2 flag. From the other side mips3 and mips32 -// are incompatible because nor mips3 is a parent for misp32, nor mips32 -// is a parent for mips3. -static uint32_t getArchFlags(ArrayRef Files) { - uint32_t Ret = Files[0].Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); - - for (const FileFlags &F : Files.slice(1)) { - uint32_t New = F.Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); - - // Check ISA compatibility. - if (isArchMatched(New, Ret)) - continue; - if (!isArchMatched(Ret, New)) { - error("target ISA '" + getArchName(Ret) + "' is incompatible with '" + - getArchName(New) + "': " + F.Filename); - return 0; - } - Ret = New; - } - return Ret; -} - -template uint32_t elf::getMipsEFlags() { - std::vector V; - for (elf::ObjectFile *F : Symtab::X->getObjectFiles()) - V.push_back({F->getName(), F->getObj().getHeader()->e_flags}); - if (V.empty()) - return 0; - checkFlags(V); - return getMiscFlags(V) | getPicFlags(V) | getArchFlags(V); -} - -static int compareMipsFpAbi(uint8_t FpA, uint8_t FpB) { - if (FpA == FpB) - return 0; - if (FpB == Mips::Val_GNU_MIPS_ABI_FP_ANY) - return 1; - if (FpB == Mips::Val_GNU_MIPS_ABI_FP_64A && - FpA == Mips::Val_GNU_MIPS_ABI_FP_64) - return 1; - if (FpB != Mips::Val_GNU_MIPS_ABI_FP_XX) - return -1; - if (FpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE || - FpA == Mips::Val_GNU_MIPS_ABI_FP_64 || - FpA == Mips::Val_GNU_MIPS_ABI_FP_64A) - return 1; - return -1; -} - -static StringRef getMipsFpAbiName(uint8_t FpAbi) { - switch (FpAbi) { - case Mips::Val_GNU_MIPS_ABI_FP_ANY: - return "any"; - case Mips::Val_GNU_MIPS_ABI_FP_DOUBLE: - return "-mdouble-float"; - case Mips::Val_GNU_MIPS_ABI_FP_SINGLE: - return "-msingle-float"; - case Mips::Val_GNU_MIPS_ABI_FP_SOFT: - return "-msoft-float"; - case Mips::Val_GNU_MIPS_ABI_FP_OLD_64: - return "-mips32r2 -mfp64 (old)"; - case Mips::Val_GNU_MIPS_ABI_FP_XX: - return "-mfpxx"; - case Mips::Val_GNU_MIPS_ABI_FP_64: - return "-mgp32 -mfp64"; - case Mips::Val_GNU_MIPS_ABI_FP_64A: - return "-mgp32 -mfp64 -mno-odd-spreg"; - default: - return "unknown"; - } -} - -uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag, - StringRef FileName) { - if (compareMipsFpAbi(NewFlag, OldFlag) >= 0) - return NewFlag; - if (compareMipsFpAbi(OldFlag, NewFlag) < 0) - error("target floating point ABI '" + getMipsFpAbiName(OldFlag) + - "' is incompatible with '" + getMipsFpAbiName(NewFlag) + "': " + - FileName); - return OldFlag; -} - -template static bool isN32Abi(const InputFile *F) { - if (auto *EF = dyn_cast>(F)) - return EF->getObj().getHeader()->e_flags & EF_MIPS_ABI2; - return false; -} - -bool elf::isMipsN32Abi(const InputFile *F) { - switch (Config->EKind) { - case ELF32LEKind: - return isN32Abi(F); - case ELF32BEKind: - return isN32Abi(F); - case ELF64LEKind: - return isN32Abi(F); - case ELF64BEKind: - return isN32Abi(F); - default: - llvm_unreachable("unknown Config->EKind"); - } -} - -template uint32_t elf::getMipsEFlags(); -template uint32_t elf::getMipsEFlags(); -template uint32_t elf::getMipsEFlags(); -template uint32_t elf::getMipsEFlags(); Property changes on: vendor/lld/dist/ELF/Mips.cpp ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: vendor/lld/dist/ELF/Arch/AArch64.cpp =================================================================== --- vendor/lld/dist/ELF/Arch/AArch64.cpp (revision 320381) +++ vendor/lld/dist/ELF/Arch/AArch64.cpp (revision 320382) @@ -1,374 +1,376 @@ //===- AArch64.cpp --------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Error.h" -#include "Memory.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.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(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; bool isPicRel(uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &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 usesOnlyLowPageBits(uint32_t Type) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const override; void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; }; } // namespace AArch64::AArch64() { CopyRel = R_AARCH64_COPY; RelativeRel = R_AARCH64_RELATIVE; IRelativeRel = R_AARCH64_IRELATIVE; GotRel = R_AARCH64_GLOB_DAT; PltRel = R_AARCH64_JUMP_SLOT; TlsDescRel = R_AARCH64_TLSDESC; TlsGotRel = R_AARCH64_TLS_TPREL64; GotEntrySize = 8; GotPltEntrySize = 8; PltEntrySize = 16; PltHeaderSize = 32; DefaultMaxPageSize = 65536; // It doesn't seem to be documented anywhere, but tls on aarch64 uses variant // 1 of the tls structures and the tcb size is 16. TcbSize = 16; } RelExpr AArch64::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { default: return R_ABS; case R_AARCH64_TLSDESC_ADR_PAGE21: return R_TLSDESC_PAGE; case R_AARCH64_TLSDESC_LD64_LO12: case R_AARCH64_TLSDESC_ADD_LO12: return R_TLSDESC; case R_AARCH64_TLSDESC_CALL: return R_TLSDESC_CALL; case R_AARCH64_TLSLE_ADD_TPREL_HI12: case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: 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: return R_PC; case R_AARCH64_ADR_PREL_PG_HI21: return R_PAGE_PC; case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: return R_GOT; case R_AARCH64_ADR_GOT_PAGE: case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: return R_GOT_PAGE_PC; case R_AARCH64_NONE: return R_NONE; } } RelExpr AArch64::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const { if (Expr == R_RELAX_TLS_GD_TO_IE) { if (Type == R_AARCH64_TLSDESC_ADR_PAGE21) return R_RELAX_TLS_GD_TO_IE_PAGE_PC; return R_RELAX_TLS_GD_TO_IE_ABS; } return Expr; } bool AArch64::usesOnlyLowPageBits(uint32_t Type) const { switch (Type) { default: return false; case R_AARCH64_ADD_ABS_LO12_NC: case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_LDST128_ABS_LO12_NC: case R_AARCH64_LDST16_ABS_LO12_NC: case R_AARCH64_LDST32_ABS_LO12_NC: case R_AARCH64_LDST64_ABS_LO12_NC: case R_AARCH64_LDST8_ABS_LO12_NC: case R_AARCH64_TLSDESC_ADD_LO12: case R_AARCH64_TLSDESC_LD64_LO12: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: return true; } } bool AArch64::isPicRel(uint32_t Type) const { return Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64; } void AArch64::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { write64le(Buf, InX::Plt->getVA()); } void AArch64::writePltHeader(uint8_t *Buf) const { const uint8_t PltData[] = { 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]! 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2])) 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[2]))] 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[2])) 0x20, 0x02, 0x1f, 0xd6, // br x17 0x1f, 0x20, 0x03, 0xd5, // nop 0x1f, 0x20, 0x03, 0xd5, // nop 0x1f, 0x20, 0x03, 0xd5 // nop }; memcpy(Buf, PltData, sizeof(PltData)); uint64_t Got = InX::GotPlt->getVA(); uint64_t Plt = InX::Plt->getVA(); relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, getAArch64Page(Got + 16) - getAArch64Page(Plt + 4)); relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16); relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16); } void AArch64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Inst[] = { 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n])) 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))] 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[n])) 0x20, 0x02, 0x1f, 0xd6 // br x17 }; memcpy(Buf, Inst, sizeof(Inst)); relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21, getAArch64Page(GotPltEntryAddr) - getAArch64Page(PltEntryAddr)); relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotPltEntryAddr); relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotPltEntryAddr); } 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, uint32_t Type, uint64_t Val) const { switch (Type) { case R_AARCH64_ABS16: case R_AARCH64_PREL16: checkIntUInt<16>(Loc, Val, Type); write16le(Loc, Val); break; case R_AARCH64_ABS32: case R_AARCH64_PREL32: checkIntUInt<32>(Loc, Val, Type); write32le(Loc, Val); break; case R_AARCH64_ABS64: case R_AARCH64_GLOB_DAT: case R_AARCH64_PREL64: write64le(Loc, Val); break; case R_AARCH64_ADD_ABS_LO12_NC: or32AArch64Imm(Loc, Val); break; case R_AARCH64_ADR_GOT_PAGE: case R_AARCH64_ADR_PREL_PG_HI21: case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case R_AARCH64_TLSDESC_ADR_PAGE21: checkInt<33>(Loc, Val, Type); write32AArch64Addr(Loc, Val >> 12); break; case R_AARCH64_ADR_PREL_LO21: checkInt<21>(Loc, Val, Type); write32AArch64Addr(Loc, Val); break; case R_AARCH64_CALL26: case R_AARCH64_JUMP26: checkInt<28>(Loc, Val, Type); or32le(Loc, (Val & 0x0FFFFFFC) >> 2); break; case R_AARCH64_CONDBR19: checkInt<21>(Loc, Val, Type); or32le(Loc, (Val & 0x1FFFFC) << 3); break; case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case R_AARCH64_TLSDESC_LD64_LO12: checkAlignment<8>(Loc, Val, Type); or32le(Loc, (Val & 0xFF8) << 7); break; case R_AARCH64_LDST8_ABS_LO12_NC: or32AArch64Imm(Loc, getBits(Val, 0, 11)); break; case R_AARCH64_LDST16_ABS_LO12_NC: or32AArch64Imm(Loc, getBits(Val, 1, 11)); break; case R_AARCH64_LDST32_ABS_LO12_NC: or32AArch64Imm(Loc, getBits(Val, 2, 11)); break; case R_AARCH64_LDST64_ABS_LO12_NC: or32AArch64Imm(Loc, getBits(Val, 3, 11)); break; case R_AARCH64_LDST128_ABS_LO12_NC: or32AArch64Imm(Loc, getBits(Val, 4, 11)); break; case R_AARCH64_MOVW_UABS_G0_NC: or32le(Loc, (Val & 0xFFFF) << 5); break; case R_AARCH64_MOVW_UABS_G1_NC: or32le(Loc, (Val & 0xFFFF0000) >> 11); break; case R_AARCH64_MOVW_UABS_G2_NC: or32le(Loc, (Val & 0xFFFF00000000) >> 27); break; case R_AARCH64_MOVW_UABS_G3: or32le(Loc, (Val & 0xFFFF000000000000) >> 43); break; case R_AARCH64_TSTBR14: checkInt<16>(Loc, Val, Type); or32le(Loc, (Val & 0xFFFC) << 3); break; case R_AARCH64_TLSLE_ADD_TPREL_HI12: checkInt<24>(Loc, Val, 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, uint32_t Type, uint64_t Val) const { // TLSDESC Global-Dynamic relocation are in the form: // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] // add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12] // .tlsdesccall [R_AARCH64_TLSDESC_CALL] // blr x1 // And it can optimized to: // movz x0, #0x0, lsl #16 // movk x0, #0x10 // nop // nop checkUInt<32>(Loc, Val, Type); 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, uint32_t 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, uint32_t Type, uint64_t Val) const { checkUInt<32>(Loc, Val, 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::createAArch64TargetInfo() { return make(); } +TargetInfo *elf::getAArch64TargetInfo() { + static AArch64 Target; + return &Target; +} Index: vendor/lld/dist/ELF/Arch/AMDGPU.cpp =================================================================== --- vendor/lld/dist/ELF/Arch/AMDGPU.cpp (revision 320381) +++ vendor/lld/dist/ELF/Arch/AMDGPU.cpp (revision 320382) @@ -1,82 +1,84 @@ //===- AMDGPU.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "Symbols.h" #include "Target.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(); void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; }; } // namespace AMDGPU::AMDGPU() { RelativeRel = R_AMDGPU_REL64; GotRel = R_AMDGPU_ABS64; GotEntrySize = 8; } void AMDGPU::relocateOne(uint8_t *Loc, uint32_t 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: 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(uint32_t Type, const SymbolBody &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: return R_PC; case R_AMDGPU_GOTPCREL: case R_AMDGPU_GOTPCREL32_LO: case R_AMDGPU_GOTPCREL32_HI: return R_GOT_PC; default: error(toString(S.File) + ": unknown relocation type: " + toString(Type)); return R_HINT; } } -TargetInfo *elf::createAMDGPUTargetInfo() { return make(); } +TargetInfo *elf::getAMDGPUTargetInfo() { + static AMDGPU Target; + return &Target; +} Index: vendor/lld/dist/ELF/Arch/ARM.cpp =================================================================== --- vendor/lld/dist/ELF/Arch/ARM.cpp (revision 320381) +++ vendor/lld/dist/ELF/Arch/ARM.cpp (revision 320382) @@ -1,432 +1,435 @@ //===- ARM.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.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(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; bool isPicRel(uint32_t Type) const override; uint32_t getDynRel(uint32_t Type) const override; int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writeIgotPlt(uint8_t *Buf, const SymbolBody &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(InputSectionBase *IS, uint64_t Off) const override; void addPltHeaderSymbols(InputSectionBase *ISD) const override; bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; }; } // namespace ARM::ARM() { CopyRel = R_ARM_COPY; RelativeRel = R_ARM_RELATIVE; IRelativeRel = R_ARM_IRELATIVE; GotRel = R_ARM_GLOB_DAT; PltRel = R_ARM_JUMP_SLOT; TlsGotRel = R_ARM_TLS_TPOFF32; TlsModuleIndexRel = R_ARM_TLS_DTPMOD32; TlsOffsetRel = R_ARM_TLS_DTPOFF32; GotEntrySize = 4; GotPltEntrySize = 4; PltEntrySize = 16; PltHeaderSize = 20; + TrapInstr = 0xd4d4d4d4; // ARM uses Variant 1 TLS TcbSize = 8; NeedsThunks = true; } RelExpr ARM::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { default: return R_ABS; 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; } } bool ARM::isPicRel(uint32_t Type) const { return (Type == R_ARM_TARGET1 && !Config->Target1Rel) || (Type == R_ARM_ABS32); } uint32_t ARM::getDynRel(uint32_t Type) const { if (Type == R_ARM_TARGET1 && !Config->Target1Rel) return R_ARM_ABS32; if (Type == R_ARM_ABS32) return Type; // Keep it going with a dummy value so that we can find more reloc errors. return R_ARM_ABS32; } void ARM::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { write32le(Buf, InX::Plt->getVA()); } void ARM::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const { // An ARM entry is the address of the ifunc resolver function. write32le(Buf, S.getVA()); } void ARM::writePltHeader(uint8_t *Buf) const { 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 }; memcpy(Buf, PltData, sizeof(PltData)); uint64_t GotPlt = InX::GotPlt->getVA(); uint64_t L1 = InX::Plt->getVA() + 8; write32le(Buf + 16, GotPlt - L1 - 8); } void ARM::addPltHeaderSymbols(InputSectionBase *ISD) const { auto *IS = cast(ISD); addSyntheticLocal("$a", STT_NOTYPE, 0, 0, IS); addSyntheticLocal("$d", STT_NOTYPE, 16, 0, IS); } void ARM::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { // FIXME: Using simple code sequence with simple relocations. // There is a more optimal sequence but it requires support for the group // relocations. See ELF for the ARM Architecture Appendix A.3 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); } void ARM::addPltSymbols(InputSectionBase *ISD, uint64_t Off) const { auto *IS = cast(ISD); addSyntheticLocal("$a", STT_NOTYPE, Off, 0, IS); addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS); } bool ARM::needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, const SymbolBody &S) const { // If S is an undefined weak symbol in an executable we don't need a Thunk. // In a DSO calls to undefined symbols, including weak ones get PLT entries // which may need a thunk. if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak() && !Config->Shared) 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 (RelocType) { 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; break; 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; break; } return false; } void ARM::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { switch (Type) { case R_ARM_ABS32: case R_ARM_BASE_PREL: case R_ARM_GLOB_DAT: case R_ARM_GOTOFF32: case R_ARM_GOT_BREL: case R_ARM_GOT_PREL: case R_ARM_REL32: case R_ARM_RELATIVE: case R_ARM_SBREL32: case R_ARM_TARGET1: case R_ARM_TARGET2: case R_ARM_TLS_GD32: case R_ARM_TLS_IE32: case R_ARM_TLS_LDM32: case R_ARM_TLS_LDO32: case R_ARM_TLS_LE32: case R_ARM_TLS_TPOFF32: case R_ARM_TLS_DTPOFF32: write32le(Loc, Val); break; case R_ARM_TLS_DTPMOD32: write32le(Loc, 1); break; case R_ARM_PREL31: checkInt<31>(Loc, Val, Type); write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000)); break; case R_ARM_CALL: // R_ARM_CALL is used for BL and BLX instructions, depending on the // value of bit 0 of Val, we must select a BL or BLX instruction if (Val & 1) { // If bit 0 of Val is 1 the target is Thumb, we must select a BLX. // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1' checkInt<26>(Loc, Val, Type); write32le(Loc, 0xfa000000 | // opcode ((Val & 2) << 23) | // H ((Val >> 2) & 0x00ffffff)); // imm24 break; } if ((read32le(Loc) & 0xfe000000) == 0xfa000000) // BLX (always unconditional) instruction to an ARM Target, select an // unconditional BL. write32le(Loc, 0xeb000000 | (read32le(Loc) & 0x00ffffff)); // fall through as BL encoding is shared with B LLVM_FALLTHROUGH; case R_ARM_JUMP24: case R_ARM_PC24: case R_ARM_PLT32: checkInt<26>(Loc, Val, Type); write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff)); break; case R_ARM_THM_JUMP11: checkInt<12>(Loc, Val, Type); write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff)); break; case R_ARM_THM_JUMP19: // Encoding T3: Val = S:J2:J1:imm6:imm11:0 checkInt<21>(Loc, Val, Type); write16le(Loc, (read16le(Loc) & 0xfbc0) | // opcode cond ((Val >> 10) & 0x0400) | // S ((Val >> 12) & 0x003f)); // imm6 write16le(Loc + 2, 0x8000 | // opcode ((Val >> 8) & 0x0800) | // J2 ((Val >> 5) & 0x2000) | // J1 ((Val >> 1) & 0x07ff)); // imm11 break; case R_ARM_THM_CALL: // R_ARM_THM_CALL is used for BL and BLX instructions, depending on the // value of bit 0 of Val, we must select a BL or BLX instruction if ((Val & 1) == 0) { // Ensure BLX destination is 4-byte aligned. As BLX instruction may // only be two byte aligned. This must be done before overflow check Val = alignTo(Val, 4); } // Bit 12 is 0 for BLX, 1 for BL write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12); // Fall through as rest of encoding is the same as B.W LLVM_FALLTHROUGH; case R_ARM_THM_JUMP24: // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0 // FIXME: Use of I1 and I2 require v6T2ops checkInt<25>(Loc, Val, Type); write16le(Loc, 0xf000 | // opcode ((Val >> 14) & 0x0400) | // S ((Val >> 12) & 0x03ff)); // imm10 write16le(Loc + 2, (read16le(Loc + 2) & 0xd000) | // opcode (((~(Val >> 10)) ^ (Val >> 11)) & 0x2000) | // J1 (((~(Val >> 11)) ^ (Val >> 13)) & 0x0800) | // J2 ((Val >> 1) & 0x07ff)); // imm11 break; case R_ARM_MOVW_ABS_NC: case R_ARM_MOVW_PREL_NC: write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) | (Val & 0x0fff)); break; case R_ARM_MOVT_ABS: case R_ARM_MOVT_PREL: checkInt<32>(Loc, Val, Type); write32le(Loc, (read32le(Loc) & ~0x000f0fff) | (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff)); break; case R_ARM_THM_MOVT_ABS: case R_ARM_THM_MOVT_PREL: // Encoding T1: A = imm4:i:imm3:imm8 checkInt<32>(Loc, Val, Type); 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, uint32_t Type) const { switch (Type) { default: return 0; case R_ARM_ABS32: case R_ARM_BASE_PREL: case R_ARM_GOTOFF32: case R_ARM_GOT_BREL: case R_ARM_GOT_PREL: case R_ARM_REL32: case R_ARM_TARGET1: case R_ARM_TARGET2: case R_ARM_TLS_GD32: case R_ARM_TLS_LDM32: case R_ARM_TLS_LDO32: case R_ARM_TLS_IE32: case R_ARM_TLS_LE32: return SignExtend64<32>(read32le(Buf)); case R_ARM_PREL31: return SignExtend64<31>(read32le(Buf)); case R_ARM_CALL: case R_ARM_JUMP24: case R_ARM_PC24: case R_ARM_PLT32: return SignExtend64<26>(read32le(Buf) << 2); case R_ARM_THM_JUMP11: return SignExtend64<12>(read16le(Buf) << 1); case R_ARM_THM_JUMP19: { // Encoding T3: A = S:J2:J1:imm10:imm6:0 uint16_t Hi = read16le(Buf); uint16_t Lo = read16le(Buf + 2); return SignExtend64<20>(((Hi & 0x0400) << 10) | // S ((Lo & 0x0800) << 8) | // J2 ((Lo & 0x2000) << 5) | // J1 ((Hi & 0x003f) << 12) | // imm6 ((Lo & 0x07ff) << 1)); // imm11:0 } case R_ARM_THM_CALL: case R_ARM_THM_JUMP24: { // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0 // I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S) // FIXME: I1 and I2 require v6T2ops uint16_t Hi = read16le(Buf); uint16_t Lo = read16le(Buf + 2); return SignExtend64<24>(((Hi & 0x0400) << 14) | // S (~((Lo ^ (Hi << 3)) << 10) & 0x00800000) | // I1 (~((Lo ^ (Hi << 1)) << 11) & 0x00400000) | // I2 ((Hi & 0x003ff) << 12) | // imm0 ((Lo & 0x007ff) << 1)); // imm11:0 } // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and // MOVT is in the range -32768 <= A < 32768 case R_ARM_MOVW_ABS_NC: case R_ARM_MOVT_ABS: case R_ARM_MOVW_PREL_NC: case R_ARM_MOVT_PREL: { uint64_t Val = read32le(Buf) & 0x000f0fff; return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff)); } case R_ARM_THM_MOVW_ABS_NC: case R_ARM_THM_MOVT_ABS: case R_ARM_THM_MOVW_PREL_NC: case R_ARM_THM_MOVT_PREL: { // Encoding T3: A = imm4:i:imm3:imm8 uint16_t Hi = read16le(Buf); uint16_t Lo = read16le(Buf + 2); return SignExtend64<16>(((Hi & 0x000f) << 12) | // imm4 ((Hi & 0x0400) << 1) | // i ((Lo & 0x7000) >> 4) | // imm3 (Lo & 0x00ff)); // imm8 } } } -TargetInfo *elf::createARMTargetInfo() { return make(); } +TargetInfo *elf::getARMTargetInfo() { + static ARM Target; + return &Target; +} Index: vendor/lld/dist/ELF/Arch/AVR.cpp =================================================================== --- vendor/lld/dist/ELF/Arch/AVR.cpp (revision 320381) +++ vendor/lld/dist/ELF/Arch/AVR.cpp (revision 320382) @@ -1,78 +1,80 @@ //===- 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 "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "Symbols.h" #include "Target.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: RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; }; } // namespace RelExpr AVR::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { case R_AVR_CALL: return R_ABS; default: error(toString(S.File) + ": unknown relocation type: " + toString(Type)); return R_HINT; } } void AVR::relocateOne(uint8_t *Loc, uint32_t 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::createAVRTargetInfo() { return make(); } +TargetInfo *elf::getAVRTargetInfo() { + static AVR Target; + return &Target; +} Index: vendor/lld/dist/ELF/Arch/Mips.cpp =================================================================== --- vendor/lld/dist/ELF/Arch/Mips.cpp (revision 320381) +++ vendor/lld/dist/ELF/Arch/Mips.cpp (revision 320382) @@ -1,422 +1,423 @@ //===- MIPS.cpp -----------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "OutputSections.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.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(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; bool isPicRel(uint32_t Type) const override; uint32_t getDynRel(uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &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, uint32_t RelocType, const InputFile *File, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; bool usesOnlyLowPageBits(uint32_t Type) const override; }; } // namespace template MIPS::MIPS() { GotPltHeaderEntriesNum = 2; DefaultMaxPageSize = 65536; GotEntrySize = sizeof(typename ELFT::uint); GotPltEntrySize = sizeof(typename ELFT::uint); PltEntrySize = 16; PltHeaderSize = 32; CopyRel = R_MIPS_COPY; PltRel = R_MIPS_JUMP_SLOT; NeedsThunks = true; + TrapInstr = 0xefefefef; if (ELFT::Is64Bits) { RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32; TlsGotRel = R_MIPS_TLS_TPREL64; TlsModuleIndexRel = R_MIPS_TLS_DTPMOD64; TlsOffsetRel = R_MIPS_TLS_DTPREL64; } else { RelativeRel = R_MIPS_REL32; TlsGotRel = R_MIPS_TLS_TPREL32; TlsModuleIndexRel = R_MIPS_TLS_DTPMOD32; TlsOffsetRel = R_MIPS_TLS_DTPREL32; } } template RelExpr MIPS::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { // See comment in the calculateMipsRelChain. if (ELFT::Is64Bits || Config->MipsN32Abi) Type &= 0xff; switch (Type) { default: return R_ABS; case R_MIPS_JALR: return R_HINT; case R_MIPS_GPREL16: case R_MIPS_GPREL32: return R_MIPS_GOTREL; case R_MIPS_26: return R_PLT; case R_MIPS_HI16: case R_MIPS_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_GOT_OFST: 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: return R_PC; case R_MIPS_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: 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: return R_MIPS_GOT_OFF32; case R_MIPS_GOT_PAGE: return R_MIPS_GOT_LOCAL_PAGE; case R_MIPS_TLS_GD: return R_MIPS_TLSGD; case R_MIPS_TLS_LDM: return R_MIPS_TLSLD; } } template bool MIPS::isPicRel(uint32_t Type) const { return Type == R_MIPS_32 || Type == R_MIPS_64; } template uint32_t MIPS::getDynRel(uint32_t Type) const { return RelativeRel; } template void MIPS::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { write32(Buf, InX::Plt->getVA()); } template static int64_t getPcRelocAddend(const uint8_t *Loc) { uint32_t Instr = read32(Loc); uint32_t Mask = 0xffffffff >> (32 - BSIZE); return SignExtend64((Instr & Mask) << SHIFT); } template static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t V) { uint32_t Mask = 0xffffffff >> (32 - BSIZE); uint32_t Instr = read32(Loc); if (SHIFT > 0) checkAlignment<(1 << SHIFT)>(Loc, V, Type); checkInt(Loc, V, Type); write32(Loc, (Instr & ~Mask) | ((V >> SHIFT) & Mask)); } template static void writeMipsHi16(uint8_t *Loc, uint64_t V) { uint32_t Instr = read32(Loc); uint16_t Res = ((V + 0x8000) >> 16) & 0xffff; write32(Loc, (Instr & 0xffff0000) | Res); } template static void writeMipsHigher(uint8_t *Loc, uint64_t V) { uint32_t Instr = read32(Loc); uint16_t Res = ((V + 0x80008000) >> 32) & 0xffff; write32(Loc, (Instr & 0xffff0000) | Res); } template static void writeMipsHighest(uint8_t *Loc, uint64_t V) { uint32_t Instr = read32(Loc); uint16_t Res = ((V + 0x800080008000) >> 48) & 0xffff; write32(Loc, (Instr & 0xffff0000) | Res); } template static void writeMipsLo16(uint8_t *Loc, uint64_t V) { uint32_t Instr = read32(Loc); write32(Loc, (Instr & 0xffff0000) | (V & 0xffff)); } template static bool isMipsR6() { const auto &FirstObj = cast>(*Config->FirstElf); uint32_t Arch = FirstObj.getObj().getHeader()->e_flags & EF_MIPS_ARCH; return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6; } template void MIPS::writePltHeader(uint8_t *Buf) const { const endianness E = ELFT::TargetEndianness; 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 } 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 write32(Buf + 24, 0x0320f809); // jalr $25 write32(Buf + 28, 0x2718fffe); // subu $24, $24, 2 uint64_t GotPlt = InX::GotPlt->getVA(); writeMipsHi16(Buf, GotPlt); writeMipsLo16(Buf + 4, GotPlt); writeMipsLo16(Buf + 8, GotPlt); } template void MIPS::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const endianness E = ELFT::TargetEndianness; write32(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry) write32(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15) // jr $25 write32(Buf + 8, isMipsR6() ? 0x03200009 : 0x03200008); write32(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry) writeMipsHi16(Buf, GotPltEntryAddr); writeMipsLo16(Buf + 4, GotPltEntryAddr); writeMipsLo16(Buf + 12, GotPltEntryAddr); } template bool MIPS::needsThunk(RelExpr Expr, uint32_t Type, const InputFile *File, const SymbolBody &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) 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 && D->isMipsPIC(); } template int64_t MIPS::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { const endianness E = ELFT::TargetEndianness; switch (Type) { default: return 0; 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) & 0x3ffffff) << 2); 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_MIPS_PC16: return getPcRelocAddend(Buf); case R_MIPS_PC19_S2: return getPcRelocAddend(Buf); case R_MIPS_PC21_S2: return getPcRelocAddend(Buf); case R_MIPS_PC26_S2: return getPcRelocAddend(Buf); case R_MIPS_PC32: return getPcRelocAddend(Buf); } } static std::pair calculateMipsRelChain(uint8_t *Loc, uint32_t 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 uint32_t Type2 = (Type >> 8) & 0xff; uint32_t 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, uint32_t Type, uint64_t Val) const { const endianness E = ELFT::TargetEndianness; // 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) 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) Val -= 0x7000; if (ELFT::Is64Bits || Config->MipsN32Abi) std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val); switch (Type) { case R_MIPS_32: case R_MIPS_GPREL32: case R_MIPS_TLS_DTPREL32: case R_MIPS_TLS_TPREL32: write32(Loc, Val); break; case R_MIPS_64: case R_MIPS_TLS_DTPREL64: case R_MIPS_TLS_TPREL64: write64(Loc, Val); break; case R_MIPS_26: write32(Loc, (read32(Loc) & ~0x3ffffff) | ((Val >> 2) & 0x3ffffff)); 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) writeMipsHi16(Loc, Val); else { checkInt<16>(Loc, Val, Type); writeMipsLo16(Loc, Val); } break; case R_MIPS_GOT_DISP: case R_MIPS_GOT_PAGE: case R_MIPS_GPREL16: case R_MIPS_TLS_GD: case R_MIPS_TLS_LDM: checkInt<16>(Loc, Val, Type); LLVM_FALLTHROUGH; case R_MIPS_CALL16: 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_GOTTPREL: case R_MIPS_TLS_TPREL_LO16: writeMipsLo16(Loc, Val); 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: writeMipsHi16(Loc, Val); break; case R_MIPS_HIGHER: writeMipsHigher(Loc, Val); break; case R_MIPS_HIGHEST: writeMipsHighest(Loc, Val); break; case R_MIPS_JALR: // Ignore this optimization relocation for now break; case R_MIPS_PC16: applyMipsPcReloc(Loc, Type, Val); break; case R_MIPS_PC19_S2: applyMipsPcReloc(Loc, Type, Val); break; case R_MIPS_PC21_S2: applyMipsPcReloc(Loc, Type, Val); break; case R_MIPS_PC26_S2: applyMipsPcReloc(Loc, Type, Val); break; case R_MIPS_PC32: applyMipsPcReloc(Loc, Type, Val); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } template bool MIPS::usesOnlyLowPageBits(uint32_t Type) const { return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST; } -template TargetInfo *elf::createMipsTargetInfo() { - return make>(); +template TargetInfo *elf::getMipsTargetInfo() { + static MIPS Target; + return &Target; } -template TargetInfo *elf::createMipsTargetInfo(); -template TargetInfo *elf::createMipsTargetInfo(); -template TargetInfo *elf::createMipsTargetInfo(); -template TargetInfo *elf::createMipsTargetInfo(); +template TargetInfo *elf::getMipsTargetInfo(); +template TargetInfo *elf::getMipsTargetInfo(); +template TargetInfo *elf::getMipsTargetInfo(); +template TargetInfo *elf::getMipsTargetInfo(); Index: vendor/lld/dist/ELF/Arch/MipsArchTree.cpp =================================================================== --- vendor/lld/dist/ELF/Arch/MipsArchTree.cpp (nonexistent) +++ vendor/lld/dist/ELF/Arch/MipsArchTree.cpp (revision 320382) @@ -0,0 +1,369 @@ +//===- MipsArchTree.cpp --------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// This file contains a helper function for the Writer. +// +//===---------------------------------------------------------------------===// + +#include "Error.h" +#include "InputFiles.h" +#include "SymbolTable.h" +#include "Writer.h" + +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/MipsABIFlags.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::ELF; + +using namespace lld; +using namespace lld::elf; + +namespace { +struct ArchTreeEdge { + uint32_t Child; + uint32_t Parent; +}; + +struct FileFlags { + StringRef Filename; + uint32_t Flags; +}; +} + +static StringRef getAbiName(uint32_t Flags) { + switch (Flags) { + case 0: + return "n64"; + case EF_MIPS_ABI2: + return "n32"; + case EF_MIPS_ABI_O32: + return "o32"; + case EF_MIPS_ABI_O64: + return "o64"; + case EF_MIPS_ABI_EABI32: + return "eabi32"; + case EF_MIPS_ABI_EABI64: + return "eabi64"; + default: + return "unknown"; + } +} + +static StringRef getNanName(bool IsNan2008) { + return IsNan2008 ? "2008" : "legacy"; +} + +static StringRef getFpName(bool IsFp64) { return IsFp64 ? "64" : "32"; } + +static void checkFlags(ArrayRef Files) { + uint32_t ABI = Files[0].Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); + bool Nan = Files[0].Flags & EF_MIPS_NAN2008; + bool Fp = Files[0].Flags & EF_MIPS_FP64; + + for (const FileFlags &F : Files.slice(1)) { + uint32_t ABI2 = F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); + if (ABI != ABI2) + error("target ABI '" + getAbiName(ABI) + "' is incompatible with '" + + getAbiName(ABI2) + "': " + F.Filename); + + bool Nan2 = F.Flags & EF_MIPS_NAN2008; + if (Nan != Nan2) + error("target -mnan=" + getNanName(Nan) + " is incompatible with -mnan=" + + getNanName(Nan2) + ": " + F.Filename); + + bool Fp2 = F.Flags & EF_MIPS_FP64; + if (Fp != Fp2) + error("target -mfp" + getFpName(Fp) + " is incompatible with -mfp" + + getFpName(Fp2) + ": " + F.Filename); + } +} + +static uint32_t getMiscFlags(ArrayRef Files) { + uint32_t Ret = 0; + for (const FileFlags &F : Files) + Ret |= F.Flags & + (EF_MIPS_ABI | EF_MIPS_ABI2 | EF_MIPS_ARCH_ASE | EF_MIPS_NOREORDER | + EF_MIPS_MICROMIPS | EF_MIPS_NAN2008 | EF_MIPS_32BITMODE); + return Ret; +} + +static uint32_t getPicFlags(ArrayRef Files) { + // Check PIC/non-PIC compatibility. + bool IsPic = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); + for (const FileFlags &F : Files.slice(1)) { + bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); + if (IsPic && !IsPic2) + warn("linking abicalls code with non-abicalls file: " + F.Filename); + if (!IsPic && IsPic2) + warn("linking non-abicalls code with abicalls file: " + F.Filename); + } + + // Compute the result PIC/non-PIC flag. + uint32_t Ret = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); + for (const FileFlags &F : Files.slice(1)) + Ret &= F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); + + // PIC code is inherently CPIC and may not set CPIC flag explicitly. + if (Ret & EF_MIPS_PIC) + Ret |= EF_MIPS_CPIC; + return Ret; +} + +static ArchTreeEdge ArchTree[] = { + // MIPS32R6 and MIPS64R6 are not compatible with other extensions + // MIPS64R2 extensions. + {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, EF_MIPS_ARCH_64R2}, + {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, EF_MIPS_ARCH_64R2}, + {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, EF_MIPS_ARCH_64R2}, + {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, EF_MIPS_ARCH_64R2}, + // MIPS64 extensions. + {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, EF_MIPS_ARCH_64}, + {EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, EF_MIPS_ARCH_64}, + {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64}, + // MIPS V extensions. + {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5}, + // R5000 extensions. + {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400}, + // MIPS IV extensions. + {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, EF_MIPS_ARCH_4}, + {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, EF_MIPS_ARCH_4}, + {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4}, + // VR4100 extensions. + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, + // MIPS III extensions. + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_4, EF_MIPS_ARCH_3}, + // MIPS32 extensions. + {EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32}, + // MIPS II extensions. + {EF_MIPS_ARCH_3, EF_MIPS_ARCH_2}, + {EF_MIPS_ARCH_32, EF_MIPS_ARCH_2}, + // MIPS I extensions. + {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, EF_MIPS_ARCH_1}, + {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1}, +}; + +static bool isArchMatched(uint32_t New, uint32_t Res) { + if (New == Res) + return true; + if (New == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, Res)) + return true; + if (New == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, Res)) + return true; + for (const auto &Edge : ArchTree) { + if (Res == Edge.Child) { + Res = Edge.Parent; + if (Res == New) + return true; + } + } + return false; +} + +static StringRef getMachName(uint32_t Flags) { + switch (Flags & EF_MIPS_MACH) { + case EF_MIPS_MACH_NONE: + return ""; + case EF_MIPS_MACH_3900: + return "r3900"; + case EF_MIPS_MACH_4010: + return "r4010"; + case EF_MIPS_MACH_4100: + return "r4100"; + case EF_MIPS_MACH_4650: + return "r4650"; + case EF_MIPS_MACH_4120: + return "r4120"; + case EF_MIPS_MACH_4111: + return "r4111"; + case EF_MIPS_MACH_5400: + return "vr5400"; + case EF_MIPS_MACH_5900: + return "vr5900"; + case EF_MIPS_MACH_5500: + return "vr5500"; + case EF_MIPS_MACH_9000: + return "rm9000"; + case EF_MIPS_MACH_LS2E: + return "loongson2e"; + case EF_MIPS_MACH_LS2F: + return "loongson2f"; + case EF_MIPS_MACH_LS3A: + return "loongson3a"; + case EF_MIPS_MACH_OCTEON: + return "octeon"; + case EF_MIPS_MACH_OCTEON2: + return "octeon2"; + case EF_MIPS_MACH_OCTEON3: + return "octeon3"; + case EF_MIPS_MACH_SB1: + return "sb1"; + case EF_MIPS_MACH_XLR: + return "xlr"; + default: + return "unknown machine"; + } +} + +static StringRef getArchName(uint32_t Flags) { + StringRef S = getMachName(Flags); + if (!S.empty()) + return S; + + switch (Flags & EF_MIPS_ARCH) { + case EF_MIPS_ARCH_1: + return "mips1"; + case EF_MIPS_ARCH_2: + return "mips2"; + case EF_MIPS_ARCH_3: + return "mips3"; + case EF_MIPS_ARCH_4: + return "mips4"; + case EF_MIPS_ARCH_5: + return "mips5"; + case EF_MIPS_ARCH_32: + return "mips32"; + case EF_MIPS_ARCH_64: + return "mips64"; + case EF_MIPS_ARCH_32R2: + return "mips32r2"; + case EF_MIPS_ARCH_64R2: + return "mips64r2"; + case EF_MIPS_ARCH_32R6: + return "mips32r6"; + case EF_MIPS_ARCH_64R6: + return "mips64r6"; + default: + return "unknown arch"; + } +} + +// There are (arguably too) many MIPS ISAs out there. Their relationships +// can be represented as a forest. If all input files have ISAs which +// reachable by repeated proceeding from the single child to the parent, +// these input files are compatible. In that case we need to return "highest" +// ISA. If there are incompatible input files, we show an error. +// For example, mips1 is a "parent" of mips2 and such files are compatible. +// Output file gets EF_MIPS_ARCH_2 flag. From the other side mips3 and mips32 +// are incompatible because nor mips3 is a parent for misp32, nor mips32 +// is a parent for mips3. +static uint32_t getArchFlags(ArrayRef Files) { + uint32_t Ret = Files[0].Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); + + for (const FileFlags &F : Files.slice(1)) { + uint32_t New = F.Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); + + // Check ISA compatibility. + if (isArchMatched(New, Ret)) + continue; + if (!isArchMatched(Ret, New)) { + error("target ISA '" + getArchName(Ret) + "' is incompatible with '" + + getArchName(New) + "': " + F.Filename); + return 0; + } + Ret = New; + } + return Ret; +} + +template uint32_t elf::getMipsEFlags() { + std::vector V; + for (elf::ObjectFile *F : Symtab::X->getObjectFiles()) + V.push_back({F->getName(), F->getObj().getHeader()->e_flags}); + if (V.empty()) + return 0; + checkFlags(V); + return getMiscFlags(V) | getPicFlags(V) | getArchFlags(V); +} + +static int compareMipsFpAbi(uint8_t FpA, uint8_t FpB) { + if (FpA == FpB) + return 0; + if (FpB == Mips::Val_GNU_MIPS_ABI_FP_ANY) + return 1; + if (FpB == Mips::Val_GNU_MIPS_ABI_FP_64A && + FpA == Mips::Val_GNU_MIPS_ABI_FP_64) + return 1; + if (FpB != Mips::Val_GNU_MIPS_ABI_FP_XX) + return -1; + if (FpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE || + FpA == Mips::Val_GNU_MIPS_ABI_FP_64 || + FpA == Mips::Val_GNU_MIPS_ABI_FP_64A) + return 1; + return -1; +} + +static StringRef getMipsFpAbiName(uint8_t FpAbi) { + switch (FpAbi) { + case Mips::Val_GNU_MIPS_ABI_FP_ANY: + return "any"; + case Mips::Val_GNU_MIPS_ABI_FP_DOUBLE: + return "-mdouble-float"; + case Mips::Val_GNU_MIPS_ABI_FP_SINGLE: + return "-msingle-float"; + case Mips::Val_GNU_MIPS_ABI_FP_SOFT: + return "-msoft-float"; + case Mips::Val_GNU_MIPS_ABI_FP_OLD_64: + return "-mips32r2 -mfp64 (old)"; + case Mips::Val_GNU_MIPS_ABI_FP_XX: + return "-mfpxx"; + case Mips::Val_GNU_MIPS_ABI_FP_64: + return "-mgp32 -mfp64"; + case Mips::Val_GNU_MIPS_ABI_FP_64A: + return "-mgp32 -mfp64 -mno-odd-spreg"; + default: + return "unknown"; + } +} + +uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag, + StringRef FileName) { + if (compareMipsFpAbi(NewFlag, OldFlag) >= 0) + return NewFlag; + if (compareMipsFpAbi(OldFlag, NewFlag) < 0) + error("target floating point ABI '" + getMipsFpAbiName(OldFlag) + + "' is incompatible with '" + getMipsFpAbiName(NewFlag) + "': " + + FileName); + return OldFlag; +} + +template static bool isN32Abi(const InputFile *F) { + if (auto *EF = dyn_cast>(F)) + return EF->getObj().getHeader()->e_flags & EF_MIPS_ABI2; + return false; +} + +bool elf::isMipsN32Abi(const InputFile *F) { + switch (Config->EKind) { + case ELF32LEKind: + return isN32Abi(F); + case ELF32BEKind: + return isN32Abi(F); + case ELF64LEKind: + return isN32Abi(F); + case ELF64BEKind: + return isN32Abi(F); + default: + llvm_unreachable("unknown Config->EKind"); + } +} + +template uint32_t elf::getMipsEFlags(); +template uint32_t elf::getMipsEFlags(); +template uint32_t elf::getMipsEFlags(); +template uint32_t elf::getMipsEFlags(); Property changes on: vendor/lld/dist/ELF/Arch/MipsArchTree.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/ELF/Arch/PPC.cpp =================================================================== --- vendor/lld/dist/ELF/Arch/PPC.cpp (revision 320381) +++ vendor/lld/dist/ELF/Arch/PPC.cpp (revision 320382) @@ -1,63 +1,65 @@ //===- PPC.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Error.h" -#include "Memory.h" #include "Symbols.h" #include "Target.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() {} + PPC() { GotBaseSymOff = 0x8000; } void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; }; } // namespace void PPC::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { switch (Type) { case R_PPC_ADDR16_HA: write16be(Loc, (Val + 0x8000) >> 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_REL24: write32be(Loc, read32be(Loc) | (Val & 0x3FFFFFC)); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } RelExpr PPC::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { case R_PPC_REL24: case R_PPC_REL32: return R_PC; default: return R_ABS; } } -TargetInfo *elf::createPPCTargetInfo() { return make(); } +TargetInfo *elf::getPPCTargetInfo() { + static PPC Target; + return &Target; +} Index: vendor/lld/dist/ELF/Arch/PPC64.cpp =================================================================== --- vendor/lld/dist/ELF/Arch/PPC64.cpp (revision 320381) +++ vendor/lld/dist/ELF/Arch/PPC64.cpp (revision 320382) @@ -1,215 +1,217 @@ //===- PPC64.cpp ----------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Error.h" -#include "Memory.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.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; static uint64_t PPC64TocOffset = 0x8000; uint64_t elf::getPPC64TocBase() { // The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The // TOC starts where the first of these sections starts. We always create a // .got when we see a relocation that uses it, so for us the start is always // the .got. uint64_t TocVA = InX::Got->getVA(); // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 // thus permitting a full 64 Kbytes segment. Note that the glibc startup // code (crt1.o) assumes that you can get from the TOC base to the // start of the .toc section with only a single (signed) 16-bit relocation. return TocVA + PPC64TocOffset; } namespace { class PPC64 final : public TargetInfo { public: PPC64(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) 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, uint32_t Type, uint64_t Val) const override; }; } // namespace // Relocation masks following the #lo(value), #hi(value), #ha(value), // #higher(value), #highera(value), #highest(value), and #highesta(value) // macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi // document. static uint16_t applyPPCLo(uint64_t V) { return V; } static uint16_t applyPPCHi(uint64_t V) { return V >> 16; } static uint16_t applyPPCHa(uint64_t V) { return (V + 0x8000) >> 16; } static uint16_t applyPPCHigher(uint64_t V) { return V >> 32; } static uint16_t applyPPCHighera(uint64_t V) { return (V + 0x8000) >> 32; } static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; } static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; } PPC64::PPC64() { PltRel = GotRel = R_PPC64_GLOB_DAT; RelativeRel = R_PPC64_RELATIVE; GotEntrySize = 8; GotPltEntrySize = 8; PltEntrySize = 32; PltHeaderSize = 0; // 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; } RelExpr PPC64::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { default: return R_ABS; case R_PPC64_TOC16: case R_PPC64_TOC16_DS: case R_PPC64_TOC16_HA: case R_PPC64_TOC16_HI: case R_PPC64_TOC16_LO: case R_PPC64_TOC16_LO_DS: return R_GOTREL; case R_PPC64_TOC: return R_PPC_TOC; case R_PPC64_REL24: return R_PPC_PLT_OPD; } } void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { uint64_t Off = GotPltEntryAddr - getPPC64TocBase(); // FIXME: What we should do, in theory, is get the offset of the function // descriptor in the .opd section, and use that as the offset from %r2 (the // TOC-base pointer). Instead, we have the GOT-entry offset, and that will // be a pointer to the function descriptor in the .opd section. Using // this scheme is simpler, but requires an extra indirection per PLT dispatch. write32be(Buf, 0xf8410028); // std %r2, 40(%r1) write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11) write32be(Buf + 12, 0xe96c0000); // ld %r11,0(%r12) write32be(Buf + 16, 0x7d6903a6); // mtctr %r11 write32be(Buf + 20, 0xe84c0008); // ld %r2,8(%r12) write32be(Buf + 24, 0xe96c0010); // ld %r11,16(%r12) write32be(Buf + 28, 0x4e800420); // bctr } static std::pair toAddr16Rel(uint32_t Type, uint64_t Val) { uint64_t V = Val - PPC64TocOffset; switch (Type) { case R_PPC64_TOC16: return {R_PPC64_ADDR16, V}; case R_PPC64_TOC16_DS: return {R_PPC64_ADDR16_DS, V}; case R_PPC64_TOC16_HA: return {R_PPC64_ADDR16_HA, V}; case R_PPC64_TOC16_HI: return {R_PPC64_ADDR16_HI, V}; case R_PPC64_TOC16_LO: return {R_PPC64_ADDR16_LO, V}; case R_PPC64_TOC16_LO_DS: return {R_PPC64_ADDR16_LO_DS, V}; default: return {Type, Val}; } } void PPC64::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // For a TOC-relative relocation, proceed in terms of the corresponding // ADDR16 relocation type. std::tie(Type, Val) = toAddr16Rel(Type, Val); switch (Type) { case R_PPC64_ADDR14: { checkAlignment<4>(Loc, Val, Type); // Preserve the AA/LK bits in the branch instruction uint8_t AALK = Loc[3]; write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc)); break; } case R_PPC64_ADDR16: checkInt<16>(Loc, Val, Type); write16be(Loc, Val); break; case R_PPC64_ADDR16_DS: checkInt<16>(Loc, Val, Type); write16be(Loc, (read16be(Loc) & 3) | (Val & ~3)); break; case R_PPC64_ADDR16_HA: case R_PPC64_REL16_HA: write16be(Loc, applyPPCHa(Val)); break; case R_PPC64_ADDR16_HI: case R_PPC64_REL16_HI: write16be(Loc, applyPPCHi(Val)); break; case R_PPC64_ADDR16_HIGHER: write16be(Loc, applyPPCHigher(Val)); break; case R_PPC64_ADDR16_HIGHERA: write16be(Loc, applyPPCHighera(Val)); break; case R_PPC64_ADDR16_HIGHEST: write16be(Loc, applyPPCHighest(Val)); break; case R_PPC64_ADDR16_HIGHESTA: write16be(Loc, applyPPCHighesta(Val)); break; case R_PPC64_ADDR16_LO: write16be(Loc, applyPPCLo(Val)); break; case R_PPC64_ADDR16_LO_DS: case R_PPC64_REL16_LO: write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(Val) & ~3)); break; case R_PPC64_ADDR32: case R_PPC64_REL32: checkInt<32>(Loc, Val, Type); write32be(Loc, Val); break; case R_PPC64_ADDR64: case R_PPC64_REL64: case R_PPC64_TOC: write64be(Loc, Val); break; case R_PPC64_REL24: { uint32_t Mask = 0x03FFFFFC; checkInt<24>(Loc, Val, Type); write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask)); break; } default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } -TargetInfo *elf::createPPC64TargetInfo() { return make(); } +TargetInfo *elf::getPPC64TargetInfo() { + static PPC64 Target; + return &Target; +} Index: vendor/lld/dist/ELF/Arch/X86.cpp =================================================================== --- vendor/lld/dist/ELF/Arch/X86.cpp (revision 320381) +++ vendor/lld/dist/ELF/Arch/X86.cpp (revision 320382) @@ -1,363 +1,364 @@ //===- X86.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.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 final : public TargetInfo { public: X86(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; void writeGotPltHeader(uint8_t *Buf) const override; uint32_t getDynRel(uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writeIgotPlt(uint8_t *Buf, const SymbolBody &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, uint32_t Type, uint64_t Val) const override; RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const override; void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; }; } // namespace X86::X86() { + GotBaseSymOff = -1; CopyRel = R_386_COPY; GotRel = R_386_GLOB_DAT; PltRel = R_386_JUMP_SLOT; IRelativeRel = R_386_IRELATIVE; RelativeRel = R_386_RELATIVE; TlsGotRel = R_386_TLS_TPOFF; TlsModuleIndexRel = R_386_TLS_DTPMOD32; TlsOffsetRel = R_386_TLS_DTPOFF32; GotEntrySize = 4; GotPltEntrySize = 4; PltEntrySize = 16; PltHeaderSize = 16; TlsGdRelaxSkip = 2; - - // 0xCC is the "int3" (call debug exception handler) instruction. - TrapInstr = 0xcccccccc; + TrapInstr = 0xcccccccc; // 0xcc = INT3 } RelExpr X86::getRelExpr(uint32_t Type, const SymbolBody &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; case R_386_TLS_LDM: return R_TLSLD; 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 can be calculated in two different ways. // Usual calculation is G + A - GOT what means an offset in GOT table // (R_GOT_FROM_END). When instruction pointed by relocation has no base // register, then relocations can be used when PIC code is disabled. In that // case calculation is G + A, it resolves to an address of entry in GOT // (R_GOT) and not an offset. // // To check that instruction has no base register we scan ModR/M byte. // See "Table 2-2. 32-Bit Addressing Forms with the ModR/M Byte" // (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/ // 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf) if ((Loc[-1] & 0xc7) != 0x5) return R_GOT_FROM_END; if (Config->Pic) error(toString(S.File) + ": relocation " + toString(Type) + " against '" + S.getName() + "' without base register can not be used when PIC enabled"); return 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: error(toString(S.File) + ": unknown relocation type: " + toString(Type)); return R_HINT; } } RelExpr X86::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const { switch (Expr) { default: return Expr; case R_RELAX_TLS_GD_TO_IE: return R_RELAX_TLS_GD_TO_IE_END; case R_RELAX_TLS_GD_TO_LE: return R_RELAX_TLS_GD_TO_LE_NEG; } } void X86::writeGotPltHeader(uint8_t *Buf) const { write32le(Buf, InX::Dynamic->getVA()); } void X86::writeGotPlt(uint8_t *Buf, const SymbolBody &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 SymbolBody &S) const { // An x86 entry is the address of the ifunc resolver function. write32le(Buf, S.getVA()); } uint32_t X86::getDynRel(uint32_t Type) const { if (Type == R_386_TLS_LE) return R_386_TLS_TPOFF; if (Type == R_386_TLS_LE_32) return R_386_TLS_TPOFF32; return Type; } void X86::writePltHeader(uint8_t *Buf) const { if (Config->Pic) { const uint8_t V[] = { 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl GOTPLT+4(%ebx) 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *GOTPLT+8(%ebx) 0x90, 0x90, 0x90, 0x90 // nop }; memcpy(Buf, V, sizeof(V)); uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); uint32_t GotPlt = InX::GotPlt->getVA() - Ebx; write32le(Buf + 2, GotPlt + 4); write32le(Buf + 8, GotPlt + 8); return; } const uint8_t PltData[] = { 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushl (GOTPLT+4) 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *(GOTPLT+8) 0x90, 0x90, 0x90, 0x90 // nop }; memcpy(Buf, PltData, sizeof(PltData)); uint32_t GotPlt = InX::GotPlt->getVA(); write32le(Buf + 2, GotPlt + 4); write32le(Buf + 8, GotPlt + 8); } void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Inst[] = { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, // jmp *foo_in_GOT|*foo@GOT(%ebx) 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $reloc_offset 0xe9, 0x00, 0x00, 0x00, 0x00 // jmp .PLT0@PC }; memcpy(Buf, Inst, sizeof(Inst)); if (Config->Pic) { // jmp *foo@GOT(%ebx) uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); Buf[1] = 0xa3; write32le(Buf + 2, GotPltEntryAddr - Ebx); } else { // jmp *foo_in_GOT Buf[1] = 0x25; write32le(Buf + 2, GotPltEntryAddr); } write32le(Buf + 7, RelOff); write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); } int64_t X86::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { switch (Type) { default: return 0; 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)); } } void X86::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // 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. switch (Type) { case R_386_8: checkUInt<8>(Loc, Val, Type); *Loc = Val; break; case R_386_PC8: checkInt<8>(Loc, Val, Type); *Loc = Val; break; case R_386_16: checkUInt<16>(Loc, Val, Type); write16le(Loc, Val); break; case R_386_PC16: // R_386_PC16 is normally used with 16 bit code. In that situation // the PC is 16 bits, just like the addend. This means that it can // point from any 16 bit address to any other if the possibility // of wrapping is included. // The only restriction we have to check then is that the destination // address fits in 16 bits. That is impossible to do here. The problem is // that we are passed the final value, which already had the // current location subtracted from it. // We just check that Val fits in 17 bits. This misses some cases, but // should have no false positives. checkInt<17>(Loc, Val, Type); write16le(Loc, Val); break; default: checkInt<32>(Loc, Val, Type); write32le(Loc, Val); } } void X86::relaxTlsGdToLe(uint8_t *Loc, uint32_t 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, 0x00, 0x00, 0x00, 0x00 // subl 0(%ebx), %eax }; memcpy(Loc - 3, Inst, sizeof(Inst)); write32le(Loc + 5, Val); } void X86::relaxTlsGdToIe(uint8_t *Loc, uint32_t 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, 0x00, 0x00, 0x00, 0x00 // addl 0(%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, uint32_t 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, uint32_t 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)); } -TargetInfo *elf::createX86TargetInfo() { return make(); } +TargetInfo *elf::getX86TargetInfo() { + static X86 Target; + return &Target; +} Index: vendor/lld/dist/ELF/Arch/X86_64.cpp =================================================================== --- vendor/lld/dist/ELF/Arch/X86_64.cpp (revision 320381) +++ vendor/lld/dist/ELF/Arch/X86_64.cpp (revision 320382) @@ -1,468 +1,473 @@ //===- X86_64.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.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 final : public TargetInfo { public: X86_64(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; bool isPicRel(uint32_t Type) const override; void writeGotPltHeader(uint8_t *Buf) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &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, uint32_t Type, uint64_t Val) const override; RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const override; void relaxGot(uint8_t *Loc, uint64_t Val) const override; void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; private: void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, uint8_t ModRm) const; }; } // namespace template X86_64::X86_64() { + GotBaseSymOff = -1; CopyRel = R_X86_64_COPY; GotRel = R_X86_64_GLOB_DAT; PltRel = R_X86_64_JUMP_SLOT; RelativeRel = R_X86_64_RELATIVE; IRelativeRel = R_X86_64_IRELATIVE; TlsGotRel = R_X86_64_TPOFF64; TlsModuleIndexRel = R_X86_64_DTPMOD64; TlsOffsetRel = R_X86_64_DTPOFF64; GotEntrySize = 8; GotPltEntrySize = 8; PltEntrySize = 16; PltHeaderSize = 16; TlsGdRelaxSkip = 2; + TrapInstr = 0xcccccccc; // 0xcc = INT3 // Align to the large page size (known as a superpage or huge page). // FreeBSD automatically promotes large, superpage-aligned allocations. DefaultImageBase = 0x200000; - - // 0xCC is the "int3" (call debug exception handler) instruction. - TrapInstr = 0xcccccccc; } template RelExpr X86_64::getRelExpr(uint32_t Type, const SymbolBody &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_NONE: return R_NONE; default: error(toString(S.File) + ": unknown relocation type: " + toString(Type)); return R_HINT; } } template void X86_64::writeGotPltHeader(uint8_t *Buf) const { // The first entry holds the value of _DYNAMIC. It is not clear why that is // required, but it is documented in the psabi and the glibc dynamic linker // seems to use it (note that this is relevant for linking ld.so, not any // other program). write64le(Buf, InX::Dynamic->getVA()); } template void X86_64::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const { // See comments in X86TargetInfo::writeGotPlt. write32le(Buf, S.getPltVA() + 6); } template void X86_64::writePltHeader(uint8_t *Buf) const { const uint8_t PltData[] = { 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOTPLT+8(%rip) 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOTPLT+16(%rip) 0x0f, 0x1f, 0x40, 0x00 // nop }; memcpy(Buf, PltData, sizeof(PltData)); uint64_t GotPlt = InX::GotPlt->getVA(); uint64_t Plt = InX::Plt->getVA(); write32le(Buf + 2, GotPlt - Plt + 2); // GOTPLT+8 write32le(Buf + 8, GotPlt - Plt + 4); // GOTPLT+16 } template void X86_64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Inst[] = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip) 0x68, 0x00, 0x00, 0x00, 0x00, // pushq 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[0] }; memcpy(Buf, Inst, sizeof(Inst)); write32le(Buf + 2, GotPltEntryAddr - PltEntryAddr - 6); write32le(Buf + 7, Index); write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); } template bool X86_64::isPicRel(uint32_t Type) const { return Type != R_X86_64_PC32 && Type != R_X86_64_32 && Type != R_X86_64_TPOFF32; } template void X86_64::relaxTlsGdToLe(uint8_t *Loc, uint32_t 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, 0x00, 0x00, 0x00, 0x00 // 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, uint32_t 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, 0x00, 0x00, 0x00, 0x00 // 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, uint32_t 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, uint32_t 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, uint32_t Type, uint64_t Val) const { switch (Type) { case R_X86_64_8: checkUInt<8>(Loc, Val, Type); *Loc = Val; break; case R_X86_64_16: checkUInt<16>(Loc, Val, Type); write16le(Loc, Val); break; case R_X86_64_32: checkUInt<32>(Loc, Val, Type); write32le(Loc, Val); break; case R_X86_64_32S: case R_X86_64_TPOFF32: case R_X86_64_GOT32: case R_X86_64_GOTPCREL: case R_X86_64_GOTPCRELX: case R_X86_64_REX_GOTPCRELX: case R_X86_64_PC32: case R_X86_64_GOTTPOFF: case R_X86_64_PLT32: case R_X86_64_TLSGD: case R_X86_64_TLSLD: case R_X86_64_DTPOFF32: case R_X86_64_SIZE32: checkInt<32>(Loc, Val, Type); 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: write64le(Loc, Val); break; default: llvm_unreachable("unexpected relocation"); } } template RelExpr X86_64::adjustRelaxExpr(uint32_t 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); } -TargetInfo *elf::createX32TargetInfo() { return make>(); } -TargetInfo *elf::createX86_64TargetInfo() { return make>(); } +TargetInfo *elf::getX32TargetInfo() { + static X86_64 Target; + return &Target; +} + +TargetInfo *elf::getX86_64TargetInfo() { + static X86_64 Target; + return &Target; +} Index: vendor/lld/dist/ELF/CMakeLists.txt =================================================================== --- vendor/lld/dist/ELF/CMakeLists.txt (revision 320381) +++ vendor/lld/dist/ELF/CMakeLists.txt (revision 320382) @@ -1,74 +1,74 @@ 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 Arch/AArch64.cpp Arch/AMDGPU.cpp Arch/ARM.cpp Arch/AVR.cpp Arch/Mips.cpp + Arch/MipsArchTree.cpp Arch/PPC.cpp Arch/PPC64.cpp Arch/X86.cpp Arch/X86_64.cpp Driver.cpp DriverUtils.cpp EhFrame.cpp Error.cpp Filesystem.cpp GdbIndex.cpp ICF.cpp InputFiles.cpp InputSection.cpp LTO.cpp LinkerScript.cpp MapFile.cpp MarkLive.cpp - Mips.cpp OutputSections.cpp Relocations.cpp ScriptLexer.cpp ScriptParser.cpp Strings.cpp SymbolTable.cpp Symbols.cpp SyntheticSections.cpp Target.cpp Thunks.cpp Writer.cpp LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} Analysis BinaryFormat BitReader BitWriter Codegen Core DebugInfoDWARF Demangle IPO Linker LTO Object Option Passes MC Support Target TransformUtils LINK_LIBS lldConfig lldCore ${LLVM_PTHREAD_LIB} DEPENDS ELFOptionsTableGen ${tablegen_deps} ) Index: vendor/lld/dist/ELF/Config.h =================================================================== --- vendor/lld/dist/ELF/Config.h (revision 320381) +++ vendor/lld/dist/ELF/Config.h (revision 320382) @@ -1,236 +1,236 @@ //===- Config.h -------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_ELF_CONFIG_H #define LLD_ELF_CONFIG_H #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/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; struct Symbol; enum ELFKind { ELFNoneKind, ELF32LEKind, ELF32BEKind, ELF64LEKind, ELF64BEKind }; // For --build-id. enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid }; // For --discard-{all,locals,none}. enum class DiscardPolicy { Default, All, Locals, None }; // For --strip-{all,debug}. enum class StripPolicy { None, All, Debug }; // For --unresolved-symbols. enum class UnresolvedPolicy { ReportError, Warn, WarnAll, Ignore, IgnoreAll }; // For --sort-section and linkerscript sorting rules. enum class SortSectionPolicy { Default, None, Alignment, Name, Priority }; // For --target2 enum class Target2Policy { Abs, Rel, GotRel }; struct SymbolVersion { llvm::StringRef Name; bool IsExternCpp; bool HasWildcard; }; // This struct contains symbols version definition that // can be found in version script if it is used for link. struct VersionDefinition { llvm::StringRef Name; uint16_t Id = 0; std::vector Globals; size_t NameOff = 0; // Offset in the string table }; // Structure for mapping renamed symbols struct RenamedSymbol { Symbol *Target; - uint8_t OrigBinding; + uint8_t OriginalBinding; }; // This struct contains the global configuration for the linker. // Most fields are direct mapping from the command line options // and such fields have the same name as the corresponding options. // Most fields are initialized by the driver. struct Configuration { InputFile *FirstElf = nullptr; uint8_t OSABI = 0; llvm::CachePruningPolicy ThinLTOCachePolicy; llvm::StringMap SectionStartMap; llvm::StringRef DynamicLinker; llvm::StringRef Entry; llvm::StringRef Emulation; llvm::StringRef Fini; llvm::StringRef Init; llvm::StringRef LTOAAPipeline; llvm::StringRef LTONewPmPasses; llvm::StringRef MapFile; llvm::StringRef OutputFile; llvm::StringRef OptRemarksFilename; llvm::StringRef SoName; llvm::StringRef Sysroot; llvm::StringRef ThinLTOCacheDir; std::string Rpath; std::vector VersionDefinitions; std::vector AuxiliaryList; std::vector SearchPaths; std::vector SymbolOrderingFile; std::vector Undefined; std::vector VersionScriptGlobals; std::vector VersionScriptLocals; std::vector BuildIdVector; llvm::MapVector RenamedSymbols; bool AllowMultipleDefinition; bool AsNeeded = false; bool Bsymbolic; bool BsymbolicFunctions; bool ColorDiagnostics = false; bool CompressDebugSections; bool DefineCommon; bool Demangle = true; bool DisableVerify; bool EhFrameHdr; bool EmitRelocs; bool EnableNewDtags; bool ExportDynamic; bool FatalWarnings; bool GcSections; bool GdbIndex; bool GnuHash; bool ICF; bool MipsN32Abi = false; bool NoGnuUnique; bool NoUndefinedVersion; bool Nostdlib; bool OFormatBinary; bool Omagic; bool OptRemarksWithHotness; bool Pie; bool PrintGcSections; bool Relocatable; bool SaveTemps; bool SingleRoRx; bool Shared; bool Static = false; bool SysvHash; bool Target1Rel; bool Threads; bool Trace; bool Verbose; bool WarnCommon; bool WarnMissingEntry; bool ZCombreloc; bool ZExecstack; bool ZNocopyreloc; bool ZNodelete; bool ZNodlopen; bool ZNow; bool ZOrigin; bool ZRelro; bool ZRodynamic; bool ZText; bool ExitEarly; bool ZWxneeded; DiscardPolicy Discard; SortSectionPolicy SortSection; StripPolicy Strip; UnresolvedPolicy UnresolvedSymbols; Target2Policy Target2; BuildIdKind BuildId = BuildIdKind::None; ELFKind EKind = ELFNoneKind; uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL; uint16_t EMachine = llvm::ELF::EM_NONE; uint64_t ErrorLimit = 20; uint64_t ImageBase; uint64_t MaxPageSize; uint64_t ZStackSize; unsigned LTOPartitions; unsigned LTOO; unsigned Optimize; unsigned ThinLTOJobs; // The following config options do not directly correspond to any // particualr command line options. // True if we need to pass through relocations in input files to the // output file. Usually false because we consume relocations. bool CopyRelocs; // True if the target is ELF64. False if ELF32. bool Is64; // True if the target is little-endian. False if big-endian. bool IsLE; // endianness::little if IsLE is true. endianness::big otherwise. llvm::support::endianness Endianness; // True if the target is the little-endian MIPS64. // // The reason why we have this variable only for the MIPS is because // we use this often. Some ELF headers for MIPS64EL are in a // mixed-endian (which is horrible and I'd say that's a serious spec // bug), and we need to know whether we are reading MIPS ELF files or // not in various places. // // (Note that MIPS64EL is not a typo for MIPS64LE. This is the official // name whatever that means. A fun hypothesis is that "EL" is short for // little-endian written in the little-endian order, but I don't know // if that's true.) bool IsMips64EL; // The ELF spec defines two types of relocation table entries, RELA and // REL. RELA is a triplet of (offset, info, addend) while REL is a // tuple of (offset, info). Addends for REL are implicit and read from // the location where the relocations are applied. So, REL is more // compact than RELA but requires a bit of more work to process. // // (From the linker writer's view, this distinction is not necessary. // If the ELF had chosen whichever and sticked with it, it would have // been easier to write code to process relocations, but it's too late // to change the spec.) // // Each ABI defines its relocation type. IsRela is true if target // uses RELA. As far as we know, all 64-bit ABIs are using RELA. A // few 32-bit ABIs are using RELA too. bool IsRela; // True if we are creating position-independent code. bool Pic; // 4 for ELF32, 8 for ELF64. int Wordsize; }; // The only instance of Configuration struct. extern Configuration *Config; } // namespace elf } // namespace lld #endif Index: vendor/lld/dist/ELF/Driver.cpp =================================================================== --- vendor/lld/dist/ELF/Driver.cpp (revision 320381) +++ vendor/lld/dist/ELF/Driver.cpp (revision 320382) @@ -1,1012 +1,1057 @@ //===- Driver.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // The driver drives the entire linking process. It is responsible for // parsing command line options and doing whatever it is instructed to do. // // One notable thing in the LLD's driver when compared to other linkers is // that the LLD's driver is agnostic on the host operating system. // Other linkers usually have implicit default values (such as a dynamic // linker path or library paths) for each host OS. // // I don't think implicit default values are useful because they are // usually explicitly specified by the compiler driver. They can even // be harmful when you are doing cross-linking. Therefore, in LLD, we // simply trust the compiler driver to pass all required options and // don't try to make effort on our side. // //===----------------------------------------------------------------------===// #include "Driver.h" #include "Config.h" #include "Error.h" #include "Filesystem.h" #include "ICF.h" #include "InputFiles.h" #include "InputSection.h" #include "LinkerScript.h" #include "Memory.h" #include "OutputSections.h" #include "ScriptParser.h" #include "Strings.h" #include "SymbolTable.h" #include "SyntheticSections.h" #include "Target.h" #include "Threads.h" #include "Writer.h" #include "lld/Config/Version.h" #include "lld/Driver/Driver.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" #include #include using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::sys; using namespace lld; using namespace lld::elf; Configuration *elf::Config; LinkerDriver *elf::Driver; BumpPtrAllocator elf::BAlloc; StringSaver elf::Saver{BAlloc}; std::vector elf::SpecificAllocBase::Instances; static void setConfigs(); bool elf::link(ArrayRef Args, bool CanExitEarly, raw_ostream &Error) { ErrorCount = 0; ErrorOS = &Error; Argv0 = Args[0]; InputSections.clear(); Tar = nullptr; Config = make(); Driver = make(); Script = make(); Driver->main(Args, CanExitEarly); freeArena(); return !ErrorCount; } // Parses a linker -m option. static std::tuple parseEmulation(StringRef Emul) { uint8_t OSABI = 0; StringRef S = Emul; if (S.endswith("_fbsd")) { S = S.drop_back(5); OSABI = ELFOSABI_FREEBSD; } std::pair Ret = StringSwitch>(S) .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64}) .Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM}) .Case("elf32_x86_64", {ELF32LEKind, EM_X86_64}) .Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS}) .Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS}) .Case("elf32ppc", {ELF32BEKind, EM_PPC}) .Case("elf64btsmip", {ELF64BEKind, EM_MIPS}) .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS}) .Case("elf64ppc", {ELF64BEKind, EM_PPC64}) .Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64}) .Case("elf_i386", {ELF32LEKind, EM_386}) .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU}) .Default({ELFNoneKind, EM_NONE}); if (Ret.first == ELFNoneKind) { if (S == "i386pe" || S == "i386pep" || S == "thumb2pe") error("Windows targets are not supported on the ELF frontend: " + Emul); else error("unknown emulation: " + Emul); } return std::make_tuple(Ret.first, Ret.second, OSABI); } // Returns slices of MB by parsing MB as an archive file. // Each slice consists of a member file in the archive. std::vector> static getArchiveMembers( MemoryBufferRef MB) { std::unique_ptr File = check(Archive::create(MB), MB.getBufferIdentifier() + ": failed to parse archive"); std::vector> V; Error Err = Error::success(); for (const ErrorOr &COrErr : File->children(Err)) { Archive::Child C = check(COrErr, MB.getBufferIdentifier() + ": could not get the child of the archive"); MemoryBufferRef MBRef = check(C.getMemoryBufferRef(), MB.getBufferIdentifier() + ": could not get the buffer for a child of the archive"); V.push_back(std::make_pair(MBRef, C.getChildOffset())); } if (Err) fatal(MB.getBufferIdentifier() + ": Archive::children failed: " + toString(std::move(Err))); // Take ownership of memory buffers created for members of thin archives. for (std::unique_ptr &MB : File->takeThinBuffers()) make>(std::move(MB)); return V; } // Opens a file and create a file object. Path has to be resolved already. void LinkerDriver::addFile(StringRef Path, bool WithLOption) { using namespace sys::fs; Optional Buffer = readFile(Path); if (!Buffer.hasValue()) return; MemoryBufferRef MBRef = *Buffer; if (InBinary) { Files.push_back(make(MBRef)); return; } switch (identify_magic(MBRef.getBuffer())) { case file_magic::unknown: readLinkerScript(MBRef); return; case file_magic::archive: { // Handle -whole-archive. if (InWholeArchive) { for (const auto &P : getArchiveMembers(MBRef)) Files.push_back(createObjectFile(P.first, Path, P.second)); return; } std::unique_ptr File = check(Archive::create(MBRef), Path + ": failed to parse archive"); // If an archive file has no symbol table, it is likely that a user // is attempting LTO and using a default ar command that doesn't // understand the LLVM bitcode file. It is a pretty common error, so // we'll handle it as if it had a symbol table. if (!File->isEmpty() && !File->hasSymbolTable()) { for (const auto &P : getArchiveMembers(MBRef)) Files.push_back(make(P.first, Path, P.second)); return; } // Handle the regular case. Files.push_back(make(std::move(File))); return; } case file_magic::elf_shared_object: if (Config->Relocatable) { error("attempted static link of dynamic object " + Path); return; } + // DSOs usually have DT_SONAME tags in their ELF headers, and the // sonames are used to identify DSOs. But if they are missing, // they are identified by filenames. We don't know whether the new // file has a DT_SONAME or not because we haven't parsed it yet. // Here, we set the default soname for the file because we might // need it later. // // If a file was specified by -lfoo, the directory part is not // significant, as a user did not specify it. This behavior is // compatible with GNU. - Files.push_back(createSharedFile( - MBRef, WithLOption ? sys::path::filename(Path) : Path)); + Files.push_back( + createSharedFile(MBRef, WithLOption ? path::filename(Path) : Path)); return; default: if (InLib) Files.push_back(make(MBRef, "", 0)); else Files.push_back(createObjectFile(MBRef)); } } // Add a given library by searching it from input search paths. void LinkerDriver::addLibrary(StringRef Name) { if (Optional Path = searchLibrary(Name)) addFile(*Path, /*WithLOption=*/true); else error("unable to find library -l" + Name); } // This function is called on startup. We need this for LTO since // LTO calls LLVM functions to compile bitcode files to native code. // Technically this can be delayed until we read bitcode files, but // we don't bother to do lazily because the initialization is fast. static void initLLVM(opt::InputArgList &Args) { InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmPrinters(); InitializeAllAsmParsers(); // Parse and evaluate -mllvm options. std::vector V; V.push_back("lld (LLVM option parsing)"); for (auto *Arg : Args.filtered(OPT_mllvm)) V.push_back(Arg->getValue()); cl::ParseCommandLineOptions(V.size(), V.data()); } // Some command line options or some combinations of them are not allowed. // This function checks for such errors. static void checkOptions(opt::InputArgList &Args) { // The MIPS ABI as of 2016 does not support the GNU-style symbol lookup // table which is a relatively new feature. if (Config->EMachine == EM_MIPS && Config->GnuHash) error("the .gnu.hash section is not compatible with the MIPS target."); if (Config->Pie && Config->Shared) error("-shared and -pie may not be used together"); if (!Config->Shared && !Config->AuxiliaryList.empty()) error("-f may not be used without -shared"); if (Config->Relocatable) { if (Config->Shared) error("-r and -shared may not be used together"); if (Config->GcSections) error("-r and --gc-sections may not be used together"); if (Config->ICF) error("-r and --icf may not be used together"); if (Config->Pie) error("-r and -pie may not be used together"); } } static int getInteger(opt::InputArgList &Args, unsigned Key, int Default) { int V = Default; if (auto *Arg = Args.getLastArg(Key)) { StringRef S = Arg->getValue(); if (!to_integer(S, V, 10)) error(Arg->getSpelling() + ": number expected, but got " + S); } return V; } static const char *getReproduceOption(opt::InputArgList &Args) { if (auto *Arg = Args.getLastArg(OPT_reproduce)) return Arg->getValue(); return getenv("LLD_REPRODUCE"); } static bool hasZOption(opt::InputArgList &Args, StringRef Key) { for (auto *Arg : Args.filtered(OPT_z)) if (Key == Arg->getValue()) return true; return false; } static uint64_t getZOptionValue(opt::InputArgList &Args, StringRef Key, uint64_t Default) { for (auto *Arg : Args.filtered(OPT_z)) { std::pair KV = StringRef(Arg->getValue()).split('='); if (KV.first == Key) { - uint64_t Result; + uint64_t Result = Default; if (!to_integer(KV.second, Result)) error("invalid " + Key + ": " + KV.second); return Result; } } return Default; } void LinkerDriver::main(ArrayRef ArgsArr, bool CanExitEarly) { ELFOptTable Parser; opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); // Interpret this flag early because error() depends on them. Config->ErrorLimit = getInteger(Args, OPT_error_limit, 20); // Handle -help if (Args.hasArg(OPT_help)) { printHelp(ArgsArr[0]); return; } // Handle -v or -version. // // A note about "compatible with GNU linkers" message: this is a hack for // scripts generated by GNU Libtool 2.4.6 (released in February 2014 and // still the newest version in March 2017) or earlier to recognize LLD as // a GNU compatible linker. As long as an output for the -v option // contains "GNU" or "with BFD", they recognize us as GNU-compatible. // // This is somewhat ugly hack, but in reality, we had no choice other // than doing this. Considering the very long release cycle of Libtool, // it is not easy to improve it to recognize LLD as a GNU compatible // linker in a timely manner. Even if we can make it, there are still a // lot of "configure" scripts out there that are generated by old version // of Libtool. We cannot convince every software developer to migrate to // the latest version and re-generate scripts. So we have this hack. if (Args.hasArg(OPT_v) || Args.hasArg(OPT_version)) message(getLLDVersion() + " (compatible with GNU linkers)"); // ld.bfd always exits after printing out the version string. // ld.gold proceeds if a given option is -v. Because gold's behavior // is more permissive than ld.bfd, we chose what gold does here. if (Args.hasArg(OPT_version)) return; Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown); if (const char *Path = getReproduceOption(Args)) { // Note that --reproduce is a debug option so you can ignore it // if you are trying to understand the whole picture of the code. Expected> ErrOrWriter = TarWriter::create(Path, path::stem(Path)); if (ErrOrWriter) { Tar = ErrOrWriter->get(); Tar->append("response.txt", createResponseFile(Args)); Tar->append("version.txt", getLLDVersion() + "\n"); make>(std::move(*ErrOrWriter)); } else { error(Twine("--reproduce: failed to open ") + Path + ": " + toString(ErrOrWriter.takeError())); } } readConfigs(Args); initLLVM(Args); createFiles(Args); inferMachineType(); setConfigs(); checkOptions(Args); if (ErrorCount) return; switch (Config->EKind) { case ELF32LEKind: link(Args); return; case ELF32BEKind: link(Args); return; case ELF64LEKind: link(Args); return; case ELF64BEKind: link(Args); return; default: llvm_unreachable("unknown Config->EKind"); } } static bool getArg(opt::InputArgList &Args, unsigned K1, unsigned K2, bool Default) { if (auto *Arg = Args.getLastArg(K1, K2)) return Arg->getOption().getID() == K1; return Default; } static std::vector getArgs(opt::InputArgList &Args, int Id) { std::vector V; for (auto *Arg : Args.filtered(Id)) V.push_back(Arg->getValue()); return V; } static std::string getRpath(opt::InputArgList &Args) { std::vector V = getArgs(Args, OPT_rpath); return llvm::join(V.begin(), V.end(), ":"); } // Determines what we should do if there are remaining unresolved // symbols after the name resolution. static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) { // -noinhibit-exec or -r imply some default values. if (Args.hasArg(OPT_noinhibit_exec)) return UnresolvedPolicy::WarnAll; if (Args.hasArg(OPT_relocatable)) return UnresolvedPolicy::IgnoreAll; UnresolvedPolicy ErrorOrWarn = getArg(Args, OPT_error_unresolved_symbols, OPT_warn_unresolved_symbols, true) ? UnresolvedPolicy::ReportError : UnresolvedPolicy::Warn; // Process the last of -unresolved-symbols, -no-undefined or -z defs. for (auto *Arg : llvm::reverse(Args)) { switch (Arg->getOption().getID()) { case OPT_unresolved_symbols: { StringRef S = Arg->getValue(); if (S == "ignore-all" || S == "ignore-in-object-files") return UnresolvedPolicy::Ignore; if (S == "ignore-in-shared-libs" || S == "report-all") return ErrorOrWarn; error("unknown --unresolved-symbols value: " + S); continue; } case OPT_no_undefined: return ErrorOrWarn; case OPT_z: if (StringRef(Arg->getValue()) == "defs") return ErrorOrWarn; continue; } } // -shared implies -unresolved-symbols=ignore-all because missing // symbols are likely to be resolved at runtime using other DSOs. if (Config->Shared) return UnresolvedPolicy::Ignore; return ErrorOrWarn; } static Target2Policy getTarget2(opt::InputArgList &Args) { StringRef S = Args.getLastArgValue(OPT_target2, "got-rel"); if (S == "rel") return Target2Policy::Rel; if (S == "abs") return Target2Policy::Abs; if (S == "got-rel") return Target2Policy::GotRel; error("unknown --target2 option: " + S); return Target2Policy::GotRel; } static bool isOutputFormatBinary(opt::InputArgList &Args) { if (auto *Arg = Args.getLastArg(OPT_oformat)) { StringRef S = Arg->getValue(); if (S == "binary") return true; error("unknown --oformat value: " + S); } return false; } static DiscardPolicy getDiscard(opt::InputArgList &Args) { if (Args.hasArg(OPT_relocatable)) return DiscardPolicy::None; auto *Arg = Args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none); if (!Arg) return DiscardPolicy::Default; if (Arg->getOption().getID() == OPT_discard_all) return DiscardPolicy::All; if (Arg->getOption().getID() == OPT_discard_locals) return DiscardPolicy::Locals; return DiscardPolicy::None; } static StringRef getDynamicLinker(opt::InputArgList &Args) { auto *Arg = Args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker); if (!Arg || Arg->getOption().getID() == OPT_no_dynamic_linker) return ""; return Arg->getValue(); } static StripPolicy getStrip(opt::InputArgList &Args) { if (Args.hasArg(OPT_relocatable)) return StripPolicy::None; auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug); if (!Arg) return StripPolicy::None; if (Arg->getOption().getID() == OPT_strip_all) return StripPolicy::All; return StripPolicy::Debug; } static uint64_t parseSectionAddress(StringRef S, opt::Arg *Arg) { uint64_t VA = 0; if (S.startswith("0x")) S = S.drop_front(2); if (!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 std::pair getHashStyle(opt::InputArgList &Args) { StringRef S = Args.getLastArgValue(OPT_hash_style, "sysv"); if (S == "sysv") return {true, false}; if (S == "gnu") return {false, true}; if (S != "both") error("unknown -hash-style: " + S); return {true, true}; } // Parse --build-id or --build-id= .. 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. 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. Options for Windows 8 app store are not recognized too (e.g. ``/APPCONTAINER``). 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. LLD uses Microsoft ``lib.exe`` tool to create an import library file. Windows resource files support :good:`Done`. If an ``.res`` file is given, LLD converts the file to a COFF - file using ``cvtres.exe`` command and link it. + 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 :none:`No progress has been made`. Microsoft linker can interpret the CodeGen debug info (old-style debug info) and PDB to emit an .pdb file. LLD doesn't support neither. 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: vendor/lld/dist/lib/Driver/DarwinLdDriver.cpp =================================================================== --- vendor/lld/dist/lib/Driver/DarwinLdDriver.cpp (revision 320381) +++ vendor/lld/dist/lib/Driver/DarwinLdDriver.cpp (revision 320382) @@ -1,1237 +1,1239 @@ //===- 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/Core/ArchiveLibraryFile.h" #include "lld/Core/Error.h" #include "lld/Core/File.h" #include "lld/Core/Instrumentation.h" #include "lld/Core/LLVM.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) \ - OPT_##ID, +#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) \ - { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ - PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS }, +#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, raw_ostream &diag, bool wholeArchive, bool upwardDylib) { if (ctx.logInputFiles()) diag << path << "\n"; 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, raw_ostream &diag) { std::vector> files = loadFile(ctx, path, diag, 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, raw_ostream &diagnostics) { // 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, raw_ostream &diagnostics) { // 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, raw_ostream &diagnostics) { // 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()) { diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n'; } addFile(path, ctx, forceLoad, false, diagnostics); 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, raw_ostream &diagnostics) { // 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) { diagnostics << "error: missing arg value for '" << parsedArgs.getArgString(missingIndex) << "' expected " << missingCount << " argument(s).\n"; return false; } for (auto unknownArg : parsedArgs.filtered(OPT_UNKNOWN)) { diagnostics << "warning: ignoring unknown argument: " << unknownArg->getAsString(parsedArgs) << "\n"; } // 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) { diagnostics << "error: unknown arch named '" << archStr->getValue() << "'\n"; 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 diagnostics << "error: -arch not specified and could not be inferred\n"; 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)) { diagnostics << "error: malformed macosx_version_min value\n"; return false; } break; case OPT_ios_version_min: os = MachOLinkingContext::OS::iOS; if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), minOSVersion)) { diagnostics << "error: malformed ios_version_min value\n"; return false; } break; case OPT_ios_simulator_version_min: os = MachOLinkingContext::OS::iOS_simulator; if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), minOSVersion)) { diagnostics << "error: malformed ios_simulator_version_min value\n"; 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)) { diagnostics << "error: image_base expects a hex number\n"; return false; } else if (baseAddress < ctx.pageZeroSize()) { diagnostics << "error: image_base overlaps with __PAGEZERO\n"; return false; } else if (baseAddress % ctx.pageSize()) { diagnostics << "error: image_base must be a multiple of page size (" << "0x" << llvm::utohexstr(ctx.pageSize()) << ")\n"; 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) { diagnostics << "error: -compatibility_version can only be used with -dylib\n"; return false; } uint32_t parsedVers; if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) { diagnostics << "error: -compatibility_version value is malformed\n"; return false; } ctx.setCompatibilityVersion(parsedVers); } if (llvm::opt::Arg *vers = parsedArgs.getLastArg(OPT_current_version)) { if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) { diagnostics << "-current_version can only be used with -dylib\n"; return false; } uint32_t parsedVers; if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) { diagnostics << "error: -current_version value is malformed\n"; 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)) { diagnostics << "error: -sectalign alignment value '" << alignStr << "' not a valid number\n"; return false; } uint16_t align = 1 << llvm::countTrailingZeros(alignValue); if (!llvm::isPowerOf2_64(alignValue)) { diagnostics << "warning: alignment for '-sectalign " << segName << " " << sectName << llvm::format(" 0x%llX", alignValue) << "' is not a power of two, using " << llvm::format("0x%08X", align) << "\n"; } 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) diagnostics << "warning: -keep_private_externs only used in -r mode\n"; } // 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())) { diagnostics << "warning: " << ec.message() << ", processing '-dependency_info " << depInfo->getValue() << "'\n"; } } // 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 (parsedArgs.getLastArg(OPT_v)) { diagnostics << "Library search paths:\n"; for (auto path : ctx.searchDirs()) { diagnostics << " " << path << '\n'; } diagnostics << "Framework search paths:\n"; for (auto path : ctx.frameworkDirs()) { diagnostics << " " << path << '\n'; } } // Handle -exported_symbols_list for (auto expFile : parsedArgs.filtered(OPT_exported_symbols_list)) { if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) { diagnostics << "error: -exported_symbols_list cannot be combined " << "with -unexported_symbol[s_list]\n"; return false; } ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList); if (std::error_code ec = parseExportsList(expFile->getValue(), ctx, diagnostics)) { diagnostics << "error: " << ec.message() << ", processing '-exported_symbols_list " << expFile->getValue() << "'\n"; return false; } } // Handle -exported_symbol for (auto symbol : parsedArgs.filtered(OPT_exported_symbol)) { if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) { diagnostics << "error: -exported_symbol cannot be combined " << "with -unexported_symbol[s_list]\n"; 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) { diagnostics << "error: -unexported_symbols_list cannot be combined " << "with -exported_symbol[s_list]\n"; return false; } ctx.setExportMode(MachOLinkingContext::ExportMode::blackList); if (std::error_code ec = parseExportsList(expFile->getValue(), ctx, diagnostics)) { diagnostics << "error: " << ec.message() << ", processing '-unexported_symbols_list " << expFile->getValue() << "'\n"; return false; } } // Handle -unexported_symbol for (auto symbol : parsedArgs.filtered(OPT_unexported_symbol)) { if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) { diagnostics << "error: -unexported_symbol cannot be combined " << "with -exported_symbol[s_list]\n"; 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) { diagnostics << "warning: -multi_module is obsolete and being ignored\n"; } else { if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) { diagnostics << "warning: -single_module being ignored. " "It is only for use when producing a dylib\n"; } } } // Handle obsolete ObjC options: -objc_gc_compaction, -objc_gc, -objc_gc_only if (parsedArgs.getLastArg(OPT_objc_gc_compaction)) { diagnostics << "error: -objc_gc_compaction is not supported\n"; return false; } if (parsedArgs.getLastArg(OPT_objc_gc)) { diagnostics << "error: -objc_gc is not supported\n"; return false; } if (parsedArgs.getLastArg(OPT_objc_gc_only)) { diagnostics << "error: -objc_gc_only is not supported\n"; 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)) { diagnostics << "-pie can only be used when targeting " "Mac OS X 10.5 or later\n"; return false; } break; case MachOLinkingContext::OS::iOS: if ((minOSVersion < 0x00040200) && (pie->getOption().getID() == OPT_pie)) { diagnostics << "-pie can only be used when targeting " "iOS 4.2 or later\n"; return false; } break; case MachOLinkingContext::OS::iOS_simulator: if (pie->getOption().getID() == OPT_no_pie) { diagnostics << "iOS simulator programs must be built PIE\n"; 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: diagnostics << "warning: " << pie->getSpelling() << " being ignored. " << "It is only used when linking main executables\n"; break; default: diagnostics << pie->getSpelling() << " can only used when linking main executables\n"; 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)) { diagnostics << "error: malformed sdkVersion value\n"; 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. diagnostics << "warning: -sdk_version is required when emitting " "min version load command. " "Setting sdk version to match provided min version\n"; 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)) { diagnostics << "error: malformed source_version value\n"; 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)) { diagnostics << "error: stack_size expects a hex number\n"; return false; } if ((stackSizeVal % ctx.pageSize()) != 0) { diagnostics << "error: stack_size must be a multiple of page size (" << "0x" << llvm::utohexstr(ctx.pageSize()) << ")\n"; 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, diagnostics)) { diagnostics << "error: " << ec.message() << ", processing '-order_file " << orderFile->getValue() << "'\n"; 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 { diagnostics << "error: invalid option to -undefined " "[ warning | error | suppress | dynamic_lookup ]\n"; 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) { diagnostics << "error: can't use -undefined warning or suppress with " "-twolevel_namespace\n"; 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) { diagnostics << "error: -rpath can only be used when targeting " "OS X 10.5 or later\n"; } else { diagnostics << "error: -rpath can only be used when targeting " "iOS 2.0 or later\n"; } return false; } break; default: diagnostics << "error: -rpath can only be used when creating " "a dynamic final linked image\n"; 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 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, diagnostics); break; case OPT_upward_library: addFile(arg->getValue(), ctx, false, true, diagnostics); break; case OPT_force_load: addFile(arg->getValue(), ctx, true, false, diagnostics); break; case OPT_l: case OPT_upward_l: upward = (arg->getOption().getID() == OPT_upward_l); resolvedPath = ctx.searchLibrary(arg->getValue()); if (!resolvedPath) { diagnostics << "Unable to find library for " << arg->getSpelling() << arg->getValue() << "\n"; return false; } else if (ctx.testingFileUsage()) { diagnostics << "Found " << (upward ? "upward " : " ") << "library " << canonicalizePath(resolvedPath.getValue()) << '\n'; } addFile(resolvedPath.getValue(), ctx, globalWholeArchive, upward, diagnostics); break; case OPT_framework: case OPT_upward_framework: upward = (arg->getOption().getID() == OPT_upward_framework); resolvedPath = ctx.findPathForFramework(arg->getValue()); if (!resolvedPath) { diagnostics << "Unable to find framework for " << arg->getSpelling() << " " << arg->getValue() << "\n"; return false; } else if (ctx.testingFileUsage()) { diagnostics << "Found " << (upward ? "upward " : " ") << "framework " << canonicalizePath(resolvedPath.getValue()) << '\n'; } addFile(resolvedPath.getValue(), ctx, globalWholeArchive, upward, diagnostics); break; case OPT_filelist: if (auto ec = loadFileList(arg->getValue(), ctx, globalWholeArchive, diagnostics)) { handleAllErrors(std::move(ec), [&](const llvm::ErrorInfoBase &EI) { diagnostics << "error: "; EI.log(diagnostics); diagnostics << ", processing '-filelist " << arg->getValue() << "'\n"; }); 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) { diagnostics << "error: can't open -sectcreate file " << fileName << "\n"; return false; } ctx.addSectCreateSection(seg, sect, std::move(*contentOrErr)); } break; } } if (ctx.getNodes().empty()) { diagnostics << "No input files\n"; return false; } // Validate the combination of options used. return ctx.validate(diagnostics); } 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, raw_ostream &diagnostics) { MachOLinkingContext ctx; if (!parse(args, ctx, diagnostics)) 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. diagnostics << "Failed to run passes on file '" << ctx.outputPath() << "': "; logAllUnhandledErrors(std::move(ec), diagnostics, 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. diagnostics << "Failed to write file '" << ctx.outputPath() << "': "; logAllUnhandledErrors(std::move(ec), diagnostics, std::string()); return false; } return true; } } // end namespace mach_o } // end namespace lld Index: vendor/lld/dist/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp =================================================================== --- vendor/lld/dist/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp (revision 320381) +++ vendor/lld/dist/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp (revision 320382) @@ -1,1635 +1,1635 @@ //===- lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp --------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file Converts from in-memory normalized mach-o to in-memory Atoms. /// /// +------------+ /// | normalized | /// +------------+ /// | /// | /// v /// +-------+ /// | Atoms | /// +-------+ #include "ArchHandler.h" #include "Atoms.h" #include "File.h" #include "MachONormalizedFile.h" #include "MachONormalizedFileBinaryUtils.h" #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" #include "llvm/Support/Format.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/raw_ostream.h" using namespace llvm::MachO; using namespace lld::mach_o::normalized; #define DEBUG_TYPE "normalized-file-to-atoms" namespace lld { namespace mach_o { namespace { // anonymous #define ENTRY(seg, sect, type, atomType) \ {seg, sect, type, DefinedAtom::atomType } struct MachORelocatableSectionToAtomType { StringRef segmentName; StringRef sectionName; SectionType sectionType; DefinedAtom::ContentType atomType; }; const MachORelocatableSectionToAtomType sectsToAtomType[] = { ENTRY("__TEXT", "__text", S_REGULAR, typeCode), ENTRY("__TEXT", "__text", S_REGULAR, typeResolver), ENTRY("__TEXT", "__cstring", S_CSTRING_LITERALS, typeCString), ENTRY("", "", S_CSTRING_LITERALS, typeCString), ENTRY("__TEXT", "__ustring", S_REGULAR, typeUTF16String), ENTRY("__TEXT", "__const", S_REGULAR, typeConstant), ENTRY("__TEXT", "__const_coal", S_COALESCED, typeConstant), ENTRY("__TEXT", "__eh_frame", S_COALESCED, typeCFI), ENTRY("__TEXT", "__eh_frame", S_REGULAR, typeCFI), ENTRY("__TEXT", "__literal4", S_4BYTE_LITERALS, typeLiteral4), ENTRY("__TEXT", "__literal8", S_8BYTE_LITERALS, typeLiteral8), ENTRY("__TEXT", "__literal16", S_16BYTE_LITERALS, typeLiteral16), ENTRY("__TEXT", "__gcc_except_tab", S_REGULAR, typeLSDA), ENTRY("__DATA", "__data", S_REGULAR, typeData), ENTRY("__DATA", "__datacoal_nt", S_COALESCED, typeData), ENTRY("__DATA", "__const", S_REGULAR, typeConstData), ENTRY("__DATA", "__cfstring", S_REGULAR, typeCFString), ENTRY("__DATA", "__mod_init_func", S_MOD_INIT_FUNC_POINTERS, typeInitializerPtr), ENTRY("__DATA", "__mod_term_func", S_MOD_TERM_FUNC_POINTERS, typeTerminatorPtr), ENTRY("__DATA", "__got", S_NON_LAZY_SYMBOL_POINTERS, typeGOT), ENTRY("__DATA", "__bss", S_ZEROFILL, typeZeroFill), ENTRY("", "", S_NON_LAZY_SYMBOL_POINTERS, typeGOT), ENTRY("__DATA", "__interposing", S_INTERPOSING, typeInterposingTuples), ENTRY("__DATA", "__thread_vars", S_THREAD_LOCAL_VARIABLES, typeThunkTLV), ENTRY("__DATA", "__thread_data", S_THREAD_LOCAL_REGULAR, typeTLVInitialData), ENTRY("__DATA", "__thread_bss", S_THREAD_LOCAL_ZEROFILL, typeTLVInitialZeroFill), ENTRY("__DATA", "__objc_imageinfo", S_REGULAR, typeObjCImageInfo), ENTRY("__DATA", "__objc_catlist", S_REGULAR, typeObjC2CategoryList), ENTRY("", "", S_INTERPOSING, typeInterposingTuples), ENTRY("__LD", "__compact_unwind", S_REGULAR, typeCompactUnwindInfo), ENTRY("", "", S_REGULAR, typeUnknown) }; #undef ENTRY /// Figures out ContentType of a mach-o section. DefinedAtom::ContentType atomTypeFromSection(const Section §ion, bool &customSectionName) { // First look for match of name and type. Empty names in table are wildcards. customSectionName = false; for (const MachORelocatableSectionToAtomType *p = sectsToAtomType ; p->atomType != DefinedAtom::typeUnknown; ++p) { if (p->sectionType != section.type) continue; if (!p->segmentName.equals(section.segmentName) && !p->segmentName.empty()) continue; if (!p->sectionName.equals(section.sectionName) && !p->sectionName.empty()) continue; customSectionName = p->segmentName.empty() && p->sectionName.empty(); return p->atomType; } // Look for code denoted by section attributes if (section.attributes & S_ATTR_PURE_INSTRUCTIONS) return DefinedAtom::typeCode; return DefinedAtom::typeUnknown; } enum AtomizeModel { atomizeAtSymbols, atomizeFixedSize, atomizePointerSize, atomizeUTF8, atomizeUTF16, atomizeCFI, atomizeCU, atomizeCFString }; /// Returns info on how to atomize a section of the specified ContentType. void sectionParseInfo(DefinedAtom::ContentType atomType, unsigned int &sizeMultiple, DefinedAtom::Scope &scope, DefinedAtom::Merge &merge, AtomizeModel &atomizeModel) { struct ParseInfo { DefinedAtom::ContentType atomType; unsigned int sizeMultiple; DefinedAtom::Scope scope; DefinedAtom::Merge merge; AtomizeModel atomizeModel; }; #define ENTRY(type, size, scope, merge, model) \ {DefinedAtom::type, size, DefinedAtom::scope, DefinedAtom::merge, model } static const ParseInfo parseInfo[] = { ENTRY(typeCode, 1, scopeGlobal, mergeNo, atomizeAtSymbols), ENTRY(typeData, 1, scopeGlobal, mergeNo, atomizeAtSymbols), ENTRY(typeConstData, 1, scopeGlobal, mergeNo, atomizeAtSymbols), ENTRY(typeZeroFill, 1, scopeGlobal, mergeNo, atomizeAtSymbols), ENTRY(typeConstant, 1, scopeGlobal, mergeNo, atomizeAtSymbols), ENTRY(typeCString, 1, scopeLinkageUnit, mergeByContent, atomizeUTF8), ENTRY(typeUTF16String, 1, scopeLinkageUnit, mergeByContent, atomizeUTF16), ENTRY(typeCFI, 4, scopeTranslationUnit, mergeNo, atomizeCFI), ENTRY(typeLiteral4, 4, scopeLinkageUnit, mergeByContent, atomizeFixedSize), ENTRY(typeLiteral8, 8, scopeLinkageUnit, mergeByContent, atomizeFixedSize), ENTRY(typeLiteral16, 16, scopeLinkageUnit, mergeByContent, atomizeFixedSize), ENTRY(typeCFString, 4, scopeLinkageUnit, mergeByContent, atomizeCFString), ENTRY(typeInitializerPtr, 4, scopeTranslationUnit, mergeNo, atomizePointerSize), ENTRY(typeTerminatorPtr, 4, scopeTranslationUnit, mergeNo, atomizePointerSize), ENTRY(typeCompactUnwindInfo, 4, scopeTranslationUnit, mergeNo, atomizeCU), ENTRY(typeGOT, 4, scopeLinkageUnit, mergeByContent, atomizePointerSize), ENTRY(typeObjC2CategoryList, 4, scopeTranslationUnit, mergeByContent, atomizePointerSize), ENTRY(typeUnknown, 1, scopeGlobal, mergeNo, atomizeAtSymbols) }; #undef ENTRY const int tableLen = sizeof(parseInfo) / sizeof(ParseInfo); for (int i=0; i < tableLen; ++i) { if (parseInfo[i].atomType == atomType) { sizeMultiple = parseInfo[i].sizeMultiple; scope = parseInfo[i].scope; merge = parseInfo[i].merge; atomizeModel = parseInfo[i].atomizeModel; return; } } // Unknown type is atomized by symbols. sizeMultiple = 1; scope = DefinedAtom::scopeGlobal; merge = DefinedAtom::mergeNo; atomizeModel = atomizeAtSymbols; } Atom::Scope atomScope(uint8_t scope) { switch (scope) { case N_EXT: return Atom::scopeGlobal; case N_PEXT: case N_PEXT | N_EXT: return Atom::scopeLinkageUnit; case 0: return Atom::scopeTranslationUnit; } llvm_unreachable("unknown scope value!"); } void appendSymbolsInSection(const std::vector &inSymbols, uint32_t sectionIndex, SmallVector &outSyms) { for (const Symbol &sym : inSymbols) { // Only look at definition symbols. if ((sym.type & N_TYPE) != N_SECT) continue; if (sym.sect != sectionIndex) continue; outSyms.push_back(&sym); } } void atomFromSymbol(DefinedAtom::ContentType atomType, const Section §ion, MachOFile &file, uint64_t symbolAddr, StringRef symbolName, uint16_t symbolDescFlags, Atom::Scope symbolScope, uint64_t nextSymbolAddr, bool scatterable, bool copyRefs) { // Mach-O symbol table does have size in it. Instead the size is the // difference between this and the next symbol. uint64_t size = nextSymbolAddr - symbolAddr; uint64_t offset = symbolAddr - section.address; bool noDeadStrip = (symbolDescFlags & N_NO_DEAD_STRIP) || !scatterable; if (isZeroFillSection(section.type)) { file.addZeroFillDefinedAtom(symbolName, symbolScope, offset, size, noDeadStrip, copyRefs, §ion); } else { DefinedAtom::Merge merge = (symbolDescFlags & N_WEAK_DEF) ? DefinedAtom::mergeAsWeak : DefinedAtom::mergeNo; bool thumb = (symbolDescFlags & N_ARM_THUMB_DEF); if (atomType == DefinedAtom::typeUnknown) { // Mach-O needs a segment and section name. Concatentate those two // with a / separator (e.g. "seg/sect") to fit into the lld model // of just a section name. std::string segSectName = section.segmentName.str() + "/" + section.sectionName.str(); file.addDefinedAtomInCustomSection(symbolName, symbolScope, atomType, merge, thumb, noDeadStrip, offset, size, segSectName, true, §ion); } else { if ((atomType == lld::DefinedAtom::typeCode) && (symbolDescFlags & N_SYMBOL_RESOLVER)) { atomType = lld::DefinedAtom::typeResolver; } file.addDefinedAtom(symbolName, symbolScope, atomType, merge, offset, size, thumb, noDeadStrip, copyRefs, §ion); } } } llvm::Error processSymboledSection(DefinedAtom::ContentType atomType, const Section §ion, const NormalizedFile &normalizedFile, MachOFile &file, bool scatterable, bool copyRefs) { // Find section's index. uint32_t sectIndex = 1; for (auto § : normalizedFile.sections) { if (§ == §ion) break; ++sectIndex; } // Find all symbols in this section. SmallVector symbols; appendSymbolsInSection(normalizedFile.globalSymbols, sectIndex, symbols); appendSymbolsInSection(normalizedFile.localSymbols, sectIndex, symbols); // Sort symbols. std::sort(symbols.begin(), symbols.end(), [](const Symbol *lhs, const Symbol *rhs) -> bool { if (lhs == rhs) return false; // First by address. uint64_t lhsAddr = lhs->value; uint64_t rhsAddr = rhs->value; if (lhsAddr != rhsAddr) return lhsAddr < rhsAddr; // If same address, one is an alias so sort by scope. Atom::Scope lScope = atomScope(lhs->scope); Atom::Scope rScope = atomScope(rhs->scope); if (lScope != rScope) return lScope < rScope; // If same address and scope, see if one might be better as // the alias. bool lPrivate = (lhs->name.front() == 'l'); bool rPrivate = (rhs->name.front() == 'l'); if (lPrivate != rPrivate) return lPrivate; // If same address and scope, sort by name. return lhs->name < rhs->name; }); // Debug logging of symbols. //for (const Symbol *sym : symbols) // llvm::errs() << " sym: " // << llvm::format("0x%08llx ", (uint64_t)sym->value) // << ", " << sym->name << "\n"; // If section has no symbols and no content, there are no atoms. if (symbols.empty() && section.content.empty()) return llvm::Error::success(); if (symbols.empty()) { // Section has no symbols, put all content in one anoymous atom. atomFromSymbol(atomType, section, file, section.address, StringRef(), 0, Atom::scopeTranslationUnit, section.address + section.content.size(), scatterable, copyRefs); } else if (symbols.front()->value != section.address) { // Section has anonymous content before first symbol. atomFromSymbol(atomType, section, file, section.address, StringRef(), 0, Atom::scopeTranslationUnit, symbols.front()->value, scatterable, copyRefs); } const Symbol *lastSym = nullptr; for (const Symbol *sym : symbols) { if (lastSym != nullptr) { // Ignore any assembler added "ltmpNNN" symbol at start of section // if there is another symbol at the start. if ((lastSym->value != sym->value) || lastSym->value != section.address || !lastSym->name.startswith("ltmp")) { atomFromSymbol(atomType, section, file, lastSym->value, lastSym->name, lastSym->desc, atomScope(lastSym->scope), sym->value, scatterable, copyRefs); } } lastSym = sym; } if (lastSym != nullptr) { atomFromSymbol(atomType, section, file, lastSym->value, lastSym->name, lastSym->desc, atomScope(lastSym->scope), section.address + section.content.size(), scatterable, copyRefs); } // If object built without .subsections_via_symbols, add reference chain. if (!scatterable) { MachODefinedAtom *prevAtom = nullptr; file.eachAtomInSection(section, [&](MachODefinedAtom *atom, uint64_t offset)->void { if (prevAtom) prevAtom->addReference(Reference::KindNamespace::all, Reference::KindArch::all, Reference::kindLayoutAfter, 0, atom, 0); prevAtom = atom; }); } return llvm::Error::success(); } llvm::Error processSection(DefinedAtom::ContentType atomType, const Section §ion, bool customSectionName, const NormalizedFile &normalizedFile, MachOFile &file, bool scatterable, bool copyRefs) { const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch); const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); // Get info on how to atomize section. unsigned int sizeMultiple; DefinedAtom::Scope scope; DefinedAtom::Merge merge; AtomizeModel atomizeModel; sectionParseInfo(atomType, sizeMultiple, scope, merge, atomizeModel); // Validate section size. if ((section.content.size() % sizeMultiple) != 0) return llvm::make_error(Twine("Section ") + section.segmentName + "/" + section.sectionName + " has size (" + Twine(section.content.size()) + ") which is not a multiple of " + Twine(sizeMultiple)); if (atomizeModel == atomizeAtSymbols) { // Break section up into atoms each with a fixed size. return processSymboledSection(atomType, section, normalizedFile, file, scatterable, copyRefs); } else { unsigned int size; for (unsigned int offset = 0, e = section.content.size(); offset != e;) { switch (atomizeModel) { case atomizeFixedSize: // Break section up into atoms each with a fixed size. size = sizeMultiple; break; case atomizePointerSize: // Break section up into atoms each the size of a pointer. size = is64 ? 8 : 4; break; case atomizeUTF8: // Break section up into zero terminated c-strings. size = 0; for (unsigned int i = offset; i < e; ++i) { if (section.content[i] == 0) { size = i + 1 - offset; break; } } break; case atomizeUTF16: // Break section up into zero terminated UTF16 strings. size = 0; for (unsigned int i = offset; i < e; i += 2) { if ((section.content[i] == 0) && (section.content[i + 1] == 0)) { size = i + 2 - offset; break; } } break; case atomizeCFI: // Break section up into dwarf unwind CFIs (FDE or CIE). size = read32(§ion.content[offset], isBig) + 4; if (offset+size > section.content.size()) { return llvm::make_error(Twine("Section ") + section.segmentName + "/" + section.sectionName + " is malformed. Size of CFI " "starting at offset (" + Twine(offset) + ") is past end of section."); } break; case atomizeCU: // Break section up into compact unwind entries. size = is64 ? 32 : 20; break; case atomizeCFString: // Break section up into NS/CFString objects. size = is64 ? 32 : 16; break; case atomizeAtSymbols: break; } if (size == 0) { return llvm::make_error(Twine("Section ") + section.segmentName + "/" + section.sectionName + " is malformed. The last atom " "is not zero terminated."); } if (customSectionName) { // Mach-O needs a segment and section name. Concatentate those two // with a / separator (e.g. "seg/sect") to fit into the lld model // of just a section name. std::string segSectName = section.segmentName.str() + "/" + section.sectionName.str(); file.addDefinedAtomInCustomSection(StringRef(), scope, atomType, merge, false, false, offset, size, segSectName, true, §ion); } else { file.addDefinedAtom(StringRef(), scope, atomType, merge, offset, size, false, false, copyRefs, §ion); } offset += size; } } return llvm::Error::success(); } const Section* findSectionCoveringAddress(const NormalizedFile &normalizedFile, uint64_t address) { for (const Section &s : normalizedFile.sections) { uint64_t sAddr = s.address; if ((sAddr <= address) && (address < sAddr+s.content.size())) { return &s; } } return nullptr; } const MachODefinedAtom * findAtomCoveringAddress(const NormalizedFile &normalizedFile, MachOFile &file, uint64_t addr, Reference::Addend &addend) { const Section *sect = nullptr; sect = findSectionCoveringAddress(normalizedFile, addr); if (!sect) return nullptr; uint32_t offsetInTarget; uint64_t offsetInSect = addr - sect->address; auto atom = file.findAtomCoveringAddress(*sect, offsetInSect, &offsetInTarget); addend = offsetInTarget; return atom; } // Walks all relocations for a section in a normalized .o file and // creates corresponding lld::Reference objects. llvm::Error convertRelocs(const Section §ion, const NormalizedFile &normalizedFile, bool scatterable, MachOFile &file, ArchHandler &handler) { // Utility function for ArchHandler to find atom by its address. auto atomByAddr = [&] (uint32_t sectIndex, uint64_t addr, const lld::Atom **atom, Reference::Addend *addend) -> llvm::Error { if (sectIndex > normalizedFile.sections.size()) return llvm::make_error(Twine("out of range section " "index (") + Twine(sectIndex) + ")"); const Section *sect = nullptr; if (sectIndex == 0) { sect = findSectionCoveringAddress(normalizedFile, addr); if (!sect) return llvm::make_error(Twine("address (" + Twine(addr) + ") is not in any section")); } else { sect = &normalizedFile.sections[sectIndex-1]; } uint32_t offsetInTarget; uint64_t offsetInSect = addr - sect->address; *atom = file.findAtomCoveringAddress(*sect, offsetInSect, &offsetInTarget); *addend = offsetInTarget; return llvm::Error::success(); }; // Utility function for ArchHandler to find atom by its symbol index. auto atomBySymbol = [&] (uint32_t symbolIndex, const lld::Atom **result) -> llvm::Error { // Find symbol from index. const Symbol *sym = nullptr; uint32_t numStabs = normalizedFile.stabsSymbols.size(); uint32_t numLocal = normalizedFile.localSymbols.size(); uint32_t numGlobal = normalizedFile.globalSymbols.size(); uint32_t numUndef = normalizedFile.undefinedSymbols.size(); assert(symbolIndex >= numStabs && "Searched for stab via atomBySymbol?"); if (symbolIndex < numStabs+numLocal) { sym = &normalizedFile.localSymbols[symbolIndex-numStabs]; } else if (symbolIndex < numStabs+numLocal+numGlobal) { sym = &normalizedFile.globalSymbols[symbolIndex-numStabs-numLocal]; } else if (symbolIndex < numStabs+numLocal+numGlobal+numUndef) { sym = &normalizedFile.undefinedSymbols[symbolIndex-numStabs-numLocal- numGlobal]; } else { return llvm::make_error(Twine("symbol index (") + Twine(symbolIndex) + ") out of range"); } // Find atom from symbol. if ((sym->type & N_TYPE) == N_SECT) { if (sym->sect > normalizedFile.sections.size()) return llvm::make_error(Twine("symbol section index (") + Twine(sym->sect) + ") out of range "); const Section &symSection = normalizedFile.sections[sym->sect-1]; uint64_t targetOffsetInSect = sym->value - symSection.address; MachODefinedAtom *target = file.findAtomCoveringAddress(symSection, targetOffsetInSect); if (target) { *result = target; return llvm::Error::success(); } return llvm::make_error("no atom found for defined symbol"); } else if ((sym->type & N_TYPE) == N_UNDF) { const lld::Atom *target = file.findUndefAtom(sym->name); if (target) { *result = target; return llvm::Error::success(); } return llvm::make_error("no undefined atom found for sym"); } else { // Search undefs return llvm::make_error("no atom found for symbol"); } }; const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); // Use old-school iterator so that paired relocations can be grouped. for (auto it=section.relocations.begin(), e=section.relocations.end(); it != e; ++it) { const Relocation &reloc = *it; // Find atom this relocation is in. if (reloc.offset > section.content.size()) return llvm::make_error( Twine("r_address (") + Twine(reloc.offset) + ") is larger than section size (" + Twine(section.content.size()) + ")"); uint32_t offsetInAtom; MachODefinedAtom *inAtom = file.findAtomCoveringAddress(section, reloc.offset, &offsetInAtom); assert(inAtom && "r_address in range, should have found atom"); uint64_t fixupAddress = section.address + reloc.offset; const lld::Atom *target = nullptr; Reference::Addend addend = 0; Reference::KindValue kind; if (handler.isPairedReloc(reloc)) { // Handle paired relocations together. const Relocation &reloc2 = *++it; auto relocErr = handler.getPairReferenceInfo( reloc, reloc2, inAtom, offsetInAtom, fixupAddress, isBig, scatterable, atomByAddr, atomBySymbol, &kind, &target, &addend); if (relocErr) { return handleErrors(std::move(relocErr), [&](std::unique_ptr GE) { return llvm::make_error( Twine("bad relocation (") + GE->getMessage() + ") in section " + section.segmentName + "/" + section.sectionName + " (r1_address=" + Twine::utohexstr(reloc.offset) + ", r1_type=" + Twine(reloc.type) + ", r1_extern=" + Twine(reloc.isExtern) + ", r1_length=" + Twine((int)reloc.length) + ", r1_pcrel=" + Twine(reloc.pcRel) + (!reloc.scattered ? (Twine(", r1_symbolnum=") + Twine(reloc.symbol)) : (Twine(", r1_scattered=1, r1_value=") + Twine(reloc.value))) + ")" + ", (r2_address=" + Twine::utohexstr(reloc2.offset) + ", r2_type=" + Twine(reloc2.type) + ", r2_extern=" + Twine(reloc2.isExtern) + ", r2_length=" + Twine((int)reloc2.length) + ", r2_pcrel=" + Twine(reloc2.pcRel) + (!reloc2.scattered ? (Twine(", r2_symbolnum=") + Twine(reloc2.symbol)) : (Twine(", r2_scattered=1, r2_value=") + Twine(reloc2.value))) + ")" ); }); } } else { // Use ArchHandler to convert relocation record into information // needed to instantiate an lld::Reference object. auto relocErr = handler.getReferenceInfo( reloc, inAtom, offsetInAtom, fixupAddress, isBig, atomByAddr, atomBySymbol, &kind, &target, &addend); if (relocErr) { return handleErrors(std::move(relocErr), [&](std::unique_ptr GE) { return llvm::make_error( Twine("bad relocation (") + GE->getMessage() + ") in section " + section.segmentName + "/" + section.sectionName + " (r_address=" + Twine::utohexstr(reloc.offset) + ", r_type=" + Twine(reloc.type) + ", r_extern=" + Twine(reloc.isExtern) + ", r_length=" + Twine((int)reloc.length) + ", r_pcrel=" + Twine(reloc.pcRel) + (!reloc.scattered ? (Twine(", r_symbolnum=") + Twine(reloc.symbol)) : (Twine(", r_scattered=1, r_value=") + Twine(reloc.value))) + ")" ); }); } } // Instantiate an lld::Reference object and add to its atom. inAtom->addReference(Reference::KindNamespace::mach_o, handler.kindArch(), kind, offsetInAtom, target, addend); } return llvm::Error::success(); } bool isDebugInfoSection(const Section §ion) { if ((section.attributes & S_ATTR_DEBUG) == 0) return false; return section.segmentName.equals("__DWARF"); } static const Atom* findDefinedAtomByName(MachOFile &file, Twine name) { std::string strName = name.str(); for (auto *atom : file.defined()) if (atom->name() == strName) return atom; return nullptr; } static StringRef copyDebugString(StringRef str, BumpPtrAllocator &alloc) { char *strCopy = alloc.Allocate(str.size() + 1); memcpy(strCopy, str.data(), str.size()); strCopy[str.size()] = '\0'; return strCopy; } llvm::Error parseStabs(MachOFile &file, const NormalizedFile &normalizedFile, bool copyRefs) { if (normalizedFile.stabsSymbols.empty()) return llvm::Error::success(); // FIXME: Kill this off when we can move to sane yaml parsing. std::unique_ptr allocator; if (copyRefs) allocator = llvm::make_unique(); enum { start, inBeginEnd } state = start; const Atom *currentAtom = nullptr; uint64_t currentAtomAddress = 0; StabsDebugInfo::StabsList stabsList; for (const auto &stabSym : normalizedFile.stabsSymbols) { Stab stab(nullptr, stabSym.type, stabSym.sect, stabSym.desc, stabSym.value, stabSym.name); switch (state) { case start: switch (static_cast(stabSym.type)) { case N_BNSYM: state = inBeginEnd; currentAtomAddress = stabSym.value; Reference::Addend addend; currentAtom = findAtomCoveringAddress(normalizedFile, file, currentAtomAddress, addend); if (addend != 0) return llvm::make_error( "Non-zero addend for BNSYM '" + stabSym.name + "' in " + file.path()); if (currentAtom) stab.atom = currentAtom; else { // FIXME: ld64 just issues a warning here - should we match that? return llvm::make_error( "can't find atom for stabs BNSYM at " + Twine::utohexstr(stabSym.value) + " in " + file.path()); } break; case N_SO: case N_OSO: // Not associated with an atom, just copy. if (copyRefs) stab.str = copyDebugString(stabSym.name, *allocator); else stab.str = stabSym.name; break; case N_GSYM: { auto colonIdx = stabSym.name.find(':'); if (colonIdx != StringRef::npos) { StringRef name = stabSym.name.substr(0, colonIdx); currentAtom = findDefinedAtomByName(file, "_" + name); stab.atom = currentAtom; if (copyRefs) stab.str = copyDebugString(stabSym.name, *allocator); else stab.str = stabSym.name; } else { currentAtom = findDefinedAtomByName(file, stabSym.name); stab.atom = currentAtom; if (copyRefs) stab.str = copyDebugString(stabSym.name, *allocator); else stab.str = stabSym.name; } if (stab.atom == nullptr) return llvm::make_error( "can't find atom for N_GSYM stabs" + stabSym.name + " in " + file.path()); break; } case N_FUN: return llvm::make_error( "old-style N_FUN stab '" + stabSym.name + "' unsupported"); default: return llvm::make_error( "unrecognized stab symbol '" + stabSym.name + "'"); } break; case inBeginEnd: stab.atom = currentAtom; switch (static_cast(stabSym.type)) { case N_ENSYM: state = start; currentAtom = nullptr; break; case N_FUN: // Just copy the string. if (copyRefs) stab.str = copyDebugString(stabSym.name, *allocator); else stab.str = stabSym.name; break; default: return llvm::make_error( "unrecognized stab symbol '" + stabSym.name + "'"); } } llvm::dbgs() << "Adding to stabsList: " << stab << "\n"; stabsList.push_back(stab); } file.setDebugInfo(llvm::make_unique(std::move(stabsList))); // FIXME: Kill this off when we fix YAML memory ownership. file.debugInfo()->setAllocator(std::move(allocator)); return llvm::Error::success(); } static llvm::DataExtractor dataExtractorFromSection(const NormalizedFile &normalizedFile, const Section &S) { const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch); const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); StringRef SecData(reinterpret_cast(S.content.data()), S.content.size()); return llvm::DataExtractor(SecData, !isBig, is64 ? 8 : 4); } // FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE // inspection" code if possible. static uint32_t getCUAbbrevOffset(llvm::DataExtractor abbrevData, uint64_t abbrCode) { uint64_t curCode; uint32_t offset = 0; while ((curCode = abbrevData.getULEB128(&offset)) != abbrCode) { // Tag abbrevData.getULEB128(&offset); // DW_CHILDREN abbrevData.getU8(&offset); // Attributes while (abbrevData.getULEB128(&offset) | abbrevData.getULEB128(&offset)) ; } return offset; } // FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE // inspection" code if possible. static Expected getIndexedString(const NormalizedFile &normalizedFile, llvm::dwarf::Form form, llvm::DataExtractor infoData, uint32_t &infoOffset, const Section &stringsSection) { if (form == llvm::dwarf::DW_FORM_string) return infoData.getCStr(&infoOffset); if (form != llvm::dwarf::DW_FORM_strp) return llvm::make_error( "string field encoded without DW_FORM_strp"); uint32_t stringOffset = infoData.getU32(&infoOffset); llvm::DataExtractor stringsData = dataExtractorFromSection(normalizedFile, stringsSection); return stringsData.getCStr(&stringOffset); } // FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE // inspection" code if possible. static llvm::Expected readCompUnit(const NormalizedFile &normalizedFile, const Section &info, const Section &abbrev, const Section &strings, StringRef path) { // FIXME: Cribbed from llvm-dwp -- should share "lightweight CU DIE // inspection" code if possible. uint32_t offset = 0; llvm::dwarf::DwarfFormat Format = llvm::dwarf::DwarfFormat::DWARF32; auto infoData = dataExtractorFromSection(normalizedFile, info); uint32_t length = infoData.getU32(&offset); if (length == 0xffffffff) { Format = llvm::dwarf::DwarfFormat::DWARF64; infoData.getU64(&offset); } else if (length > 0xffffff00) return llvm::make_error("Malformed DWARF in " + path); uint16_t version = infoData.getU16(&offset); if (version < 2 || version > 4) return llvm::make_error("Unsupported DWARF version in " + path); infoData.getU32(&offset); // Abbrev offset (should be zero) uint8_t addrSize = infoData.getU8(&offset); uint32_t abbrCode = infoData.getULEB128(&offset); auto abbrevData = dataExtractorFromSection(normalizedFile, abbrev); uint32_t abbrevOffset = getCUAbbrevOffset(abbrevData, abbrCode); uint64_t tag = abbrevData.getULEB128(&abbrevOffset); if (tag != llvm::dwarf::DW_TAG_compile_unit) return llvm::make_error("top level DIE is not a compile unit"); // DW_CHILDREN abbrevData.getU8(&abbrevOffset); uint32_t name; llvm::dwarf::Form form; + llvm::DWARFFormParams formParams = {version, addrSize, Format}; TranslationUnitSource tu; while ((name = abbrevData.getULEB128(&abbrevOffset)) | (form = static_cast( abbrevData.getULEB128(&abbrevOffset))) && (name != 0 || form != 0)) { switch (name) { case llvm::dwarf::DW_AT_name: { if (auto eName = getIndexedString(normalizedFile, form, infoData, offset, strings)) tu.name = *eName; else return eName.takeError(); break; } case llvm::dwarf::DW_AT_comp_dir: { if (auto eName = getIndexedString(normalizedFile, form, infoData, offset, strings)) tu.path = *eName; else return eName.takeError(); break; } default: - llvm::DWARFFormValue::skipValue(form, infoData, &offset, version, - addrSize, Format); + llvm::DWARFFormValue::skipValue(form, infoData, &offset, formParams); } } return tu; } llvm::Error parseDebugInfo(MachOFile &file, const NormalizedFile &normalizedFile, bool copyRefs) { // Find the interesting debug info sections. const Section *debugInfo = nullptr; const Section *debugAbbrev = nullptr; const Section *debugStrings = nullptr; for (auto &s : normalizedFile.sections) { if (s.segmentName == "__DWARF") { if (s.sectionName == "__debug_info") debugInfo = &s; else if (s.sectionName == "__debug_abbrev") debugAbbrev = &s; else if (s.sectionName == "__debug_str") debugStrings = &s; } } if (!debugInfo) return parseStabs(file, normalizedFile, copyRefs); if (debugInfo->content.size() == 0) return llvm::Error::success(); if (debugInfo->content.size() < 12) return llvm::make_error("Malformed __debug_info section in " + file.path() + ": too small"); if (!debugAbbrev) return llvm::make_error("Missing __dwarf_abbrev section in " + file.path()); if (auto tuOrErr = readCompUnit(normalizedFile, *debugInfo, *debugAbbrev, *debugStrings, file.path())) { // FIXME: Kill of allocator and code under 'copyRefs' when we fix YAML // memory ownership. std::unique_ptr allocator; if (copyRefs) { allocator = llvm::make_unique(); tuOrErr->name = copyDebugString(tuOrErr->name, *allocator); tuOrErr->path = copyDebugString(tuOrErr->path, *allocator); } file.setDebugInfo(llvm::make_unique(std::move(*tuOrErr))); if (copyRefs) file.debugInfo()->setAllocator(std::move(allocator)); } else return tuOrErr.takeError(); return llvm::Error::success(); } static int64_t readSPtr(bool is64, bool isBig, const uint8_t *addr) { if (is64) return read64(addr, isBig); int32_t res = read32(addr, isBig); return res; } /// --- Augmentation String Processing --- struct CIEInfo { bool _augmentationDataPresent = false; bool _mayHaveEH = false; uint32_t _offsetOfLSDA = ~0U; uint32_t _offsetOfPersonality = ~0U; uint32_t _offsetOfFDEPointerEncoding = ~0U; uint32_t _augmentationDataLength = ~0U; }; typedef llvm::DenseMap CIEInfoMap; static llvm::Error processAugmentationString(const uint8_t *augStr, CIEInfo &cieInfo, unsigned &len) { if (augStr[0] == '\0') { len = 1; return llvm::Error::success(); } if (augStr[0] != 'z') return llvm::make_error("expected 'z' at start of " "augmentation string"); cieInfo._augmentationDataPresent = true; uint64_t idx = 1; uint32_t offsetInAugmentationData = 0; while (augStr[idx] != '\0') { if (augStr[idx] == 'L') { cieInfo._offsetOfLSDA = offsetInAugmentationData; // This adds a single byte to the augmentation data. ++offsetInAugmentationData; ++idx; continue; } if (augStr[idx] == 'P') { cieInfo._offsetOfPersonality = offsetInAugmentationData; // This adds a single byte to the augmentation data for the encoding, // then a number of bytes for the pointer data. // FIXME: We are assuming 4 is correct here for the pointer size as we // always currently use delta32ToGOT. offsetInAugmentationData += 5; ++idx; continue; } if (augStr[idx] == 'R') { cieInfo._offsetOfFDEPointerEncoding = offsetInAugmentationData; // This adds a single byte to the augmentation data. ++offsetInAugmentationData; ++idx; continue; } if (augStr[idx] == 'e') { if (augStr[idx + 1] != 'h') return llvm::make_error("expected 'eh' in " "augmentation string"); cieInfo._mayHaveEH = true; idx += 2; continue; } ++idx; } cieInfo._augmentationDataLength = offsetInAugmentationData; len = idx + 1; return llvm::Error::success(); } static llvm::Error processCIE(const NormalizedFile &normalizedFile, MachOFile &file, mach_o::ArchHandler &handler, const Section *ehFrameSection, MachODefinedAtom *atom, uint64_t offset, CIEInfoMap &cieInfos) { const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); const uint8_t *frameData = atom->rawContent().data(); CIEInfo cieInfo; uint32_t size = read32(frameData, isBig); uint64_t cieIDField = size == 0xffffffffU ? sizeof(uint32_t) + sizeof(uint64_t) : sizeof(uint32_t); uint64_t versionField = cieIDField + sizeof(uint32_t); uint64_t augmentationStringField = versionField + sizeof(uint8_t); unsigned augmentationStringLength = 0; if (auto err = processAugmentationString(frameData + augmentationStringField, cieInfo, augmentationStringLength)) return err; if (cieInfo._offsetOfPersonality != ~0U) { // If we have augmentation data for the personality function, then we may // need to implicitly generate its relocation. // Parse the EH Data field which is pointer sized. uint64_t EHDataField = augmentationStringField + augmentationStringLength; const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch); unsigned EHDataFieldSize = (cieInfo._mayHaveEH ? (is64 ? 8 : 4) : 0); // Parse Code Align Factor which is a ULEB128. uint64_t CodeAlignField = EHDataField + EHDataFieldSize; unsigned lengthFieldSize = 0; llvm::decodeULEB128(frameData + CodeAlignField, &lengthFieldSize); // Parse Data Align Factor which is a SLEB128. uint64_t DataAlignField = CodeAlignField + lengthFieldSize; llvm::decodeSLEB128(frameData + DataAlignField, &lengthFieldSize); // Parse Return Address Register which is a byte. uint64_t ReturnAddressField = DataAlignField + lengthFieldSize; // Parse the augmentation length which is a ULEB128. uint64_t AugmentationLengthField = ReturnAddressField + 1; uint64_t AugmentationLength = llvm::decodeULEB128(frameData + AugmentationLengthField, &lengthFieldSize); if (AugmentationLength != cieInfo._augmentationDataLength) return llvm::make_error("CIE augmentation data length " "mismatch"); // Get the start address of the augmentation data. uint64_t AugmentationDataField = AugmentationLengthField + lengthFieldSize; // Parse the personality function from the augmentation data. uint64_t PersonalityField = AugmentationDataField + cieInfo._offsetOfPersonality; // Parse the personality encoding. // FIXME: Verify that this is a 32-bit pcrel offset. uint64_t PersonalityFunctionField = PersonalityField + 1; if (atom->begin() != atom->end()) { // If we have an explicit relocation, then make sure it matches this // offset as this is where we'd expect it to be applied to. DefinedAtom::reference_iterator CurrentRef = atom->begin(); if (CurrentRef->offsetInAtom() != PersonalityFunctionField) return llvm::make_error("CIE personality reloc at " "wrong offset"); if (++CurrentRef != atom->end()) return llvm::make_error("CIE contains too many relocs"); } else { // Implicitly generate the personality function reloc. It's assumed to // be a delta32 offset to a GOT entry. // FIXME: Parse the encoding and check this. int32_t funcDelta = read32(frameData + PersonalityFunctionField, isBig); uint64_t funcAddress = ehFrameSection->address + offset + PersonalityFunctionField; funcAddress += funcDelta; const MachODefinedAtom *func = nullptr; Reference::Addend addend; func = findAtomCoveringAddress(normalizedFile, file, funcAddress, addend); atom->addReference(Reference::KindNamespace::mach_o, handler.kindArch(), handler.unwindRefToPersonalityFunctionKind(), PersonalityFunctionField, func, addend); } } else if (atom->begin() != atom->end()) { // Otherwise, we expect there to be no relocations in this atom as the only // relocation would have been to the personality function. return llvm::make_error("unexpected relocation in CIE"); } cieInfos[atom] = std::move(cieInfo); return llvm::Error::success(); } static llvm::Error processFDE(const NormalizedFile &normalizedFile, MachOFile &file, mach_o::ArchHandler &handler, const Section *ehFrameSection, MachODefinedAtom *atom, uint64_t offset, const CIEInfoMap &cieInfos) { const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch); // Compiler wasn't lazy and actually told us what it meant. // Unfortunately, the compiler may not have generated references for all of // [cie, func, lsda] and so we still need to parse the FDE and add references // for any the compiler didn't generate. if (atom->begin() != atom->end()) atom->sortReferences(); DefinedAtom::reference_iterator CurrentRef = atom->begin(); // This helper returns the reference (if one exists) at the offset we are // currently processing. It automatically increments the ref iterator if we // do return a ref, and throws an error if we pass over a ref without // comsuming it. auto currentRefGetter = [&CurrentRef, &atom](uint64_t Offset)->const Reference* { // If there are no more refs found, then we are done. if (CurrentRef == atom->end()) return nullptr; const Reference *Ref = *CurrentRef; // If we haven't reached the offset for this reference, then return that // we don't yet have a reference to process. if (Offset < Ref->offsetInAtom()) return nullptr; // If the offset is equal, then we want to process this ref. if (Offset == Ref->offsetInAtom()) { ++CurrentRef; return Ref; } // The current ref is at an offset which is earlier than the current // offset, then we failed to consume it when we should have. In this case // throw an error. llvm::report_fatal_error("Skipped reference when processing FDE"); }; // Helper to either get the reference at this current location, and verify // that it is of the expected type, or add a reference of that type. // Returns the reference target. auto verifyOrAddReference = [&](uint64_t targetAddress, Reference::KindValue refKind, uint64_t refAddress, bool allowsAddend)->const Atom* { if (auto *ref = currentRefGetter(refAddress)) { // The compiler already emitted a relocation for the CIE ref. This should // have been converted to the correct type of reference in // get[Pair]ReferenceInfo(). assert(ref->kindValue() == refKind && "Incorrect EHFrame reference kind"); return ref->target(); } Reference::Addend addend; auto *target = findAtomCoveringAddress(normalizedFile, file, targetAddress, addend); atom->addReference(Reference::KindNamespace::mach_o, handler.kindArch(), refKind, refAddress, target, addend); if (!allowsAddend) assert(!addend && "EHFrame reference cannot have addend"); return target; }; const uint8_t *startFrameData = atom->rawContent().data(); const uint8_t *frameData = startFrameData; uint32_t size = read32(frameData, isBig); uint64_t cieFieldInFDE = size == 0xffffffffU ? sizeof(uint32_t) + sizeof(uint64_t) : sizeof(uint32_t); // Linker needs to fixup a reference from the FDE to its parent CIE (a // 32-bit byte offset backwards in the __eh_frame section). uint32_t cieDelta = read32(frameData + cieFieldInFDE, isBig); uint64_t cieAddress = ehFrameSection->address + offset + cieFieldInFDE; cieAddress -= cieDelta; auto *cieRefTarget = verifyOrAddReference(cieAddress, handler.unwindRefToCIEKind(), cieFieldInFDE, false); const MachODefinedAtom *cie = dyn_cast(cieRefTarget); assert(cie && cie->contentType() == DefinedAtom::typeCFI && "FDE's CIE field does not point at the start of a CIE."); const CIEInfo &cieInfo = cieInfos.find(cie)->second; // Linker needs to fixup reference from the FDE to the function it's // describing. FIXME: there are actually different ways to do this, and the // particular method used is specified in the CIE's augmentation fields // (hopefully) uint64_t rangeFieldInFDE = cieFieldInFDE + sizeof(uint32_t); int64_t functionFromFDE = readSPtr(is64, isBig, frameData + rangeFieldInFDE); uint64_t rangeStart = ehFrameSection->address + offset + rangeFieldInFDE; rangeStart += functionFromFDE; verifyOrAddReference(rangeStart, handler.unwindRefToFunctionKind(), rangeFieldInFDE, true); // Handle the augmentation data if there is any. if (cieInfo._augmentationDataPresent) { // First process the augmentation data length field. uint64_t augmentationDataLengthFieldInFDE = rangeFieldInFDE + 2 * (is64 ? sizeof(uint64_t) : sizeof(uint32_t)); unsigned lengthFieldSize = 0; uint64_t augmentationDataLength = llvm::decodeULEB128(frameData + augmentationDataLengthFieldInFDE, &lengthFieldSize); if (cieInfo._offsetOfLSDA != ~0U && augmentationDataLength > 0) { // Look at the augmentation data field. uint64_t augmentationDataFieldInFDE = augmentationDataLengthFieldInFDE + lengthFieldSize; int64_t lsdaFromFDE = readSPtr(is64, isBig, frameData + augmentationDataFieldInFDE); uint64_t lsdaStart = ehFrameSection->address + offset + augmentationDataFieldInFDE + lsdaFromFDE; verifyOrAddReference(lsdaStart, handler.unwindRefToFunctionKind(), augmentationDataFieldInFDE, true); } } return llvm::Error::success(); } llvm::Error addEHFrameReferences(const NormalizedFile &normalizedFile, MachOFile &file, mach_o::ArchHandler &handler) { const Section *ehFrameSection = nullptr; for (auto §ion : normalizedFile.sections) if (section.segmentName == "__TEXT" && section.sectionName == "__eh_frame") { ehFrameSection = §ion; break; } // No __eh_frame so nothing to do. if (!ehFrameSection) return llvm::Error::success(); llvm::Error ehFrameErr = llvm::Error::success(); CIEInfoMap cieInfos; file.eachAtomInSection(*ehFrameSection, [&](MachODefinedAtom *atom, uint64_t offset) -> void { assert(atom->contentType() == DefinedAtom::typeCFI); // Bail out if we've encountered an error. if (ehFrameErr) return; const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); if (ArchHandler::isDwarfCIE(isBig, atom)) ehFrameErr = processCIE(normalizedFile, file, handler, ehFrameSection, atom, offset, cieInfos); else ehFrameErr = processFDE(normalizedFile, file, handler, ehFrameSection, atom, offset, cieInfos); }); return ehFrameErr; } llvm::Error parseObjCImageInfo(const Section §, const NormalizedFile &normalizedFile, MachOFile &file) { // struct objc_image_info { // uint32_t version; // initially 0 // uint32_t flags; // }; ArrayRef content = sect.content; if (content.size() != 8) return llvm::make_error(sect.segmentName + "/" + sect.sectionName + " in file " + file.path() + " should be 8 bytes in size"); const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch); uint32_t version = read32(content.data(), isBig); if (version) return llvm::make_error(sect.segmentName + "/" + sect.sectionName + " in file " + file.path() + " should have version=0"); uint32_t flags = read32(content.data() + 4, isBig); if (flags & (MachOLinkingContext::objc_supports_gc | MachOLinkingContext::objc_gc_only)) return llvm::make_error(sect.segmentName + "/" + sect.sectionName + " in file " + file.path() + " uses GC. This is not supported"); if (flags & MachOLinkingContext::objc_retainReleaseForSimulator) file.setObjcConstraint(MachOLinkingContext::objc_retainReleaseForSimulator); else file.setObjcConstraint(MachOLinkingContext::objc_retainRelease); file.setSwiftVersion((flags >> 8) & 0xFF); return llvm::Error::success(); } /// Converts normalized mach-o file into an lld::File and lld::Atoms. llvm::Expected> objectToAtoms(const NormalizedFile &normalizedFile, StringRef path, bool copyRefs) { std::unique_ptr file(new MachOFile(path)); if (auto ec = normalizedObjectToAtoms(file.get(), normalizedFile, copyRefs)) return std::move(ec); return std::unique_ptr(std::move(file)); } llvm::Expected> dylibToAtoms(const NormalizedFile &normalizedFile, StringRef path, bool copyRefs) { // Instantiate SharedLibraryFile object. std::unique_ptr file(new MachODylibFile(path)); if (auto ec = normalizedDylibToAtoms(file.get(), normalizedFile, copyRefs)) return std::move(ec); return std::unique_ptr(std::move(file)); } } // anonymous namespace namespace normalized { static bool isObjCImageInfo(const Section §) { return (sect.segmentName == "__OBJC" && sect.sectionName == "__image_info") || (sect.segmentName == "__DATA" && sect.sectionName == "__objc_imageinfo"); } llvm::Error normalizedObjectToAtoms(MachOFile *file, const NormalizedFile &normalizedFile, bool copyRefs) { DEBUG(llvm::dbgs() << "******** Normalizing file to atoms: " << file->path() << "\n"); bool scatterable = ((normalizedFile.flags & MH_SUBSECTIONS_VIA_SYMBOLS) != 0); // Create atoms from each section. for (auto § : normalizedFile.sections) { // If this is a debug-info section parse it specially. if (isDebugInfoSection(sect)) continue; // If the file contains an objc_image_info struct, then we should parse the // ObjC flags and Swift version. if (isObjCImageInfo(sect)) { if (auto ec = parseObjCImageInfo(sect, normalizedFile, *file)) return ec; // We then skip adding atoms for this section as we use the ObjCPass to // re-emit this data after it has been aggregated for all files. continue; } bool customSectionName; DefinedAtom::ContentType atomType = atomTypeFromSection(sect, customSectionName); if (auto ec = processSection(atomType, sect, customSectionName, normalizedFile, *file, scatterable, copyRefs)) return ec; } // Create atoms from undefined symbols. for (auto &sym : normalizedFile.undefinedSymbols) { // Undefinded symbols with n_value != 0 are actually tentative definitions. if (sym.value == Hex64(0)) { file->addUndefinedAtom(sym.name, copyRefs); } else { file->addTentativeDefAtom(sym.name, atomScope(sym.scope), sym.value, DefinedAtom::Alignment(1 << (sym.desc >> 8)), copyRefs); } } // Convert mach-o relocations to References std::unique_ptr handler = ArchHandler::create(normalizedFile.arch); for (auto § : normalizedFile.sections) { if (isDebugInfoSection(sect)) continue; if (llvm::Error ec = convertRelocs(sect, normalizedFile, scatterable, *file, *handler)) return ec; } // Add additional arch-specific References file->eachDefinedAtom([&](MachODefinedAtom* atom) -> void { handler->addAdditionalReferences(*atom); }); // Each __eh_frame section needs references to both __text (the function we're // providing unwind info for) and itself (FDE -> CIE). These aren't // represented in the relocations on some architectures, so we have to add // them back in manually there. if (auto ec = addEHFrameReferences(normalizedFile, *file, *handler)) return ec; // Process mach-o data-in-code regions array. That information is encoded in // atoms as References at each transition point. unsigned nextIndex = 0; for (const DataInCode &entry : normalizedFile.dataInCode) { ++nextIndex; const Section* s = findSectionCoveringAddress(normalizedFile, entry.offset); if (!s) { return llvm::make_error(Twine("LC_DATA_IN_CODE address (" + Twine(entry.offset) + ") is not in any section")); } uint64_t offsetInSect = entry.offset - s->address; uint32_t offsetInAtom; MachODefinedAtom *atom = file->findAtomCoveringAddress(*s, offsetInSect, &offsetInAtom); if (offsetInAtom + entry.length > atom->size()) { return llvm::make_error(Twine("LC_DATA_IN_CODE entry " "(offset=" + Twine(entry.offset) + ", length=" + Twine(entry.length) + ") crosses atom boundary.")); } // Add reference that marks start of data-in-code. atom->addReference(Reference::KindNamespace::mach_o, handler->kindArch(), handler->dataInCodeTransitionStart(*atom), offsetInAtom, atom, entry.kind); // Peek at next entry, if it starts where this one ends, skip ending ref. if (nextIndex < normalizedFile.dataInCode.size()) { const DataInCode &nextEntry = normalizedFile.dataInCode[nextIndex]; if (nextEntry.offset == (entry.offset + entry.length)) continue; } // If data goes to end of function, skip ending ref. if ((offsetInAtom + entry.length) == atom->size()) continue; // Add reference that marks end of data-in-code. atom->addReference(Reference::KindNamespace::mach_o, handler->kindArch(), handler->dataInCodeTransitionEnd(*atom), offsetInAtom+entry.length, atom, 0); } // Cache some attributes on the file for use later. file->setFlags(normalizedFile.flags); file->setArch(normalizedFile.arch); file->setOS(normalizedFile.os); file->setMinVersion(normalizedFile.minOSverson); file->setMinVersionLoadCommandKind(normalizedFile.minOSVersionKind); // Sort references in each atom to their canonical order. for (const DefinedAtom* defAtom : file->defined()) { reinterpret_cast(defAtom)->sortReferences(); } if (auto err = parseDebugInfo(*file, normalizedFile, copyRefs)) return err; return llvm::Error::success(); } llvm::Error normalizedDylibToAtoms(MachODylibFile *file, const NormalizedFile &normalizedFile, bool copyRefs) { file->setInstallName(normalizedFile.installName); file->setCompatVersion(normalizedFile.compatVersion); file->setCurrentVersion(normalizedFile.currentVersion); // Tell MachODylibFile object about all symbols it exports. if (!normalizedFile.exportInfo.empty()) { // If exports trie exists, use it instead of traditional symbol table. for (const Export &exp : normalizedFile.exportInfo) { bool weakDef = (exp.flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION); // StringRefs from export iterator are ephemeral, so force copy. file->addExportedSymbol(exp.name, weakDef, true); } } else { for (auto &sym : normalizedFile.globalSymbols) { assert((sym.scope & N_EXT) && "only expect external symbols here"); bool weakDef = (sym.desc & N_WEAK_DEF); file->addExportedSymbol(sym.name, weakDef, copyRefs); } } // Tell MachODylibFile object about all dylibs it re-exports. for (const DependentDylib &dep : normalizedFile.dependentDylibs) { if (dep.kind == llvm::MachO::LC_REEXPORT_DYLIB) file->addReExportedDylib(dep.path); } return llvm::Error::success(); } void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType, StringRef &segmentName, StringRef §ionName, SectionType §ionType, SectionAttr §ionAttrs, bool &relocsToDefinedCanBeImplicit) { for (const MachORelocatableSectionToAtomType *p = sectsToAtomType ; p->atomType != DefinedAtom::typeUnknown; ++p) { if (p->atomType != atomType) continue; // Wild carded entries are ignored for reverse lookups. if (p->segmentName.empty() || p->sectionName.empty()) continue; segmentName = p->segmentName; sectionName = p->sectionName; sectionType = p->sectionType; sectionAttrs = 0; relocsToDefinedCanBeImplicit = false; if (atomType == DefinedAtom::typeCode) sectionAttrs = S_ATTR_PURE_INSTRUCTIONS; if (atomType == DefinedAtom::typeCFI) relocsToDefinedCanBeImplicit = true; return; } llvm_unreachable("content type not yet supported"); } llvm::Expected> normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path, bool copyRefs) { switch (normalizedFile.fileType) { case MH_DYLIB: case MH_DYLIB_STUB: return dylibToAtoms(normalizedFile, path, copyRefs); case MH_OBJECT: return objectToAtoms(normalizedFile, path, copyRefs); default: llvm_unreachable("unhandled MachO file type!"); } } } // namespace normalized } // namespace mach_o } // namespace lld Index: vendor/lld/dist/test/COFF/safeseh.test =================================================================== --- vendor/lld/dist/test/COFF/safeseh.test (revision 320381) +++ vendor/lld/dist/test/COFF/safeseh.test (nonexistent) @@ -1,51 +0,0 @@ -# RUN: sed s/FEAT_VALUE/1/ %s | yaml2obj > %t.obj -# RUN: lld-link /out:%t.exe /subsystem:console /entry:main /safeseh %t.obj - -# RUN: sed s/FEAT_VALUE/0/ %s | yaml2obj > %t.obj -# RUN: not lld-link /out:%t.exe /subsystem:console /entry:main \ -# RUN: /safeseh %t.obj >& %t.log -# RUN: FileCheck %s < %t.log - -# CHECK: /safeseh: {{.*}} is not compatible with SEH - ---- !COFF -header: - Machine: IMAGE_FILE_MACHINE_I386 - Characteristics: [ ] -sections: - - Name: .text - Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] - Alignment: 1 - SectionData: 0000000000000000 -symbols: - - Name: '@comp.id' - Value: 14766605 - SectionNumber: 65535 - SimpleType: IMAGE_SYM_TYPE_NULL - ComplexType: IMAGE_SYM_DTYPE_NULL - StorageClass: IMAGE_SYM_CLASS_STATIC - - Name: '@feat.00' - Value: FEAT_VALUE - SectionNumber: 65535 - SimpleType: IMAGE_SYM_TYPE_NULL - ComplexType: IMAGE_SYM_DTYPE_NULL - StorageClass: IMAGE_SYM_CLASS_STATIC - - Name: .text - Value: 0 - SectionNumber: 1 - SimpleType: IMAGE_SYM_TYPE_NULL - ComplexType: IMAGE_SYM_DTYPE_NULL - StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: - Length: 8 - NumberOfRelocations: 0 - NumberOfLinenumbers: 0 - CheckSum: 0 - Number: 0 - - Name: _main - Value: 0 - SectionNumber: 1 - SimpleType: IMAGE_SYM_TYPE_NULL - ComplexType: IMAGE_SYM_DTYPE_FUNCTION - StorageClass: IMAGE_SYM_CLASS_EXTERNAL -... Index: vendor/lld/dist/test/COFF/Inputs/associative-comdat-2.s =================================================================== --- vendor/lld/dist/test/COFF/Inputs/associative-comdat-2.s (nonexistent) +++ vendor/lld/dist/test/COFF/Inputs/associative-comdat-2.s (revision 320382) @@ -0,0 +1,13 @@ +# Defines foo and foo_assoc globals. foo is comdat, and foo_assoc is comdat +# associative with it. foo_assoc should be discarded iff foo is discarded, +# either by linker GC or normal comdat merging. + + .section .rdata,"dr",associative,foo + .p2align 3 + .quad foo + + .section .data,"dw",discard,foo + .globl foo # @foo + .p2align 2 +foo: + .long 42 Property changes on: vendor/lld/dist/test/COFF/Inputs/associative-comdat-2.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/COFF/Inputs/pdb1.yaml =================================================================== --- vendor/lld/dist/test/COFF/Inputs/pdb1.yaml (revision 320381) +++ vendor/lld/dist/test/COFF/Inputs/pdb1.yaml (revision 320382) @@ -1,306 +1,302 @@ --- !COFF header: Machine: IMAGE_FILE_MACHINE_AMD64 Characteristics: [ ] sections: - Name: .drectve Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] Alignment: 1 SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220 - Name: '.debug$S' Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] Alignment: 1 Subsections: - !Symbols Records: - Kind: S_OBJNAME ObjNameSym: Signature: 0 ObjectName: 'D:\b\ret42-main.obj' - Kind: S_COMPILE3 Compile3Sym: Flags: [ SecurityChecks, HotPatch ] Machine: X64 FrontendMajor: 19 FrontendMinor: 0 FrontendBuild: 23026 FrontendQFE: 0 BackendMajor: 19 BackendMinor: 0 BackendBuild: 23026 BackendQFE: 0 Version: 'Microsoft (R) Optimizing Compiler' - !Symbols Records: - Kind: S_GPROC32_ID ProcSym: - PtrParent: 0 - PtrEnd: 0 - PtrNext: 0 CodeSize: 14 DbgStart: 4 DbgEnd: 9 FunctionType: 4101 - Segment: 0 Flags: [ ] DisplayName: main - Kind: S_FRAMEPROC FrameProcSym: TotalFrameBytes: 40 PaddingFrameBytes: 0 OffsetToPadding: 0 BytesOfCalleeSavedRegisters: 0 OffsetOfExceptionHandler: 0 SectionIdOfExceptionHandler: 0 Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] - Kind: S_PROC_ID_END ScopeEndSym: - !Lines CodeSize: 14 Flags: [ ] RelocOffset: 0 RelocSegment: 0 Blocks: - FileName: 'd:\b\ret42-main.c' Lines: - Offset: 0 LineStart: 2 IsStatement: true EndDelta: 0 Columns: - !FileChecksums Checksums: - FileName: 'd:\b\ret42-main.c' Kind: MD5 Checksum: C538722F63570DF6705DDE06FE96E5D1 - !StringTable Strings: - 'd:\b\ret42-main.c' - !Symbols Records: - Kind: S_BUILDINFO BuildInfoSym: BuildId: 4110 Relocations: - VirtualAddress: 140 SymbolName: main Type: IMAGE_REL_AMD64_SECREL - VirtualAddress: 144 SymbolName: main Type: IMAGE_REL_AMD64_SECTION - VirtualAddress: 196 SymbolName: main Type: IMAGE_REL_AMD64_SECREL - VirtualAddress: 200 SymbolName: main Type: IMAGE_REL_AMD64_SECTION - Name: '.debug$T' Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] Alignment: 1 Types: - Kind: LF_ARGLIST ArgList: ArgIndices: [ ] - Kind: LF_PROCEDURE Procedure: ReturnType: 116 CallConv: NearC Options: [ None ] ParameterCount: 0 ArgumentList: 4096 - Kind: LF_POINTER Pointer: ReferentType: 4097 Attrs: 65548 - Kind: LF_ARGLIST ArgList: ArgIndices: [ 0 ] - Kind: LF_PROCEDURE Procedure: ReturnType: 116 CallConv: NearC Options: [ None ] ParameterCount: 0 ArgumentList: 4099 - Kind: LF_FUNC_ID FuncId: ParentScope: 0 FunctionType: 4100 Name: main - Kind: LF_FUNC_ID FuncId: ParentScope: 0 FunctionType: 4097 Name: foo - Kind: LF_STRING_ID StringId: Id: 0 String: 'D:\b' - Kind: LF_STRING_ID StringId: Id: 0 String: 'C:\vs14\VC\BIN\amd64\cl.exe' - Kind: LF_STRING_ID StringId: Id: 0 String: '-Z7 -c -MT -IC:\vs14\VC\INCLUDE -IC:\vs14\VC\ATLMFC\INCLUDE -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.10150.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared"' - Kind: LF_SUBSTR_LIST StringList: StringIndices: [ 4105 ] - Kind: LF_STRING_ID StringId: Id: 4106 String: ' -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X' - Kind: LF_STRING_ID StringId: Id: 0 String: ret42-main.c - Kind: LF_STRING_ID StringId: Id: 0 String: 'D:\b\vc140.pdb' - Kind: LF_BUILDINFO BuildInfo: ArgIndices: [ 4103, 4104, 4108, 4109, 4107 ] - Name: '.text$mn' Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] Alignment: 16 SectionData: 4883EC28E8000000004883C428C3 Relocations: - VirtualAddress: 5 SymbolName: foo Type: IMAGE_REL_AMD64_REL32 - Name: .xdata Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] Alignment: 4 SectionData: '0104010004420000' - Name: .pdata Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] Alignment: 4 SectionData: '000000000E00000000000000' Relocations: - VirtualAddress: 0 SymbolName: '$LN3' Type: IMAGE_REL_AMD64_ADDR32NB - VirtualAddress: 4 SymbolName: '$LN3' Type: IMAGE_REL_AMD64_ADDR32NB - VirtualAddress: 8 SymbolName: '$unwind$main' Type: IMAGE_REL_AMD64_ADDR32NB symbols: - Name: '@comp.id' Value: 17062386 SectionNumber: -1 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - Name: '@feat.00' Value: 2147484048 SectionNumber: -1 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - Name: .drectve Value: 0 SectionNumber: 1 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC SectionDefinition: Length: 47 NumberOfRelocations: 0 NumberOfLinenumbers: 0 CheckSum: 0 Number: 0 - Name: '.debug$S' Value: 0 SectionNumber: 2 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC SectionDefinition: Length: 304 NumberOfRelocations: 4 NumberOfLinenumbers: 0 CheckSum: 0 Number: 0 - Name: '.debug$T' Value: 0 SectionNumber: 3 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC SectionDefinition: Length: 636 NumberOfRelocations: 0 NumberOfLinenumbers: 0 CheckSum: 0 Number: 0 - Name: '.text$mn' Value: 0 SectionNumber: 4 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC SectionDefinition: Length: 14 NumberOfRelocations: 1 NumberOfLinenumbers: 0 CheckSum: 1682752513 Number: 0 - Name: foo Value: 0 SectionNumber: 0 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_FUNCTION StorageClass: IMAGE_SYM_CLASS_EXTERNAL - Name: main Value: 0 SectionNumber: 4 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_FUNCTION StorageClass: IMAGE_SYM_CLASS_EXTERNAL - Name: '$LN3' Value: 0 SectionNumber: 4 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_LABEL - Name: .xdata Value: 0 SectionNumber: 5 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC SectionDefinition: Length: 8 NumberOfRelocations: 0 NumberOfLinenumbers: 0 CheckSum: 264583633 Number: 0 - Name: '$unwind$main' Value: 0 SectionNumber: 5 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - Name: .pdata Value: 0 SectionNumber: 6 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC SectionDefinition: Length: 12 NumberOfRelocations: 3 NumberOfLinenumbers: 0 CheckSum: 361370162 Number: 0 - Name: '$pdata$main' Value: 0 SectionNumber: 6 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC ... Index: vendor/lld/dist/test/COFF/Inputs/pdb_comdat_bar.yaml =================================================================== --- vendor/lld/dist/test/COFF/Inputs/pdb_comdat_bar.yaml (nonexistent) +++ vendor/lld/dist/test/COFF/Inputs/pdb_comdat_bar.yaml (revision 320382) @@ -0,0 +1,440 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_OBJNAME + ObjNameSym: + Signature: 0 + ObjectName: 'C:\src\llvm-project\build\pdb_comdat_bar.obj' + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ SecurityChecks, HotPatch ] + Machine: X64 + FrontendMajor: 19 + FrontendMinor: 0 + FrontendBuild: 24215 + FrontendQFE: 1 + BackendMajor: 19 + BackendMinor: 0 + BackendBuild: 24215 + BackendQFE: 1 + Version: 'Microsoft (R) Optimizing Compiler' + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + PtrParent: 0 + PtrEnd: 0 + PtrNext: 0 + CodeSize: 14 + DbgStart: 4 + DbgEnd: 9 + FunctionType: 4102 + Segment: 0 + Flags: [ ] + DisplayName: bar + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 40 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 14 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\pdb_comdat_bar.c' + Lines: + - Offset: 0 + LineStart: 3 + IsStatement: true + EndDelta: 0 + - Offset: 4 + LineStart: 4 + IsStatement: true + EndDelta: 0 + - Offset: 9 + LineStart: 5 + IsStatement: true + EndDelta: 0 + Columns: + - !Symbols + Records: + - Kind: S_GDATA32 + DataSym: + Type: 116 + DisplayName: global + - !FileChecksums + Checksums: + - FileName: 'c:\src\llvm-project\build\pdb_comdat_bar.c' + Kind: MD5 + Checksum: 365279DB4FCBEDD721BBFC3B14A953C2 + - FileName: 'c:\src\llvm-project\build\foo.h' + Kind: MD5 + Checksum: D74D834EFAC3AE2B45E606A8320B1D5C + - !StringTable + Strings: + - 'c:\src\llvm-project\build\pdb_comdat_bar.c' + - 'c:\src\llvm-project\build\foo.h' + - !Symbols + Records: + - Kind: S_BUILDINFO + BuildInfoSym: + BuildId: 4110 + Relocations: + - VirtualAddress: 168 + SymbolName: bar + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 172 + SymbolName: bar + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 224 + SymbolName: bar + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 228 + SymbolName: bar + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 288 + SymbolName: global + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 292 + SymbolName: global + Type: IMAGE_REL_AMD64_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Types: + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 0 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 3 + CallConv: NearC + Options: [ None ] + ParameterCount: 0 + ArgumentList: 4096 + - Kind: LF_POINTER + Pointer: + ReferentType: 4097 + Attrs: 65548 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: foo + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 3 + CallConv: NearC + Options: [ None ] + ParameterCount: 0 + ArgumentList: 4100 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4101 + Name: bar + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um' + - Kind: LF_SUBSTR_LIST + StringList: + StringIndices: [ 4105 ] + - Kind: LF_STRING_ID + StringId: + Id: 4106 + String: ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: pdb_comdat_bar.c + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build\vc140.pdb' + - Kind: LF_BUILDINFO + BuildInfo: + ArgIndices: [ 4103, 4104, 4108, 4109, 4107 ] + - Name: .bss + Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 4883EC28E8000000004883C428C3 + Relocations: + - VirtualAddress: 5 + SymbolName: foo + Type: IMAGE_REL_AMD64_REL32 + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 8B0500000000FFC0890500000000C3 + Relocations: + - VirtualAddress: 2 + SymbolName: global + Type: IMAGE_REL_AMD64_REL32 + - VirtualAddress: 10 + SymbolName: global + Type: IMAGE_REL_AMD64_REL32 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + PtrParent: 0 + PtrEnd: 0 + PtrNext: 0 + CodeSize: 15 + DbgStart: 0 + DbgEnd: 14 + FunctionType: 4099 + Segment: 0 + Flags: [ ] + DisplayName: foo + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 0 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ MarkedInline, AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 15 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\foo.h' + Lines: + - Offset: 0 + LineStart: 2 + IsStatement: true + EndDelta: 0 + - Offset: 0 + LineStart: 3 + IsStatement: true + EndDelta: 0 + - Offset: 14 + LineStart: 4 + IsStatement: true + EndDelta: 0 + Columns: + Relocations: + - VirtualAddress: 44 + SymbolName: foo + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 48 + SymbolName: foo + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 100 + SymbolName: foo + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 104 + SymbolName: foo + Type: IMAGE_REL_AMD64_SECTION + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '0104010004420000' + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '000000000E00000000000000' + Relocations: + - VirtualAddress: 0 + SymbolName: '$LN3' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: '$LN3' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 8 + SymbolName: '$unwind$bar' + Type: IMAGE_REL_AMD64_ADDR32NB +symbols: + - Name: .drectve + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 47 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$S' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 460 + NumberOfRelocations: 6 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$T' + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 628 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: .bss + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 4 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: global + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: '.text$mn' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 14 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 1682752513 + Number: 0 + - Name: '.text$mn' + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 15 + NumberOfRelocations: 2 + NumberOfLinenumbers: 0 + CheckSum: 1746394828 + Number: 0 + Selection: IMAGE_COMDAT_SELECT_ANY + - Name: '.debug$S' + Value: 0 + SectionNumber: 7 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 148 + NumberOfRelocations: 4 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 6 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: foo + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: bar + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: '$LN3' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_LABEL + - Name: .xdata + Value: 0 + SectionNumber: 8 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 264583633 + Number: 0 + - Name: '$unwind$bar' + Value: 0 + SectionNumber: 8 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .pdata + Value: 0 + SectionNumber: 9 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 361370162 + Number: 0 + - Name: '$pdata$bar' + Value: 0 + SectionNumber: 9 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC +... Index: vendor/lld/dist/test/COFF/Inputs/pdb_comdat_main.yaml =================================================================== --- vendor/lld/dist/test/COFF/Inputs/pdb_comdat_main.yaml (nonexistent) +++ vendor/lld/dist/test/COFF/Inputs/pdb_comdat_main.yaml (revision 320382) @@ -0,0 +1,446 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_OBJNAME + ObjNameSym: + Signature: 0 + ObjectName: 'C:\src\llvm-project\build\pdb_comdat_main.obj' + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ SecurityChecks, HotPatch ] + Machine: X64 + FrontendMajor: 19 + FrontendMinor: 0 + FrontendBuild: 24215 + FrontendQFE: 1 + BackendMajor: 19 + BackendMinor: 0 + BackendBuild: 24215 + BackendQFE: 1 + Version: 'Microsoft (R) Optimizing Compiler' + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + PtrParent: 0 + PtrEnd: 0 + PtrNext: 0 + CodeSize: 24 + DbgStart: 4 + DbgEnd: 19 + FunctionType: 4102 + Segment: 0 + Flags: [ ] + DisplayName: main + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 40 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 24 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\pdb_comdat_main.c' + Lines: + - Offset: 0 + LineStart: 2 + IsStatement: true + EndDelta: 0 + - Offset: 4 + LineStart: 3 + IsStatement: true + EndDelta: 0 + - Offset: 9 + LineStart: 4 + IsStatement: true + EndDelta: 0 + - Offset: 14 + LineStart: 5 + IsStatement: true + EndDelta: 0 + - Offset: 19 + LineStart: 6 + IsStatement: true + EndDelta: 0 + Columns: + - !Symbols + Records: + - Kind: S_GDATA32 + DataSym: + Type: 116 + DisplayName: global + - !FileChecksums + Checksums: + - FileName: 'c:\src\llvm-project\build\pdb_comdat_main.c' + Kind: MD5 + Checksum: F969E51BBE373436D81492EB61387F36 + - FileName: 'c:\src\llvm-project\build\foo.h' + Kind: MD5 + Checksum: D74D834EFAC3AE2B45E606A8320B1D5C + - !StringTable + Strings: + - 'c:\src\llvm-project\build\pdb_comdat_main.c' + - 'c:\src\llvm-project\build\foo.h' + - !Symbols + Records: + - Kind: S_BUILDINFO + BuildInfoSym: + BuildId: 4111 + Relocations: + - VirtualAddress: 168 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 172 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 224 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 228 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 304 + SymbolName: global + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 308 + SymbolName: global + Type: IMAGE_REL_AMD64_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Types: + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 0 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 3 + CallConv: NearC + Options: [ None ] + ParameterCount: 0 + ArgumentList: 4096 + - Kind: LF_POINTER + Pointer: + ReferentType: 4097 + Attrs: 65548 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: foo + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 116 + CallConv: NearC + Options: [ None ] + ParameterCount: 0 + ArgumentList: 4100 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4101 + Name: main + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: bar + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um' + - Kind: LF_SUBSTR_LIST + StringList: + StringIndices: [ 4106 ] + - Kind: LF_STRING_ID + StringId: + Id: 4107 + String: ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: pdb_comdat_main.c + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build\vc140.pdb' + - Kind: LF_BUILDINFO + BuildInfo: + ArgIndices: [ 4104, 4105, 4109, 4110, 4108 ] + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 4883EC28E800000000E800000000B82A0000004883C428C3 + Relocations: + - VirtualAddress: 5 + SymbolName: foo + Type: IMAGE_REL_AMD64_REL32 + - VirtualAddress: 10 + SymbolName: bar + Type: IMAGE_REL_AMD64_REL32 + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 8B0500000000FFC0890500000000C3 + Relocations: + - VirtualAddress: 2 + SymbolName: global + Type: IMAGE_REL_AMD64_REL32 + - VirtualAddress: 10 + SymbolName: global + Type: IMAGE_REL_AMD64_REL32 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + PtrParent: 0 + PtrEnd: 0 + PtrNext: 0 + CodeSize: 15 + DbgStart: 0 + DbgEnd: 14 + FunctionType: 4099 + Segment: 0 + Flags: [ ] + DisplayName: foo + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 0 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ MarkedInline, AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 15 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\foo.h' + Lines: + - Offset: 0 + LineStart: 2 + IsStatement: true + EndDelta: 0 + - Offset: 0 + LineStart: 3 + IsStatement: true + EndDelta: 0 + - Offset: 14 + LineStart: 4 + IsStatement: true + EndDelta: 0 + Columns: + Relocations: + - VirtualAddress: 44 + SymbolName: foo + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 48 + SymbolName: foo + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 100 + SymbolName: foo + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 104 + SymbolName: foo + Type: IMAGE_REL_AMD64_SECTION + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '0104010004420000' + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '000000001800000000000000' + Relocations: + - VirtualAddress: 0 + SymbolName: '$LN3' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: '$LN3' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 8 + SymbolName: '$unwind$main' + Type: IMAGE_REL_AMD64_ADDR32NB +symbols: + - Name: .drectve + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 47 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$S' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 480 + NumberOfRelocations: 6 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$T' + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 648 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.text$mn' + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 24 + NumberOfRelocations: 2 + NumberOfLinenumbers: 0 + CheckSum: 492663294 + Number: 0 + - Name: '.text$mn' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 15 + NumberOfRelocations: 2 + NumberOfLinenumbers: 0 + CheckSum: 1746394828 + Number: 0 + Selection: IMAGE_COMDAT_SELECT_ANY + - Name: '.debug$S' + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 148 + NumberOfRelocations: 4 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 5 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: foo + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: bar + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: main + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: '$LN3' + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_LABEL + - Name: .xdata + Value: 0 + SectionNumber: 7 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 264583633 + Number: 0 + - Name: '$unwind$main' + Value: 0 + SectionNumber: 7 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .pdata + Value: 0 + SectionNumber: 8 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 2942184094 + Number: 0 + - Name: '$pdata$main' + Value: 0 + SectionNumber: 8 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: global + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... Index: vendor/lld/dist/test/COFF/Inputs/pdb_lines_1.yaml =================================================================== --- vendor/lld/dist/test/COFF/Inputs/pdb_lines_1.yaml (nonexistent) +++ vendor/lld/dist/test/COFF/Inputs/pdb_lines_1.yaml (revision 320382) @@ -0,0 +1,480 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_OBJNAME + ObjNameSym: + Signature: 0 + ObjectName: 'C:\src\llvm-project\build\pdb_lines_1.obj' + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ SecurityChecks, HotPatch ] + Machine: X64 + FrontendMajor: 19 + FrontendMinor: 0 + FrontendBuild: 24215 + FrontendQFE: 1 + BackendMajor: 19 + BackendMinor: 0 + BackendBuild: 24215 + BackendQFE: 1 + Version: 'Microsoft (R) Optimizing Compiler' + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + PtrParent: 0 + PtrEnd: 0 + PtrNext: 0 + CodeSize: 19 + DbgStart: 4 + DbgEnd: 14 + FunctionType: 4102 + Segment: 0 + Flags: [ ] + DisplayName: main + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 40 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 19 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\pdb_lines_1.c' + Lines: + - Offset: 0 + LineStart: 2 + IsStatement: true + EndDelta: 0 + - Offset: 4 + LineStart: 3 + IsStatement: true + EndDelta: 0 + - Offset: 9 + LineStart: 4 + IsStatement: true + EndDelta: 0 + - Offset: 14 + LineStart: 5 + IsStatement: true + EndDelta: 0 + Columns: + - !FileChecksums + Checksums: + - FileName: 'c:\src\llvm-project\build\pdb_lines_1.c' + Kind: MD5 + Checksum: 4EB19DCD86C3BA2238A255C718572E7B + - FileName: 'c:\src\llvm-project\build\foo.h' + Kind: MD5 + Checksum: 061EB73ABB642532857A4F1D9CBAC323 + - !StringTable + Strings: + - 'c:\src\llvm-project\build\pdb_lines_1.c' + - 'c:\src\llvm-project\build\foo.h' + - !Symbols + Records: + - Kind: S_BUILDINFO + BuildInfoSym: + BuildId: 4111 + Relocations: + - VirtualAddress: 164 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 168 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 220 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 224 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Types: + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 3 + CallConv: NearC + Options: [ None ] + ParameterCount: 0 + ArgumentList: 4096 + - Kind: LF_POINTER + Pointer: + ReferentType: 4097 + Attrs: 65548 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: foo + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 0 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 116 + CallConv: NearC + Options: [ None ] + ParameterCount: 0 + ArgumentList: 4100 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4101 + Name: main + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: bar + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um' + - Kind: LF_SUBSTR_LIST + StringList: + StringIndices: [ 4106 ] + - Kind: LF_STRING_ID + StringId: + Id: 4107 + String: ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: pdb_lines_1.c + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build\vc140.pdb' + - Kind: LF_BUILDINFO + BuildInfo: + ArgIndices: [ 4104, 4105, 4109, 4110, 4108 ] + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 4883EC28E800000000B82A0000004883C428C3 + Relocations: + - VirtualAddress: 5 + SymbolName: foo + Type: IMAGE_REL_AMD64_REL32 + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 4883EC28E8000000004883C428C3 + Relocations: + - VirtualAddress: 5 + SymbolName: bar + Type: IMAGE_REL_AMD64_REL32 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + PtrParent: 0 + PtrEnd: 0 + PtrNext: 0 + CodeSize: 14 + DbgStart: 4 + DbgEnd: 9 + FunctionType: 4099 + Segment: 0 + Flags: [ ] + DisplayName: foo + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 40 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ MarkedInline, AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 14 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\foo.h' + Lines: + - Offset: 0 + LineStart: 2 + IsStatement: true + EndDelta: 0 + - Offset: 4 + LineStart: 3 + IsStatement: true + EndDelta: 0 + - Offset: 9 + LineStart: 4 + IsStatement: true + EndDelta: 0 + Columns: + Relocations: + - VirtualAddress: 44 + SymbolName: foo + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 48 + SymbolName: foo + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 100 + SymbolName: foo + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 104 + SymbolName: foo + Type: IMAGE_REL_AMD64_SECTION + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '0104010004420000' + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '000000000E00000000000000' + Relocations: + - VirtualAddress: 0 + SymbolName: '$LN3' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: '$LN3' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 8 + SymbolName: '$unwind$foo' + Type: IMAGE_REL_AMD64_ADDR32NB + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '0104010004420000' + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '000000001300000000000000' + Relocations: + - VirtualAddress: 0 + SymbolName: '$LN3' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: '$LN3' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 8 + SymbolName: '$unwind$main' + Type: IMAGE_REL_AMD64_ADDR32NB +symbols: + - Name: .drectve + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 47 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$S' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 432 + NumberOfRelocations: 4 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$T' + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 644 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.text$mn' + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 19 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 791570821 + Number: 0 + - Name: '.text$mn' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 14 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 1682752513 + Number: 0 + Selection: IMAGE_COMDAT_SELECT_ANY + - Name: '.debug$S' + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 148 + NumberOfRelocations: 4 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 5 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: bar + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: foo + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: main + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: '$LN3' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_LABEL + - Name: '$LN3' + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_LABEL + - Name: .xdata + Value: 0 + SectionNumber: 7 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 264583633 + Number: 5 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: '$unwind$foo' + Value: 0 + SectionNumber: 7 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .pdata + Value: 0 + SectionNumber: 8 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 361370162 + Number: 5 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: '$pdata$foo' + Value: 0 + SectionNumber: 8 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .xdata + Value: 0 + SectionNumber: 9 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 264583633 + Number: 0 + - Name: '$unwind$main' + Value: 0 + SectionNumber: 9 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .pdata + Value: 0 + SectionNumber: 10 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 4063508168 + Number: 0 + - Name: '$pdata$main' + Value: 0 + SectionNumber: 10 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC +... Index: vendor/lld/dist/test/COFF/Inputs/pdb_lines_2.yaml =================================================================== --- vendor/lld/dist/test/COFF/Inputs/pdb_lines_2.yaml (nonexistent) +++ vendor/lld/dist/test/COFF/Inputs/pdb_lines_2.yaml (revision 320382) @@ -0,0 +1,209 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_OBJNAME + ObjNameSym: + Signature: 0 + ObjectName: 'C:\src\llvm-project\build\pdb_lines_2.obj' + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ SecurityChecks, HotPatch ] + Machine: X64 + FrontendMajor: 19 + FrontendMinor: 0 + FrontendBuild: 24215 + FrontendQFE: 1 + BackendMajor: 19 + BackendMinor: 0 + BackendBuild: 24215 + BackendQFE: 1 + Version: 'Microsoft (R) Optimizing Compiler' + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + PtrParent: 0 + PtrEnd: 0 + PtrNext: 0 + CodeSize: 1 + DbgStart: 0 + DbgEnd: 0 + FunctionType: 4098 + Segment: 0 + Flags: [ ] + DisplayName: bar + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 0 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 1 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\pdb_lines_2.c' + Lines: + - Offset: 0 + LineStart: 1 + IsStatement: true + EndDelta: 0 + - Offset: 0 + LineStart: 2 + IsStatement: true + EndDelta: 0 + Columns: + - !FileChecksums + Checksums: + - FileName: 'c:\src\llvm-project\build\pdb_lines_2.c' + Kind: MD5 + Checksum: DF91CB3A2B8D917486574BB50CAC4CC7 + - !StringTable + Strings: + - 'c:\src\llvm-project\build\pdb_lines_2.c' + - !Symbols + Records: + - Kind: S_BUILDINFO + BuildInfoSym: + BuildId: 4106 + Relocations: + - VirtualAddress: 164 + SymbolName: bar + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 168 + SymbolName: bar + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 220 + SymbolName: bar + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 224 + SymbolName: bar + Type: IMAGE_REL_AMD64_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Types: + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 3 + CallConv: NearC + Options: [ None ] + ParameterCount: 0 + ArgumentList: 4096 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: bar + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um' + - Kind: LF_SUBSTR_LIST + StringList: + StringIndices: [ 4101 ] + - Kind: LF_STRING_ID + StringId: + Id: 4102 + String: ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: pdb_lines_2.c + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build\vc140.pdb' + - Kind: LF_BUILDINFO + BuildInfo: + ArgIndices: [ 4099, 4100, 4104, 4105, 4103 ] + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: C3 +symbols: + - Name: .drectve + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 47 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$S' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 360 + NumberOfRelocations: 4 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$T' + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 568 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.text$mn' + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 40735498 + Number: 0 + - Name: bar + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... Index: vendor/lld/dist/test/COFF/associative-comdat.s =================================================================== --- vendor/lld/dist/test/COFF/associative-comdat.s (nonexistent) +++ vendor/lld/dist/test/COFF/associative-comdat.s (revision 320382) @@ -0,0 +1,46 @@ +# RUN: llvm-mc -triple=x86_64-windows-msvc %s -filetype=obj -o %t1.obj +# RUN: llvm-mc -triple=x86_64-windows-msvc %S/Inputs/associative-comdat-2.s -filetype=obj -o %t2.obj + +# RUN: lld-link -entry:main %t1.obj %t2.obj -out:%t.gc.exe +# RUN: llvm-readobj -sections %t.gc.exe | FileCheck %s + +# RUN: lld-link -entry:main %t1.obj %t2.obj -opt:noref -out:%t.nogc.exe +# RUN: llvm-readobj -sections %t.nogc.exe | FileCheck %s + +# CHECK: Sections [ +# CHECK: Section { +# CHECK: Number: 1 +# CHECK-LABEL: Name: .data (2E 64 61 74 61 00 00 00) +# CHECK-NEXT: VirtualSize: 0x4 +# CHECK: Section { +# CHECK-LABEL: Name: .rdata (2E 72 64 61 74 61 00 00) +# This is the critical check to show that only *one* definition of +# foo_assoc was retained. This *must* be 8, not 16. +# CHECK-NEXT: VirtualSize: 0x8 + + .text + .def main; + .scl 2; + .type 32; + .endef + .globl main # -- Begin function main + .p2align 4, 0x90 +main: # @main +# BB#0: + movl foo(%rip), %eax + retq + # -- End function + +# Defines foo and foo_assoc globals. foo is comdat, and foo_assoc is comdat +# associative with it. foo_assoc should be discarded iff foo is discarded, +# either by linker GC or normal comdat merging. + + .section .rdata,"dr",associative,foo + .p2align 3 + .quad foo + + .section .data,"dw",discard,foo + .globl foo # @foo + .p2align 2 +foo: + .long 42 Property changes on: vendor/lld/dist/test/COFF/associative-comdat.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/COFF/def-name.test =================================================================== --- vendor/lld/dist/test/COFF/def-name.test (revision 320381) +++ vendor/lld/dist/test/COFF/def-name.test (revision 320382) @@ -1,28 +1,26 @@ -# REQUIRES: winres - # RUN: rm -rf %t # RUN: mkdir -p %t # RUN: cd %t # RUN: yaml2obj < %p/Inputs/ret42.yaml > in.obj # RUN: lld-link /entry:main in.obj # RUN: lld-link /entry:main /dll in.obj # RUN: echo -e "NAME foo\n" > fooexe.def # RUN: echo -e "LIBRARY foo\n" > foodll.def # RUN: lld-link /entry:main /def:fooexe.def in.obj # RUN: lld-link /entry:main /def:foodll.def /dll in.obj # RUN: lld-link /entry:main /out:bar.exe /def:fooexe.def in.obj # RUN: lld-link /entry:main /out:bar.dll /def:foodll.def /dll in.obj # RUN: llvm-readobj in.exe | FileCheck %s # RUN: llvm-readobj in.dll | FileCheck %s # RUN: llvm-readobj foo.exe | FileCheck %s # RUN: llvm-readobj foo.dll | FileCheck %s # RUN: llvm-readobj bar.exe | FileCheck %s # RUN: llvm-readobj bar.dll | FileCheck %s CHECK: File: Index: vendor/lld/dist/test/COFF/dll.test =================================================================== --- vendor/lld/dist/test/COFF/dll.test (revision 320381) +++ vendor/lld/dist/test/COFF/dll.test (revision 320382) @@ -1,52 +1,50 @@ -# REQUIRES: winres - # RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj # RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \ # RUN: /export:mangled # RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=EXPORT %s EXPORT: Export Table: EXPORT: DLL name: dll.test.tmp.dll EXPORT: Ordinal RVA Name EXPORT-NEXT: 0 0 EXPORT-NEXT: 1 0x1008 exportfn1 EXPORT-NEXT: 2 0x1010 exportfn2 EXPORT-NEXT: 3 0x1010 exportfn3 EXPORT-NEXT: 4 0x1010 mangled # RUN: yaml2obj < %p/Inputs/export2.yaml > %t5.obj # RUN: rm -f %t5.lib # RUN: llvm-ar cru %t5.lib %t5.obj # RUN: lld-link /out:%t5.dll /dll %t.obj %t5.lib /export:mangled2 # RUN: llvm-objdump -p %t5.dll | FileCheck -check-prefix=EXPORT2 %s EXPORT2: Export Table: EXPORT2: DLL name: dll.test.tmp5.dll EXPORT2: Ordinal RVA Name EXPORT2-NEXT: 0 0 EXPORT2-NEXT: 1 0x1010 exportfn3 EXPORT2-NEXT: 2 0x101c mangled2 # RUN: llvm-as -o %t.lto.obj %p/Inputs/export.ll # RUN: lld-link /out:%t.lto.dll /dll %t.lto.obj /export:exportfn1 /export:exportfn2 # RUN: llvm-objdump -p %t.lto.dll | FileCheck -check-prefix=EXPORT-LTO %s EXPORT-LTO: Export Table: EXPORT-LTO: DLL name: dll.test.tmp.lto.dll EXPORT-LTO: Ordinal RVA Name EXPORT-LTO-NEXT: 0 0 EXPORT-LTO-NEXT: 1 0x1010 exportfn1 EXPORT-LTO-NEXT: 2 0x1020 exportfn2 EXPORT-LTO-NEXT: 3 0x1030 exportfn3 # RUN: lld-link /out:%t.dll /dll %t.obj /implib:%t2.lib \ # RUN: /export:exportfn1 /export:exportfn2 # RUN: yaml2obj < %p/Inputs/import.yaml > %t2.obj # RUN: lld-link /out:%t2.exe /entry:main %t2.obj %t2.lib # RUN: llvm-readobj -coff-imports %t2.exe | FileCheck -check-prefix=IMPORT %s # RUN: lld-link /out:%t2.lto.exe /entry:main %t2.obj %t.lto.lib # RUN: llvm-readobj -coff-imports %t2.lto.exe | FileCheck -check-prefix=IMPORT %s IMPORT: Symbol: exportfn1 IMPORT: Symbol: exportfn2 Index: vendor/lld/dist/test/COFF/dllimport-gc.test =================================================================== --- vendor/lld/dist/test/COFF/dllimport-gc.test (revision 320381) +++ vendor/lld/dist/test/COFF/dllimport-gc.test (revision 320382) @@ -1,58 +1,56 @@ -# REQUIRES: winres - # RUN: yaml2obj < %p/Inputs/export.yaml > %t-lib.obj # RUN: lld-link /out:%t.dll /dll %t-lib.obj /implib:%t.lib /export:exportfn1 # RUN: yaml2obj < %p/Inputs/oldname.yaml > %t-oldname.obj # RUN: yaml2obj < %s > %t.obj # RUN: lld-link /out:%t1.exe /entry:main %t.obj %t-oldname.obj %t.lib # RUN: llvm-readobj -coff-imports %t1.exe | FileCheck -check-prefix=REF %s # REF-NOT: Symbol: exportfn1 # RUN: lld-link /out:%t2.exe /entry:main %t.obj %t-oldname.obj %t.lib /opt:noref # RUN: llvm-readobj -coff-imports %t2.exe | FileCheck -check-prefix=NOREF %s # NOREF: Symbol: exportfn1 --- !COFF header: Machine: IMAGE_FILE_MACHINE_AMD64 Characteristics: [] sections: - Name: .text Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] Alignment: 4 SectionData: 0000000000000000 symbols: - Name: .text Value: 0 SectionNumber: 1 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC SectionDefinition: Length: 8 NumberOfRelocations: 0 NumberOfLinenumbers: 0 CheckSum: 0 Number: 0 - Name: main Value: 0 SectionNumber: 1 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_FUNCTION StorageClass: IMAGE_SYM_CLASS_EXTERNAL - Name: exportfn1 Value: 0 SectionNumber: 0 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_EXTERNAL - Name: exportfn1_alias Value: 0 SectionNumber: 0 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_EXTERNAL ... Index: vendor/lld/dist/test/COFF/guardcf.test =================================================================== --- vendor/lld/dist/test/COFF/guardcf.test (nonexistent) +++ vendor/lld/dist/test/COFF/guardcf.test (revision 320382) @@ -0,0 +1,74 @@ +# RUN: yaml2obj < %s > %t.obj +# RUN: lld-link /entry:main /out:%t.exe %t.obj + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 000000000000 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 6 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __guard_fids_count + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __guard_fids_table + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __guard_flags + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __guard_iat_count + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __guard_iat_table + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __guard_longjmp_count + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __guard_longjmp_table + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... Index: vendor/lld/dist/test/COFF/hello32.test =================================================================== --- vendor/lld/dist/test/COFF/hello32.test (revision 320381) +++ vendor/lld/dist/test/COFF/hello32.test (revision 320382) @@ -1,131 +1,131 @@ # RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj # RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \ # RUN: /entry:main@0 /out:%t.exe /appcontainer # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s # RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s HEADER: Format: COFF-i386 HEADER-NEXT: Arch: i386 HEADER-NEXT: AddressSize: 32bit HEADER-NEXT: ImageFileHeader { HEADER-NEXT: Machine: IMAGE_FILE_MACHINE_I386 (0x14C) HEADER-NEXT: SectionCount: 4 HEADER-NEXT: TimeDateStamp: 1970-01-01 00:00:00 (0x0) HEADER-NEXT: PointerToSymbolTable: 0x0 HEADER-NEXT: SymbolCount: 0 HEADER-NEXT: OptionalHeaderSize: 224 HEADER-NEXT: Characteristics [ (0x102) HEADER-NEXT: IMAGE_FILE_32BIT_MACHINE (0x100) HEADER-NEXT: IMAGE_FILE_EXECUTABLE_IMAGE (0x2) HEADER-NEXT: ] HEADER-NEXT: } HEADER-NEXT: ImageOptionalHeader { -HEADER-NEXT: MajorLinkerVersion: 0 +HEADER-NEXT: MajorLinkerVersion: 14 HEADER-NEXT: MinorLinkerVersion: 0 HEADER-NEXT: SizeOfCode: 512 HEADER-NEXT: SizeOfInitializedData: 1536 HEADER-NEXT: SizeOfUninitializedData: 0 HEADER-NEXT: AddressOfEntryPoint: 0x2000 HEADER-NEXT: BaseOfCode: 0x2000 HEADER-NEXT: BaseOfData: 0x0 HEADER-NEXT: ImageBase: 0x400000 HEADER-NEXT: SectionAlignment: 4096 HEADER-NEXT: FileAlignment: 512 HEADER-NEXT: MajorOperatingSystemVersion: 6 HEADER-NEXT: MinorOperatingSystemVersion: 0 HEADER-NEXT: MajorImageVersion: 0 HEADER-NEXT: MinorImageVersion: 0 HEADER-NEXT: MajorSubsystemVersion: 6 HEADER-NEXT: MinorSubsystemVersion: 0 HEADER-NEXT: SizeOfImage: 16896 HEADER-NEXT: SizeOfHeaders: 512 HEADER-NEXT: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3) HEADER-NEXT: Characteristics [ (0x9940) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_APPCONTAINER (0x1000) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE (0x40) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_NO_BIND (0x800) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT (0x100) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000) HEADER-NEXT: ] HEADER-NEXT: SizeOfStackReserve: 1048576 HEADER-NEXT: SizeOfStackCommit: 4096 HEADER-NEXT: SizeOfHeapReserve: 1048576 HEADER-NEXT: SizeOfHeapCommit: 4096 HEADER-NEXT: NumberOfRvaAndSize: 16 HEADER-NEXT: DataDirectory { HEADER-NEXT: ExportTableRVA: 0x0 HEADER-NEXT: ExportTableSize: 0x0 HEADER-NEXT: ImportTableRVA: 0x3000 HEADER-NEXT: ImportTableSize: 0x28 HEADER-NEXT: ResourceTableRVA: 0x0 HEADER-NEXT: ResourceTableSize: 0x0 HEADER-NEXT: ExceptionTableRVA: 0x0 HEADER-NEXT: ExceptionTableSize: 0x0 HEADER-NEXT: CertificateTableRVA: 0x0 HEADER-NEXT: CertificateTableSize: 0x0 HEADER-NEXT: BaseRelocationTableRVA: 0x4000 HEADER-NEXT: BaseRelocationTableSize: 0x10 HEADER-NEXT: DebugRVA: 0x0 HEADER-NEXT: DebugSize: 0x0 HEADER-NEXT: ArchitectureRVA: 0x0 HEADER-NEXT: ArchitectureSize: 0x0 HEADER-NEXT: GlobalPtrRVA: 0x0 HEADER-NEXT: GlobalPtrSize: 0x0 HEADER-NEXT: TLSTableRVA: 0x0 HEADER-NEXT: TLSTableSize: 0x0 HEADER-NEXT: LoadConfigTableRVA: 0x0 HEADER-NEXT: LoadConfigTableSize: 0x0 HEADER-NEXT: BoundImportRVA: 0x0 HEADER-NEXT: BoundImportSize: 0x0 HEADER-NEXT: IATRVA: 0x3034 HEADER-NEXT: IATSize: 0xC HEADER-NEXT: DelayImportDescriptorRVA: 0x0 HEADER-NEXT: DelayImportDescriptorSize: 0x0 HEADER-NEXT: CLRRuntimeHeaderRVA: 0x0 HEADER-NEXT: CLRRuntimeHeaderSize: 0x0 HEADER-NEXT: ReservedRVA: 0x0 HEADER-NEXT: ReservedSize: 0x0 HEADER-NEXT: } HEADER-NEXT: } HEADER-NEXT: DOSHeader { HEADER-NEXT: Magic: MZ HEADER-NEXT: UsedBytesInTheLastPage: 0 HEADER-NEXT: FileSizeInPages: 0 HEADER-NEXT: NumberOfRelocationItems: 0 HEADER-NEXT: HeaderSizeInParagraphs: 0 HEADER-NEXT: MinimumExtraParagraphs: 0 HEADER-NEXT: MaximumExtraParagraphs: 0 HEADER-NEXT: InitialRelativeSS: 0 HEADER-NEXT: InitialSP: 0 HEADER-NEXT: Checksum: 0 HEADER-NEXT: InitialIP: 0 HEADER-NEXT: InitialRelativeCS: 0 HEADER-NEXT: AddressOfRelocationTable: 64 HEADER-NEXT: OverlayNumber: 0 HEADER-NEXT: OEMid: 0 HEADER-NEXT: OEMinfo: 0 HEADER-NEXT: AddressOfNewExeHeader: 64 HEADER-NEXT: } IMPORTS: Format: COFF-i386 IMPORTS: Arch: i386 IMPORTS: AddressSize: 32bit IMPORTS: Import { IMPORTS: Name: std32.dll IMPORTS: ImportLookupTableRVA: 0x3028 IMPORTS: ImportAddressTableRVA: 0x3034 IMPORTS: Symbol: ExitProcess (0) IMPORTS: Symbol: MessageBoxA (1) IMPORTS: } BASEREL: BaseReloc [ BASEREL: Entry { BASEREL: Type: HIGHLOW BASEREL: Address: 0x2005 BASEREL: } BASEREL: Entry { BASEREL: Type: HIGHLOW BASEREL: Address: 0x200C BASEREL: } BASEREL: ] Index: vendor/lld/dist/test/COFF/icf-associative.test =================================================================== --- vendor/lld/dist/test/COFF/icf-associative.test (revision 320381) +++ vendor/lld/dist/test/COFF/icf-associative.test (revision 320382) @@ -1,104 +1,104 @@ # RUN: yaml2obj < %s > %t.obj # RUN: lld-link /entry:foo /out:%t.exe /subsystem:console /include:bar \ # RUN: /debug /verbose %t.obj > %t.log 2>&1 # RUN: FileCheck %s < %t.log # CHECK: Selected foo # CHECK: Removed bar --- !COFF header: Machine: IMAGE_FILE_MACHINE_AMD64 Characteristics: [] sections: - Name: '.text$mn' Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] Alignment: 16 SectionData: 4883EC28E8000000004883C428C3 - - Name: '.debug$S' + - Name: '.debug_blah' Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] Alignment: 1 SectionData: 0000000000000000000000000000 - Name: '.text$mn' Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] Alignment: 16 SectionData: 4883EC28E8000000004883C428C3 - - Name: '.debug$S' + - Name: '.debug_blah' Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] Alignment: 1 SectionData: FFFFFFFFFFFFFFFFFFFFFFFFFFFF symbols: - Name: '.text$mn' Value: 0 SectionNumber: 1 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC SectionDefinition: Length: 14 NumberOfRelocations: 0 NumberOfLinenumbers: 0 CheckSum: 1682752513 Number: 0 Selection: IMAGE_COMDAT_SELECT_ANY - - Name: '.debug$S' + - Name: '.debug_blah' Value: 0 SectionNumber: 2 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC SectionDefinition: Length: 14 NumberOfRelocations: 0 NumberOfLinenumbers: 0 CheckSum: 0 Number: 1 Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE - Name: '.text$mn' Value: 0 SectionNumber: 3 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC SectionDefinition: Length: 14 NumberOfRelocations: 0 NumberOfLinenumbers: 0 CheckSum: 1682752513 Number: 0 Selection: IMAGE_COMDAT_SELECT_ANY - - Name: '.debug$S' + - Name: '.debug_blah' Value: 0 SectionNumber: 4 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC SectionDefinition: Length: 14 NumberOfRelocations: 0 NumberOfLinenumbers: 0 CheckSum: 0 Number: 3 Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE - Name: foo Value: 0 SectionNumber: 1 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_FUNCTION StorageClass: IMAGE_SYM_CLASS_EXTERNAL - Name: bar Value: 0 SectionNumber: 3 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_FUNCTION StorageClass: IMAGE_SYM_CLASS_EXTERNAL ... Index: vendor/lld/dist/test/COFF/manifestinput.test =================================================================== --- vendor/lld/dist/test/COFF/manifestinput.test (revision 320381) +++ vendor/lld/dist/test/COFF/manifestinput.test (revision 320382) @@ -1,10 +1,35 @@ -# REQUIRES: winres +# REQUIRES: win_mt # RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj # RUN: lld-link /out:%t.exe /entry:main \ # RUN: /manifestuac:"level='requireAdministrator'" \ # RUN: /manifestinput:%p/Inputs/manifestinput.test %t.obj # RUN: FileCheck %s < %t.exe.manifest CHECK: CHECK: + +# RUN: yaml2obj %p/Inputs/ret42.yaml > %t.obj +# RUN: lld-link /out:%t.exe /entry:main \ +# RUN: /manifest:embed \ +# RUN: /manifestuac:"level='requireAdministrator'" \ +# RUN: /manifestinput:%p/Inputs/manifestinput.test %t.obj +# RUN: llvm-readobj -coff-resources -file-headers %t.exe | FileCheck %s \ +# RUN: -check-prefix TEST_EMBED + +TEST_EMBED: ResourceTableRVA: 0x1000 +TEST_EMBED-NEXT: ResourceTableSize: 0x298 +TEST_EMBED-DAG: Resources [ +TEST_EMBED-NEXT: Total Number of Resources: 1 +TEST_EMBED-DAG: Number of String Entries: 0 +TEST_EMBED-NEXT: Number of ID Entries: 1 +TEST_EMBED-NEXT: Type: kRT_MANIFEST (ID 24) [ +TEST_EMBED-NEXT: Table Offset: 0x18 +TEST_EMBED-NEXT: Number of String Entries: 0 +TEST_EMBED-NEXT: Number of ID Entries: 1 +TEST_EMBED-NEXT: Name: (ID 1) [ +TEST_EMBED-NEXT: Table Offset: 0x30 +TEST_EMBED-NEXT: Number of String Entries: 0 +TEST_EMBED-NEXT: Number of ID Entries: 1 +TEST_EMBED-NEXT: Language: (ID 1033) [ +TEST_EMBED-NEXT: Entry Offset: 0x48 Index: vendor/lld/dist/test/COFF/noentry.test =================================================================== --- vendor/lld/dist/test/COFF/noentry.test (revision 320381) +++ vendor/lld/dist/test/COFF/noentry.test (revision 320382) @@ -1,10 +1,8 @@ -# REQUIRES: winres - # RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj # RUN: lld-link /out:%t.dll /dll %t.obj # RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=ENTRY %s # RUN: lld-link /out:%t.dll /dll /noentry %t.obj # RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=NOENTRY %s ENTRY: AddressOfEntryPoint: 0x1000 NOENTRY: AddressOfEntryPoint: 0x0 Index: vendor/lld/dist/test/COFF/out.test =================================================================== --- vendor/lld/dist/test/COFF/out.test (revision 320381) +++ vendor/lld/dist/test/COFF/out.test (revision 320382) @@ -1,18 +1,17 @@ -# REQUIRES: winres # RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj # RUN: mkdir -p %T/out/tmp # RUN: cp %t.obj %T/out/out1.obj # RUN: cp %t.obj %T/out/tmp/out2 # RUN: cp %t.obj %T/out/tmp/out3.xyz # RUN: rm -f out1.exe out2.exe out3.exe out3.dll # RUN: lld-link /entry:main %T/out/out1.obj # RUN: lld-link /entry:main %T/out/tmp/out2 # RUN: lld-link /dll /entry:main %T/out/tmp/out3.xyz # RUN: llvm-readobj out1.exe | FileCheck %s # RUN: llvm-readobj out2.exe | FileCheck %s # RUN: llvm-readobj out3.dll | FileCheck %s CHECK: File: Index: vendor/lld/dist/test/COFF/pdb-comdat.test =================================================================== --- vendor/lld/dist/test/COFF/pdb-comdat.test (nonexistent) +++ vendor/lld/dist/test/COFF/pdb-comdat.test (revision 320382) @@ -0,0 +1,100 @@ +Consider this example program with an inline function "foo": + +==> foo.h <== +extern int global; +__inline void foo() { + ++global; +} +void bar(); +==> pdb_comdat_main.c <== +#include "foo.h" +int main(void) { + foo(); + bar(); + return 42; +} +==> pdb_comdat_bar.c <== +#include "foo.h" +void bar(void) { + foo(); +} + +Both object files will contain debug info for foo, but only the debug info from +pdb_comdat_main.obj should be included in the PDB. + +RUN: rm -rf %t && mkdir -p %t && cd %t +RUN: yaml2obj %S/Inputs/pdb_comdat_main.yaml -o pdb_comdat_main.obj +RUN: yaml2obj %S/Inputs/pdb_comdat_bar.yaml -o pdb_comdat_bar.obj +RUN: lld-link pdb_comdat_main.obj pdb_comdat_bar.obj -out:t.exe -debug -pdb:t.pdb -nodefaultlib -entry:main +RUN: llvm-pdbutil dump -l -symbols t.pdb | FileCheck %s + +CHECK: Lines +CHECK: ============================================================ +CHECK-LABEL: Mod 0000 | `{{.*}}pdb_comdat_main.obj`: +CHECK: c:\src\llvm-project\build\pdb_comdat_main.c (MD5: F969E51BBE373436D81492EB61387F36) +CHECK: c:\src\llvm-project\build\foo.h (MD5: D74D834EFAC3AE2B45E606A8320B1D5C) +CHECK-LABEL: Mod 0001 | `{{.*}}pdb_comdat_bar.obj`: +CHECK: c:\src\llvm-project\build\pdb_comdat_bar.c (MD5: 365279DB4FCBEDD721BBFC3B14A953C2) +CHECK-NOT: c:\src\llvm-project\build\foo.h +CHECK-LABEL: Mod 0002 | `* Linker *`: + +CHECK: Symbols +CHECK: ============================================================ +CHECK-LABEL: Mod 0000 | `{{.*}}pdb_comdat_main.obj`: +CHECK: - S_OBJNAME [size = 56] sig=0, `C:\src\llvm-project\build\pdb_comdat_main.obj` +CHECK: - S_COMPILE3 [size = 60] +CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, language = c +CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1 +CHECK: flags = security checks | hot patchable +CHECK: - S_GPROC32_ID [size = 44] `main` + FIXME: We need to fill in "end". +CHECK: parent = 0, addr = 0002:0000, code size = 24, end = 0 +CHECK: debug start = 4, debug end = 19, flags = none +CHECK: - S_FRAMEPROC [size = 32] +CHECK: size = 40, padding size = 0, offset to padding = 0 +CHECK: bytes of callee saved registers = 0, exception handler addr = 0000:0000 +CHECK: flags = has async eh | opt speed +CHECK: - S_END [size = 4] +CHECK: - S_GDATA32 [size = 24] `global` +CHECK: type = 0x0074 (int), addr = 0000:0000 +CHECK: - S_BUILDINFO [size = 8] BuildId = `4106` +CHECK: - S_GPROC32_ID [size = 44] `foo` +CHECK: parent = 0, addr = 0002:0032, code size = 15, end = 0 +CHECK: debug start = 0, debug end = 14, flags = none +CHECK: - S_FRAMEPROC [size = 32] +CHECK: size = 0, padding size = 0, offset to padding = 0 +CHECK: bytes of callee saved registers = 0, exception handler addr = 0000:0000 +CHECK: flags = marked inline | has async eh | opt speed +CHECK: - S_END [size = 4] +CHECK-LABEL: Mod 0001 | `{{.*}}pdb_comdat_bar.obj`: +CHECK: - S_OBJNAME [size = 56] sig=0, `C:\src\llvm-project\build\pdb_comdat_bar.obj` +CHECK: - S_COMPILE3 [size = 60] +CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, language = c +CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1 +CHECK: flags = security checks | hot patchable +CHECK: - S_GPROC32_ID [size = 44] `bar` +CHECK: parent = 0, addr = 0002:0048, code size = 14, end = 0 +CHECK: debug start = 4, debug end = 9, flags = none +CHECK: - S_FRAMEPROC [size = 32] +CHECK: size = 40, padding size = 0, offset to padding = 0 +CHECK: bytes of callee saved registers = 0, exception handler addr = 0000:0000 +CHECK: flags = has async eh | opt speed +CHECK: - S_END [size = 4] +CHECK: - S_GDATA32 [size = 24] `global` +CHECK: type = 0x0074 (int), addr = 0000:0000 +CHECK: - S_BUILDINFO [size = 8] BuildId = `4109` +CHECK-NOT: - S_GPROC32_ID {{.*}} `foo` +CHECK-LABEL: Mod 0002 | `* Linker *`: + +Reorder the object files and verify that the other table is selected. + +RUN: lld-link pdb_comdat_bar.obj pdb_comdat_main.obj -out:t.exe -debug -pdb:t.pdb -nodefaultlib -entry:main +RUN: llvm-pdbutil dump -l t.pdb | FileCheck %s --check-prefix=REORDER + +REORDER-LABEL: Mod 0000 | `{{.*}}pdb_comdat_bar.obj`: +REORDER: c:\src\llvm-project\build\pdb_comdat_bar.c (MD5: 365279DB4FCBEDD721BBFC3B14A953C2) +REORDER: c:\src\llvm-project\build\foo.h (MD5: D74D834EFAC3AE2B45E606A8320B1D5C) +REORDER-LABEL: Mod 0001 | `{{.*}}pdb_comdat_main.obj`: +REORDER: c:\src\llvm-project\build\pdb_comdat_main.c +REORDER-NOT: c:\src\llvm-project\build\foo.h +REORDER-LABEL: Mod 0002 | `* Linker *`: Index: vendor/lld/dist/test/COFF/pdb-lib.s =================================================================== --- vendor/lld/dist/test/COFF/pdb-lib.s (revision 320381) +++ vendor/lld/dist/test/COFF/pdb-lib.s (revision 320382) @@ -1,32 +1,32 @@ # RUN: rm -rf %t && mkdir -p %t && cd %t # RUN: llvm-mc -filetype=obj -triple=i686-windows-msvc %s -o foo.obj # RUN: llc %S/Inputs/bar.ll -filetype=obj -mtriple=i686-windows-msvc -o bar.obj # RUN: llvm-lib bar.obj -out:bar.lib # RUN: lld-link -debug -pdb:foo.pdb foo.obj bar.lib -out:foo.exe -entry:main -# RUN: llvm-pdbutil raw -modules %t/foo.pdb | FileCheck %s +# RUN: llvm-pdbutil dump -modules %t/foo.pdb | FileCheck %s # Make sure that the PDB has module descriptors. foo.obj and bar.lib should be # absolute paths, and bar.obj should be the relative path passed to llvm-lib. # CHECK: Modules # CHECK-NEXT: ============================================================ # CHECK-NEXT: Mod 0000 | Name: `{{.*pdb-lib.s.tmp[/\\]foo.obj}}`: # CHECK-NEXT: Obj: `{{.*pdb-lib.s.tmp[/\\]foo.obj}}`: # CHECK-NEXT: debug stream: 9, # files: 0, has ec info: false # CHECK-NEXT: Mod 0001 | Name: `bar.obj`: # CHECK-NEXT: Obj: `{{.*pdb-lib.s.tmp[/\\]bar.lib}}`: # CHECK-NEXT: debug stream: 10, # files: 0, has ec info: false # CHECK-NEXT: Mod 0002 | Name: `* Linker *`: # CHECK-NEXT: Obj: ``: # CHECK-NEXT: debug stream: 11, # files: 0, has ec info: false .def _main; .scl 2; .type 32; .endef .globl _main _main: calll _bar xor %eax, %eax retl Index: vendor/lld/dist/test/COFF/pdb-safeseh.yaml =================================================================== --- vendor/lld/dist/test/COFF/pdb-safeseh.yaml (nonexistent) +++ vendor/lld/dist/test/COFF/pdb-safeseh.yaml (revision 320382) @@ -0,0 +1,85 @@ +# RUN: yaml2obj %s -o %t.obj +# RUN: lld-link -debug -entry:main -out:%t.exe -pdb:%t.pdb %t.obj +# RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s + +# There is an S_GDATA32 symbol record with .secrel32 and .secidx relocations in +# it in this debug info. This is similar to the relocations in the loadcfg.obj +# file in the MSVC CRT. We need to make sure that our relocation logic matches +# MSVC's for these absolute, linker-provided symbols. + +# CHECK: Mod 0000 | +# CHECK-NEXT: - S_GDATA32 [size = 40] `___safe_se_handler_table` +# CHECK-NEXT: type = 0x0022 (unsigned long), addr = 0003:0000 +# CHECK-NEXT: Mod 0001 | `* Linker *`: + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [ ] +sections: + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_GDATA32 + DataSym: + Type: 34 + DisplayName: ___safe_se_handler_table + - !StringTable + Strings: + Relocations: + - VirtualAddress: 20 + SymbolName: ___safe_se_handler_table + Type: IMAGE_REL_I386_SECREL + - VirtualAddress: 24 + SymbolName: ___safe_se_handler_table + Type: IMAGE_REL_I386_SECTION + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 488D0500000000C3 + Relocations: + - VirtualAddress: 3 + SymbolName: ___safe_se_handler_table + Type: IMAGE_REL_I386_REL32 +symbols: + - Name: '.debug$S' + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 372 + NumberOfRelocations: 6 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.text$mn' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 1092178131 + Number: 0 + - Name: _main + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: ___safe_se_handler_table + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... + Index: vendor/lld/dist/test/COFF/pdb-secrel-absolute.yaml =================================================================== --- vendor/lld/dist/test/COFF/pdb-secrel-absolute.yaml (nonexistent) +++ vendor/lld/dist/test/COFF/pdb-secrel-absolute.yaml (revision 320382) @@ -0,0 +1,84 @@ +# RUN: yaml2obj %s -o %t.obj +# RUN: lld-link -debug -entry:main -out:%t.exe -pdb:%t.pdb %t.obj +# RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s + +# There is an S_GDATA32 symbol record with .secrel32 and .secidx relocations in +# it in this debug info. This is similar to the relocations in the loadcfg.obj +# file in the MSVC CRT. We need to make sure that our relocation logic matches +# MSVC's for these absolute, linker-provided symbols. + +# CHECK: Mod 0000 | +# CHECK-NEXT: - S_GDATA32 [size = 36] `__guard_fids_table` +# CHECK-NEXT: type = 0x0022 (unsigned long), addr = 0003:0000 +# CHECK-NEXT: Mod 0001 | `* Linker *`: + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_GDATA32 + DataSym: + Type: 34 + DisplayName: __guard_fids_table + - !StringTable + Strings: + Relocations: + - VirtualAddress: 20 + SymbolName: __guard_fids_table + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 24 + SymbolName: __guard_fids_table + Type: IMAGE_REL_AMD64_SECTION + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 488D0500000000C3 + Relocations: + - VirtualAddress: 3 + SymbolName: __guard_fids_table + Type: IMAGE_REL_AMD64_REL32 +symbols: + - Name: '.debug$S' + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 372 + NumberOfRelocations: 6 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.text$mn' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 1092178131 + Number: 0 + - Name: main + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __guard_fids_table + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... Index: vendor/lld/dist/test/COFF/pdb-source-lines.test =================================================================== --- vendor/lld/dist/test/COFF/pdb-source-lines.test (nonexistent) +++ vendor/lld/dist/test/COFF/pdb-source-lines.test (revision 320382) @@ -0,0 +1,124 @@ +Test the linker line tables on roughly the following example: + +==> foo.h <== +void bar(void); +inline void foo(void) { + bar(); +} +==> pdb_lines_1.c <== +#include "foo.h" +int main(void) { + foo(); + return 42; +} +==> pdb_lines_2.c <== +void bar(void) { +} + +$ cl -c -Z7 pdb_lines*.c + +RUN: yaml2obj %S/Inputs/pdb_lines_1.yaml -o %t.pdb_lines_1.obj +RUN: yaml2obj %S/Inputs/pdb_lines_2.yaml -o %t.pdb_lines_2.obj +RUN: lld-link -debug -entry:main -nodefaultlib -out:%t.exe -pdb:%t.pdb %t.pdb_lines_1.obj %t.pdb_lines_2.obj +RUN: llvm-pdbutil pdb2yaml -modules -module-files -subsections=lines,fc %t.pdb | FileCheck %s + +CHECK-LABEL: DbiStream: +CHECK-NEXT: VerHeader: V110 +CHECK-NEXT: Age: 1 +CHECK-NEXT: BuildNumber: 0 +CHECK-NEXT: PdbDllVersion: 0 +CHECK-NEXT: PdbDllRbld: 0 +CHECK-NEXT: Flags: 0 +CHECK-NEXT: MachineType: x86 +CHECK-NEXT: Modules: + +CHECK-LABEL: - Module: {{.*}}pdb_lines_1.obj +CHECK-NEXT: ObjFile: {{.*}}pdb_lines_1.obj +CHECK-NEXT: SourceFiles: +CHECK-NEXT: - '{{.*}}pdb_lines_1.c' +CHECK-NEXT: - '{{.*}}foo.h' +CHECK-NEXT: Subsections: +CHECK-NEXT: - !Lines +CHECK-NEXT: CodeSize: 19 +CHECK-NEXT: Flags: [ ] +CHECK-NEXT: RelocOffset: 0 +CHECK-NEXT: RelocSegment: 2 +CHECK-NEXT: Blocks: +CHECK-NEXT: - FileName: '{{.*}}pdb_lines_1.c' +CHECK-NEXT: Lines: +CHECK-NEXT: - Offset: 0 +CHECK-NEXT: LineStart: 2 +CHECK-NEXT: IsStatement: true +CHECK-NEXT: EndDelta: 0 +CHECK-NEXT: - Offset: 4 +CHECK-NEXT: LineStart: 3 +CHECK-NEXT: IsStatement: true +CHECK-NEXT: EndDelta: 0 +CHECK-NEXT: - Offset: 9 +CHECK-NEXT: LineStart: 4 +CHECK-NEXT: IsStatement: true +CHECK-NEXT: EndDelta: 0 +CHECK-NEXT: - Offset: 14 +CHECK-NEXT: LineStart: 5 +CHECK-NEXT: IsStatement: true +CHECK-NEXT: EndDelta: 0 +CHECK-NEXT: Columns: +CHECK-NEXT: - !FileChecksums +CHECK-NEXT: Checksums: +CHECK-NEXT: - FileName: '{{.*}}pdb_lines_1.c' +CHECK-NEXT: Kind: MD5 +CHECK-NEXT: Checksum: 4EB19DCD86C3BA2238A255C718572E7B +CHECK-NEXT: - FileName: '{{.*}}foo.h' +CHECK-NEXT: Kind: MD5 +CHECK-NEXT: Checksum: 061EB73ABB642532857A4F1D9CBAC323 +CHECK-NEXT: - !Lines +CHECK-NEXT: CodeSize: 14 +CHECK-NEXT: Flags: [ ] +CHECK-NEXT: RelocOffset: 32 +CHECK-NEXT: RelocSegment: 2 +CHECK-NEXT: Blocks: +CHECK-NEXT: - FileName: '{{.*}}foo.h' +CHECK-NEXT: Lines: +CHECK-NEXT: - Offset: 0 +CHECK-NEXT: LineStart: 2 +CHECK-NEXT: IsStatement: true +CHECK-NEXT: EndDelta: 0 +CHECK-NEXT: - Offset: 4 +CHECK-NEXT: LineStart: 3 +CHECK-NEXT: IsStatement: true +CHECK-NEXT: EndDelta: 0 +CHECK-NEXT: - Offset: 9 +CHECK-NEXT: LineStart: 4 +CHECK-NEXT: IsStatement: true +CHECK-NEXT: EndDelta: 0 +CHECK-NEXT: Columns: + +CHECK-LABEL: - Module: {{.*}}pdb_lines_2.obj +CHECK-NEXT: ObjFile: {{.*}}pdb_lines_2.obj +CHECK-NEXT: SourceFiles: +CHECK-NEXT: - '{{.*}}pdb_lines_2.c' +CHECK-NEXT: Subsections: +CHECK-NEXT: - !Lines +CHECK-NEXT: CodeSize: 1 +CHECK-NEXT: Flags: [ ] +CHECK-NEXT: RelocOffset: 48 +CHECK-NEXT: RelocSegment: 2 +CHECK-NEXT: Blocks: +CHECK-NEXT: - FileName: '{{.*}}pdb_lines_2.c' +CHECK-NEXT: Lines: +CHECK-NEXT: - Offset: 0 +CHECK-NEXT: LineStart: 1 +CHECK-NEXT: IsStatement: true +CHECK-NEXT: EndDelta: 0 +CHECK-NEXT: - Offset: 0 +CHECK-NEXT: LineStart: 2 +CHECK-NEXT: IsStatement: true +CHECK-NEXT: EndDelta: 0 +CHECK-NEXT: Columns: +CHECK-NEXT: - !FileChecksums +CHECK-NEXT: Checksums: +CHECK-NEXT: - FileName: '{{.*}}pdb_lines_2.c' +CHECK-NEXT: Kind: MD5 +CHECK-NEXT: Checksum: DF91CB3A2B8D917486574BB50CAC4CC7 +CHECK-NEXT: - Module: '* Linker *' +CHECK-NEXT: ObjFile: '' Index: vendor/lld/dist/test/COFF/pdb-symbol-types.yaml =================================================================== --- vendor/lld/dist/test/COFF/pdb-symbol-types.yaml (nonexistent) +++ vendor/lld/dist/test/COFF/pdb-symbol-types.yaml (revision 320382) @@ -0,0 +1,344 @@ +# RUN: yaml2obj %s -o %t.obj +# RUN: lld-link %t.obj -nodefaultlib -entry:main -debug -out:%t.exe -pdb:%t.pdb +# RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s + +# To regenerate the object file: +# $ cat symbol-types.c +# struct Foo { int x; }; +# typedef struct Foo UDT_Foo; +# UDT_Foo global_foo = {42}; +# int main() { return global_foo.x; } +# $ cl -c -Z7 symbol-types.c + +# Note that the type of 'global' goes from 0x1005 in the object file to 0x1004 +# in the PDB because the LF_FUNC_ID is moved to the id stream. + +# CHECK: Symbols +# CHECK: ============================================================ +# CHECK-LABEL: Mod 0000 | `{{.*}}pdb-symbol-types.yaml.tmp.obj`: +# CHECK: - S_OBJNAME [size = 52] sig=0, `C:\src\llvm-project\build\symbol-types.obj` +# CHECK: - S_COMPILE3 [size = 60] +# CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, language = c +# CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1 +# CHECK: flags = security checks | hot patchable +# CHECK: - S_GPROC32_ID [size = 44] `main` +# CHECK: parent = 0, addr = 0002:0000, code size = 7, end = 0 +# CHECK: debug start = 0, debug end = 6, flags = none +# CHECK: - S_FRAMEPROC [size = 32] +# CHECK: size = 0, padding size = 0, offset to padding = 0 +# CHECK: bytes of callee saved registers = 0, exception handler addr = 0000:0000 +# CHECK: flags = has async eh | opt speed +# CHECK: - S_END [size = 4] +# CHECK: - S_GDATA32 [size = 28] `global_foo` +# CHECK: type = 0x1004 (Foo), addr = 0001:0000 +# CHECK: - S_UDT [size = 16] `UDT_Foo` +# CHECK: original type = 0x1004 +# CHECK: - S_UDT [size = 12] `Foo` +# CHECK: original type = 0x1004 +# CHECK: - S_BUILDINFO [size = 8] BuildId = `4106` +# CHECK-LABEL: Mod 0001 | `* Linker *`: + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_OBJNAME + ObjNameSym: + Signature: 0 + ObjectName: 'C:\src\llvm-project\build\symbol-types.obj' + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ SecurityChecks, HotPatch ] + Machine: X64 + FrontendMajor: 19 + FrontendMinor: 0 + FrontendBuild: 24215 + FrontendQFE: 1 + BackendMajor: 19 + BackendMinor: 0 + BackendBuild: 24215 + BackendQFE: 1 + Version: 'Microsoft (R) Optimizing Compiler' + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 7 + DbgStart: 0 + DbgEnd: 6 + FunctionType: 4098 + Flags: [ ] + DisplayName: main + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 0 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 7 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\symbol-types.c' + Lines: + - Offset: 0 + LineStart: 4 + IsStatement: true + EndDelta: 0 + - Offset: 0 + LineStart: 5 + IsStatement: true + EndDelta: 0 + - Offset: 6 + LineStart: 6 + IsStatement: true + EndDelta: 0 + Columns: + - !Symbols + Records: + - Kind: S_GDATA32 + DataSym: + Type: 4101 + DisplayName: global_foo + - Kind: S_UDT + UDTSym: + Type: 4101 + UDTName: UDT_Foo + - Kind: S_UDT + UDTSym: + Type: 4101 + UDTName: Foo + - !FileChecksums + Checksums: + - FileName: 'c:\src\llvm-project\build\symbol-types.c' + Kind: MD5 + Checksum: F833E1A4909FF6FEC5689A664F3BE725 + - !StringTable + Strings: + - 'c:\src\llvm-project\build\symbol-types.c' + - !Symbols + Records: + - Kind: S_BUILDINFO + BuildInfoSym: + BuildId: 4111 + Relocations: + - VirtualAddress: 164 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 168 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 220 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 224 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 284 + SymbolName: global_foo + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 288 + SymbolName: global_foo + Type: IMAGE_REL_AMD64_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Types: + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 0 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 116 + CallConv: NearC + Options: [ None ] + ParameterCount: 0 + ArgumentList: 4096 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: main + - Kind: LF_STRUCTURE + Class: + MemberCount: 0 + Options: [ None, ForwardReference, HasUniqueName ] + FieldList: 0 + Name: Foo + UniqueName: '.?AUFoo@@' + DerivationList: 0 + VTableShape: 0 + Size: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 116 + FieldOffset: 0 + Name: x + - Kind: LF_STRUCTURE + Class: + MemberCount: 1 + Options: [ None, HasUniqueName ] + FieldList: 4100 + Name: Foo + UniqueName: '.?AUFoo@@' + DerivationList: 0 + VTableShape: 0 + Size: 4 + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'c:\src\llvm-project\build\symbol-types.c' + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4101 + SourceFile: 4102 + LineNumber: 1 + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um' + - Kind: LF_SUBSTR_LIST + StringList: + StringIndices: [ 4106 ] + - Kind: LF_STRING_ID + StringId: + Id: 4107 + String: ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: symbol-types.c + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build\vc140.pdb' + - Kind: LF_BUILDINFO + BuildInfo: + ArgIndices: [ 4104, 4105, 4109, 4110, 4108 ] + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: 2A000000 + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 8B0500000000C3 + Relocations: + - VirtualAddress: 2 + SymbolName: global_foo + Type: IMAGE_REL_AMD64_REL32 +symbols: + - Name: '@comp.id' + Value: 17063575 + SectionNumber: -1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: '@feat.00' + Value: 2147484048 + SectionNumber: -1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .drectve + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 47 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$S' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 432 + NumberOfRelocations: 6 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$T' + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 732 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: .data + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 4 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 3482275674 + Number: 0 + - Name: global_foo + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: '.text$mn' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 7 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 3635526833 + Number: 0 + - Name: main + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... Index: vendor/lld/dist/test/COFF/pdb.test =================================================================== --- vendor/lld/dist/test/COFF/pdb.test (revision 320381) +++ vendor/lld/dist/test/COFF/pdb.test (revision 320382) @@ -1,199 +1,199 @@ # RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj # RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj # RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ # RUN: %t1.obj %t2.obj # RUN: llvm-pdbutil pdb2yaml -stream-metadata -stream-directory -pdb-stream \ # RUN: -dbi-stream -ipi-stream -tpi-stream %t.pdb | FileCheck %s -# RUN: llvm-pdbutil raw -modules -section-map -section-contribs \ +# RUN: llvm-pdbutil dump -modules -section-map -section-contribs \ # RUN: -types -ids %t.pdb | FileCheck -check-prefix RAW %s # CHECK: MSF: # CHECK-NEXT: SuperBlock: # CHECK-NEXT: BlockSize: 4096 # CHECK-NEXT: FreeBlockMap: 1 # CHECK-NEXT: NumBlocks: # CHECK-NEXT: NumDirectoryBytes: # CHECK-NEXT: Unknown1: 0 # CHECK-NEXT: BlockMapAddr: # CHECK-NEXT: NumDirectoryBlocks: # CHECK-NEXT: DirectoryBlocks: # CHECK-NEXT: NumStreams: # CHECK-NEXT: FileSize: # CHECK-NEXT: StreamSizes: -# CHECK-NEXT: StreamMap: +# CHECK: StreamMap: # CHECK: PdbStream: # CHECK-NEXT: Age: 1 # CHECK-NEXT: Guid: # CHECK-NEXT: Signature: 0 # CHECK-NEXT: Features: [ VC140 ] # CHECK-NEXT: Version: VC70 # CHECK-NEXT: DbiStream: # CHECK-NEXT: VerHeader: V110 # CHECK-NEXT: Age: 1 # CHECK-NEXT: BuildNumber: 0 # CHECK-NEXT: PdbDllVersion: 0 # CHECK-NEXT: PdbDllRbld: 0 # CHECK-NEXT: Flags: 0 # CHECK-NEXT: MachineType: x86 # CHECK-NEXT: TpiStream: # CHECK-NEXT: Version: VC80 # CHECK-NEXT: Records: # CHECK-NEXT: - Kind: LF_ARGLIST # CHECK-NEXT: ArgList: # CHECK-NEXT: ArgIndices: [ ] # CHECK-NEXT: - Kind: LF_PROCEDURE # CHECK-NEXT: Procedure: # CHECK-NEXT: ReturnType: 116 # CHECK-NEXT: CallConv: NearC # CHECK-NEXT: Options: [ None ] # CHECK-NEXT: ParameterCount: 0 # CHECK-NEXT: ArgumentList: 4096 # CHECK-NEXT: - Kind: LF_POINTER # CHECK-NEXT: Pointer: # CHECK-NEXT: ReferentType: 4097 # CHECK-NEXT: Attrs: 65548 # CHECK-NEXT: - Kind: LF_ARGLIST # CHECK-NEXT: ArgList: # CHECK-NEXT: ArgIndices: [ 0 ] # CHECK-NEXT: - Kind: LF_PROCEDURE # CHECK-NEXT: Procedure: # CHECK-NEXT: ReturnType: 116 # CHECK-NEXT: CallConv: NearC # CHECK-NEXT: Options: [ None ] # CHECK-NEXT: ParameterCount: 0 # CHECK-NEXT: ArgumentList: 4099 # CHECK-NEXT: IpiStream: # CHECK-NEXT: Version: VC80 # CHECK-NEXT: Records: # CHECK-NEXT: - Kind: LF_FUNC_ID # CHECK-NEXT: FuncId: # CHECK-NEXT: ParentScope: 0 # CHECK-NEXT: FunctionType: 4100 # CHECK-NEXT: Name: main # CHECK-NEXT: - Kind: LF_FUNC_ID # CHECK-NEXT: FuncId: # CHECK-NEXT: ParentScope: 0 # CHECK-NEXT: FunctionType: 4097 # CHECK-NEXT: Name: foo # CHECK-NEXT: - Kind: LF_STRING_ID # CHECK-NEXT: StringId: # CHECK-NEXT: Id: 0 # CHECK-NEXT: String: 'D:\b' # CHECK-NEXT: - Kind: LF_STRING_ID # CHECK-NEXT: StringId: # CHECK-NEXT: Id: 0 # CHECK-NEXT: String: 'C:\vs14\VC\BIN\amd64\cl.exe' # CHECK-NEXT: - Kind: LF_STRING_ID # CHECK-NEXT: StringId: # CHECK-NEXT: Id: 0 # CHECK-NEXT: String: '-Z7 -c -MT -IC:\vs14\VC\INCLUDE -IC:\vs14\VC\ATLMFC\INCLUDE -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.10150.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared"' # CHECK-NEXT: - Kind: LF_SUBSTR_LIST # CHECK-NEXT: StringList: # CHECK-NEXT: StringIndices: [ 4100 ] # CHECK-NEXT: - Kind: LF_STRING_ID # CHECK-NEXT: StringId: # CHECK-NEXT: Id: 4101 # CHECK-NEXT: String: ' -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X' # CHECK-NEXT: - Kind: LF_STRING_ID # CHECK-NEXT: StringId: # CHECK-NEXT: Id: 0 # CHECK-NEXT: String: ret42-main.c # CHECK-NEXT: - Kind: LF_STRING_ID # CHECK-NEXT: StringId: # CHECK-NEXT: Id: 0 # CHECK-NEXT: String: 'D:\b\vc140.pdb' # CHECK-NEXT: - Kind: LF_BUILDINFO # CHECK-NEXT: BuildInfo: # CHECK-NEXT: ArgIndices: [ 4098, 4099, 4103, 4104, 4102 ] # CHECK-NEXT: - Kind: LF_STRING_ID # CHECK-NEXT: StringId: # CHECK-NEXT: Id: 0 # CHECK-NEXT: String: ret42-sub.c # CHECK-NEXT: - Kind: LF_BUILDINFO # CHECK-NEXT: BuildInfo: # CHECK-NEXT: ArgIndices: [ 4098, 4099, 4106, 4104, 4102 ] RAW: Modules RAW-NEXT: ============================================================ RAW-NEXT: Mod 0000 | Name: `{{.*}}pdb.test.tmp1.obj`: RAW-NEXT: Obj: `{{.*}}pdb.test.tmp1.obj`: -RAW-NEXT: debug stream: 9, # files: 0, has ec info: false +RAW-NEXT: debug stream: 9, # files: 1, has ec info: false RAW-NEXT: Mod 0001 | Name: `{{.*}}pdb.test.tmp2.obj`: RAW-NEXT: Obj: `{{.*}}pdb.test.tmp2.obj`: -RAW-NEXT: debug stream: 10, # files: 0, has ec info: false +RAW-NEXT: debug stream: 10, # files: 1, has ec info: false RAW-NEXT: Mod 0002 | Name: `* Linker *`: RAW-NEXT: Obj: ``: RAW-NEXT: debug stream: 11, # files: 0, has ec info: false RAW: Types (TPI Stream) RAW-NEXT: ============================================================ RAW-NEXT: Showing 5 records RAW-NEXT: 0x1000 | LF_ARGLIST [size = 8] RAW-NEXT: 0x1001 | LF_PROCEDURE [size = 16] RAW-NEXT: return type = 0x0074 (int), # args = 0, param list = 0x1000 RAW-NEXT: calling conv = cdecl, options = None RAW-NEXT: 0x1002 | LF_POINTER [size = 12] RAW-NEXT: referent = 0x1001, mode = pointer, opts = None, kind = ptr64 RAW-NEXT: 0x1003 | LF_ARGLIST [size = 12] RAW-NEXT: : `` RAW-NEXT: 0x1004 | LF_PROCEDURE [size = 16] RAW-NEXT: return type = 0x0074 (int), # args = 0, param list = 0x1003 RAW-NEXT: calling conv = cdecl, options = None RAW: Types (IPI Stream) RAW-NEXT: ============================================================ RAW-NEXT: Showing 12 records RAW-NEXT: 0x1000 | LF_FUNC_ID [size = 20] RAW-NEXT: name = main, type = 0x1004, parent scope = RAW-NEXT: 0x1001 | LF_FUNC_ID [size = 16] RAW-NEXT: name = foo, type = 0x1001, parent scope = RAW-NEXT: 0x1002 | LF_STRING_ID [size = 16] ID: , String: D:\b RAW-NEXT: 0x1003 | LF_STRING_ID [size = 36] ID: , String: C:\vs14\VC\BIN\amd64\cl.exe RAW-NEXT: 0x1004 | LF_STRING_ID [size = 260] ID: , String: -Z7 -c -MT -IC:\vs14\VC\INCLUDE -IC:\vs14\VC\ATLMFC\INCLUDE -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.10150.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared" RAW-NEXT: 0x1005 | LF_SUBSTR_LIST [size = 12] RAW-NEXT: 0x1004: `-Z7 -c -MT -IC:\vs14\VC\INCLUDE -IC:\vs14\VC\ATLMFC\INCLUDE -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.10150.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared"` RAW-NEXT: 0x1006 | LF_STRING_ID [size = 132] ID: 0x1005, String: -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X RAW-NEXT: 0x1007 | LF_STRING_ID [size = 24] ID: , String: ret42-main.c RAW-NEXT: 0x1008 | LF_STRING_ID [size = 24] ID: , String: D:\b\vc140.pdb RAW-NEXT: 0x1009 | LF_BUILDINFO [size = 28] RAW-NEXT: 0x1002: `D:\b` RAW-NEXT: 0x1003: `C:\vs14\VC\BIN\amd64\cl.exe` RAW-NEXT: 0x1007: `ret42-main.c` RAW-NEXT: 0x1008: `D:\b\vc140.pdb` RAW-NEXT: 0x1006: ` -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X` RAW-NEXT: 0x100A | LF_STRING_ID [size = 20] ID: , String: ret42-sub.c RAW-NEXT: 0x100B | LF_BUILDINFO [size = 28] RAW-NEXT: 0x1002: `D:\b` RAW-NEXT: 0x1003: `C:\vs14\VC\BIN\amd64\cl.exe` RAW-NEXT: 0x100A: `ret42-sub.c` RAW-NEXT: 0x1008: `D:\b\vc140.pdb` RAW-NEXT: 0x1006: ` -I"C:\Program Files (x86)\Windows Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TC -X` RAW: Section Contributions RAW-NEXT: ============================================================ RAW-NEXT: SC | mod = 0, 65535:1288, size = 14, data crc = 0, reloc crc = 0 RAW-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE | RAW-NEXT: IMAGE_SCN_MEM_READ RAW-NEXT: SC | mod = 0, 65535:1312, size = 8, data crc = 0, reloc crc = 0 RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ RAW-NEXT: SC | mod = 0, 65535:1320, size = 12, data crc = 0, reloc crc = 0 RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ RAW-NEXT: SC | mod = 1, 65535:1144, size = 6, data crc = 0, reloc crc = 0 RAW-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE | RAW-NEXT: IMAGE_SCN_MEM_READ RAW: Section Map RAW-NEXT: ============================================================ RAW-NEXT: Section 0000 | ovl = 0, group = 0, frame = 0, name = 1 RAW-NEXT: class = 65535, offset = 0, size = RAW-NEXT: flags = read | 32 bit addr | selector RAW-NEXT: Section 0001 | ovl = 1, group = 0, frame = 0, name = 2 RAW-NEXT: class = 65535, offset = 0, size = RAW-NEXT: flags = read | execute | 32 bit addr | selector RAW-NEXT: Section 0002 | ovl = 2, group = 0, frame = 0, name = 3 RAW-NEXT: class = 65535, offset = 0, size = RAW-NEXT: flags = read | 32 bit addr | selector RAW-NEXT: Section 0003 | ovl = 3, group = 0, frame = 0, name = 4 RAW-NEXT: class = 65535, offset = 0, size = RAW-NEXT: flags = read | 32 bit addr | selector RAW-NEXT: Section 0004 | ovl = 4, group = 0, frame = 0, name = 5 RAW-NEXT: class = 65535, offset = 0, size = RAW-NEXT: flags = 32 bit addr | absolute addr Index: vendor/lld/dist/test/COFF/resource.test =================================================================== --- vendor/lld/dist/test/COFF/resource.test (revision 320381) +++ vendor/lld/dist/test/COFF/resource.test (revision 320382) @@ -1,14 +1,12 @@ -# REQUIRES: winres - # RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj # RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/resource.res # Check if the binary contains UTF-16LE string "Hello" copied from resource.res. # RUN: FileCheck --check-prefix=EXE %s < %t.exe EXE: {{H.e.l.l.o}} # RUN: llvm-readobj -file-headers %t.exe | FileCheck --check-prefix=HEADER %s HEADER: ResourceTableRVA: 0x1000 HEADER: ResourceTableSize: 0x88 Index: vendor/lld/dist/test/COFF/safeseh-diag-feat.test =================================================================== --- vendor/lld/dist/test/COFF/safeseh-diag-feat.test (nonexistent) +++ vendor/lld/dist/test/COFF/safeseh-diag-feat.test (revision 320382) @@ -0,0 +1,51 @@ +# RUN: sed s/FEAT_VALUE/1/ %s | yaml2obj > %t.obj +# RUN: lld-link /out:%t.exe /subsystem:console /entry:main /safeseh %t.obj + +# RUN: sed s/FEAT_VALUE/0/ %s | yaml2obj > %t.obj +# RUN: not lld-link /out:%t.exe /subsystem:console /entry:main \ +# RUN: /safeseh %t.obj >& %t.log +# RUN: FileCheck %s < %t.log + +# CHECK: /safeseh: {{.*}} is not compatible with SEH + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 0000000000000000 +symbols: + - Name: '@comp.id' + Value: 14766605 + SectionNumber: 65535 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: '@feat.00' + Value: FEAT_VALUE + SectionNumber: 65535 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: _main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... Index: vendor/lld/dist/test/COFF/safeseh.s =================================================================== --- vendor/lld/dist/test/COFF/safeseh.s (nonexistent) +++ vendor/lld/dist/test/COFF/safeseh.s (revision 320382) @@ -0,0 +1,60 @@ +# RUN: llvm-mc -triple i686-windows-msvc %s -filetype=obj -o %t.obj +# RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:noref -entry:main +# RUN: llvm-readobj -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-NOGC +# RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:ref -entry:main +# RUN: llvm-readobj -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-GC + +# CHECK-NOGC: LoadConfig [ +# CHECK-NOGC: Size: 0x48 +# CHECK-NOGC: SEHandlerTable: 0x401048 +# CHECK-NOGC: SEHandlerCount: 1 +# CHECK-NOGC: ] +# CHECK-NOGC: SEHTable [ +# CHECK-NOGC-NEXT: 0x402006 +# CHECK-NOGC-NEXT: ] + +# CHECK-GC: LoadConfig [ +# CHECK-GC: Size: 0x48 +# CHECK-GC: SEHandlerTable: 0x0 +# CHECK-GC: SEHandlerCount: 0 +# CHECK-GC: ] +# CHECK-GC-NOT: SEHTable + + + .def @feat.00; + .scl 3; + .type 0; + .endef + .globl @feat.00 +@feat.00 = 1 + + .def _main; + .scl 2; + .type 32; + .endef + .section .text,"xr",one_only,_main + .globl _main +_main: + movl $42, %eax + ret + +# This handler can be GCd, which will make the safeseh table empty, so it should +# appear null. + .def _my_handler; + .scl 3; + .type 32; + .endef + .section .text,"xr",one_only,_my_handler +_my_handler: + ret + +.safeseh _my_handler + + + .section .rdata,"dr" +.globl __load_config_used +__load_config_used: + .long 72 + .fill 60, 1, 0 + .long ___safe_se_handler_table + .long ___safe_se_handler_count Property changes on: vendor/lld/dist/test/COFF/safeseh.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/COFF/secidx-absolute.s =================================================================== --- vendor/lld/dist/test/COFF/secidx-absolute.s (nonexistent) +++ vendor/lld/dist/test/COFF/secidx-absolute.s (revision 320382) @@ -0,0 +1,33 @@ +# RUN: llvm-mc %s -filetype=obj -triple=x86_64-windows-msvc -o %t.obj +# RUN: lld-link -entry:main -nodefaultlib %t.obj -out:%t.exe +# RUN: llvm-readobj %t.exe -sections -section-data | FileCheck %s + +# Section relocations against absolute symbols resolve to the last real ouput +# section index plus one. + +.text +.global main +main: +ret + +.section .rdata,"dr" +.secidx __guard_fids_table + +# CHECK: Sections [ +# CHECK: Section { +# CHECK: Number: 1 +# CHECK: Name: .rdata (2E 72 64 61 74 61 00 00) +# CHECK: SectionData ( +# CHECK: 0000: 0300 |..| +# CHECK: ) +# CHECK: } +# CHECK: Section { +# CHECK: Number: 2 +# CHECK: Name: .text (2E 74 65 78 74 00 00 00) +# CHECK: VirtualSize: 0x1 +# CHECK: SectionData ( +# CHECK: 0000: C3 |.| +# CHECK: ) +# CHECK: } +# CHECK-NOT: Section +# CHECK: ] Property changes on: vendor/lld/dist/test/COFF/secidx-absolute.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/COFF/secrel-absolute.s =================================================================== --- vendor/lld/dist/test/COFF/secrel-absolute.s (nonexistent) +++ vendor/lld/dist/test/COFF/secrel-absolute.s (revision 320382) @@ -0,0 +1,14 @@ +# RUN: llvm-mc %s -filetype=obj -triple=x86_64-windows-msvc -o %t.obj +# RUN: not lld-link -entry:main -nodefaultlib %t.obj -out:%t.exe 2>&1 | FileCheck %s + +# secrel relocations against absolute symbols are errors. + +# CHECK: SECREL relocation points to a non-regular symbol: __guard_fids_table + +.text +.global main +main: +ret + +.section .rdata,"dr" +.secrel32 __guard_fids_table Property changes on: vendor/lld/dist/test/COFF/secrel-absolute.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/COFF/secrel-common.s =================================================================== --- vendor/lld/dist/test/COFF/secrel-common.s (nonexistent) +++ vendor/lld/dist/test/COFF/secrel-common.s (revision 320382) @@ -0,0 +1,41 @@ +# RUN: llvm-mc %s -filetype=obj -triple=x86_64-windows-msvc -o %t.obj +# RUN: lld-link -entry:main -nodefaultlib %t.obj -out:%t.exe +# RUN: llvm-readobj %t.exe -sections -section-data | FileCheck %s + +# Section relocations against common symbols resolve to .bss. + +# CHECK: Sections [ +# CHECK: Section { +# CHECK: Number: 1 +# CHECK: Name: .bss (2E 62 73 73 00 00 00 00) +# CHECK: VirtualSize: 0x4 +# CHECK: } +# CHECK: Section { +# CHECK: Number: 2 +# CHECK: Name: .rdata (2E 72 64 61 74 61 00 00) +# CHECK: SectionData ( +# CHECK: 0000: 00000000 01000000 |........| +# CHECK: ) +# CHECK: } +# CHECK: Section { +# CHECK: Number: 3 +# CHECK: Name: .text (2E 74 65 78 74 00 00 00) +# CHECK: VirtualSize: 0x1 +# CHECK: SectionData ( +# CHECK: 0000: C3 |.| +# CHECK: ) +# CHECK: } +# CHECK-NOT: Section +# CHECK: ] + +.text +.global main +main: +ret + +.comm common_global,4,2 + +.section .rdata,"dr" +.secrel32 common_global +.secidx common_global +.short 0 Property changes on: vendor/lld/dist/test/COFF/secrel-common.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/ELF/Inputs/exclude-libs.s =================================================================== --- vendor/lld/dist/test/ELF/Inputs/exclude-libs.s (nonexistent) +++ vendor/lld/dist/test/ELF/Inputs/exclude-libs.s (revision 320382) @@ -0,0 +1,3 @@ +.globl fn +fn: + nop Property changes on: vendor/lld/dist/test/ELF/Inputs/exclude-libs.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/ELF/arm-gnu-ifunc-plt.s =================================================================== --- vendor/lld/dist/test/ELF/arm-gnu-ifunc-plt.s (revision 320381) +++ vendor/lld/dist/test/ELF/arm-gnu-ifunc-plt.s (revision 320382) @@ -1,101 +1,101 @@ // RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabihf %S/Inputs/arm-shared.s -o %t1.o // RUN: ld.lld %t1.o --shared -o %t.so // RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabihf %s -o %t.o // RUN: ld.lld %t.so %t.o -o %tout // RUN: llvm-objdump -triple=armv7a-linux-gnueabihf -d %tout | FileCheck %s --check-prefix=DISASM // RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT // RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s // REQUIRES: arm // Check that the IRELATIVE relocations are last in the .got // CHECK: Relocations [ // CHECK-NEXT: Section (4) .rel.dyn { // CHECK-NEXT: 0x13078 R_ARM_GLOB_DAT bar2 0x0 // CHECK-NEXT: 0x1307C R_ARM_GLOB_DAT zed2 0x0 // CHECK-NEXT: 0x13080 R_ARM_IRELATIVE - 0x0 // CHECK-NEXT: 0x13084 R_ARM_IRELATIVE - 0x0 // CHECK-NEXT: } // CHECK-NEXT: Section (5) .rel.plt { // CHECK-NEXT: 0x1200C R_ARM_JUMP_SLOT bar2 0x0 // CHECK-NEXT: 0x12010 R_ARM_JUMP_SLOT zed2 0x0 // CHECK-NEXT: } // CHECK-NEXT: ] // Check that the GOT entries refer back to the ifunc resolver // GOTPLT: Contents of section .got.plt: // GOTPLT-NEXT: 12000 00000000 00000000 00000000 20100100 // GOTPLT-NEXT: 12010 20100100 // GOTPLT: Contents of section .got: // GOTPLT-NEXT: 13078 00000000 00000000 00100100 04100100 // DISASM: Disassembly of section .text: // DISASM-NEXT: foo: // DISASM-NEXT: 11000: 1e ff 2f e1 bx lr // DISASM: bar: // DISASM-NEXT: 11004: 1e ff 2f e1 bx lr // DISASM: _start: // DISASM-NEXT: 11008: 14 00 00 eb bl #80 // DISASM-NEXT: 1100c: 17 00 00 eb bl #92 // DISASM: 11010: 00 00 00 00 .word 0x00000000 // DISASM-NEXT: 11014: 04 00 00 00 .word 0x00000004 // DISASM: 11018: 05 00 00 eb bl #20 // DISASM-NEXT: 1101c: 08 00 00 eb bl #32 // DISASM-NEXT: Disassembly of section .plt: // DISASM-NEXT: $a: // DISASM-NEXT: 11020: 04 e0 2d e5 str lr, [sp, #-4]! // DISASM-NEXT: 11024: 04 e0 9f e5 ldr lr, [pc, #4] // DISASM-NEXT: 11028: 0e e0 8f e0 add lr, pc, lr // DISASM-NEXT: 1102c: 08 f0 be e5 ldr pc, [lr, #8]! // DISASM: $d: // DISASM-NEXT: 11030: d0 0f 00 00 .word 0x00000fd0 // DISASM: $a: // DISASM-NEXT: 11034: 04 c0 9f e5 ldr r12, [pc, #4] // DISASM-NEXT: 11038: 0f c0 8c e0 add r12, r12, pc // DISASM-NEXT: 1103c: 00 f0 9c e5 ldr pc, [r12] // DISASM: $d: // DISASM-NEXT: 11040: cc 0f 00 00 .word 0x00000fcc // DISASM: $a: // DISASM-NEXT: 11044: 04 c0 9f e5 ldr r12, [pc, #4] // DISASM-NEXT: 11048: 0f c0 8c e0 add r12, r12, pc // DISASM-NEXT: 1104c: 00 f0 9c e5 ldr pc, [r12] // DISASM: $d: // DISASM-NEXT: 11050: c0 0f 00 00 .word 0x00000fc0 // Alignment to 16 byte boundary not strictly necessary on ARM, but harmless -// DISASM-NEXT: 11054: 00 00 00 00 .word 0x00000000 -// DISASM-NEXT: 11058: 00 00 00 00 .word 0x00000000 -// DISASM-NEXT: 1105c: 00 00 00 00 .word 0x00000000 +// DISASM-NEXT: 11054: d4 d4 d4 d4 .word 0xd4d4d4d4 +// DISASM-NEXT: 11058: d4 d4 d4 d4 .word 0xd4d4d4d4 +// DISASM-NEXT: 1105c: d4 d4 d4 d4 .word 0xd4d4d4d4 // DISASM: $a: // DISASM-NEXT: 11060: 04 c0 9f e5 ldr r12, [pc, #4] // DISASM-NEXT: 11064: 0f c0 8c e0 add r12, r12, pc // DISASM-NEXT: 11068: 00 f0 9c e5 ldr pc, [r12] // DISASM: $d: // DISASM-NEXT: 1106c: 14 20 00 00 .word 0x00002014 // DISASM: $a: // DISASM-NEXT: 11070: 04 c0 9f e5 ldr r12, [pc, #4] // DISASM-NEXT: 11074: 0f c0 8c e0 add r12, r12, pc // DISASM-NEXT: 11078: 00 f0 9c e5 ldr pc, [r12] // DISASM: $d: // DISASM-NEXT: 1107c: 08 20 00 00 .word 0x00002008 .syntax unified .text .type foo STT_GNU_IFUNC .globl foo foo: bx lr .type bar STT_GNU_IFUNC .globl bar bar: bx lr .globl _start _start: bl foo bl bar // Create entries in the .got and .rel.dyn so that we don't just have // IRELATIVE .word bar2(got) .word zed2(got) bl bar2 bl zed2 Index: vendor/lld/dist/test/ELF/arm-got-relative.s =================================================================== --- vendor/lld/dist/test/ELF/arm-got-relative.s (revision 320381) +++ vendor/lld/dist/test/ELF/arm-got-relative.s (revision 320382) @@ -1,53 +1,53 @@ // REQUIRES: arm // RUN: llvm-mc -position-independent -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o // RUN: ld.lld %t.o -shared -o %t // RUN: llvm-readobj -s -symbols -dyn-relocations %t | FileCheck %s // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t | FileCheck -check-prefix=CODE %s .syntax unified .text .globl _start .align 2 _start: .type _start, %function ldr r3, .LGOT ldr r2, .LGOT+4 .LPIC: add r0, pc, r3 bx lr .align 2 .LGOT: - // gas implicitly uses (GOT_PREL) for _GLOBAL_OFFSET_TABLE_ in PIC - // llvm-mc needs the (GOT_PREL) suffix or it generates R_ARM_REL32 - .word _GLOBAL_OFFSET_TABLE_(GOT_PREL) - (.LPIC+8) + // gas implicitly uses (R_ARM_BASE_PREL) for _GLOBAL_OFFSET_TABLE_ in PIC + // llvm-mc generates R_ARM_REL32, this will need updating when MC changes + .word _GLOBAL_OFFSET_TABLE_ - (.LPIC+8) .word function(GOT) .globl function .align 2 function: .type function, %function bx lr // CHECK: Dynamic Relocations { -// CHECK-NEXT: 0x204C R_ARM_GLOB_DAT function 0x0 +// CHECK-NEXT: 0x2048 R_ARM_GLOB_DAT function 0x0 // CHECK: Name: _GLOBAL_OFFSET_TABLE_ -// CHECK-NEXT: Value: 0x0 +// CHECK-NEXT: Value: 0x2048 // CHECK-NEXT: Size: // CHECK-NEXT: Binding: Local // CHECK-NEXT: Type: None // CHECK-NEXT: Other [ // CHECK-NEXT: STV_HIDDEN // CHECK-NEXT: ] -// CHECK-NEXT: Section: Absolute +// CHECK-NEXT: Section: .got // CODE: Disassembly of section .text: // CODE-NEXT: _start: // CODE-NEXT: 1000: 08 30 9f e5 ldr r3, [pc, #8] // CODE-NEXT: 1004: 08 20 9f e5 ldr r2, [pc, #8] // CODE-NEXT: 1008: 03 00 8f e0 add r0, pc, r3 // CODE-NEXT: 100c: 1e ff 2f e1 bx lr // CODE:$d.1: // (_GLOBAL_OFFSET_TABLE_ = 0x2048) - (0x1008 + 8) 0x1038 // CODE-NEXT: 1010: 38 10 00 00 -// (Got(function) - GotBase = 0x4 -// CODE-NEXT: 1014: 04 00 00 00 +// (Got(function) - GotBase = 0x0 +// CODE-NEXT: 1014: 00 00 00 00 Index: vendor/lld/dist/test/ELF/arm-thumb-branch.s =================================================================== --- vendor/lld/dist/test/ELF/arm-thumb-branch.s (revision 320381) +++ vendor/lld/dist/test/ELF/arm-thumb-branch.s (revision 320382) @@ -1,60 +1,60 @@ // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar // RUN: echo "SECTIONS { \ // RUN: . = 0xb4; \ // RUN: .callee1 : { *(.callee_low) } \ // RUN: .caller : { *(.text) } \ // RUN: .callee2 : { *(.callee_high) } } " > %t.script // RUN: ld.lld --script %t.script %t %tfar -o %t2 2>&1 // RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck %s // REQUIRES: arm .syntax unified .thumb .section .callee_low, "ax",%progbits .align 2 .type callee_low,%function callee_low: bx lr .section .text, "ax",%progbits .globl _start .balign 0x10000 .type _start,%function _start: bl callee_low b callee_low beq callee_low bl callee_high b callee_high bne callee_high bl far_uncond b far_uncond bgt far_cond bx lr .section .callee_high, "ax",%progbits .align 2 .type callee_high,%function callee_high: bx lr // CHECK: Disassembly of section .callee1: // CHECK-NEXT: callee_low: // CHECK-NEXT: b4: 70 47 bx lr // CHECK-NEXT: Disassembly of section .caller: // CHECK-NEXT: _start: // CHECK-NEXT: 10000: f0 f7 58 f8 bl #-65360 // CHECK-NEXT: 10004: f0 f7 56 b8 b.w #-65364 // CHECK-NEXT: 10008: 30 f4 54 a8 beq.w #-65368 // CHECK-NEXT: 1000c: 00 f0 0c f8 bl #24 // CHECK-NEXT: 10010: 00 f0 0a b8 b.w #20 // CHECK-NEXT: 10014: 40 f0 08 80 bne.w #16 // CHECK-NEXT: 10018: ff f3 ff d7 bl #16777214 // CHECK-NEXT: 1001c: ff f3 fd 97 b.w #16777210 // CHECK-NEXT: 10020: 3f f3 ff af bgt.w #1048574 // CHECK-NEXT: 10024: 70 47 bx lr -// CHECK-NEXT: 10026: 00 00 movs r0, r0 +// CHECK-NEXT: 10026: // CHECK-NEXT: Disassembly of section .callee2: // CHECK-NEXT: callee_high: // CHECK-NEXT: 10028: 70 47 bx lr Index: vendor/lld/dist/test/ELF/arm-thumb-plt-reloc.s =================================================================== --- vendor/lld/dist/test/ELF/arm-thumb-plt-reloc.s (revision 320381) +++ vendor/lld/dist/test/ELF/arm-thumb-plt-reloc.s (revision 320382) @@ -1,108 +1,108 @@ // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %p/Inputs/arm-plt-reloc.s -o %t1 // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t2 // RUN: ld.lld %t1 %t2 -o %t // RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t | FileCheck %s // RUN: ld.lld -shared %t1 %t2 -o %t3 // RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t3 | FileCheck -check-prefix=DSOTHUMB %s // RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t3 | FileCheck -check-prefix=DSOARM %s // RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s // REQUIRES: arm // // Test PLT entry generation .syntax unified .text .align 2 .globl _start .type _start,%function _start: // FIXME, interworking is only supported for BL via BLX at the moment, when // interworking thunks are available for b.w and b.w this can be altered // to test the different forms of interworking. bl func1 bl func2 bl func3 // Executable, expect no PLT // CHECK: Disassembly of section .text: // CHECK-NEXT: func1: // CHECK-NEXT: 11000: 70 47 bx lr // CHECK: func2: // CHECK-NEXT: 11002: 70 47 bx lr // CHECK: func3: // CHECK-NEXT: 11004: 70 47 bx lr -// CHECK-NEXT: 11006: 00 00 movs r0, r0 +// CHECK-NEXT: 11006: d4 d4 // CHECK: _start: // 11008 + 4 -12 = 0x11000 = func1 // CHECK-NEXT: 11008: ff f7 fa ff bl #-12 // 1100c + 4 -14 = 0x11002 = func2 // CHECK-NEXT: 1100c: ff f7 f9 ff bl #-14 // 11010 + 4 -16 = 0x11004 = func3 // CHECK-NEXT: 11010: ff f7 f8 ff bl #-16 // Expect PLT entries as symbols can be preempted // .text is Thumb and .plt is ARM, llvm-objdump can currently only disassemble // as ARM or Thumb. Work around by disassembling twice. // DSOTHUMB: Disassembly of section .text: // DSOTHUMB: func1: // DSOTHUMB-NEXT: 1000: 70 47 bx lr // DSOTHUMB: func2: // DSOTHUMB-NEXT: 1002: 70 47 bx lr // DSOTHUMB: func3: // DSOTHUMB-NEXT: 1004: 70 47 bx lr -// DSOTHUMB-NEXT: 1006: 00 00 movs r0, r0 +// DSOTHUMB-NEXT: 1006: d4 d4 // DSOTHUMB: _start: // 0x1008 + 0x28 + 4 = 0x1034 = PLT func1 // DSOTHUMB-NEXT: 1008: 00 f0 14 e8 blx #40 // 0x100c + 0x34 + 4 = 0x1044 = PLT func2 // DSOTHUMB-NEXT: 100c: 00 f0 1a e8 blx #52 // 0x1010 + 0x40 + 4 = 0x1054 = PLT func3 // DSOTHUMB-NEXT: 1010: 00 f0 20 e8 blx #64 // DSOARM: Disassembly of section .plt: // DSOARM-NEXT: $a: // DSOARM-NEXT: 1020: 04 e0 2d e5 str lr, [sp, #-4]! // DSOARM-NEXT: 1024: 04 e0 9f e5 ldr lr, [pc, #4] // DSOARM-NEXT: 1028: 0e e0 8f e0 add lr, pc, lr // DSOARM-NEXT: 102c: 08 f0 be e5 ldr pc, [lr, #8]! // DSOARM: $d: // DSOARM-NEXT: 1030: d0 0f 00 00 .word 0x00000fd0 // 0x1028 + 8 + 0fd0 = 0x2000 // DSOARM: $a: // DSOARM-NEXT: 1034: 04 c0 9f e5 ldr r12, [pc, #4] // DSOARM-NEXT: 1038: 0f c0 8c e0 add r12, r12, pc // DSOARM-NEXT: 103c: 00 f0 9c e5 ldr pc, [r12] // DSOARM: $d: // DSOARM-NEXT: 1040: cc 0f 00 00 .word 0x00000fcc // 0x1038 + 8 + 0fcc = 0x200c // DSOARM: $a: // DSOARM-NEXT: 1044: 04 c0 9f e5 ldr r12, [pc, #4] // DSOARM-NEXT: 1048: 0f c0 8c e0 add r12, r12, pc // DSOARM-NEXT: 104c: 00 f0 9c e5 ldr pc, [r12] // DSOARM: $d: // DSOARM-NEXT: 1050: c0 0f 00 00 .word 0x00000fc0 // 0x1048 + 8 + 0fc0 = 0x2010 // DSOARM: $a: // DSOARM-NEXT: 1054: 04 c0 9f e5 ldr r12, [pc, #4] // DSOARM-NEXT: 1058: 0f c0 8c e0 add r12, r12, pc // DSOARM-NEXT: 105c: 00 f0 9c e5 ldr pc, [r12] // DSOARM: $d: // DSOARM-NEXT: 1060: b4 0f 00 00 .word 0x00000fb4 // 0x1058 + 8 + 0fb4 = 0x2014 // DSOREL: Name: .got.plt // DSOREL-NEXT: Type: SHT_PROGBITS // DSOREL-NEXT: Flags [ // DSOREL-NEXT: SHF_ALLOC // DSOREL-NEXT: SHF_WRITE // DSOREL-NEXT: ] // DSOREL-NEXT: Address: 0x2000 // DSOREL-NEXT: Offset: // DSOREL-NEXT: Size: 24 // DSOREL-NEXT: Link: // DSOREL-NEXT: Info: // DSOREL-NEXT: AddressAlignment: 4 // DSOREL-NEXT: EntrySize: // DSOREL: Relocations [ // DSOREL-NEXT: Section (4) .rel.plt { // DSOREL-NEXT: 0x200C R_ARM_JUMP_SLOT func1 0x0 // DSOREL-NEXT: 0x2010 R_ARM_JUMP_SLOT func2 0x0 // DSOREL-NEXT: 0x2014 R_ARM_JUMP_SLOT func3 0x0 Index: vendor/lld/dist/test/ELF/defsym.s =================================================================== --- vendor/lld/dist/test/ELF/defsym.s (revision 320381) +++ vendor/lld/dist/test/ELF/defsym.s (revision 320382) @@ -1,49 +1,47 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: ld.lld -o %t %t.o --defsym=foo2=foo1 # RUN: llvm-readobj -t -s %t | FileCheck %s # RUN: llvm-objdump -d -print-imm-hex %t | FileCheck %s --check-prefix=USE ## Check that we accept --defsym foo2=foo1 form. # RUN: ld.lld -o %t2 %t.o --defsym foo2=foo1 # RUN: llvm-readobj -t -s %t2 | FileCheck %s # RUN: llvm-objdump -d -print-imm-hex %t2 | FileCheck %s --check-prefix=USE -## In compare with GNU linkers, symbol defined with --defsym does -## not get aliased name in symbol table: # CHECK: Symbol { # CHECK: Name: foo1 # CHECK-NEXT: Value: 0x123 # CHECK-NEXT: Size: # CHECK-NEXT: Binding: Global # CHECK-NEXT: Type: # CHECK-NEXT: Other: # CHECK-NEXT: Section: Absolute # CHECK-NEXT: } # CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: foo1 +# CHECK-NEXT: Name: foo2 # CHECK-NEXT: Value: 0x123 # CHECK-NEXT: Size: # CHECK-NEXT: Binding: Global # CHECK-NEXT: Type: # CHECK-NEXT: Other: # CHECK-NEXT: Section: Absolute # CHECK-NEXT: } ## Check we can use foo2 and it that it is an alias for foo1. # USE: Disassembly of section .text: # USE-NEXT: _start: # USE-NEXT: movl $0x123, %edx # RUN: not ld.lld -o %t %t.o --defsym=foo2=1 2>&1 | FileCheck %s -check-prefix=ERR1 # ERR1: error: --defsym: symbol name expected, but got 1 # RUN: not ld.lld -o %t %t.o --defsym=foo2=und 2>&1 | FileCheck %s -check-prefix=ERR2 # ERR2: error: -defsym: undefined symbol: und .globl foo1 foo1 = 0x123 .global _start _start: movl $foo2, %edx Index: vendor/lld/dist/test/ELF/exclude-libs.s =================================================================== --- vendor/lld/dist/test/ELF/exclude-libs.s (nonexistent) +++ vendor/lld/dist/test/ELF/exclude-libs.s (revision 320382) @@ -0,0 +1,30 @@ +// REQUIRES: x86 + +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ +// RUN: %p/Inputs/exclude-libs.s -o %t2.o +// RUN: mkdir -p %t.dir +// RUN: rm -f %t.dir/exc.a +// RUN: llvm-ar rcs %t.dir/exc.a %t2.o + +// RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe +// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=DEFAULT %s + +// RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs=foo,bar +// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=DEFAULT %s + +// RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs foo,bar,exc.a +// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s + +// RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs foo:bar:exc.a +// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s + +// RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs=ALL +// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s + +// DEFAULT: Name: fn +// EXCLUDE-NOT: Name: fn + +.globl fn +foo: + call fn@PLT Property changes on: vendor/lld/dist/test/ELF/exclude-libs.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/ELF/global-offset-table-position-aarch64.s =================================================================== --- vendor/lld/dist/test/ELF/global-offset-table-position-aarch64.s (nonexistent) +++ vendor/lld/dist/test/ELF/global-offset-table-position-aarch64.s (revision 320382) @@ -0,0 +1,30 @@ +// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t +// RUN: ld.lld -shared %t -o %t2 +// RUN: llvm-readobj -t %t2 | FileCheck %s +// REQUIRES: aarch64 +.globl a +.type a,@object +.comm a,4,4 + +.globl f +.type f,@function +f: + adrp x0, :got:a + ldr x0, [x0, #:got_lo12:a] + +.global _start +.type _start,@function +_start: + bl f +.data +.long _GLOBAL_OFFSET_TABLE_ - . + +// CHECK: Name: _GLOBAL_OFFSET_TABLE_ (11) +// CHECK-NEXT: Value: 0x30090 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local (0x0) +// CHECK-NEXT: Type: None (0x0) +// CHECK-NEXT: Other [ (0x2) +// CHECK-NEXT: STV_HIDDEN (0x2) +// CHECK-NEXT: ] +// CHECK-NEXT: Section: .got Property changes on: vendor/lld/dist/test/ELF/global-offset-table-position-aarch64.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/ELF/global-offset-table-position-arm.s =================================================================== --- vendor/lld/dist/test/ELF/global-offset-table-position-arm.s (nonexistent) +++ vendor/lld/dist/test/ELF/global-offset-table-position-arm.s (revision 320382) @@ -0,0 +1,35 @@ +// RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabihf %s -o %t +// RUN: ld.lld -shared %t -o %t2 +// RUN: llvm-readobj -t %t2 | FileCheck %s +// REQUIRES: arm + +// The ARM _GLOBAL_OFFSET_TABLE_ should be defined at the start of the .got +.globl a +.type a,%object +.comm a,4,4 + +.globl f +.type f,%function +f: + ldr r2, .L1 +.L0: + add r2, pc +.L1: +.word _GLOBAL_OFFSET_TABLE_ - (.L0+4) +.word a(GOT) + +.global _start +.type _start,%function +_start: + bl f +.data + +// CHECK: Name: _GLOBAL_OFFSET_TABLE_ +// CHECK-NEXT: Value: 0x3068 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local +// CHECK-NEXT: Type: None +// CHECK-NEXT: Other [ (0x2) +// CHECK-NEXT: STV_HIDDEN (0x2) +// CHECK-NEXT: ] +// CHECK-NEXT: Section: .got Property changes on: vendor/lld/dist/test/ELF/global-offset-table-position-arm.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/ELF/global-offset-table-position-i386.s =================================================================== --- vendor/lld/dist/test/ELF/global-offset-table-position-i386.s (nonexistent) +++ vendor/lld/dist/test/ELF/global-offset-table-position-i386.s (revision 320382) @@ -0,0 +1,31 @@ +// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t +// RUN: ld.lld -shared %t -o %t2 +// RUN: llvm-readobj -t %t2 | FileCheck %s +// REQUIRES: x86 + +// The X86 _GLOBAL_OFFSET_TABLE_ is defined at the end of the .got section. +.globl a +.type a,@object +.comm a,4,4 + +.globl f +.type f,@function +f: +addl $_GLOBAL_OFFSET_TABLE_, %eax +movl a@GOT(%eax), %eax + +.global _start +.type _start,@function +_start: +addl $_GLOBAL_OFFSET_TABLE_, %eax +calll f@PLT + +// CHECK: Name: _GLOBAL_OFFSET_TABLE_ (1) +// CHECK-NEXT: Value: 0x306C +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local (0x0) +// CHECK-NEXT: Type: None (0x0) +// CHECK-NEXT: Other [ (0x2) +// CHECK-NEXT: STV_HIDDEN (0x2) +// CHECK-NEXT: ] +// CHECK-NEXT: Section: .got (0xA) Property changes on: vendor/lld/dist/test/ELF/global-offset-table-position-i386.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/ELF/global-offset-table-position-mips.s =================================================================== --- vendor/lld/dist/test/ELF/global-offset-table-position-mips.s (nonexistent) +++ vendor/lld/dist/test/ELF/global-offset-table-position-mips.s (revision 320382) @@ -0,0 +1,33 @@ +// RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t +// RUN: ld.lld -shared %t -o %t2 +// RUN: llvm-readobj -t %t2 | FileCheck %s + +// REQUIRES: mips + +// The Mips _GLOBAL_OFFSET_TABLE_ should be defined at the start of the .got + +.globl a +.hidden a +.type a,@object +.comm a,4,4 + +.globl f +.type f,@function +f: + ld $v0,%got_page(a)($gp) + daddiu $v0,$v0,%got_ofst(a) + +.global _start +.type _start,@function +_start: + lw $t0,%call16(f)($gp) + .word _GLOBAL_OFFSET_TABLE_ - . +// CHECK: Name: _GLOBAL_OFFSET_TABLE_ (1) +// CHECK-NEXT: Value: 0x20000 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local (0x0) +// CHECK-NEXT: Type: None (0x0) +// CHECK-NEXT: Other [ (0x2) +// CHECK-NEXT: STV_HIDDEN (0x2) +// CHECK-NEXT: ] +// CHECK-NEXT: Section: .got (0x9) Property changes on: vendor/lld/dist/test/ELF/global-offset-table-position-mips.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/ELF/global-offset-table-position.s =================================================================== --- vendor/lld/dist/test/ELF/global-offset-table-position.s (nonexistent) +++ vendor/lld/dist/test/ELF/global-offset-table-position.s (revision 320382) @@ -0,0 +1,31 @@ +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +// RUN: ld.lld -shared %t -o %t2 +// RUN: llvm-readobj -t %t2 | FileCheck %s +// REQUIRES: x86 + +// The X86_64 _GLOBAL_OFFSET_TABLE_ is defined at the end of the .got section. +.globl a +.type a,@object +.comm a,4,4 + +.globl f +.type f,@function +f: +movq a@GOTPCREL(%rip), %rax + +.global _start +.type _start,@function +_start: +callq f@PLT +.data +.long _GLOBAL_OFFSET_TABLE_ - . + +// CHECK: Name: _GLOBAL_OFFSET_TABLE_ +// CHECK-NEXT: Value: 0x30D8 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Binding: Local +// CHECK-NEXT: Type: None (0x0) +// CHECK-NEXT: Other [ +// CHECK-NEXT: STV_HIDDEN +// CHECK-NEXT: ] +// CHECK-NEXT: Section: .got Property changes on: vendor/lld/dist/test/ELF/global-offset-table-position.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/ELF/global_offset_table_shared.s =================================================================== --- vendor/lld/dist/test/ELF/global_offset_table_shared.s (revision 320381) +++ vendor/lld/dist/test/ELF/global_offset_table_shared.s (revision 320382) @@ -1,9 +1,14 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: ld.lld -shared %t -o %t2 // RUN: llvm-readobj -t %t2 | FileCheck %s -.long _GLOBAL_OFFSET_TABLE_ +.long _GLOBAL_OFFSET_TABLE_ - . // CHECK: Name: _GLOBAL_OFFSET_TABLE_ -// CHECK-NEXT: Value: +// CHECK-NEXT: Value: 0x2060 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local +// CHECK-NEXT: Type: None +// CHECK-NEXT: Other [ (0x2) +// CHECK-NEXT: STV_HIDDEN (0x2) +// CHECK-NEXT: ] +// CHECK-NEXT: Section: .got Index: vendor/lld/dist/test/ELF/invalid-z.s =================================================================== --- vendor/lld/dist/test/ELF/invalid-z.s (nonexistent) +++ vendor/lld/dist/test/ELF/invalid-z.s (revision 320382) @@ -0,0 +1,9 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: not ld.lld %t.o -o %t -z max-page-size 2>&1 | FileCheck %s +# CHECK: invalid max-page-size +# CHECK-NOT: error + +.global _start +_start: + nop Property changes on: vendor/lld/dist/test/ELF/invalid-z.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/ELF/linkerscript/discard-section-err.s =================================================================== --- vendor/lld/dist/test/ELF/linkerscript/discard-section-err.s (nonexistent) +++ vendor/lld/dist/test/ELF/linkerscript/discard-section-err.s (revision 320382) @@ -0,0 +1,23 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o + +# RUN: echo "SECTIONS { /DISCARD/ : { *(.shstrtab) } }" > %t.script +# RUN: not ld.lld -o %t --script %t.script %t.o 2>&1 | \ +# RUN: FileCheck -check-prefix=SHSTRTAB %s +# SHSTRTAB: discarding .shstrtab section is not allowed + +# RUN: echo "SECTIONS { /DISCARD/ : { *(.dynamic) } }" > %t.script +# RUN: not ld.lld -pie -o %t --script %t.script %t.o 2>&1 | \ +# RUN: FileCheck -check-prefix=DYNAMIC %s +# DYNAMIC: discarding .dynamic section is not allowed + +# RUN: echo "SECTIONS { /DISCARD/ : { *(.dynsym) } }" > %t.script +# RUN: not ld.lld -pie -o %t --script %t.script %t.o 2>&1 | \ +# RUN: FileCheck -check-prefix=DYNSYM %s +# DYNSYM: discarding .dynsym section is not allowed + +# RUN: echo "SECTIONS { /DISCARD/ : { *(.dynstr) } }" > %t.script +# RUN: not ld.lld -pie -o %t --script %t.script %t.o 2>&1 | \ +# RUN: FileCheck -check-prefix=DYNSTR %s +# DYNSTR: discarding .dynstr section is not allowed Property changes on: vendor/lld/dist/test/ELF/linkerscript/discard-section-err.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/ELF/linkerscript/sections.s =================================================================== --- vendor/lld/dist/test/ELF/linkerscript/sections.s (revision 320381) +++ vendor/lld/dist/test/ELF/linkerscript/sections.s (revision 320382) @@ -1,114 +1,108 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t # Empty SECTIONS command. # RUN: echo "SECTIONS {}" > %t.script # RUN: ld.lld -o %t1 --script %t.script %t # RUN: llvm-objdump -section-headers %t1 | \ # RUN: FileCheck -check-prefix=SEC-DEFAULT %s # SECTIONS command with the same order as default. # RUN: echo "SECTIONS { \ # RUN: .text : { *(.text) } \ # RUN: .data : { *(.data) } }" > %t.script # RUN: ld.lld -o %t2 --script %t.script %t # RUN: llvm-objdump -section-headers %t2 | \ # RUN: FileCheck -check-prefix=SEC-DEFAULT %s # Idx Name Size # SEC-DEFAULT: 1 .text 0000000e {{[0-9a-f]*}} TEXT DATA # SEC-DEFAULT: 2 .data 00000020 {{[0-9a-f]*}} DATA # SEC-DEFAULT: 3 other 00000003 {{[0-9a-f]*}} DATA # SEC-DEFAULT: 4 .bss 00000002 {{[0-9a-f]*}} BSS # SEC-DEFAULT: 5 .comment 00000008 {{[0-9a-f]*}} # SEC-DEFAULT: 6 .symtab 00000030 {{[0-9a-f]*}} # SEC-DEFAULT: 7 .shstrtab 0000003b {{[0-9a-f]*}} # SEC-DEFAULT: 8 .strtab 00000008 {{[0-9a-f]*}} # Sections are put in order specified in linker script, other than alloc # sections going first. # RUN: echo "SECTIONS { \ # RUN: .bss : { *(.bss) } \ # RUN: other : { *(other) } \ # RUN: .shstrtab : { *(.shstrtab) } \ # RUN: .symtab : { *(.symtab) } \ # RUN: .strtab : { *(.strtab) } \ # RUN: .data : { *(.data) } \ # RUN: .text : { *(.text) } }" > %t.script # RUN: ld.lld -o %t3 --script %t.script %t # RUN: llvm-objdump -section-headers %t3 | \ # RUN: FileCheck -check-prefix=SEC-ORDER %s # Idx Name Size # SEC-ORDER: 1 .bss 00000002 {{[0-9a-f]*}} BSS # SEC-ORDER: 2 other 00000003 {{[0-9a-f]*}} DATA # SEC-ORDER: 3 .shstrtab 0000003b {{[0-9a-f]*}} # SEC-ORDER: 4 .symtab 00000030 {{[0-9a-f]*}} # SEC-ORDER: 5 .strtab 00000008 {{[0-9a-f]*}} # SEC-ORDER: 6 .comment 00000008 {{[0-9a-f]*}} # SEC-ORDER: 7 .data 00000020 {{[0-9a-f]*}} DATA # SEC-ORDER: 8 .text 0000000e {{[0-9a-f]*}} TEXT DATA # .text and .data have swapped names but proper sizes and types. # RUN: echo "SECTIONS { \ # RUN: .data : { *(.text) } \ # RUN: .text : { *(.data) } }" > %t.script # RUN: ld.lld -o %t4 --script %t.script %t # RUN: llvm-objdump -section-headers %t4 | \ # RUN: FileCheck -check-prefix=SEC-SWAP-NAMES %s # Idx Name Size # SEC-SWAP-NAMES: 1 .data 0000000e {{[0-9a-f]*}} TEXT DATA # SEC-SWAP-NAMES: 2 .text 00000020 {{[0-9a-f]*}} DATA # SEC-SWAP-NAMES: 3 other 00000003 {{[0-9a-f]*}} DATA # SEC-SWAP-NAMES: 4 .bss 00000002 {{[0-9a-f]*}} BSS # SEC-SWAP-NAMES: 5 .comment 00000008 {{[0-9a-f]*}} # SEC-SWAP-NAMES: 6 .symtab 00000030 {{[0-9a-f]*}} # SEC-SWAP-NAMES: 7 .shstrtab 0000003b {{[0-9a-f]*}} # SEC-SWAP-NAMES: 8 .strtab 00000008 {{[0-9a-f]*}} -# Attemp to discard .shstrtab section. -# RUN: echo "SECTIONS { /DISCARD/ : { *(.shstrtab) } }" > %t.script -# RUN: not ld.lld -o %t5 --script %t.script %t 2>&1 | \ -# RUN: FileCheck -check-prefix=SEC-DISCARD %s -# SEC-DISCARD: discarding .shstrtab section is not allowed - # Multiple SECTIONS command specifying additional input section descriptions # for the same output section description - input sections are merged into # one output section. # RUN: echo "SECTIONS { \ # RUN: .text : { *(.text) } \ # RUN: .data : { *(.data) } } \ # RUN: SECTIONS { \ # RUN: .data : { *(other) } }" > %t.script # RUN: ld.lld -o %t6 --script %t.script %t # RUN: llvm-objdump -section-headers %t6 | \ # RUN: FileCheck -check-prefix=SEC-MULTI %s # Idx Name Size # SEC-MULTI: 1 .text 0000000e {{[0-9a-f]*}} TEXT DATA # SEC-MULTI-NEXT: .data 00000020 {{[0-9a-f]*}} DATA # SEC-MULTI-NEXT: .data 00000003 {{[0-9a-f]*}} DATA # SEC-MULTI-NEXT: .bss 00000002 {{[0-9a-f]*}} BSS # SEC-MULTI-NEXT: .comment 00000008 {{[0-9a-f]*}} # SEC-MULTI-NEXT: .symtab 00000030 {{[0-9a-f]*}} # SEC-MULTI-NEXT: .shstrtab 00000035 {{[0-9a-f]*}} # SEC-MULTI-NEXT: .strtab 00000008 {{[0-9a-f]*}} # Input section pattern contains additional semicolon. # Case found in linux kernel script. Check we are able to parse it. # RUN: echo "SECTIONS { .text : { ;;*(.text);;S = 0;; } }" > %t.script # RUN: ld.lld -o /dev/null --script %t.script %t .globl _start _start: mov $60, %rax mov $42, %rdi .section .data,"aw" .quad 10, 10, 20, 20 .section other,"aw" .short 10 .byte 20 .section .bss,"",@nobits .short 0 Index: vendor/lld/dist/test/ELF/linkerscript/segment-none.s =================================================================== --- vendor/lld/dist/test/ELF/linkerscript/segment-none.s (nonexistent) +++ vendor/lld/dist/test/ELF/linkerscript/segment-none.s (revision 320382) @@ -0,0 +1,39 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o + +## Test that section .foo is not placed in any segment when assigned to segment +## NONE in the linker script and segment NONE is not defined. +# RUN: echo "PHDRS {text PT_LOAD;} \ +# RUN: SECTIONS { \ +# RUN: .text : {*(.text .text*)} :text \ +# RUN: .foo : {*(.foo)} :NONE \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-readobj -elf-output-style=GNU -s -l %t | FileCheck %s + +## Test that section .foo is placed in segment NONE when assigned to segment +## NONE in the linker script and segment NONE is defined. +# RUN: echo "PHDRS {text PT_LOAD; NONE PT_LOAD;} \ +# RUN: SECTIONS { \ +# RUN: .text : {*(.text .text*)} :text \ +# RUN: .foo : {*(.foo)} :NONE \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-readobj -elf-output-style=GNU -s -l %t | FileCheck --check-prefix=DEFINED %s + +# CHECK: Section to Segment mapping: +# CHECK-NEXT: Segment Sections... +# CHECK-NOT: .foo + +# DEFINED: Section to Segment mapping: +# DEFINED-NEXT: Segment Sections... +# DEFINED-NEXT: 00 .text +# DEFINED-NEXT: 01 .foo + +.global _start +_start: + nop + +.section .foo,"a" +foo: + .long 0 Property changes on: vendor/lld/dist/test/ELF/linkerscript/segment-none.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/ELF/linkerscript/ttext-script.s =================================================================== --- vendor/lld/dist/test/ELF/linkerscript/ttext-script.s (nonexistent) +++ vendor/lld/dist/test/ELF/linkerscript/ttext-script.s (revision 320382) @@ -0,0 +1,11 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "SECTIONS { .text 0x200000 : { *(.text) } }" > %t.script +# RUN: ld.lld -T %t.script -Ttext 0x100000 %t.o -o %t +# RUN: llvm-readobj --elf-output-style=GNU -s %t | FileCheck %s + +# CHECK: .text PROGBITS 0000000000100000 + +.global _start +_start: +nop Property changes on: vendor/lld/dist/test/ELF/linkerscript/ttext-script.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/ELF/lto/cache.ll =================================================================== --- vendor/lld/dist/test/ELF/lto/cache.ll (revision 320381) +++ vendor/lld/dist/test/ELF/lto/cache.ll (revision 320382) @@ -1,21 +1,32 @@ ; REQUIRES: x86 ; RUN: opt -module-hash -module-summary %s -o %t.o ; RUN: opt -module-hash -module-summary %p/Inputs/cache.ll -o %t2.o ; RUN: rm -Rf %t.cache && mkdir %t.cache ; Create two files that would be removed by cache pruning due to age. ; We should only remove files matching the pattern "llvmcache-*". ; RUN: touch -t 197001011200 %t.cache/llvmcache-foo %t.cache/foo ; RUN: ld.lld --thinlto-cache-dir=%t.cache --thinlto-cache-policy prune_after=1h -o %t3 %t2.o %t.o ; Two cached objects, plus a timestamp file and "foo", minus the file we removed. ; RUN: ls %t.cache | count 4 +; Create a file of size 64KB. +; RUN: %python -c "print(' ' * 65536)" > %t.cache/llvmcache-foo + +; This should leave the file in place. +; RUN: ld.lld --thinlto-cache-dir=%t.cache --thinlto-cache-policy cache_size_bytes=128k -o %t3 %t2.o %t.o +; RUN: ls %t.cache | count 5 + +; This should remove it. +; RUN: ld.lld --thinlto-cache-dir=%t.cache --thinlto-cache-policy cache_size_bytes=32k -o %t3 %t2.o %t.o +; RUN: ls %t.cache | count 4 + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" define void @globalfunc() #0 { entry: ret void } Index: vendor/lld/dist/test/ELF/lto/wrap-2.ll =================================================================== --- vendor/lld/dist/test/ELF/lto/wrap-2.ll (revision 320381) +++ vendor/lld/dist/test/ELF/lto/wrap-2.ll (revision 320382) @@ -1,36 +1,36 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o ; RUN: llvm-as %S/Inputs/wrap-bar.ll -o %t1.o ; RUN: ld.lld %t.o %t1.o -shared -o %t.so -wrap=bar ; RUN: llvm-objdump -d %t.so | FileCheck %s ; RUN: llvm-readobj -t %t.so | FileCheck -check-prefix=BIND %s ; Make sure that calls in foo() are not eliminated and that bar is ; routed to __wrap_bar and __real_bar is routed to bar. ; CHECK: foo: ; CHECK-NEXT: pushq %rax -; CHECK-NEXT: callq{{.*}}<__wrap_bar> ; CHECK-NEXT: callq{{.*}} +; CHECK-NEXT: callq{{.*}}<__real_bar> ; Check that bar and __wrap_bar retain their original binding. ; BIND: Name: bar ; BIND-NEXT: Value: ; BIND-NEXT: Size: ; BIND-NEXT: Binding: Local ; BIND: Name: __wrap_bar ; BIND-NEXT: Value: ; BIND-NEXT: Size: ; BIND-NEXT: Binding: Local target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" declare void @bar() declare void @__real_bar() define void @foo() { call void @bar() call void @__real_bar() ret void } Index: vendor/lld/dist/test/ELF/mips-got16-relocatable.s =================================================================== --- vendor/lld/dist/test/ELF/mips-got16-relocatable.s (revision 320381) +++ vendor/lld/dist/test/ELF/mips-got16-relocatable.s (revision 320382) @@ -1,40 +1,40 @@ # Check writing updated addend for R_MIPS_GOT16 relocation, # when produce a relocatable output. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -o %t.o %s # RUN: ld.lld -r -o %t %t.o %t.o # RUN: llvm-objdump -d -r %t | FileCheck -check-prefix=OBJ %s # RUN: ld.lld -shared -o %t.so %t # RUN: llvm-objdump -d %t.so | FileCheck -check-prefix=SO %s # REQUIRES: mips # OBJ: Disassembly of section .text: # OBJ-NEXT: .text: # OBJ-NEXT: 0: 8f 99 00 00 lw $25, 0($gp) # OBJ-NEXT: 00000000: R_MIPS_GOT16 .data # OBJ-NEXT: 4: 27 24 00 00 addiu $4, $25, 0 # OBJ-NEXT: 00000004: R_MIPS_LO16 .data -# OBJ-NEXT: 8: 00 00 00 00 nop -# OBJ-NEXT: c: 00 00 00 00 nop +# OBJ-NEXT: 8: ef ef ef ef +# OBJ-NEXT: c: ef ef ef ef # OBJ-NEXT: 10: 8f 99 00 00 lw $25, 0($gp) # OBJ-NEXT: 00000010: R_MIPS_GOT16 .data # OBJ-NEXT: 14: 27 24 00 10 addiu $4, $25, 16 # OBJ-NEXT: 00000014: R_MIPS_LO16 .data # SO: Disassembly of section .text: # SO-NEXT: .text: # SO-NEXT: 10000: 8f 99 80 18 lw $25, -32744($gp) # SO-NEXT: 10004: 27 24 00 00 addiu $4, $25, 0 -# SO-NEXT: 10008: 00 00 00 00 nop -# SO-NEXT: 1000c: 00 00 00 00 nop +# SO-NEXT: 10008: ef ef ef ef +# SO-NEXT: 1000c: ef ef ef ef # SO-NEXT: 10010: 8f 99 80 18 lw $25, -32744($gp) # SO-NEXT: 10014: 27 24 00 10 addiu $4, $25, 16 .text lw $t9, %got(.data)($gp) addiu $a0, $t9, %lo(.data) .data data: .word 0 Index: vendor/lld/dist/test/ELF/mips-npic-call-pic-os.s =================================================================== --- vendor/lld/dist/test/ELF/mips-npic-call-pic-os.s (revision 320381) +++ vendor/lld/dist/test/ELF/mips-npic-call-pic-os.s (revision 320382) @@ -1,138 +1,138 @@ # REQUIRES: mips # Check LA25 stubs creation with caller in different Output Section to callee. # This stub code is necessary when non-PIC code calls PIC function. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ # RUN: %p/Inputs/mips-fpic.s -o %t-fpic.o # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ # RUN: %p/Inputs/mips-fnpic.s -o %t-fnpic.o # RUN: ld.lld -r %t-fpic.o %t-fnpic.o -o %t-sto-pic.o # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ # RUN: %p/Inputs/mips-pic.s -o %t-pic.o # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-npic.o # RUN: ld.lld %t-npic.o %t-pic.o %t-sto-pic.o -o %t.exe # RUN: llvm-objdump -d %t.exe | FileCheck %s # CHECK: Disassembly of section .text: # CHECK-NEXT: __LA25Thunk_foo1a: # CHECK-NEXT: 20000: 3c 19 00 02 lui $25, 2 # CHECK-NEXT: 20004: 08 00 80 08 j 131104 # CHECK-NEXT: 20008: 27 39 00 20 addiu $25, $25, 32 # CHECK-NEXT: 2000c: 00 00 00 00 nop # CHECK: __LA25Thunk_foo1b: # CHECK-NEXT: 20010: 3c 19 00 02 lui $25, 2 # CHECK-NEXT: 20014: 08 00 80 09 j 131108 # CHECK-NEXT: 20018: 27 39 00 24 addiu $25, $25, 36 # CHECK-NEXT: 2001c: 00 00 00 00 nop # CHECK: foo1a: # CHECK-NEXT: 20020: 00 00 00 00 nop # CHECK: foo1b: # CHECK-NEXT: 20024: 00 00 00 00 nop # CHECK: __LA25Thunk_foo2: # CHECK-NEXT: 20028: 3c 19 00 02 lui $25, 2 # CHECK-NEXT: 2002c: 08 00 80 10 j 131136 # CHECK-NEXT: 20030: 27 39 00 40 addiu $25, $25, 64 # CHECK-NEXT: 20034: 00 00 00 00 nop -# CHECK-NEXT: 20038: 00 00 00 00 nop -# CHECK-NEXT: 2003c: 00 00 00 00 nop +# CHECK-NEXT: 20038: ef ef ef ef +# CHECK-NEXT: 2003c: ef ef ef ef # CHECK: foo2: # CHECK-NEXT: 20040: 00 00 00 00 nop # CHECK: __LA25Thunk_fpic: # CHECK-NEXT: 20044: 3c 19 00 02 lui $25, 2 # CHECK-NEXT: 20048: 08 00 80 18 j 131168 # CHECK-NEXT: 2004c: 27 39 00 60 addiu $25, $25, 96 # CHECK-NEXT: 20050: 00 00 00 00 nop -# CHECK-NEXT: 20054: 00 00 00 00 nop -# CHECK-NEXT: 20058: 00 00 00 00 nop -# CHECK-NEXT: 2005c: 00 00 00 00 nop +# CHECK-NEXT: 20054: ef ef ef ef +# CHECK-NEXT: 20058: ef ef ef ef +# CHECK-NEXT: 2005c: ef ef ef ef # CHECK: fpic: # CHECK-NEXT: 20060: 00 00 00 00 nop -# CHECK-NEXT: 20064: 00 00 00 00 nop -# CHECK-NEXT: 20068: 00 00 00 00 nop -# CHECK-NEXT: 2006c: 00 00 00 00 nop +# CHECK-NEXT: 20064: ef ef ef ef +# CHECK-NEXT: 20068: ef ef ef ef +# CHECK-NEXT: 2006c: ef ef ef ef # CHECK: fnpic: # CHECK-NEXT: 20070: 00 00 00 00 nop # CHECK-NEXT: Disassembly of section differentos: # CHECK-NEXT: __start: # CHECK-NEXT: 20074: 0c 00 80 00 jal 131072 <__LA25Thunk_foo1a> # CHECK-NEXT: 20078: 00 00 00 00 nop # CHECK-NEXT: 2007c: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2> # CHECK-NEXT: 20080: 00 00 00 00 nop # CHECK-NEXT: 20084: 0c 00 80 04 jal 131088 <__LA25Thunk_foo1b> # CHECK-NEXT: 20088: 00 00 00 00 nop # CHECK-NEXT: 2008c: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2> # CHECK-NEXT: 20090: 00 00 00 00 nop # CHECK-NEXT: 20094: 0c 00 80 11 jal 131140 <__LA25Thunk_fpic> # CHECK-NEXT: 20098: 00 00 00 00 nop # CHECK-NEXT: 2009c: 0c 00 80 1c jal 131184 # CHECK-NEXT: 200a0: 00 00 00 00 nop # Make sure the thunks are created properly no matter how # objects are laid out. # # RUN: ld.lld %t-pic.o %t-npic.o %t-sto-pic.o -o %t.exe # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=REVERSE %s # REVERSE: Disassembly of section .text: # REVERSE-NEXT: __LA25Thunk_foo1a: # REVERSE-NEXT: 20000: 3c 19 00 02 lui $25, 2 # REVERSE-NEXT: 20004: 08 00 80 08 j 131104 # REVERSE-NEXT: 20008: 27 39 00 20 addiu $25, $25, 32 # REVERSE-NEXT: 2000c: 00 00 00 00 nop # REVERSE: __LA25Thunk_foo1b: # REVERSE-NEXT: 20010: 3c 19 00 02 lui $25, 2 # REVERSE-NEXT: 20014: 08 00 80 09 j 131108 # REVERSE-NEXT: 20018: 27 39 00 24 addiu $25, $25, 36 # REVERSE-NEXT: 2001c: 00 00 00 00 nop # REVERSE: foo1a: # REVERSE-NEXT: 20020: 00 00 00 00 nop # REVERSE: foo1b: # REVERSE-NEXT: 20024: 00 00 00 00 nop # REVERSE: __LA25Thunk_foo2: # REVERSE-NEXT: 20028: 3c 19 00 02 lui $25, 2 # REVERSE-NEXT: 2002c: 08 00 80 10 j 131136 # REVERSE-NEXT: 20030: 27 39 00 40 addiu $25, $25, 64 # REVERSE-NEXT: 20034: 00 00 00 00 nop -# REVERSE-NEXT: 20038: 00 00 00 00 nop -# REVERSE-NEXT: 2003c: 00 00 00 00 nop +# REVERSE-NEXT: 20038: ef ef ef ef +# REVERSE-NEXT: 2003c: ef ef ef ef # REVERSE: foo2: # REVERSE-NEXT: 20040: 00 00 00 00 nop -# REVERSE-NEXT: 20044: 00 00 00 00 nop -# REVERSE-NEXT: 20048: 00 00 00 00 nop -# REVERSE-NEXT: 2004c: 00 00 00 00 nop +# REVERSE-NEXT: 20044: ef ef ef ef +# REVERSE-NEXT: 20048: ef ef ef ef +# REVERSE-NEXT: 2004c: ef ef ef ef # REVERSE: __LA25Thunk_fpic: # REVERSE-NEXT: 20050: 3c 19 00 02 lui $25, 2 # REVERSE-NEXT: 20054: 08 00 80 18 j 131168 # REVERSE-NEXT: 20058: 27 39 00 60 addiu $25, $25, 96 # REVERSE-NEXT: 2005c: 00 00 00 00 nop # REVERSE: fpic: # REVERSE-NEXT: 20060: 00 00 00 00 nop -# REVERSE-NEXT: 20064: 00 00 00 00 nop -# REVERSE-NEXT: 20068: 00 00 00 00 nop -# REVERSE-NEXT: 2006c: 00 00 00 00 nop +# REVERSE-NEXT: 20064: ef ef ef ef +# REVERSE-NEXT: 20068: ef ef ef ef +# REVERSE-NEXT: 2006c: ef ef ef ef # REVERSE: fnpic: # REVERSE-NEXT: 20070: 00 00 00 00 nop # REVERSE-NEXT: Disassembly of section differentos: # REVERSE-NEXT: __start: # REVERSE-NEXT: 20074: 0c 00 80 00 jal 131072 <__LA25Thunk_foo1a> # REVERSE-NEXT: 20078: 00 00 00 00 nop # REVERSE-NEXT: 2007c: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2> # REVERSE-NEXT: 20080: 00 00 00 00 nop # REVERSE-NEXT: 20084: 0c 00 80 04 jal 131088 <__LA25Thunk_foo1b> # REVERSE-NEXT: 20088: 00 00 00 00 nop # REVERSE-NEXT: 2008c: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2> # REVERSE-NEXT: 20090: 00 00 00 00 nop # REVERSE-NEXT: 20094: 0c 00 80 14 jal 131152 <__LA25Thunk_fpic> # REVERSE-NEXT: 20098: 00 00 00 00 nop # REVERSE-NEXT: 2009c: 0c 00 80 1c jal 131184 # REVERSE-NEXT: 200a0: 00 00 00 00 nop .section differentos, "ax", %progbits .globl __start __start: jal foo1a jal foo2 jal foo1b jal foo2 jal fpic jal fnpic Index: vendor/lld/dist/test/ELF/mips-npic-call-pic-script.s =================================================================== --- vendor/lld/dist/test/ELF/mips-npic-call-pic-script.s (revision 320381) +++ vendor/lld/dist/test/ELF/mips-npic-call-pic-script.s (revision 320382) @@ -1,255 +1,255 @@ # REQUIRES: mips # Check LA25 stubs creation. This stub code is necessary when # non-PIC code calls PIC function. # RUN: echo "SECTIONS { .out 0x20000 : { *(.text.*) . = . + 0x100 ; *(.text) } }" > %t1.script # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ # RUN: %p/Inputs/mips-fpic.s -o %t-fpic.o # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ # RUN: %p/Inputs/mips-fnpic.s -o %t-fnpic.o # RUN: ld.lld -r %t-fpic.o %t-fnpic.o -o %t-sto-pic.o # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ # RUN: %p/Inputs/mips-pic.s -o %t-pic.o # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-npic.o # RUN: ld.lld --script %t1.script %t-npic.o %t-pic.o %t-sto-pic.o -o %t.exe # RUN: llvm-objdump -d %t.exe | FileCheck %s # CHECK: Disassembly of section .out: # CHECK-NEXT: __LA25Thunk_foo1a: # CHECK-NEXT: 20000: 3c 19 00 02 lui $25, 2 # CHECK-NEXT: 20004: 08 00 80 08 j 131104 # CHECK-NEXT: 20008: 27 39 00 20 addiu $25, $25, 32 # CHECK-NEXT: 2000c: 00 00 00 00 nop # CHECK: __LA25Thunk_foo1b: # CHECK-NEXT: 20010: 3c 19 00 02 lui $25, 2 # CHECK-NEXT: 20014: 08 00 80 09 j 131108 # CHECK-NEXT: 20018: 27 39 00 24 addiu $25, $25, 36 # CHECK-NEXT: 2001c: 00 00 00 00 nop # CHECK: foo1a: # CHECK-NEXT: 20020: 00 00 00 00 nop # CHECK: foo1b: # CHECK-NEXT: 20024: 00 00 00 00 nop # CHECK: __LA25Thunk_foo2: # CHECK-NEXT: 20028: 3c 19 00 02 lui $25, 2 # CHECK-NEXT: 2002c: 08 00 80 10 j 131136 # CHECK-NEXT: 20030: 27 39 00 40 addiu $25, $25, 64 # CHECK-NEXT: 20034: 00 00 00 00 nop -# CHECK-NEXT: 20038: 00 00 00 00 nop -# CHECK-NEXT: 2003c: 00 00 00 00 nop +# CHECK-NEXT: 20038: ef ef ef ef +# CHECK-NEXT: 2003c: ef ef ef ef # CHECK: foo2: # CHECK-NEXT: 20040: 00 00 00 00 nop -# CHECK-NEXT: 20044: 00 00 00 00 nop -# CHECK-NEXT: 20048: 00 00 00 00 nop -# CHECK-NEXT: 2004c: 00 00 00 00 nop -# CHECK-NEXT: 20050: 00 00 00 00 nop -# CHECK-NEXT: 20054: 00 00 00 00 nop -# CHECK-NEXT: 20058: 00 00 00 00 nop -# CHECK-NEXT: 2005c: 00 00 00 00 nop -# CHECK-NEXT: 20060: 00 00 00 00 nop -# CHECK-NEXT: 20064: 00 00 00 00 nop -# CHECK-NEXT: 20068: 00 00 00 00 nop -# CHECK-NEXT: 2006c: 00 00 00 00 nop -# CHECK-NEXT: 20070: 00 00 00 00 nop -# CHECK-NEXT: 20074: 00 00 00 00 nop -# CHECK-NEXT: 20078: 00 00 00 00 nop -# CHECK-NEXT: 2007c: 00 00 00 00 nop -# CHECK-NEXT: 20080: 00 00 00 00 nop -# CHECK-NEXT: 20084: 00 00 00 00 nop -# CHECK-NEXT: 20088: 00 00 00 00 nop -# CHECK-NEXT: 2008c: 00 00 00 00 nop -# CHECK-NEXT: 20090: 00 00 00 00 nop -# CHECK-NEXT: 20094: 00 00 00 00 nop -# CHECK-NEXT: 20098: 00 00 00 00 nop -# CHECK-NEXT: 2009c: 00 00 00 00 nop -# CHECK-NEXT: 200a0: 00 00 00 00 nop -# CHECK-NEXT: 200a4: 00 00 00 00 nop -# CHECK-NEXT: 200a8: 00 00 00 00 nop -# CHECK-NEXT: 200ac: 00 00 00 00 nop -# CHECK-NEXT: 200b0: 00 00 00 00 nop -# CHECK-NEXT: 200b4: 00 00 00 00 nop -# CHECK-NEXT: 200b8: 00 00 00 00 nop -# CHECK-NEXT: 200bc: 00 00 00 00 nop -# CHECK-NEXT: 200c0: 00 00 00 00 nop -# CHECK-NEXT: 200c4: 00 00 00 00 nop -# CHECK-NEXT: 200c8: 00 00 00 00 nop -# CHECK-NEXT: 200cc: 00 00 00 00 nop -# CHECK-NEXT: 200d0: 00 00 00 00 nop -# CHECK-NEXT: 200d4: 00 00 00 00 nop -# CHECK-NEXT: 200d8: 00 00 00 00 nop -# CHECK-NEXT: 200dc: 00 00 00 00 nop -# CHECK-NEXT: 200e0: 00 00 00 00 nop -# CHECK-NEXT: 200e4: 00 00 00 00 nop -# CHECK-NEXT: 200e8: 00 00 00 00 nop -# CHECK-NEXT: 200ec: 00 00 00 00 nop -# CHECK-NEXT: 200f0: 00 00 00 00 nop -# CHECK-NEXT: 200f4: 00 00 00 00 nop -# CHECK-NEXT: 200f8: 00 00 00 00 nop -# CHECK-NEXT: 200fc: 00 00 00 00 nop -# CHECK-NEXT: 20100: 00 00 00 00 nop -# CHECK-NEXT: 20104: 00 00 00 00 nop -# CHECK-NEXT: 20108: 00 00 00 00 nop -# CHECK-NEXT: 2010c: 00 00 00 00 nop -# CHECK-NEXT: 20110: 00 00 00 00 nop -# CHECK-NEXT: 20114: 00 00 00 00 nop -# CHECK-NEXT: 20118: 00 00 00 00 nop -# CHECK-NEXT: 2011c: 00 00 00 00 nop -# CHECK-NEXT: 20120: 00 00 00 00 nop -# CHECK-NEXT: 20124: 00 00 00 00 nop -# CHECK-NEXT: 20128: 00 00 00 00 nop -# CHECK-NEXT: 2012c: 00 00 00 00 nop -# CHECK-NEXT: 20130: 00 00 00 00 nop -# CHECK-NEXT: 20134: 00 00 00 00 nop -# CHECK-NEXT: 20138: 00 00 00 00 nop -# CHECK-NEXT: 2013c: 00 00 00 00 nop -# CHECK-NEXT: 20140: 00 00 00 00 nop -# CHECK-NEXT: 20144: 00 00 00 00 nop -# CHECK-NEXT: 20148: 00 00 00 00 nop -# CHECK-NEXT: 2014c: 00 00 00 00 nop +# CHECK-NEXT: 20044: ef ef ef ef +# CHECK-NEXT: 20048: ef ef ef ef +# CHECK-NEXT: 2004c: ef ef ef ef +# CHECK-NEXT: 20050: ef ef ef ef +# CHECK-NEXT: 20054: ef ef ef ef +# CHECK-NEXT: 20058: ef ef ef ef +# CHECK-NEXT: 2005c: ef ef ef ef +# CHECK-NEXT: 20060: ef ef ef ef +# CHECK-NEXT: 20064: ef ef ef ef +# CHECK-NEXT: 20068: ef ef ef ef +# CHECK-NEXT: 2006c: ef ef ef ef +# CHECK-NEXT: 20070: ef ef ef ef +# CHECK-NEXT: 20074: ef ef ef ef +# CHECK-NEXT: 20078: ef ef ef ef +# CHECK-NEXT: 2007c: ef ef ef ef +# CHECK-NEXT: 20080: ef ef ef ef +# CHECK-NEXT: 20084: ef ef ef ef +# CHECK-NEXT: 20088: ef ef ef ef +# CHECK-NEXT: 2008c: ef ef ef ef +# CHECK-NEXT: 20090: ef ef ef ef +# CHECK-NEXT: 20094: ef ef ef ef +# CHECK-NEXT: 20098: ef ef ef ef +# CHECK-NEXT: 2009c: ef ef ef ef +# CHECK-NEXT: 200a0: ef ef ef ef +# CHECK-NEXT: 200a4: ef ef ef ef +# CHECK-NEXT: 200a8: ef ef ef ef +# CHECK-NEXT: 200ac: ef ef ef ef +# CHECK-NEXT: 200b0: ef ef ef ef +# CHECK-NEXT: 200b4: ef ef ef ef +# CHECK-NEXT: 200b8: ef ef ef ef +# CHECK-NEXT: 200bc: ef ef ef ef +# CHECK-NEXT: 200c0: ef ef ef ef +# CHECK-NEXT: 200c4: ef ef ef ef +# CHECK-NEXT: 200c8: ef ef ef ef +# CHECK-NEXT: 200cc: ef ef ef ef +# CHECK-NEXT: 200d0: ef ef ef ef +# CHECK-NEXT: 200d4: ef ef ef ef +# CHECK-NEXT: 200d8: ef ef ef ef +# CHECK-NEXT: 200dc: ef ef ef ef +# CHECK-NEXT: 200e0: ef ef ef ef +# CHECK-NEXT: 200e4: ef ef ef ef +# CHECK-NEXT: 200e8: ef ef ef ef +# CHECK-NEXT: 200ec: ef ef ef ef +# CHECK-NEXT: 200f0: ef ef ef ef +# CHECK-NEXT: 200f4: ef ef ef ef +# CHECK-NEXT: 200f8: ef ef ef ef +# CHECK-NEXT: 200fc: ef ef ef ef +# CHECK-NEXT: 20100: ef ef ef ef +# CHECK-NEXT: 20104: ef ef ef ef +# CHECK-NEXT: 20108: ef ef ef ef +# CHECK-NEXT: 2010c: ef ef ef ef +# CHECK-NEXT: 20110: ef ef ef ef +# CHECK-NEXT: 20114: ef ef ef ef +# CHECK-NEXT: 20118: ef ef ef ef +# CHECK-NEXT: 2011c: ef ef ef ef +# CHECK-NEXT: 20120: ef ef ef ef +# CHECK-NEXT: 20124: ef ef ef ef +# CHECK-NEXT: 20128: ef ef ef ef +# CHECK-NEXT: 2012c: ef ef ef ef +# CHECK-NEXT: 20130: ef ef ef ef +# CHECK-NEXT: 20134: ef ef ef ef +# CHECK-NEXT: 20138: ef ef ef ef +# CHECK-NEXT: 2013c: ef ef ef ef +# CHECK-NEXT: 20140: ef ef ef ef +# CHECK-NEXT: 20144: ef ef ef ef +# CHECK-NEXT: 20148: ef ef ef ef +# CHECK-NEXT: 2014c: ef ef ef ef # CHECK: __start: # CHECK-NEXT: 20150: 0c 00 80 00 jal 131072 <__LA25Thunk_foo1a> # CHECK-NEXT: 20154: 00 00 00 00 nop # CHECK-NEXT: 20158: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2> # CHECK-NEXT: 2015c: 00 00 00 00 nop # CHECK-NEXT: 20160: 0c 00 80 04 jal 131088 <__LA25Thunk_foo1b> # CHECK-NEXT: 20164: 00 00 00 00 nop # CHECK-NEXT: 20168: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2> # CHECK-NEXT: 2016c: 00 00 00 00 nop # CHECK-NEXT: 20170: 0c 00 80 60 jal 131456 <__LA25Thunk_fpic> # CHECK-NEXT: 20174: 00 00 00 00 nop # CHECK-NEXT: 20178: 0c 00 80 68 jal 131488 # CHECK-NEXT: 2017c: 00 00 00 00 nop # CHECK: __LA25Thunk_fpic: # CHECK-NEXT: 20180: 3c 19 00 02 lui $25, 2 # CHECK-NEXT: 20184: 08 00 80 64 j 131472 # CHECK-NEXT: 20188: 27 39 01 90 addiu $25, $25, 400 # CHECK-NEXT: 2018c: 00 00 00 00 nop # CHECK: fpic: # CHECK-NEXT: 20190: 00 00 00 00 nop -# CHECK-NEXT: 20194: 00 00 00 00 nop -# CHECK-NEXT: 20198: 00 00 00 00 nop -# CHECK-NEXT: 2019c: 00 00 00 00 nop +# CHECK-NEXT: 20194: ef ef ef ef +# CHECK-NEXT: 20198: ef ef ef ef +# CHECK-NEXT: 2019c: ef ef ef ef # CHECK: fnpic: # CHECK-NEXT: 201a0: 00 00 00 00 nop .text .globl __start __start: jal foo1a jal foo2 jal foo1b jal foo2 jal fpic jal fnpic # Test script with orphans added to existing OutputSection, the .text.1 and # .text.2 sections will be added to .text # RUN: echo "SECTIONS { .text 0x20000 : { *(.text) } }" > %t2.script # RUN: ld.lld --script %t2.script %t-npic.o %t-pic.o %t-sto-pic.o -o %t2.exe # RUN: llvm-objdump -d %t2.exe | FileCheck -check-prefix=ORPH1 %s # ORPH1: Disassembly of section .text: # ORPH1-NEXT: __start: # ORPH1-NEXT: 20000: 0c 00 80 15 jal 131156 <__LA25Thunk_foo1a> # ORPH1-NEXT: 20004: 00 00 00 00 nop # ORPH1-NEXT: 20008: 0c 00 80 22 jal 131208 <__LA25Thunk_foo2> # ORPH1-NEXT: 2000c: 00 00 00 00 nop # ORPH1-NEXT: 20010: 0c 00 80 19 jal 131172 <__LA25Thunk_foo1b> # ORPH1-NEXT: 20014: 00 00 00 00 nop # ORPH1-NEXT: 20018: 0c 00 80 22 jal 131208 <__LA25Thunk_foo2> # ORPH1-NEXT: 2001c: 00 00 00 00 nop # ORPH1-NEXT: 20020: 0c 00 80 0c jal 131120 <__LA25Thunk_fpic> # ORPH1-NEXT: 20024: 00 00 00 00 nop # ORPH1-NEXT: 20028: 0c 00 80 14 jal 131152 # ORPH1-NEXT: 2002c: 00 00 00 00 nop # ORPH1: __LA25Thunk_fpic: # ORPH1-NEXT: 20030: 3c 19 00 02 lui $25, 2 # ORPH1-NEXT: 20034: 08 00 80 10 j 131136 # ORPH1-NEXT: 20038: 27 39 00 40 addiu $25, $25, 64 # ORPH1-NEXT: 2003c: 00 00 00 00 nop # ORPH1: fpic: # ORPH1-NEXT: 20040: 00 00 00 00 nop -# ORPH1-NEXT: 20044: 00 00 00 00 nop -# ORPH1-NEXT: 20048: 00 00 00 00 nop -# ORPH1-NEXT: 2004c: 00 00 00 00 nop +# ORPH1-NEXT: 20044: ef ef ef ef +# ORPH1-NEXT: 20048: ef ef ef ef +# ORPH1-NEXT: 2004c: ef ef ef ef # ORPH1: fnpic: # ORPH1-NEXT: 20050: 00 00 00 00 nop # ORPH1: __LA25Thunk_foo1a: # ORPH1-NEXT: 20054: 3c 19 00 02 lui $25, 2 # ORPH1-NEXT: 20058: 08 00 80 20 j 131200 # ORPH1-NEXT: 2005c: 27 39 00 80 addiu $25, $25, 128 # ORPH1-NEXT: 20060: 00 00 00 00 nop # ORPH1: __LA25Thunk_foo1b: # ORPH1-NEXT: 20064: 3c 19 00 02 lui $25, 2 # ORPH1-NEXT: 20068: 08 00 80 21 j 131204 # ORPH1-NEXT: 2006c: 27 39 00 84 addiu $25, $25, 132 # ORPH1-NEXT: 20070: 00 00 00 00 nop -# ORPH1-NEXT: 20074: 00 00 00 00 nop -# ORPH1-NEXT: 20078: 00 00 00 00 nop -# ORPH1-NEXT: 2007c: 00 00 00 00 nop +# ORPH1-NEXT: 20074: ef ef ef ef +# ORPH1-NEXT: 20078: ef ef ef ef +# ORPH1-NEXT: 2007c: ef ef ef ef # ORPH1: foo1a: # ORPH1-NEXT: 20080: 00 00 00 00 nop # ORPH1: foo1b: # ORPH1-NEXT: 20084: 00 00 00 00 nop # ORPH1: __LA25Thunk_foo2: # ORPH1-NEXT: 20088: 3c 19 00 02 lui $25, 2 # ORPH1-NEXT: 2008c: 08 00 80 28 j 131232 # ORPH1-NEXT: 20090: 27 39 00 a0 addiu $25, $25, 160 # ORPH1-NEXT: 20094: 00 00 00 00 nop -# ORPH1-NEXT: 20098: 00 00 00 00 nop -# ORPH1-NEXT: 2009c: 00 00 00 00 nop +# ORPH1-NEXT: 20098: ef ef ef ef +# ORPH1-NEXT: 2009c: ef ef ef ef # ORPH1: foo2: # ORPH1-NEXT: 200a0: 00 00 00 00 nop # Test script with orphans added to new OutputSection, the .text.1 and # .text.2 sections will form a new OutputSection .text # RUN: echo "SECTIONS { .out 0x20000 : { *(.text) } }" > %t3.script # RUN: ld.lld --script %t3.script %t-npic.o %t-pic.o %t-sto-pic.o -o %t3.exe # RUN: llvm-objdump -d %t3.exe | FileCheck -check-prefix=ORPH2 %s # ORPH2: Disassembly of section .out: # ORPH2-NEXT: __start: # ORPH2-NEXT: 20000: 0c 00 80 18 jal 131168 <__LA25Thunk_foo1a> # ORPH2-NEXT: 20004: 00 00 00 00 nop # ORPH2-NEXT: 20008: 0c 00 80 22 jal 131208 <__LA25Thunk_foo2> # ORPH2-NEXT: 2000c: 00 00 00 00 nop # ORPH2-NEXT: 20010: 0c 00 80 1c jal 131184 <__LA25Thunk_foo1b> # ORPH2-NEXT: 20014: 00 00 00 00 nop # ORPH2-NEXT: 20018: 0c 00 80 22 jal 131208 <__LA25Thunk_foo2> # ORPH2-NEXT: 2001c: 00 00 00 00 nop # ORPH2-NEXT: 20020: 0c 00 80 0c jal 131120 <__LA25Thunk_fpic> # ORPH2-NEXT: 20024: 00 00 00 00 nop # ORPH2-NEXT: 20028: 0c 00 80 14 jal 131152 # ORPH2-NEXT: 2002c: 00 00 00 00 nop # ORPH2: __LA25Thunk_fpic: # ORPH2-NEXT: 20030: 3c 19 00 02 lui $25, 2 # ORPH2-NEXT: 20034: 08 00 80 10 j 131136 # ORPH2-NEXT: 20038: 27 39 00 40 addiu $25, $25, 64 # ORPH2-NEXT: 2003c: 00 00 00 00 nop # ORPH2: fpic: # ORPH2-NEXT: 20040: 00 00 00 00 nop -# ORPH2-NEXT: 20044: 00 00 00 00 nop -# ORPH2-NEXT: 20048: 00 00 00 00 nop -# ORPH2-NEXT: 2004c: 00 00 00 00 nop +# ORPH2-NEXT: 20044: ef ef ef ef +# ORPH2-NEXT: 20048: ef ef ef ef +# ORPH2-NEXT: 2004c: ef ef ef ef # ORPH2: fnpic: # ORPH2-NEXT: 20050: 00 00 00 00 nop # ORPH2-NEXT: Disassembly of section .text: # ORPH2-NEXT: __LA25Thunk_foo1a: # ORPH2-NEXT: 20060: 3c 19 00 02 lui $25, 2 # ORPH2-NEXT: 20064: 08 00 80 20 j 131200 # ORPH2-NEXT: 20068: 27 39 00 80 addiu $25, $25, 128 # ORPH2-NEXT: 2006c: 00 00 00 00 nop # ORPH2: __LA25Thunk_foo1b: # ORPH2-NEXT: 20070: 3c 19 00 02 lui $25, 2 # ORPH2-NEXT: 20074: 08 00 80 21 j 131204 # ORPH2-NEXT: 20078: 27 39 00 84 addiu $25, $25, 132 # ORPH2-NEXT: 2007c: 00 00 00 00 nop # ORPH2: foo1a: # ORPH2-NEXT: 20080: 00 00 00 00 nop # ORPH2: foo1b: # ORPH2-NEXT: 20084: 00 00 00 00 nop # ORPH2: __LA25Thunk_foo2: # ORPH2-NEXT: 20088: 3c 19 00 02 lui $25, 2 # ORPH2-NEXT: 2008c: 08 00 80 28 j 131232 # ORPH2-NEXT: 20090: 27 39 00 a0 addiu $25, $25, 160 # ORPH2-NEXT: 20094: 00 00 00 00 nop -# ORPH2-NEXT: 20098: 00 00 00 00 nop -# ORPH2-NEXT: 2009c: 00 00 00 00 nop +# ORPH2-NEXT: 20098: ef ef ef ef +# ORPH2-NEXT: 2009c: ef ef ef ef # ORPH2: foo2: # ORPH2-NEXT: 200a0: 00 00 00 00 nop Index: vendor/lld/dist/test/ELF/mips-npic-call-pic.s =================================================================== --- vendor/lld/dist/test/ELF/mips-npic-call-pic.s (revision 320381) +++ vendor/lld/dist/test/ELF/mips-npic-call-pic.s (revision 320382) @@ -1,145 +1,145 @@ # REQUIRES: mips # Check LA25 stubs creation. This stub code is necessary when # non-PIC code calls PIC function. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ # RUN: %p/Inputs/mips-fpic.s -o %t-fpic.o # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ # RUN: %p/Inputs/mips-fnpic.s -o %t-fnpic.o # RUN: ld.lld -r %t-fpic.o %t-fnpic.o -o %t-sto-pic.o # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ # RUN: %p/Inputs/mips-pic.s -o %t-pic.o # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-npic.o # RUN: ld.lld %t-npic.o %t-pic.o %t-sto-pic.o -o %t.exe # RUN: llvm-objdump -d %t.exe | FileCheck %s # CHECK: Disassembly of section .text: # CHECK-NEXT: __start: # CHECK-NEXT: 20000: 0c 00 80 0c jal 131120 <__LA25Thunk_foo1a> # CHECK-NEXT: 20004: 00 00 00 00 nop # CHECK-NEXT: 20008: 0c 00 80 16 jal 131160 <__LA25Thunk_foo2> # CHECK-NEXT: 2000c: 00 00 00 00 nop # CHECK-NEXT: 20010: 0c 00 80 10 jal 131136 <__LA25Thunk_foo1b> # CHECK-NEXT: 20014: 00 00 00 00 nop # CHECK-NEXT: 20018: 0c 00 80 16 jal 131160 <__LA25Thunk_foo2> # CHECK-NEXT: 2001c: 00 00 00 00 nop # CHECK-NEXT: 20020: 0c 00 80 1d jal 131188 <__LA25Thunk_fpic> # CHECK-NEXT: 20024: 00 00 00 00 nop # CHECK-NEXT: 20028: 0c 00 80 28 jal 131232 # CHECK-NEXT: 2002c: 00 00 00 00 nop # # CHECK: __LA25Thunk_foo1a: # CHECK-NEXT: 20030: 3c 19 00 02 lui $25, 2 # CHECK-NEXT: 20034: 08 00 80 14 j 131152 # CHECK-NEXT: 20038: 27 39 00 50 addiu $25, $25, 80 # CHECK-NEXT: 2003c: 00 00 00 00 nop # CHECK: __LA25Thunk_foo1b: # CHECK-NEXT: 20040: 3c 19 00 02 lui $25, 2 # CHECK-NEXT: 20044: 08 00 80 15 j 131156 # CHECK-NEXT: 20048: 27 39 00 54 addiu $25, $25, 84 # CHECK-NEXT: 2004c: 00 00 00 00 nop # CHECK: foo1a: # CHECK-NEXT: 20050: 00 00 00 00 nop # CHECK: foo1b: # CHECK-NEXT: 20054: 00 00 00 00 nop # CHECK: __LA25Thunk_foo2: # CHECK-NEXT: 20058: 3c 19 00 02 lui $25, 2 # CHECK-NEXT: 2005c: 08 00 80 1c j 131184 # CHECK-NEXT: 20060: 27 39 00 70 addiu $25, $25, 112 # CHECK-NEXT: 20064: 00 00 00 00 nop -# CHECK-NEXT: 20068: 00 00 00 00 nop -# CHECK-NEXT: 2006c: 00 00 00 00 nop +# CHECK-NEXT: 20068: ef ef ef ef +# CHECK-NEXT: 2006c: ef ef ef ef # CHECK: foo2: # CHECK-NEXT: 20070: 00 00 00 00 nop # CHECK: __LA25Thunk_fpic: # CHECK-NEXT: 20074: 3c 19 00 02 lui $25, 2 # CHECK-NEXT: 20078: 08 00 80 24 j 131216 # CHECK-NEXT: 2007c: 27 39 00 90 addiu $25, $25, 144 # CHECK-NEXT: 20080: 00 00 00 00 nop -# CHECK-NEXT: 20084: 00 00 00 00 nop -# CHECK-NEXT: 20088: 00 00 00 00 nop -# CHECK-NEXT: 2008c: 00 00 00 00 nop +# CHECK-NEXT: 20084: ef ef ef ef +# CHECK-NEXT: 20088: ef ef ef ef +# CHECK-NEXT: 2008c: ef ef ef ef # CHECK: fpic: # CHECK-NEXT: 20090: 00 00 00 00 nop -# CHECK-NEXT: 20094: 00 00 00 00 nop -# CHECK-NEXT: 20098: 00 00 00 00 nop -# CHECK-NEXT: 2009c: 00 00 00 00 nop +# CHECK-NEXT: 20094: ef ef ef ef +# CHECK-NEXT: 20098: ef ef ef ef +# CHECK-NEXT: 2009c: ef ef ef ef # CHECK: fnpic: # CHECK-NEXT: 200a0: 00 00 00 00 nop # Make sure the thunks are created properly no matter how # objects are laid out. # # RUN: ld.lld %t-pic.o %t-npic.o %t-sto-pic.o -o %t.exe # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=REVERSE %s # REVERSE: Disassembly of section .text: # REVERSE-NEXT: __LA25Thunk_foo1a: # REVERSE-NEXT: 20000: 3c 19 00 02 lui $25, 2 # REVERSE-NEXT: 20004: 08 00 80 08 j 131104 # REVERSE-NEXT: 20008: 27 39 00 20 addiu $25, $25, 32 # REVERSE-NEXT: 2000c: 00 00 00 00 nop # REVERSE: __LA25Thunk_foo1b: # REVERSE-NEXT: 20010: 3c 19 00 02 lui $25, 2 # REVERSE-NEXT: 20014: 08 00 80 09 j 131108 # REVERSE-NEXT: 20018: 27 39 00 24 addiu $25, $25, 36 # REVERSE-NEXT: 2001c: 00 00 00 00 nop # REVERSE: foo1a: # REVERSE-NEXT: 20020: 00 00 00 00 nop # REVERSE: foo1b: # REVERSE-NEXT: 20024: 00 00 00 00 nop # REVERSE: __LA25Thunk_foo2: # REVERSE-NEXT: 20028: 3c 19 00 02 lui $25, 2 # REVERSE-NEXT: 2002c: 08 00 80 10 j 131136 # REVERSE-NEXT: 20030: 27 39 00 40 addiu $25, $25, 64 # REVERSE-NEXT: 20034: 00 00 00 00 nop -# REVERSE-NEXT: 20038: 00 00 00 00 nop -# REVERSE-NEXT: 2003c: 00 00 00 00 nop +# REVERSE-NEXT: 20038: ef ef ef ef +# REVERSE-NEXT: 2003c: ef ef ef ef # REVERSE: foo2: # REVERSE-NEXT: 20040: 00 00 00 00 nop -# REVERSE-NEXT: 20044: 00 00 00 00 nop -# REVERSE-NEXT: 20048: 00 00 00 00 nop -# REVERSE-NEXT: 2004c: 00 00 00 00 nop +# REVERSE-NEXT: 20044: ef ef ef ef +# REVERSE-NEXT: 20048: ef ef ef ef +# REVERSE-NEXT: 2004c: ef ef ef ef # REVERSE: __start: # REVERSE-NEXT: 20050: 0c 00 80 00 jal 131072 <__LA25Thunk_foo1a> # REVERSE-NEXT: 20054: 00 00 00 00 nop # REVERSE-NEXT: 20058: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2> # REVERSE-NEXT: 2005c: 00 00 00 00 nop # REVERSE-NEXT: 20060: 0c 00 80 04 jal 131088 <__LA25Thunk_foo1b> # REVERSE-NEXT: 20064: 00 00 00 00 nop # REVERSE-NEXT: 20068: 0c 00 80 0a jal 131112 <__LA25Thunk_foo2> # REVERSE-NEXT: 2006c: 00 00 00 00 nop # REVERSE-NEXT: 20070: 0c 00 80 20 jal 131200 <__LA25Thunk_fpic> # REVERSE-NEXT: 20074: 00 00 00 00 nop # REVERSE-NEXT: 20078: 0c 00 80 28 jal 131232 # REVERSE-NEXT: 2007c: 00 00 00 00 nop # REVERSE: __LA25Thunk_fpic: # REVERSE-NEXT: 20080: 3c 19 00 02 lui $25, 2 # REVERSE-NEXT: 20084: 08 00 80 24 j 131216 # REVERSE-NEXT: 20088: 27 39 00 90 addiu $25, $25, 144 # REVERSE-NEXT: 2008c: 00 00 00 00 nop # REVERSE: fpic: # REVERSE-NEXT: 20090: 00 00 00 00 nop -# REVERSE-NEXT: 20094: 00 00 00 00 nop -# REVERSE-NEXT: 20098: 00 00 00 00 nop -# REVERSE-NEXT: 2009c: 00 00 00 00 nop +# REVERSE-NEXT: 20094: ef ef ef ef +# REVERSE-NEXT: 20098: ef ef ef ef +# REVERSE-NEXT: 2009c: ef ef ef ef # REVERSE: fnpic: # REVERSE-NEXT: 200a0: 00 00 00 00 nop .text .globl __start __start: jal foo1a jal foo2 jal foo1b jal foo2 jal fpic jal fnpic Index: vendor/lld/dist/test/ELF/mips-plt-r6.s =================================================================== --- vendor/lld/dist/test/ELF/mips-plt-r6.s (revision 320381) +++ vendor/lld/dist/test/ELF/mips-plt-r6.s (revision 320382) @@ -1,38 +1,38 @@ # Check PLT entries generation in case of R6 ABI version. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ # RUN: -mcpu=mips32r6 %s -o %t1.o # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ # RUN: -mcpu=mips32r6 %S/Inputs/mips-dynamic.s -o %t2.o # RUN: ld.lld %t2.o -shared -o %t.so # RUN: ld.lld %t1.o %t.so -o %t.exe # RUN: llvm-objdump -d %t.exe | FileCheck %s # REQUIRES: mips # CHECK: Disassembly of section .text: # CHECK-NEXT: __start: # CHECK-NEXT: 20000: 0c 00 80 0c jal 131120 # ^-- 0x20030 gotplt[foo0] # CHECK-NEXT: 20004: 00 00 00 00 nop # # CHECK-NEXT: Disassembly of section .plt: # CHECK-NEXT: .plt: -# CHECK-NEXT: 20010: 3c 1c 00 03 aui $zero, $gp, 3 +# CHECK-NEXT: 20010: 3c 1c 00 03 aui $gp, $zero, 3 # CHECK-NEXT: 20014: 8f 99 00 04 lw $25, 4($gp) # CHECK-NEXT: 20018: 27 9c 00 04 addiu $gp, $gp, 4 # CHECK-NEXT: 2001c: 03 1c c0 23 subu $24, $24, $gp # CHECK-NEXT: 20020: 03 e0 78 25 move $15, $ra # CHECK-NEXT: 20024: 00 18 c0 82 srl $24, $24, 2 # CHECK-NEXT: 20028: 03 20 f8 09 jalr $25 # CHECK-NEXT: 2002c: 27 18 ff fe addiu $24, $24, -2 -# CHECK-NEXT: 20030: 3c 0f 00 03 aui $zero, $15, 3 +# CHECK-NEXT: 20030: 3c 0f 00 03 aui $15, $zero, 3 # CHECK-NEXT: 20034: 8d f9 00 0c lw $25, 12($15) # CHECK-NEXT: 20038: 03 20 00 09 jr $25 # CHECK-NEXT: 2003c: 25 f8 00 0c addiu $24, $15, 12 .text .global __start __start: jal foo0 # R_MIPS_26 against 'foo0' from DSO Index: vendor/lld/dist/test/ELF/wrap.s =================================================================== --- vendor/lld/dist/test/ELF/wrap.s (revision 320381) +++ vendor/lld/dist/test/ELF/wrap.s (revision 320382) @@ -1,19 +1,27 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/wrap.s -o %t2 // RUN: ld.lld -o %t3 %t %t2 -wrap foo -wrap nosuchsym // RUN: llvm-objdump -d -print-imm-hex %t3 | FileCheck %s // RUN: ld.lld -o %t3 %t %t2 --wrap foo -wrap=nosuchsym // RUN: llvm-objdump -d -print-imm-hex %t3 | FileCheck %s // CHECK: _start: // CHECK-NEXT: movl $0x11010, %edx // CHECK-NEXT: movl $0x11010, %edx // CHECK-NEXT: movl $0x11000, %edx +// RUN: llvm-readobj -t -s %t3 | FileCheck -check-prefix=SYM %s +// SYM: Name: __real_foo +// SYM-NEXT: Value: 0x11000 +// SYM: Name: __wrap_foo +// SYM-NEXT: Value: 0x11010 +// SYM: Name: foo +// SYM-NEXT: Value: 0x11010 + .global _start _start: movl $foo, %edx movl $__wrap_foo, %edx movl $__real_foo, %edx Index: vendor/lld/dist/test/lit.cfg =================================================================== --- vendor/lld/dist/test/lit.cfg (revision 320381) +++ vendor/lld/dist/test/lit.cfg (revision 320382) @@ -1,269 +1,268 @@ # -*- Python -*- import os import platform import re import subprocess import locale import lit.formats import lit.util # Configuration file for the 'lit' test runner. # name: The name of this test suite. config.name = 'lld' # Tweak PATH for Win32 if sys.platform in ['win32']: # Seek sane tools in directories and set to $PATH. path = getattr(config, 'lit_tools_dir', None) path = lit_config.getToolsPath(path, config.environment['PATH'], ['cmp.exe', 'grep.exe', 'sed.exe']) if path is not None: path = os.path.pathsep.join((path, config.environment['PATH'])) config.environment['PATH'] = path # Choose between lit's internal shell pipeline runner and a real shell. If # LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override. use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL") if use_lit_shell: # 0 is external, "" is default, and everything else is internal. execute_external = (use_lit_shell == "0") else: # Otherwise we default to internal on Windows and external elsewhere, as # bash on Windows is usually very slow. execute_external = (not sys.platform in ['win32']) # testFormat: The test format to use to interpret tests. # # For now we require '&&' between commands, until they get globally killed and # the test runner updated. config.test_format = lit.formats.ShTest(execute_external) # suffixes: A list of file extensions to treat as test files. -config.suffixes = ['.ll', '.s', '.objtxt', '.test'] +config.suffixes = ['.ll', '.s', '.test', '.yaml', '.objtxt'] # excludes: A list of directories to exclude from the testsuite. The 'Inputs' # subdirectories contain auxiliary inputs for various tests in their parent # directories. config.excludes = ['Inputs'] # test_source_root: The root path where tests are located. config.test_source_root = os.path.dirname(__file__) # test_exec_root: The root path where tests should be run. lld_obj_root = getattr(config, 'lld_obj_root', None) if lld_obj_root is not None: config.test_exec_root = os.path.join(lld_obj_root, 'test') # Set llvm_{src,obj}_root for use by others. config.llvm_src_root = getattr(config, 'llvm_src_root', None) config.llvm_obj_root = getattr(config, 'llvm_obj_root', None) # Tweak the PATH to include the tools dir and the scripts dir. if lld_obj_root is not None: lld_tools_dir = getattr(config, 'lld_tools_dir', None) if not lld_tools_dir: lit_config.fatal('No LLD tools dir set!') llvm_tools_dir = getattr(config, 'llvm_tools_dir', None) if not llvm_tools_dir: lit_config.fatal('No LLVM tools dir set!') path = os.path.pathsep.join((lld_tools_dir, llvm_tools_dir, config.environment['PATH'])) path = os.path.pathsep.join((os.path.join(getattr(config, 'llvm_src_root', None),'test','Scripts'),path)) config.environment['PATH'] = path lld_libs_dir = getattr(config, 'lld_libs_dir', None) if not lld_libs_dir: lit_config.fatal('No LLD libs dir set!') llvm_libs_dir = getattr(config, 'llvm_libs_dir', None) if not llvm_libs_dir: lit_config.fatal('No LLVM libs dir set!') path = os.path.pathsep.join((lld_libs_dir, llvm_libs_dir, config.environment.get('LD_LIBRARY_PATH',''))) config.environment['LD_LIBRARY_PATH'] = path # Propagate LLVM_SRC_ROOT into the environment. config.environment['LLVM_SRC_ROOT'] = getattr(config, 'llvm_src_root', '') # Propagate PYTHON_EXECUTABLE into the environment config.environment['PYTHON_EXECUTABLE'] = getattr(config, 'python_executable', '') ### # Check that the object root is known. if config.test_exec_root is None: # Otherwise, we haven't loaded the site specific configuration (the user is # probably trying to run on a test file directly, and either the site # configuration hasn't been created by the build system, or we are in an # out-of-tree build situation). # Check for 'lld_site_config' user parameter, and use that if available. site_cfg = lit_config.params.get('lld_site_config', None) if site_cfg and os.path.exists(site_cfg): lit_config.load_config(config, site_cfg) raise SystemExit # Try to detect the situation where we are using an out-of-tree build by # looking for 'llvm-config'. # # FIXME: I debated (i.e., wrote and threw away) adding logic to # automagically generate the lit.site.cfg if we are in some kind of fresh # build situation. This means knowing how to invoke the build system though, # and I decided it was too much magic. We should solve this by just having # the .cfg files generated during the configuration step. llvm_config = lit.util.which('llvm-config', config.environment['PATH']) if not llvm_config: lit_config.fatal('No site specific configuration available!') # Get the source and object roots. llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip() llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip() lld_src_root = os.path.join(llvm_src_root, "tools", "lld") lld_obj_root = os.path.join(llvm_obj_root, "tools", "lld") # Validate that we got a tree which points to here, using the standard # tools/lld layout. this_src_root = os.path.dirname(config.test_source_root) if os.path.realpath(lld_src_root) != os.path.realpath(this_src_root): lit_config.fatal('No site specific configuration available!') # Check that the site specific configuration exists. site_cfg = os.path.join(lld_obj_root, 'test', 'lit.site.cfg') if not os.path.exists(site_cfg): lit_config.fatal( 'No site specific configuration available! You may need to ' 'run "make test" in your lld build directory.') # Okay, that worked. Notify the user of the automagic, and reconfigure. lit_config.note('using out-of-tree build at %r' % lld_obj_root) lit_config.load_config(config, site_cfg) raise SystemExit # For each occurrence of a lld tool name as its own word, replace it # with the full path to the build directory holding that tool. This # ensures that we are testing the tools just built and not some random # tools that might happen to be in the user's PATH. # Regex assertions to reject neighbor hyphens/dots (seen in some tests). # For example, we want to prefix 'lld' and 'ld.lld' but not the 'lld' inside # of 'ld.lld'. NoPreJunk = r"(?