diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 05cc4db5af749..7d01b7f33deca 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -90,7 +90,7 @@ bool elf::link(ArrayRef args, bool canExitEarly, archiveFiles.clear(); binaryFiles.clear(); bitcodeFiles.clear(); - lazyObjFiles.clear(); + lazyBitcodeFiles.clear(); objectFiles.clear(); sharedFiles.clear(); backwardReferences.clear(); @@ -248,7 +248,7 @@ void LinkerDriver::addFile(StringRef path, bool withLOption) { for (const std::pair &p : getArchiveMembers(mbref)) - files.push_back(make(p.first, path, p.second)); + files.push_back(createLazyFile(p.first, path, p.second)); return; } @@ -273,7 +273,7 @@ void LinkerDriver::addFile(StringRef path, bool withLOption) { case file_magic::bitcode: case file_magic::elf_relocatable: if (inLib) - files.push_back(make(mbref, "", 0)); + files.push_back(createLazyFile(mbref, "", 0)); else files.push_back(createObjectFile(mbref)); break; diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index fb1fca1c7f0f2..cf8fd1dfc3137 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -46,7 +46,7 @@ uint32_t InputFile::nextGroupId; std::vector elf::archiveFiles; std::vector elf::binaryFiles; std::vector elf::bitcodeFiles; -std::vector elf::lazyObjFiles; +std::vector elf::lazyBitcodeFiles; std::vector elf::objectFiles; std::vector elf::sharedFiles; @@ -186,9 +186,13 @@ template static void doParseFile(InputFile *file) { } // Lazy object file - if (auto *f = dyn_cast(file)) { - lazyObjFiles.push_back(f); - f->parse(); + if (file->lazy) { + if (auto *f = dyn_cast(file)) { + lazyBitcodeFiles.push_back(f); + f->parseLazy(); + } else { + cast>(file)->parseLazy(); + } return; } @@ -1130,15 +1134,14 @@ template void ObjFile::initializeSymbols() { // defined symbol in a .eh_frame becomes dangling symbols. if (sec == &InputSection::discarded) { Undefined und{this, name, binding, stOther, type, secIdx}; - // !ArchiveFile::parsed or LazyObjFile::extracted means that the file + // !ArchiveFile::parsed or !LazyObjFile::lazy means that the file // containing this object has not finished processing, i.e. this symbol is // a result of a lazy symbol extract. We should demote the lazy symbol to // an Undefined so that any relocations outside of the group to it will // trigger a discarded section error. if ((sym->symbolKind == Symbol::LazyArchiveKind && !cast(sym->file)->parsed) || - (sym->symbolKind == Symbol::LazyObjectKind && - cast(sym->file)->extracted)) { + (sym->symbolKind == Symbol::LazyObjectKind && !sym->file->lazy)) { sym->replace(und); // Prevent LTO from internalizing the symbol in case there is a // reference to this symbol from this file. @@ -1630,9 +1633,10 @@ static uint8_t getOsAbi(const Triple &t) { } BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName, - uint64_t offsetInArchive) + uint64_t offsetInArchive, bool lazy) : InputFile(BitcodeKind, mb) { this->archiveName = archiveName; + this->lazy = lazy; std::string path = mb.getBufferIdentifier().str(); if (config->thinLTOIndexOnly) @@ -1718,6 +1722,12 @@ template void BitcodeFile::parse() { addDependentLibrary(l, this); } +void BitcodeFile::parseLazy() { + for (const lto::InputFile::Symbol &sym : obj->symbols()) + if (!sym.isUndefined()) + symtab->addSymbol(LazyObject{*this, saver.save(sym.getName())}); +} + void BinaryFile::parse() { ArrayRef data = arrayRefFromStringRef(mb.getBuffer()); auto *section = make(this, SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, @@ -1744,7 +1754,7 @@ void BinaryFile::parse() { InputFile *elf::createObjectFile(MemoryBufferRef mb, StringRef archiveName, uint64_t offsetInArchive) { if (isBitcode(mb)) - return make(mb, archiveName, offsetInArchive); + return make(mb, archiveName, offsetInArchive, /*lazy=*/false); switch (getELFKind(mb, archiveName)) { case ELF32LEKind: @@ -1760,41 +1770,20 @@ InputFile *elf::createObjectFile(MemoryBufferRef mb, StringRef archiveName, } } -void LazyObjFile::extract() { - if (extracted) - return; - extracted = true; - - InputFile *file = createObjectFile(mb, archiveName, offsetInArchive); - file->groupId = groupId; - - // Copy symbol vector so that the new InputFile doesn't have to - // insert the same defined symbols to the symbol table again. - file->symbols = std::move(symbols); +InputFile *elf::createLazyFile(MemoryBufferRef mb, StringRef archiveName, + uint64_t offsetInArchive) { + if (isBitcode(mb)) + return make(mb, archiveName, offsetInArchive, /*lazy=*/true); - parseFile(file); + auto *file = + cast(createObjectFile(mb, archiveName, offsetInArchive)); + file->lazy = true; + return file; } -template void LazyObjFile::parse() { +template void ObjFile::parseLazy() { using Elf_Sym = typename ELFT::Sym; - // A lazy object file wraps either a bitcode file or an ELF file. - if (isBitcode(this->mb)) { - std::unique_ptr obj = - CHECK(lto::InputFile::create(this->mb), this); - for (const lto::InputFile::Symbol &sym : obj->symbols()) { - if (sym.isUndefined()) - continue; - symtab->addSymbol(LazyObject{*this, saver.save(sym.getName())}); - } - return; - } - - if (getELFKind(this->mb, archiveName) != config->ekind) { - error("incompatible file: " + this->mb.getBufferIdentifier()); - return; - } - // Find a symbol table. ELFFile obj = check(ELFFile::create(mb.getBuffer())); ArrayRef sections = CHECK(obj.sections(), this); @@ -1825,16 +1814,16 @@ template void LazyObjFile::parse() { continue; sym->resolve(LazyObject{*this, sym->getName()}); - // If extracted, stop iterating because this->symbols has been transferred - // to the instantiated ObjFile. - if (extracted) + // If extracted, stop iterating because the symbol resolution has been + // done by ObjFile::parse. + if (!lazy) return; } return; } } -bool LazyObjFile::shouldExtractForCommon(const StringRef &name) { +bool InputFile::shouldExtractForCommon(StringRef name) { if (isBitcode(mb)) return isBitcodeNonCommonDef(mb, name, archiveName); @@ -1855,11 +1844,6 @@ template void BitcodeFile::parse(); template void BitcodeFile::parse(); template void BitcodeFile::parse(); -template void LazyObjFile::parse(); -template void LazyObjFile::parse(); -template void LazyObjFile::parse(); -template void LazyObjFile::parse(); - template class elf::ObjFile; template class elf::ObjFile; template class elf::ObjFile; diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h index e15f8798ae1c9..dd39bc397a0fd 100644 --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -101,6 +101,10 @@ class InputFile { // Get filename to use for linker script processing. StringRef getNameForScript() const; + // Check if a non-common symbol should be extracted to override a common + // definition. + bool shouldExtractForCommon(StringRef name); + // If not empty, this stores the name of the archive containing this file. // We use this string for creating error messages. SmallString<0> archiveName; @@ -132,6 +136,11 @@ class InputFile { ELFKind ekind = ELFNoneKind; uint8_t osabi = 0; uint8_t abiVersion = 0; + + // True if this is a relocatable object file/bitcode file between --start-lib + // and --end-lib. + bool lazy = false; + // True if this is an argument for --just-symbols. Usually false. bool justSymbols = false; @@ -211,6 +220,7 @@ template class ObjFile : public ELFFileBase { } void parse(bool ignoreComdats = false); + void parseLazy(); StringRef getShtGroupSignature(ArrayRef sections, const Elf_Shdr &sec); @@ -294,36 +304,6 @@ template class ObjFile : public ELFFileBase { llvm::once_flag initDwarf; }; -// LazyObjFile is analogous to ArchiveFile in the sense that -// the file contains lazy symbols. The difference is that -// LazyObjFile wraps a single file instead of multiple files. -// -// This class is used for --start-lib and --end-lib options which -// instruct the linker to link object files between them with the -// archive file semantics. -class LazyObjFile : public InputFile { -public: - LazyObjFile(MemoryBufferRef m, StringRef archiveName, - uint64_t offsetInArchive) - : InputFile(LazyObjKind, m), offsetInArchive(offsetInArchive) { - this->archiveName = archiveName; - } - - static bool classof(const InputFile *f) { return f->kind() == LazyObjKind; } - - template void parse(); - void extract(); - - // Check if a non-common symbol should be extracted to override a common - // definition. - bool shouldExtractForCommon(const StringRef &name); - - bool extracted = false; - -private: - uint64_t offsetInArchive; -}; - // An ArchiveFile object represents a .a file. class ArchiveFile : public InputFile { public: @@ -354,9 +334,10 @@ class ArchiveFile : public InputFile { class BitcodeFile : public InputFile { public: BitcodeFile(MemoryBufferRef m, StringRef archiveName, - uint64_t offsetInArchive); + uint64_t offsetInArchive, bool lazy); static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; } template void parse(); + void parseLazy(); std::unique_ptr obj; }; @@ -406,6 +387,8 @@ class BinaryFile : public InputFile { InputFile *createObjectFile(MemoryBufferRef mb, StringRef archiveName = "", uint64_t offsetInArchive = 0); +InputFile *createLazyFile(MemoryBufferRef mb, StringRef archiveName, + uint64_t offsetInArchive); inline bool isBitcode(MemoryBufferRef mb) { return identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode; @@ -416,7 +399,7 @@ std::string replaceThinLTOSuffix(StringRef path); extern std::vector archiveFiles; extern std::vector binaryFiles; extern std::vector bitcodeFiles; -extern std::vector lazyObjFiles; +extern std::vector lazyBitcodeFiles; extern std::vector objectFiles; extern std::vector sharedFiles; diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 46dc77a6789c5..b1632b8bae8a3 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -278,8 +278,8 @@ void BitcodeCompiler::add(BitcodeFile &f) { // This is needed because this is what GNU gold plugin does and we have a // distributed build system that depends on that behavior. static void thinLTOCreateEmptyIndexFiles() { - for (LazyObjFile *f : lazyObjFiles) { - if (f->extracted || !isBitcode(f->mb)) + for (BitcodeFile *f : lazyBitcodeFiles) { + if (!f->lazy) continue; std::string path = replaceThinLTOSuffix(getThinLTOOutputFile(f->getName())); std::unique_ptr os = openFile(path + ".thinlto.bc"); diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index f00d3217a6af4..f6f0ad0087d74 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -256,10 +256,12 @@ void Symbol::parseSymbolVersion() { } void Symbol::extract() const { - if (auto *sym = dyn_cast(this)) + if (auto *sym = dyn_cast(this)) { cast(sym->file)->extract(sym->sym); - else - cast(this->file)->extract(); + } else if (file->lazy) { + file->lazy = false; + parseFile(file); + } } MemoryBufferRef LazyArchive::getMemberBuffer() { @@ -711,8 +713,7 @@ template void Symbol::resolveLazy(const LazyT &other) { return; } } else if (auto *loSym = dyn_cast(&other)) { - LazyObjFile *obj = cast(loSym->file); - if (obj->shouldExtractForCommon(loSym->getName())) { + if (loSym->file->shouldExtractForCommon(loSym->getName())) { replaceCommon(*this, other); return; } diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index b0b7832135a7f..beb45ec141470 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -430,7 +430,9 @@ class LazyObject : public Symbol { public: LazyObject(InputFile &file, StringRef name) : Symbol(LazyObjectKind, &file, name, llvm::ELF::STB_GLOBAL, - llvm::ELF::STV_DEFAULT, llvm::ELF::STT_NOTYPE) {} + llvm::ELF::STV_DEFAULT, llvm::ELF::STT_NOTYPE) { + isUsedInRegularObj = false; + } static bool classof(const Symbol *s) { return s->kind() == LazyObjectKind; } }; diff --git a/lld/test/ELF/lazy-arch-conflict.s b/lld/test/ELF/lazy-arch-conflict.s index 991476c5d6ec9..b6b41ae1025ac 100644 --- a/lld/test/ELF/lazy-arch-conflict.s +++ b/lld/test/ELF/lazy-arch-conflict.s @@ -4,4 +4,4 @@ # RUN: echo '.globl foo; foo:' | llvm-mc -filetype=obj -triple=i686-pc-linux - -o %t32.o # RUN: not ld.lld %t64.o --start-lib %t32.o --end-lib -o /dev/null 2>&1 | FileCheck %s -# CHECK: error: incompatible file: {{.*}}32.o +# CHECK: error: {{.*}}32.o is incompatible with {{.*}}64.o