From: Fangrui Song Date: Tue, 15 Feb 2022 17:38:00 +0000 (-0800) Subject: [ELF] Parse archives as --start-lib object files X-Git-Tag: upstream/15.0.7~16385 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3d85424096ff1e20ca735cbe455870cea7ed098f;p=platform%2Fupstream%2Fllvm.git [ELF] Parse archives as --start-lib object files https://maskray.me/blog/2022-01-16-archives-and-start-lib For every definition in an extracted archive member, we intern the symbol twice, once for the archive index entry, once for the .o symbol table after extraction. This is inefficient. Symbols in a --start-lib ObjFile/BitcodeFile are only interned once because the result is cached in symbols[i]. Just handle an archive using the --start-lib code path. We can therefore remove ArchiveFile and LazyArchive. For many projects, archive member extraction ratio is high and it is a net performance win. Linking a Release build of clang is 1.01x as fast. Note: --start-lib scans symbols in the same order that llvm-ar adds them to the index, so in the common case the semantics should be identical. If the archive symbol table was created in a different order, or is incomplete, this strategy may have different semantics. Such cases are considered user error. The `is neither ET_REL nor LLVM bitcode` error is changed to a warning. Previously an archive may have such members without a diagnostic. Using a warning prevents breakage. * For some tests, the diagnostics get improved where we did not consider the archive member name: `b.a:` => `b.a(b.o):`. * `no-obj.s`: the link is now allowed, matching GNU ld * `archive-no-index.s`: the `is neither ET_REL nor LLVM bitcode` diagnostic is demoted to a warning. * `incompatible.s`: even when an archive is unextracted, we may report an "incompatible with" error. --- I recently decreased sizeof(SymbolUnion) by 8 and decreased memory usage quite a bit, so retaining `symbols` for un-extracted archive members should not cause a memory usage problem. Reviewed By: peter.smith Differential Revision: https://reviews.llvm.org/D119074 --- diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index f586d01..aee700d 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -49,6 +49,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Config/llvm-config.h" #include "llvm/LTO/LTO.h" +#include "llvm/Object/Archive.h" #include "llvm/Remarks/HotnessThresholdParser.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" @@ -96,7 +97,6 @@ bool elf::link(ArrayRef args, llvm::raw_ostream &stdoutOS, inputSections.clear(); outputSections.clear(); memoryBuffers.clear(); - archiveFiles.clear(); binaryFiles.clear(); bitcodeFiles.clear(); lazyBitcodeFiles.clear(); @@ -228,32 +228,30 @@ void LinkerDriver::addFile(StringRef path, bool withLOption) { return; } - std::unique_ptr file = - CHECK(Archive::create(mbref), path + ": failed to parse archive"); - - // If an archive file has no symbol table, it may be intentional (used as a - // group of lazy object files where the symbol table is not useful), or the - // user is attempting LTO and using a default ar command that doesn't - // understand the LLVM bitcode file. Treat the archive as a group of lazy - // object files. - if (file->isEmpty() || file->hasSymbolTable()) { - // Handle the regular case. - files.push_back(make(std::move(file))); - return; - } - + auto members = getArchiveMembers(mbref); + archiveFiles.emplace_back(path, members.size()); + + // Handle archives and --start-lib/--end-lib using the same code path. This + // scans all the ELF relocatable object files and bitcode files in the + // archive rather than just the index file, with the benefit that the + // symbols are only loaded once. For many projects archives see high + // utilization rates and it is a net performance win. --start-lib scans + // symbols in the same order that llvm-ar adds them to the index, so in the + // common case the semantics are identical. If the archive symbol table was + // created in a different order, or is incomplete, this strategy has + // different semantics. Such output differences are considered user error. + // // All files within the archive get the same group ID to allow mutual // references for --warn-backrefs. bool saved = InputFile::isInGroup; InputFile::isInGroup = true; - for (const std::pair &p : - getArchiveMembers(mbref)) { + for (const std::pair &p : members) { auto magic = identify_magic(p.first.getBuffer()); if (magic == file_magic::bitcode || magic == file_magic::elf_relocatable) files.push_back(createLazyFile(p.first, path, p.second)); else - error(path + ": archive member '" + p.first.getBufferIdentifier() + - "' is neither ET_REL nor LLVM bitcode"); + warn(path + ": archive member '" + p.first.getBufferIdentifier() + + "' is neither ET_REL nor LLVM bitcode"); } InputFile::isInGroup = saved; if (!saved) @@ -1470,13 +1468,16 @@ void LinkerDriver::createFiles(opt::InputArgList &args) { // Iterate over argv to process input files and positional arguments. InputFile::isInGroup = false; + bool hasInput = false; for (auto *arg : args) { switch (arg->getOption().getID()) { case OPT_library: addLibrary(arg->getValue()); + hasInput = true; break; case OPT_INPUT: addFile(arg->getValue(), /*withLOption=*/false); + hasInput = true; break; case OPT_defsym: { StringRef from; @@ -1565,7 +1566,7 @@ void LinkerDriver::createFiles(opt::InputArgList &args) { } } - if (files.empty() && errorCount() == 0) + if (files.empty() && !hasInput && errorCount() == 0) error("no input files"); } @@ -1721,10 +1722,7 @@ static void handleLibcall(StringRef name) { return; MemoryBufferRef mb; - if (auto *lo = dyn_cast(sym)) - mb = lo->file->mb; - else - mb = cast(sym)->getMemberBuffer(); + mb = cast(sym)->file->mb; if (isBitcode(mb)) sym->extract(); diff --git a/lld/ELF/Driver.h b/lld/ELF/Driver.h index 878b5d3..8a7e5e4 100644 --- a/lld/ELF/Driver.h +++ b/lld/ELF/Driver.h @@ -42,6 +42,9 @@ private: std::unique_ptr lto; std::vector files; + +public: + SmallVector, 0> archiveFiles; }; // Parses command line options. diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 9f759e6..4f5c69f 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -43,7 +43,6 @@ bool InputFile::isInGroup; uint32_t InputFile::nextGroupId; SmallVector> elf::memoryBuffers; -SmallVector elf::archiveFiles; SmallVector elf::binaryFiles; SmallVector elf::bitcodeFiles; SmallVector elf::lazyBitcodeFiles; @@ -176,13 +175,6 @@ template static void doParseFile(InputFile *file) { return; } - // .a file - if (auto *f = dyn_cast(file)) { - archiveFiles.push_back(f); - f->parse(); - return; - } - // Lazy object file if (file->lazy) { if (auto *f = dyn_cast(file)) { @@ -1116,14 +1108,12 @@ void ObjFile::initializeSymbols(const object::ELFFile &obj) { // defined symbol in a .eh_frame becomes dangling symbols. if (sec == &InputSection::discarded) { Undefined und{this, StringRef(), binding, stOther, type, secIdx}; - // !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 && !sym->file->lazy)) { + // !LazyObjFile::lazy indicates 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::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. @@ -1159,44 +1149,6 @@ void ObjFile::initializeSymbols(const object::ELFFile &obj) { } } -ArchiveFile::ArchiveFile(std::unique_ptr &&file) - : InputFile(ArchiveKind, file->getMemoryBufferRef()), - file(std::move(file)) {} - -void ArchiveFile::parse() { - SymbolTable &symtab = *elf::symtab; - for (const Archive::Symbol &sym : file->symbols()) - symtab.addSymbol(LazyArchive{*this, sym}); - - // Inform a future invocation of ObjFile::initializeSymbols() that this - // archive has been processed. - parsed = true; -} - -// Returns a buffer pointing to a member file containing a given symbol. -void ArchiveFile::extract(const Archive::Symbol &sym) { - Archive::Child c = - CHECK(sym.getMember(), toString(this) + - ": could not get the member for symbol " + - toELFString(sym)); - - if (!seen.insert(c.getChildOffset()).second) - return; - - MemoryBufferRef mb = - CHECK(c.getMemoryBufferRef(), - toString(this) + - ": could not get the buffer for the member defining symbol " + - toELFString(sym)); - - if (tar && c.getParent()->isThin()) - tar->append(relativeToRoot(CHECK(c.getFullName(), this)), mb.getBuffer()); - - InputFile *file = createObjectFile(mb, getName(), c.getChildOffset()); - file->groupId = groupId; - parseFile(file); -} - // The handling of tentative definitions (COMMON symbols) in archives is murky. // A tentative definition will be promoted to a global definition if there are // no non-tentative definitions to dominate it. When we hold a tentative @@ -1263,36 +1215,6 @@ static bool isNonCommonDef(MemoryBufferRef mb, StringRef symName, } } -bool ArchiveFile::shouldExtractForCommon(const Archive::Symbol &sym) { - Archive::Child c = - CHECK(sym.getMember(), toString(this) + - ": could not get the member for symbol " + - toELFString(sym)); - MemoryBufferRef mb = - CHECK(c.getMemoryBufferRef(), - toString(this) + - ": could not get the buffer for the member defining symbol " + - toELFString(sym)); - - if (isBitcode(mb)) - return isBitcodeNonCommonDef(mb, sym.getName(), getName()); - - return isNonCommonDef(mb, sym.getName(), getName()); -} - -size_t ArchiveFile::getMemberCount() const { - size_t count = 0; - Error err = Error::success(); - for (const Archive::Child &c : file->children(err)) { - (void)c; - ++count; - } - // This function is used by --print-archive-stats=, where an error does not - // really matter. - consumeError(std::move(err)); - return count; -} - unsigned SharedFile::vernauxNum; // Parse the version definitions in the object file if present, and return a diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h index 7634586..bbd3072 100644 --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -15,8 +15,8 @@ #include "lld/Common/Reproduce.h" #include "llvm/ADT/DenseSet.h" #include "llvm/BinaryFormat/Magic.h" -#include "llvm/Object/Archive.h" #include "llvm/Object/ELF.h" +#include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/Threading.h" namespace llvm { @@ -35,8 +35,6 @@ std::string toString(const elf::InputFile *f); namespace elf { -using llvm::object::Archive; - class InputSection; class Symbol; @@ -310,33 +308,6 @@ private: llvm::once_flag initDwarf; }; -// An ArchiveFile object represents a .a file. -class ArchiveFile : public InputFile { -public: - explicit ArchiveFile(std::unique_ptr &&file); - static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; } - void parse(); - - // Pulls out an object file that contains a definition for Sym and - // returns it. If the same file was instantiated before, this - // function does nothing (so we don't instantiate the same file - // more than once.) - void extract(const Archive::Symbol &sym); - - // Check if a non-common symbol should be extracted to override a common - // definition. - bool shouldExtractForCommon(const Archive::Symbol &sym); - - size_t getMemberCount() const; - size_t getExtractedMemberCount() const { return seen.size(); } - - bool parsed = false; - -private: - std::unique_ptr file; - llvm::DenseSet seen; -}; - class BitcodeFile : public InputFile { public: BitcodeFile(MemoryBufferRef m, StringRef archiveName, @@ -403,7 +374,6 @@ inline bool isBitcode(MemoryBufferRef mb) { std::string replaceThinLTOSuffix(StringRef path); extern SmallVector> memoryBuffers; -extern SmallVector archiveFiles; extern SmallVector binaryFiles; extern SmallVector bitcodeFiles; extern SmallVector lazyBitcodeFiles; diff --git a/lld/ELF/MapFile.cpp b/lld/ELF/MapFile.cpp index a201ec5..54cacb8 100644 --- a/lld/ELF/MapFile.cpp +++ b/lld/ELF/MapFile.cpp @@ -19,6 +19,7 @@ //===----------------------------------------------------------------------===// #include "MapFile.h" +#include "Driver.h" #include "InputFiles.h" #include "LinkerScript.h" #include "OutputSections.h" @@ -307,7 +308,19 @@ void elf::writeArchiveStats() { } os << "members\textracted\tarchive\n"; - for (const ArchiveFile *f : archiveFiles) - os << f->getMemberCount() << '\t' << f->getExtractedMemberCount() << '\t' - << f->getName() << '\n'; + + SmallVector archives; + DenseMap all, extracted; + for (ELFFileBase *file : objectFiles) + if (file->archiveName.size()) + ++extracted[CachedHashStringRef(file->archiveName)]; + for (BitcodeFile *file : bitcodeFiles) + if (file->archiveName.size()) + ++extracted[CachedHashStringRef(file->archiveName)]; + for (std::pair f : driver->archiveFiles) { + unsigned &v = extracted[CachedHashString(f.first)]; + os << f.second << '\t' << v << '\t' << f.first << '\n'; + // If the archive occurs multiple times, other instances have a count of 0. + v = 0; + } } diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 86a2819..e604d35 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -33,10 +33,6 @@ std::string lld::toString(const elf::Symbol &sym) { return ret; } -std::string lld::toELFString(const Archive::Symbol &b) { - return demangle(b.getName(), config->demangle); -} - Defined *ElfSym::bss; Defined *ElfSym::etext1; Defined *ElfSym::etext2; @@ -129,7 +125,6 @@ static uint64_t getSymVA(const Symbol &sym, int64_t addend) { case Symbol::SharedKind: case Symbol::UndefinedKind: return 0; - case Symbol::LazyArchiveKind: case Symbol::LazyObjectKind: llvm_unreachable("lazy symbol reached writer"); case Symbol::CommonKind: @@ -246,24 +241,12 @@ void Symbol::parseSymbolVersion() { } void Symbol::extract() const { - if (auto *sym = dyn_cast(this)) { - cast(sym->file)->extract(sym->sym); - } else if (file->lazy) { + if (file->lazy) { file->lazy = false; parseFile(file); } } -MemoryBufferRef LazyArchive::getMemberBuffer() { - Archive::Child c = - CHECK(sym.getMember(), - "could not get the member for symbol " + toELFString(sym)); - - return CHECK(c.getMemoryBufferRef(), - "could not get the buffer for the member defining symbol " + - toELFString(sym)); -} - uint8_t Symbol::computeBinding() const { if ((visibility != STV_DEFAULT && visibility != STV_PROTECTED) || versionId == VER_NDX_LOCAL) @@ -428,9 +411,6 @@ void Symbol::resolve(const Symbol &other) { case Symbol::DefinedKind: resolveDefined(cast(other)); break; - case Symbol::LazyArchiveKind: - resolveLazy(cast(other)); - break; case Symbol::LazyObjectKind: resolveLazy(cast(other)); break; @@ -691,14 +671,7 @@ template void Symbol::resolveLazy(const LazyT &other) { // For common objects, we want to look for global or weak definitions that // should be extracted as the canonical definition instead. if (isCommon() && elf::config->fortranCommon) { - if (auto *laSym = dyn_cast(&other)) { - ArchiveFile *archive = cast(laSym->file); - const Archive::Symbol &archiveSym = laSym->sym; - if (archive->shouldExtractForCommon(archiveSym)) { - replaceCommon(*this, other); - return; - } - } else if (auto *loSym = dyn_cast(&other)) { + if (auto *loSym = dyn_cast(&other)) { if (loSym->file->shouldExtractForCommon(getName())) { replaceCommon(*this, other); return; diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index c499964..6cd8370 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -17,7 +17,6 @@ #include "lld/Common/LLVM.h" #include "lld/Common/Memory.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/Object/Archive.h" #include "llvm/Object/ELF.h" #include @@ -25,11 +24,6 @@ namespace lld { // Returns a string representation for a symbol for diagnostics. std::string toString(const elf::Symbol &); -// There are two different ways to convert an Archive::Symbol to a string: -// One for Microsoft name mangling and one for Itanium name mangling. -// Call the functions toCOFFString and toELFString, not just toString. -std::string toELFString(const llvm::object::Archive::Symbol &); - namespace elf { class CommonSymbol; class Defined; @@ -59,7 +53,6 @@ public: CommonKind, SharedKind, UndefinedKind, - LazyArchiveKind, LazyObjectKind, }; @@ -152,9 +145,7 @@ public: bool isLocal() const { return binding == llvm::ELF::STB_LOCAL; } - bool isLazy() const { - return symbolKind == LazyArchiveKind || symbolKind == LazyObjectKind; - } + bool isLazy() const { return symbolKind == LazyObjectKind; } // True if this is an undefined weak symbol. This only works once // all input files have been added. @@ -417,36 +408,15 @@ public: uint32_t alignment; }; -// LazyArchive and LazyObject represent a symbols that is not yet in the link, -// but we know where to find it if needed. If the resolver finds both Undefined -// and Lazy for the same name, it will ask the Lazy to load a file. +// LazyObject symbols represent symbols in object files between --start-lib and +// --end-lib options. LLD also handles traditional archives as if all the files +// in the archive are surrounded by --start-lib and --end-lib. // // A special complication is the handling of weak undefined symbols. They should // not load a file, but we have to remember we have seen both the weak undefined // and the lazy. We represent that with a lazy symbol with a weak binding. This // means that code looking for undefined symbols normally also has to take lazy // symbols into consideration. - -// 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. -class LazyArchive : public Symbol { -public: - LazyArchive(InputFile &file, const llvm::object::Archive::Symbol s) - : Symbol(LazyArchiveKind, &file, s.getName(), llvm::ELF::STB_GLOBAL, - llvm::ELF::STV_DEFAULT, llvm::ELF::STT_NOTYPE), - sym(s) {} - - static bool classof(const Symbol *s) { return s->kind() == LazyArchiveKind; } - - MemoryBufferRef getMemberBuffer(); - - const llvm::object::Archive::Symbol sym; -}; - -// LazyObject symbols represents symbols in object files between -// --start-lib and --end-lib options. class LazyObject : public Symbol { public: LazyObject(InputFile &file) @@ -505,8 +475,7 @@ union SymbolUnion { alignas(CommonSymbol) char b[sizeof(CommonSymbol)]; alignas(Undefined) char c[sizeof(Undefined)]; alignas(SharedSymbol) char d[sizeof(SharedSymbol)]; - alignas(LazyArchive) char e[sizeof(LazyArchive)]; - alignas(LazyObject) char f[sizeof(LazyObject)]; + alignas(LazyObject) char e[sizeof(LazyObject)]; }; // It is important to keep the size of SymbolUnion small for performance and @@ -527,7 +496,6 @@ static inline void assertSymbols() { AssertSymbol(); AssertSymbol(); AssertSymbol(); - AssertSymbol(); AssertSymbol(); } @@ -539,8 +507,6 @@ size_t Symbol::getSymbolSize() const { return sizeof(CommonSymbol); case DefinedKind: return sizeof(Defined); - case LazyArchiveKind: - return sizeof(LazyArchive); case LazyObjectKind: return sizeof(LazyObject); case SharedKind: diff --git a/lld/test/ELF/archive-as-start-lib.s b/lld/test/ELF/archive-as-start-lib.s new file mode 100644 index 0000000..aa86ce8 --- /dev/null +++ b/lld/test/ELF/archive-as-start-lib.s @@ -0,0 +1,31 @@ +# REQUIRES: x86 + +# RUN: rm -rf %t && split-file %s %t && cd %t +# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o +# RUN: llvm-mc -filetype=obj -triple=x86_64 b.s -o b.o + +## Create an archive with incomplete index: foo is missing. +# RUN: llvm-ar --format=gnu rc a.a a.o +# RUN: llvm-ar --format=gnu rcS b.a b.o && tail -c +9 b.a > b-tail +# RUN: cat a.a b-tail > weird.a +# RUN: llvm-nm --print-armap weird.a | FileCheck %s --check-prefix=ARMAP + +# ARMAP: Archive map +# ARMAP-NEXT: _start in a.o +# ARMAP-EMPTY: + +## The incomplete archive index is ignored. -u foo extracts weird.a(b.o). +## In GNU ld, foo is undefined. +# RUN: ld.lld -m elf_x86_64 -u foo weird.a -o lazy +# RUN: llvm-nm lazy | FileCheck %s --implicit-check-not={{.}} + +# CHECK: [[#%x,]] T _start +# CHECK: [[#%x,]] T foo + +#--- a.s +.globl _start +_start: + +#--- b.s +.globl foo +foo: diff --git a/lld/test/ELF/archive-no-index.s b/lld/test/ELF/archive-no-index.s index 2590517..23b019e 100644 --- a/lld/test/ELF/archive-no-index.s +++ b/lld/test/ELF/archive-no-index.s @@ -9,9 +9,9 @@ # RUN: ld.lld -shared %t.archive.o -o %t.so # RUN: llvm-ar crS %t.a %t.so -# RUN: not ld.lld %t.o %t.a --noinhibit-exec -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR +# RUN: ld.lld %t.o %t.a -o /dev/null 2>&1 | FileCheck %s --check-prefix=WARN -# ERR: error: {{.*}}.a: archive member '{{.*}}.so' is neither ET_REL nor LLVM bitcode +# WARN: warning: {{.*}}.a: archive member '{{.*}}.so' is neither ET_REL nor LLVM bitcode .globl _start _start: diff --git a/lld/test/ELF/archive-thin-missing-member.s b/lld/test/ELF/archive-thin-missing-member.s index 473ebe9..1d77045 100644 --- a/lld/test/ELF/archive-thin-missing-member.s +++ b/lld/test/ELF/archive-thin-missing-member.s @@ -13,13 +13,11 @@ # Test error when thin archive has symbol table but member is missing. # RUN: not ld.lld --entry=_Z1fi -m elf_amd64_fbsd %t-syms.a -o /dev/null 2>&1 | FileCheck -DMSG=%errc_ENOENT %s --check-prefix=ERR2 -# ERR2: {{.*}}-syms.a: could not get the buffer for the member defining symbol f(int): '{{.*}}.o': [[MSG]] -# RUN: not ld.lld --entry=_Z1fi --no-demangle -m elf_amd64_fbsd %t-syms.a -o /dev/null 2>&1 | FileCheck -DMSG=%errc_ENOENT %s --check-prefix=ERR2MANGLE -# ERR2MANGLE: {{.*}}-syms.a: could not get the buffer for the member defining symbol _Z1fi: '{{.*}}.o': [[MSG]] +# RUN: not ld.lld --entry=_Z1fi --no-demangle -m elf_amd64_fbsd %t-syms.a -o /dev/null 2>&1 | FileCheck -DMSG=%errc_ENOENT %s --check-prefix=ERR2 # Test error when thin archive is linked using --whole-archive but member is missing. -# RUN: not ld.lld --entry=_Z1fi --whole-archive %t-syms.a -o /dev/null 2>&1 | FileCheck -DMSG=%errc_ENOENT %s --check-prefix=ERR3 -# ERR3: {{.*}}-syms.a: could not get the buffer for a child of the archive: '{{.*}}.o': [[MSG]] +# RUN: not ld.lld --entry=_Z1fi --whole-archive %t-syms.a -o /dev/null 2>&1 | FileCheck -DMSG=%errc_ENOENT %s --check-prefix=ERR2 +# ERR2: {{.*}}-syms.a: could not get the buffer for a child of the archive: '{{.*}}.o': [[MSG]] .global _Z1fi _Z1fi: diff --git a/lld/test/ELF/incompatible-ar-first.s b/lld/test/ELF/incompatible-ar-first.s index a82a55a..f9688fd 100644 --- a/lld/test/ELF/incompatible-ar-first.s +++ b/lld/test/ELF/incompatible-ar-first.s @@ -8,8 +8,7 @@ // We used to crash when // * The first object seen by the symbol table is from an archive. // * -m was not used. -// CHECK: .a({{.*}}a.o) is incompatible with {{.*}}b.o -// RUN: not ld.lld --start-lib %ta.o --end-lib %tb.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK2 +// RUN: not ld.lld --start-lib %ta.o --end-lib %tb.o -o /dev/null 2>&1 | FileCheck %s -// CHECK2: {{.*}}b.o is incompatible{{$}} +// CHECK: {{.*}}b.o is incompatible{{$}} diff --git a/lld/test/ELF/incompatible.s b/lld/test/ELF/incompatible.s index c274dfd..39c2510 100644 --- a/lld/test/ELF/incompatible.s +++ b/lld/test/ELF/incompatible.s @@ -58,14 +58,19 @@ // RUN: FileCheck --check-prefix=A-AND-FREEBSD-SCRIPT %s // A-AND-FREEBSD-SCRIPT: a.o is incompatible with elf32-i386-freebsd +/// %tb.a is not extracted, but we report an error anyway. +// RUN: rm -f %tb.a && llvm-ar rc %tb.a %tb.o +// RUN: not ld.lld %ta.o %tb.a -o /dev/null 2>&1 | FileCheck --check-prefix=UNEXTRACTED-ARCHIVE %s +// UNEXTRACTED-ARCHIVE: {{.*}}.a({{.*}}b.o) is incompatible with {{.*}}a.o + // We used to fail to identify this incompatibility and crash trying to // read a 64 bit file as a 32 bit one. -// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/archive2.s -o %ta.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/archive2.s -o %tc.o // RUN: rm -f %t.a -// RUN: llvm-ar rc %t.a %ta.o -// RUN: llvm-mc -filetype=obj -triple=i686-linux %s -o %tb.o -// RUN: not ld.lld %t.a %tb.o 2>&1 -o /dev/null | FileCheck --check-prefix=ARCHIVE %s -// ARCHIVE: .a({{.*}}a.o) is incompatible with {{.*}}b.o +// RUN: llvm-ar rc %t.a %tc.o +// RUN: llvm-mc -filetype=obj -triple=i686-linux %s -o %td.o +// RUN: not ld.lld %t.a %td.o 2>&1 -o /dev/null | FileCheck --check-prefix=ARCHIVE %s +// ARCHIVE: {{.*}}d.o is incompatible .global _start _start: .data diff --git a/lld/test/ELF/lto/comdat-mixed-archive.test b/lld/test/ELF/lto/comdat-mixed-archive.test index 98cba1f..52cd4cf 100644 --- a/lld/test/ELF/lto/comdat-mixed-archive.test +++ b/lld/test/ELF/lto/comdat-mixed-archive.test @@ -27,8 +27,8 @@ BCSYM: U bar BCSYM-NEXT: W foo ;; Check that the symbols are handled in the expected order. -TRACE: lib.a: lazy definition of foo -TRACE-NEXT: lib.a: lazy definition of bar +TRACE: lib.a(obj.o): lazy definition of foo +TRACE-NEXT: lib.a(obj.o): lazy definition of bar TRACE-NEXT: lib.a(bc.bc): reference to bar TRACE-NEXT: lib.a(obj.o): reference to foo TRACE-NEXT: lib.a(obj.o): definition of bar diff --git a/lld/test/ELF/lto/exclude-libs-libcall.ll b/lld/test/ELF/lto/exclude-libs-libcall.ll index ece587f..3fdffb4 100644 --- a/lld/test/ELF/lto/exclude-libs-libcall.ll +++ b/lld/test/ELF/lto/exclude-libs-libcall.ll @@ -6,7 +6,7 @@ ; RUN: ld.lld -shared --exclude-libs=b.a %t/a.bc %t/b.a -o %t.so -y __divti3 2>&1 | FileCheck %s --check-prefix=TRACE ; RUN: llvm-readelf --dyn-syms %t.so | FileCheck %s -; TRACE: {{.*}}/b.a: lazy definition of __divti3 +; TRACE: {{.*}}/b.a(b.o): lazy definition of __divti3 ; TRACE-NEXT: lto.tmp: reference to __divti3 ; TRACE-NEXT: {{.*}}/b.a(b.o): definition of __divti3 diff --git a/lld/test/ELF/no-obj.s b/lld/test/ELF/no-obj.s index 4e8bcee..ce89ca9 100644 --- a/lld/test/ELF/no-obj.s +++ b/lld/test/ELF/no-obj.s @@ -2,9 +2,7 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: rm -f %t.a // RUN: llvm-ar rcs %t.a %t.o -// RUN: not ld.lld -o /dev/null -u _start %t.a 2>&1 | FileCheck %s - -// CHECK: target emulation unknown: -m or at least one .o file required +// RUN: ld.lld -o /dev/null -u _start %t.a 2>&1 | count 0 .global _start _start: diff --git a/lld/test/ELF/trace-symbols.s b/lld/test/ELF/trace-symbols.s index f5211b3..785414e 100644 --- a/lld/test/ELF/trace-symbols.s +++ b/lld/test/ELF/trace-symbols.s @@ -50,7 +50,7 @@ # RUN: FileCheck -check-prefix=FOO_AND_COMMON %s # FOO_AND_COMMON: trace-symbols.s.tmp: reference to foo # FOO_AND_COMMON: trace-symbols.s.tmp2: definition of foo -# FOO_AND_COMMON: trace-symbols.s.tmp1.a: lazy definition of common +# FOO_AND_COMMON: trace-symbols.s.tmp1.a({{.*}}.tmp1): lazy definition of common # RUN: ld.lld -y foo -y common %t %t1.so %t2 -o %t3 | \ # RUN: FileCheck -check-prefix=SHLIBDCOMMON %s