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);
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 {
ArrayRef<coff_relocation> Relocs;
+ // Used by the garbage collector.
+ bool Live;
+
private:
StringRef SectionName;
std::vector<SectionChunk *> AssocChildren;
- // Used by the garbage collector.
- bool Live;
-
// Used for ICF (Identical COMDAT Folding)
void replace(SectionChunk *Other);
uint32_t Class[2] = {0, 0};
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.
// COMDAT section chunks are dead by default. Add non-COMDAT chunks.
for (Chunk *C : Chunks)
if (auto *SC = dyn_cast<SectionChunk>(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);
};
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())
uint32_t Modi = File->ModuleDBI->getModuleIndex();
for (Chunk *C : Chunks) {
auto *SecChunk = dyn_cast<SectionChunk>(C);
- if (!SecChunk || !SecChunk->isLive())
+ if (!SecChunk || !SecChunk->Live)
continue;
pdb::SectionContrib SC = createSectionContrib(SecChunk, Modi);
File->ModuleDBI->setFirstSectionContrib(SC);
DebugChecksumsSubsectionRef Checksums;
std::vector<ulittle32_t *> StringTableReferences;
for (SectionChunk *DebugChunk : File->getDebugChunks()) {
- if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S")
+ if (!DebugChunk->Live || DebugChunk->getSectionName() != ".debug$S")
continue;
ArrayRef<uint8_t> RelocatedDebugContents =
// reference itself to point at the IAT entry.
Sym->replaceKeepingName(Imp, sizeof(DefinedImportData));
cast<DefinedImportData>(Sym)->IsRuntimePseudoReloc = true;
+
+ // There may exist symbols named .refptr.<name> which only consist
+ // of a single pointer to <name>. If it turns out <name> is
+ // automatically imported, we don't need to keep the .refptr.<name>
+ // pointer at all, but redirect all accesses to it to the IAT entry
+ // for __imp_<name> instead, and drop the whole .refptr.<name> chunk.
+ DefinedRegular *Refptr =
+ dyn_cast_or_null<DefinedRegular>(find((".refptr." + Name).str()));
+ size_t PtrSize = Config->is64() ? 8 : 4;
+ if (Refptr && Refptr->getChunk()->getSize() == PtrSize) {
+ SectionChunk *SC = dyn_cast_or_null<SectionChunk>(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;
}
bool Symbol::isLive() const {
if (auto *R = dyn_cast<DefinedRegular>(this))
- return R->getChunk()->isLive();
+ return R->getChunk()->Live;
if (auto *Imp = dyn_cast<DefinedImportData>(this))
return Imp->File->Live;
if (auto *Imp = dyn_cast<DefinedImportThunk>(this))
std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> Map;
for (Chunk *C : Symtab->getChunks()) {
auto *SC = dyn_cast<SectionChunk>(C);
- if (SC && !SC->isLive()) {
+ if (SC && !SC->Live) {
if (Config->Verbose)
SC->printDiscardedMessage();
continue;
// We only care about live section chunks. Common chunks and other chunks
// don't generally contain relocations.
SectionChunk *SC = dyn_cast<SectionChunk>(C);
- if (!SC || !SC->isLive())
+ if (!SC || !SC->Live)
continue;
for (const coff_relocation &Reloc : SC->Relocs) {
// 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.
for (Chunk *C : Symtab->getChunks()) {
auto *SC = dyn_cast<SectionChunk>(C);
- if (!SC || !SC->isLive())
+ if (!SC || !SC->Live)
continue;
SC->getRuntimePseudoRelocs(Rels);
}
--- /dev/null
+# 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