Index: ELF/Driver.h =================================================================== --- ELF/Driver.h +++ ELF/Driver.h @@ -35,6 +35,7 @@ llvm::BumpPtrAllocator Alloc; bool WholeArchive = false; + bool InLib = false; std::vector> Files; std::vector> OwningMBs; }; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -129,7 +129,10 @@ Files.push_back(createSharedFile(MBRef)); return; default: - Files.push_back(createObjectFile(MBRef)); + if (InLib) + Files.push_back(createLazyObjectFile(MBRef)); + else + Files.push_back(createObjectFile(MBRef)); } } @@ -359,6 +362,12 @@ case OPT_no_whole_archive: WholeArchive = false; break; + case OPT_start_lib: + InLib = true; + break; + case OPT_end_lib: + InLib = false; + break; } } Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -36,7 +36,14 @@ // The root class of input files. class InputFile { public: - enum Kind { ObjectKind, SharedKind, ArchiveKind, BitcodeKind }; + enum Kind { + ObjectKind, + LazyObjectKind, + SharedKind, + ArchiveKind, + BitcodeKind + }; + Kind kind() const { return FileKind; } StringRef getName() const { return MB.getBufferIdentifier(); } @@ -62,9 +69,10 @@ typedef typename ELFT::SymRange Elf_Sym_Range; ELFFileBase(Kind K, MemoryBufferRef M); + static bool classof(const InputFile *F) { Kind K = F->kind(); - return K == ObjectKind || K == SharedKind; + return K == ObjectKind || K == LazyObjectKind || K == SharedKind; } static ELFKind getELFKind(); @@ -154,6 +162,24 @@ llvm::SpecificBumpPtrAllocator> EHAlloc; }; +template class LazyObjectFile : public ELFFileBase { + typedef ELFFileBase Base; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::SymRange Elf_Sym_Range; + +public: + explicit LazyObjectFile(MemoryBufferRef M); + static bool classof(const InputFile *F) { + return F->kind() == Base::LazyObjectKind; + } + void parse(); + + llvm::MutableArrayRef getLazySymbols() { return LazySymbols; } + +private: + std::vector LazySymbols; +}; + class ArchiveFile : public InputFile { public: explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} @@ -165,11 +191,11 @@ // (So that we don't instantiate same members more than once.) MemoryBufferRef getMember(const Archive::Symbol *Sym); - llvm::MutableArrayRef getLazySymbols() { return LazySymbols; } + llvm::MutableArrayRef getLazySymbols() { return LazySymbols; } private: std::unique_ptr File; - std::vector LazySymbols; + std::vector LazySymbols; llvm::DenseSet Seen; }; @@ -228,6 +254,7 @@ std::unique_ptr createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = ""); +std::unique_ptr createLazyObjectFile(MemoryBufferRef MB); std::unique_ptr createSharedFile(MemoryBufferRef MB); } // namespace elf Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -282,6 +282,10 @@ } template void elf::ObjectFile::initializeSymbols() { + for (const Elf_Shdr &Sec : this->ELFObj.sections()) + if (Sec.sh_type == SHT_DYNSYM) + this->Symtab = &Sec; + this->initStringTable(); Elf_Sym_Range Syms = this->getElfSymbols(false); uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end()); @@ -336,6 +340,19 @@ } } +template +LazyObjectFile::LazyObjectFile(MemoryBufferRef M) + : ELFFileBase(Base::LazyObjectKind, M) {} + +template void LazyObjectFile::parse() { + this->initStringTable(); + Elf_Sym_Range Syms = this->getElfSymbols(true); + uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end()); + LazySymbols.reserve(NumSymbols); + for (const Elf_Sym &Sym : Syms) + LazySymbols.emplace_back(check(Sym.getName(this->StringTable)), this->MB); +} + void ArchiveFile::parse() { File = check(Archive::create(MB), "failed to parse archive"); @@ -560,6 +577,10 @@ return F; } +std::unique_ptr elf::createLazyObjectFile(MemoryBufferRef MB) { + return createELFFile(MB); +} + std::unique_ptr elf::createSharedFile(MemoryBufferRef MB) { return createELFFile(MB); } @@ -574,6 +595,11 @@ template class elf::ObjectFile; template class elf::ObjectFile; +template class elf::LazyObjectFile; +template class elf::LazyObjectFile; +template class elf::LazyObjectFile; +template class elf::LazyObjectFile; + template class elf::SharedFile; template class elf::SharedFile; template class elf::SharedFile; Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -48,6 +48,8 @@ def enable_new_dtags : Flag<["--"], "enable-new-dtags">, HelpText<"Enable new dynamic tags">; +def end_lib : Flag<["--"], "end-lib">; + def entry : Separate<["--", "-"], "entry">, MetaVarName<"">, HelpText<"Name of entry point symbol">; @@ -121,6 +123,8 @@ def soname : Joined<["-"], "soname=">, HelpText<"Set DT_SONAME">; +def start_lib : Flag<["--"], "start-lib">; + def strip_all : Flag<["--"], "strip-all">, HelpText<"Strip all symbols">; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -1502,7 +1502,8 @@ break; case SymbolBody::UndefinedElfKind: case SymbolBody::UndefinedKind: - case SymbolBody::LazyKind: + case SymbolBody::LazyArchiveKind: + case SymbolBody::LazyObjectKind: break; case SymbolBody::DefinedBitcodeKind: llvm_unreachable("should have been replaced"); Index: ELF/SymbolTable.h =================================================================== --- ELF/SymbolTable.h +++ ELF/SymbolTable.h @@ -88,7 +88,7 @@ llvm::DenseSet ComdatGroups; // The symbol table owns all file objects. - std::vector> ArchiveFiles; + std::vector> OwningFiles; std::vector>> ObjectFiles; std::vector>> SharedFiles; std::vector> BitcodeFiles; Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -54,7 +54,7 @@ // .a file if (auto *F = dyn_cast(FileP)) { - ArchiveFiles.emplace_back(cast(File.release())); + OwningFiles.emplace_back(cast(File.release())); F->parse(); for (Lazy &Sym : F->getLazySymbols()) addLazy(&Sym); @@ -85,6 +85,15 @@ return; } + // Lazy .o file + if (auto *F = dyn_cast>(FileP)) { + OwningFiles.emplace_back(cast(File.release())); + F->parse(); + for (Lazy &Sym : F->getLazySymbols()) + addLazy(&Sym); + return; + } + // .o file auto *F = cast>(FileP); ObjectFiles.emplace_back(cast>(File.release())); @@ -302,8 +311,8 @@ } // Fetch a member file that has the definition for L. - // getMember returns nullptr if the member was already read from the library. - if (std::unique_ptr File = L->getMember()) + // getObject returns nullptr if the member was already read from the library. + if (std::unique_ptr File = L->getObject()) addFile(std::move(File)); } Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -57,7 +57,8 @@ DefinedLast = DefinedSyntheticKind, UndefinedElfKind, UndefinedKind, - LazyKind + LazyArchiveKind, + LazyObjectKind, }; Kind kind() const { return static_cast(SymbolKind); } @@ -68,7 +69,9 @@ } bool isDefined() const { return SymbolKind <= DefinedLast; } bool isCommon() const { return SymbolKind == DefinedCommonKind; } - bool isLazy() const { return SymbolKind == LazyKind; } + bool isLazy() const { + return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind; + } bool isShared() const { return SymbolKind == SharedKind; } bool isLocal() const { return Binding == llvm::ELF::STB_LOCAL; } bool isUsedInRegularObj() const { return IsUsedInRegularObj; } @@ -130,8 +133,8 @@ Type(Type), Binding(Binding), StOther(StOther), Name({Name.data(), Name.size()}) { assert(!isLocal()); - IsUsedInRegularObj = - K != SharedKind && K != LazyKind && K != DefinedBitcodeKind; + IsUsedInRegularObj = K != SharedKind && K != LazyArchiveKind && + K != LazyObjectKind && K != DefinedBitcodeKind; } SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type); @@ -345,22 +348,51 @@ // the same name, it will ask the Lazy to load a file. class Lazy : public SymbolBody { public: - Lazy(ArchiveFile *F, const llvm::object::Archive::Symbol S) - : SymbolBody(LazyKind, S.getName(), llvm::ELF::STB_GLOBAL, - llvm::ELF::STV_DEFAULT, /* Type */ 0), - File(F), Sym(S) {} - - static bool classof(const SymbolBody *S) { return S->kind() == LazyKind; } + static bool classof(const SymbolBody *S) { + return S->kind() == LazyArchiveKind || S->kind() == LazyObjectKind; + } // Returns an object file for this symbol, or a nullptr if the file // was already returned. - std::unique_ptr getMember(); + std::unique_ptr getObject(); + +protected: + Lazy(SymbolBody::Kind K, StringRef Name) + : SymbolBody(K, Name, llvm::ELF::STB_GLOBAL, llvm::ELF::STV_DEFAULT, + /* Type */ 0) {} +}; + +class LazyArchive : public Lazy { +public: + LazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S) + : Lazy(LazyArchiveKind, S.getName()), File(F), Sym(S) {} + + static bool classof(const SymbolBody *S) { + return S->kind() == LazyArchiveKind; + } + + std::unique_ptr getObject(); private: ArchiveFile *File; const llvm::object::Archive::Symbol Sym; }; +class LazyObject : public Lazy { +public: + LazyObject(StringRef Name, MemoryBufferRef M) + : Lazy(LazyObjectKind, Name), MBRef(M) {} + + static bool classof(const SymbolBody *S) { + return S->kind() == LazyObjectKind; + } + + std::unique_ptr getObject(); + +private: + MemoryBufferRef MBRef; +}; + // Some linker-generated symbols need to be created as // DefinedRegular symbols. template struct ElfSym { Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -78,7 +78,8 @@ case SymbolBody::UndefinedElfKind: case SymbolBody::UndefinedKind: return 0; - case SymbolBody::LazyKind: + case SymbolBody::LazyArchiveKind: + case SymbolBody::LazyObjectKind: assert(Body.isUsedInRegularObj() && "lazy symbol reached writer"); return 0; case SymbolBody::DefinedBitcodeKind: @@ -91,8 +92,8 @@ uint8_t Type) : SymbolKind(K), MustBeInDynSym(false), NeedsCopyOrPltAddr(false), Type(Type), Binding(STB_LOCAL), StOther(StOther), NameOffset(NameOffset) { - IsUsedInRegularObj = - K != SharedKind && K != LazyKind && K != DefinedBitcodeKind; + IsUsedInRegularObj = K != SharedKind && K != LazyArchiveKind && + K != LazyObjectKind && K != DefinedBitcodeKind; } // Returns true if a symbol can be replaced at load-time by a symbol @@ -281,16 +282,24 @@ : Defined(SymbolBody::DefinedCommonKind, N, Binding, Visibility, Type), Alignment(Alignment), Size(Size) {} -std::unique_ptr Lazy::getMember() { +std::unique_ptr Lazy::getObject() { + return cast(this)->getObject(); +} + +std::unique_ptr LazyArchive::getObject() { MemoryBufferRef MBRef = File->getMember(&Sym); - // getMember returns an empty buffer if the member was already + // getObject returns an empty buffer if the member was already // read from the library. if (MBRef.getBuffer().empty()) return std::unique_ptr(nullptr); return createObjectFile(MBRef, File->getName()); } +std::unique_ptr LazyObject::getObject() { + return createObjectFile(MBRef); +} + // Returns the demangled C++ symbol name for Name. std::string elf::demangle(StringRef Name) { #if !defined(HAVE_CXXABI_H) Index: test/ELF/start-lib.s =================================================================== --- /dev/null +++ test/ELF/start-lib.s @@ -0,0 +1,16 @@ +// REQUIRES: x86 + +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ +// RUN: %p/Inputs/whole-archive.s -o %t2.o + +// RUN: ld.lld -o %t3 %t1.o %t2.o +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=ADDED %s +// ADDED: Name: _bar + +// RUN: ld.lld -o %t3 %t1.o --start-lib %t2.o +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=LIB %s +// LIB-NOT: Name: _bar + +.globl _start +_start: