Index: lld/trunk/COFF/Chunks.h =================================================================== --- lld/trunk/COFF/Chunks.h +++ lld/trunk/COFF/Chunks.h @@ -174,16 +174,6 @@ StringRef getDebugName() override; - // Returns true if the chunk was not dropped by GC. - bool isLive() { return Live; } - - // Used by the garbage collector. - void markLive() { - assert(Config->DoGC && "should only mark things live from GC"); - assert(!isLive() && "Cannot mark an already live section!"); - Live = true; - } - // True if this is a codeview debug info chunk. These will not be laid out in // the image. Instead they will end up in the PDB, if one is requested. bool isCodeView() const { @@ -224,13 +214,13 @@ ArrayRef Relocs; + // Used by the garbage collector. + bool Live; + private: StringRef SectionName; std::vector AssocChildren; - // Used by the garbage collector. - bool Live; - // Used for ICF (Identical COMDAT Folding) void replace(SectionChunk *Other); uint32_t Class[2] = {0, 0}; Index: lld/trunk/COFF/Chunks.cpp =================================================================== --- lld/trunk/COFF/Chunks.cpp +++ lld/trunk/COFF/Chunks.cpp @@ -758,12 +758,12 @@ void MergeChunk::finalizeContents() { for (SectionChunk *C : Sections) - if (C->isLive()) + if (C->Live) Builder.add(toStringRef(C->getContents())); Builder.finalize(); for (SectionChunk *C : Sections) { - if (!C->isLive()) + if (!C->Live) continue; size_t Off = Builder.getOffset(toStringRef(C->getContents())); C->setOutputSection(Out); Index: lld/trunk/COFF/ICF.cpp =================================================================== --- lld/trunk/COFF/ICF.cpp +++ lld/trunk/COFF/ICF.cpp @@ -80,7 +80,7 @@ bool ICF::isEligible(SectionChunk *C) { // Non-comdat chunks, dead chunks, and writable chunks are not elegible. bool Writable = C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE; - if (!C->isCOMDAT() || !C->isLive() || Writable) + if (!C->isCOMDAT() || !C->Live || Writable) return false; // Code sections are eligible. Index: lld/trunk/COFF/MarkLive.cpp =================================================================== --- lld/trunk/COFF/MarkLive.cpp +++ lld/trunk/COFF/MarkLive.cpp @@ -32,13 +32,13 @@ // COMDAT section chunks are dead by default. Add non-COMDAT chunks. for (Chunk *C : Chunks) if (auto *SC = dyn_cast(C)) - if (SC->isLive()) + if (SC->Live) Worklist.push_back(SC); auto Enqueue = [&](SectionChunk *C) { - if (C->isLive()) + if (C->Live) return; - C->markLive(); + C->Live = true; Worklist.push_back(C); }; @@ -57,7 +57,7 @@ while (!Worklist.empty()) { SectionChunk *SC = Worklist.pop_back_val(); - assert(SC->isLive() && "We mark as live when pushing onto the worklist!"); + assert(SC->Live && "We mark as live when pushing onto the worklist!"); // Mark all symbols listed in the relocation table for this section. for (Symbol *B : SC->symbols()) Index: lld/trunk/COFF/PDB.cpp =================================================================== --- lld/trunk/COFF/PDB.cpp +++ lld/trunk/COFF/PDB.cpp @@ -821,7 +821,7 @@ uint32_t Modi = File->ModuleDBI->getModuleIndex(); for (Chunk *C : Chunks) { auto *SecChunk = dyn_cast(C); - if (!SecChunk || !SecChunk->isLive()) + if (!SecChunk || !SecChunk->Live) continue; pdb::SectionContrib SC = createSectionContrib(SecChunk, Modi); File->ModuleDBI->setFirstSectionContrib(SC); @@ -851,7 +851,7 @@ DebugChecksumsSubsectionRef Checksums; std::vector StringTableReferences; for (SectionChunk *DebugChunk : File->getDebugChunks()) { - if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S") + if (!DebugChunk->Live || DebugChunk->getSectionName() != ".debug$S") continue; ArrayRef RelocatedDebugContents = Index: lld/trunk/COFF/SymbolTable.cpp =================================================================== --- lld/trunk/COFF/SymbolTable.cpp +++ lld/trunk/COFF/SymbolTable.cpp @@ -169,6 +169,23 @@ // reference itself to point at the IAT entry. Sym->replaceKeepingName(Imp, sizeof(DefinedImportData)); cast(Sym)->IsRuntimePseudoReloc = true; + + // There may exist symbols named .refptr. which only consist + // of a single pointer to . If it turns out is + // automatically imported, we don't need to keep the .refptr. + // pointer at all, but redirect all accesses to it to the IAT entry + // for __imp_ instead, and drop the whole .refptr. chunk. + DefinedRegular *Refptr = + dyn_cast_or_null(find((".refptr." + Name).str())); + size_t PtrSize = Config->is64() ? 8 : 4; + if (Refptr && Refptr->getChunk()->getSize() == PtrSize) { + SectionChunk *SC = dyn_cast_or_null(Refptr->getChunk()); + if (SC && SC->Relocs.size() == 1 && *SC->symbols().begin() == Sym) { + log("Replacing .refptr." + Name + " with " + Imp->getName()); + Refptr->getChunk()->Live = false; + Refptr->replaceKeepingName(Imp, sizeof(DefinedImportData)); + } + } return true; } Index: lld/trunk/COFF/Symbols.cpp =================================================================== --- lld/trunk/COFF/Symbols.cpp +++ lld/trunk/COFF/Symbols.cpp @@ -54,7 +54,7 @@ bool Symbol::isLive() const { if (auto *R = dyn_cast(this)) - return R->getChunk()->isLive(); + return R->getChunk()->Live; if (auto *Imp = dyn_cast(this)) return Imp->File->Live; if (auto *Imp = dyn_cast(this)) Index: lld/trunk/COFF/Writer.cpp =================================================================== --- lld/trunk/COFF/Writer.cpp +++ lld/trunk/COFF/Writer.cpp @@ -435,7 +435,7 @@ std::map, std::vector> Map; for (Chunk *C : Symtab->getChunks()) { auto *SC = dyn_cast(C); - if (SC && !SC->isLive()) { + if (SC && !SC->Live) { if (Config->Verbose) SC->printDiscardedMessage(); continue; @@ -1014,7 +1014,7 @@ // We only care about live section chunks. Common chunks and other chunks // don't generally contain relocations. SectionChunk *SC = dyn_cast(C); - if (!SC || !SC->isLive()) + if (!SC || !SC->Live) continue; for (const coff_relocation &Reloc : SC->Relocs) { @@ -1097,7 +1097,7 @@ // is associated with something like a vtable and the vtable is discarded. // In this case, the associated gfids section is discarded, and we don't // mark the virtual member functions as address-taken by the vtable. - if (!C->isLive()) + if (!C->Live) continue; // Validate that the contents look like symbol table indices. @@ -1153,7 +1153,7 @@ for (Chunk *C : Symtab->getChunks()) { auto *SC = dyn_cast(C); - if (!SC || !SC->isLive()) + if (!SC || !SC->Live) continue; SC->getRuntimePseudoRelocs(Rels); } Index: lld/trunk/test/COFF/autoimport-refptr.s =================================================================== --- lld/trunk/test/COFF/autoimport-refptr.s +++ lld/trunk/test/COFF/autoimport-refptr.s @@ -0,0 +1,65 @@ +# REQUIRES: x86 + +# RUN: echo -e ".global variable\n.global DllMainCRTStartup\n.text\nDllMainCRTStartup:\nret\n.data\nvariable:\n.long 42" > %t-lib.s +# RUN: llvm-mc -triple=x86_64-windows-gnu %t-lib.s -filetype=obj -o %t-lib.obj +# RUN: lld-link -out:%t-lib.dll -dll -entry:DllMainCRTStartup %t-lib.obj -lldmingw -implib:%t-lib.lib + +# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj +# RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib -verbose + +# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s +# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DISASM %s +# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=CONTENTS %s + +# IMPORTS: Import { +# IMPORTS-NEXT: Name: autoimport-refptr.s.tmp-lib.dll +# IMPORTS-NEXT: ImportLookupTableRVA: 0x2030 +# IMPORTS-NEXT: ImportAddressTableRVA: 0x2040 +# IMPORTS-NEXT: Symbol: variable (0) +# IMPORTS-NEXT: } + +# DISASM: Disassembly of section .text: +# DISASM: .text: +# Relative offset at 0x1002 pointing at the IAT at 0x2040 +# DISASM: 140001000: 48 8b 05 39 10 00 00 movq 4153(%rip), %rax +# DISASM: 140001007: 8b 00 movl (%rax), %eax +# Relative offset at 0x100b pointing at the .refptr.localvar stub at +# 0x2000 +# DISASM: 140001009: 48 8b 0d f0 0f 00 00 movq 4080(%rip), %rcx +# DISASM: 140001010: 03 01 addl (%rcx), %eax +# DISASM: 140001012: c3 retq + +# relocs: pointing at an empty list of runtime pseudo relocs. +# localvar: 42 +# CONTENTS: Contents of section .data: +# CONTENTS: 140003000 08200040 01000000 08200040 01000000 +# CONTENTS: 140003010 2a000000 + + .global main + .global localvar + .text +main: + movq .refptr.variable(%rip), %rax + movl (%rax), %eax + movq .refptr.localvar(%rip), %rcx + addl (%rcx), %eax + ret + + .data +relocs: + .quad __RUNTIME_PSEUDO_RELOC_LIST__ + .quad __RUNTIME_PSEUDO_RELOC_LIST_END__ +localvar: + .int 42 + +# Normally the compiler wouldn't emit a stub for a variable that is +# emitted in the same translation unit. + .section .rdata$.refptr.localvar,"dr",discard,.refptr.localvar + .global .refptr.localvar +.refptr.localvar: + .quad localvar + + .section .rdata$.refptr.variable,"dr",discard,.refptr.variable + .global .refptr.variable +.refptr.variable: + .quad variable