Index: ELF/Driver.h =================================================================== --- ELF/Driver.h +++ ELF/Driver.h @@ -34,7 +34,10 @@ class LinkerDriver { public: - void link(ArrayRef Args); + void main(ArrayRef Args); + void createFiles(llvm::opt::InputArgList &Args); + template void link(llvm::opt::InputArgList &Args); + void addFile(StringRef Path); private: Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -20,6 +20,7 @@ using namespace llvm; using namespace llvm::ELF; +using namespace llvm::object; using namespace lld; using namespace lld::elf2; @@ -32,7 +33,7 @@ LinkerDriver D; Config = &C; Driver = &D; - Driver->link(Args.slice(1)); + Driver->main(Args.slice(1)); } static void setELFType(StringRef Emul) { @@ -131,12 +132,31 @@ return Default; } -void LinkerDriver::link(ArrayRef ArgsArr) { +void LinkerDriver::main(ArrayRef ArgsArr) { initSymbols(); - // Parse command line options. opt::InputArgList Args = Parser.parse(ArgsArr); + createFiles(Args); + switch (Config->ElfKind) { + case ELF32LEKind: + link(Args); + return; + case ELF32BEKind: + link(Args); + return; + case ELF64LEKind: + link(Args); + return; + case ELF64BEKind: + link(Args); + return; + default: + llvm_unreachable("Invalid kind"); + } +} + +void LinkerDriver::createFiles(opt::InputArgList &Args) { for (auto *Arg : Args.filtered(OPT_L)) Config->InputSearchPaths.push_back(Arg->getValue()); @@ -223,8 +243,10 @@ B = Arg->getValue(); error(A + " is incompatible with " + B); } +} - SymbolTable Symtab; +template void LinkerDriver::link(opt::InputArgList &Args) { + SymbolTable Symtab; for (std::unique_ptr &F : Files) Symtab.addFile(std::move(F)); @@ -236,5 +258,5 @@ Config->OutputFile = "a.out"; // Write the result to the file. - writeResult(&Symtab); + writeResult(&Symtab); } Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -23,7 +23,7 @@ namespace elf2 { class SymbolBody; -class SymbolTable; +template class SymbolTable; template class SymbolTableSection; template class StringTableSection; template class InputSection; @@ -148,7 +148,7 @@ typedef typename llvm::object::ELFFile::Elf_Sym Elf_Sym; typedef typename llvm::object::ELFFile::Elf_Sym_Range Elf_Sym_Range; typedef typename OutputSectionBase::uintX_t uintX_t; - SymbolTableSection(SymbolTable &Table, + SymbolTableSection(SymbolTable &Table, StringTableSection &StrTabSec); void finalize() override; @@ -161,7 +161,7 @@ void writeLocalSymbols(uint8_t *&Buf); void writeGlobalSymbols(uint8_t *&Buf); - SymbolTable &Table; + SymbolTable &Table; StringTableSection &StrTabSec; unsigned NumVisible = 0; unsigned NumLocals = 0; @@ -267,7 +267,7 @@ typedef typename llvm::object::ELFFile::Elf_Dyn Elf_Dyn; public: - DynamicSection(SymbolTable &SymTab); + DynamicSection(SymbolTable &SymTab); void finalize() override; void writeTo(uint8_t *Buf) override; @@ -276,7 +276,7 @@ OutputSection *FiniArraySec = nullptr; private: - SymbolTable &SymTab; + SymbolTable &SymTab; const ELFSymbolBody *InitSym = nullptr; const ELFSymbolBody *FiniSym = nullptr; }; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -273,7 +273,7 @@ } template -DynamicSection::DynamicSection(SymbolTable &SymTab) +DynamicSection::DynamicSection(SymbolTable &SymTab) : OutputSectionBase(".dynamic", llvm::ELF::SHT_DYNAMIC, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE), @@ -544,7 +544,7 @@ template SymbolTableSection::SymbolTableSection( - SymbolTable &Table, StringTableSection &StrTabSec) + SymbolTable &Table, StringTableSection &StrTabSec) : OutputSectionBase( StrTabSec.isDynamic() ? ".dynsym" : ".symtab", StrTabSec.isDynamic() ? llvm::ELF::SHT_DYNSYM : llvm::ELF::SHT_SYMTAB, Index: ELF/SymbolTable.h =================================================================== --- ELF/SymbolTable.h +++ ELF/SymbolTable.h @@ -27,7 +27,7 @@ // an undefined symbol. Or, if there's a conflict between a lazy and a // undefined, it'll read an archive member to read a real definition // to replace the lazy symbol. The logic is implemented in resolve(). -class SymbolTable { +template class SymbolTable { public: SymbolTable(); @@ -63,23 +63,18 @@ void addUndefinedSym(StringRef Name); - template void addSyntheticSym(StringRef Name, OutputSection &Section, typename llvm::object::ELFFile::uintX_t Value); - template void addIgnoredSym(StringRef Name); + void addIgnoredSym(StringRef Name); private: Symbol *insert(SymbolBody *New); - template void addELFFile(ELFFileBase *File); void addELFFile(ELFFileBase *File); void addLazy(Lazy *New); void addMemberFile(Lazy *Body); - template void addUndefinedSym(StringRef Name); - - template void init(uint16_t EMachine); - template void resolve(SymbolBody *Body); - template + void init(uint16_t EMachine); + void resolve(SymbolBody *Body); void reportConflict(const SymbolBody &Old, const SymbolBody &New); std::vector> ArchiveFiles; Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -20,14 +20,15 @@ using namespace lld; using namespace lld::elf2; -SymbolTable::SymbolTable() {} +template SymbolTable::SymbolTable() {} -bool SymbolTable::shouldUseRela() const { +template bool SymbolTable::shouldUseRela() const { ELFKind K = getFirstELF()->getELFKind(); return K == ELF64LEKind || K == ELF64BEKind; } -void SymbolTable::addFile(std::unique_ptr File) { +template +void SymbolTable::addFile(std::unique_ptr File) { if (auto *AF = dyn_cast(File.get())) { ArchiveFiles.emplace_back(std::move(File)); AF->parse(); @@ -64,54 +65,36 @@ error("Unknown target machine"); } -void SymbolTable::addUndefinedSym(StringRef Name) { - switch (getFirstELF()->getELFKind()) { - case ELF32LEKind: - addUndefinedSym(Name); - break; - case ELF32BEKind: - addUndefinedSym(Name); - break; - case ELF64LEKind: - addUndefinedSym(Name); - break; - case ELF64BEKind: - addUndefinedSym(Name); - break; - default: - llvm_unreachable("Invalid kind"); - } -} - -template void SymbolTable::addUndefinedSym(StringRef Name) { - resolve(new (Alloc) Undefined(Name, Undefined::Optional)); +template void SymbolTable::addUndefinedSym(StringRef Name) { + resolve(new (Alloc) Undefined(Name, Undefined::Optional)); } template -void SymbolTable::addSyntheticSym(StringRef Name, OutputSection &Section, - typename ELFFile::uintX_t Value) { +void SymbolTable::addSyntheticSym(StringRef Name, + OutputSection &Section, + typename ELFFile::uintX_t Value) { typedef typename DefinedSynthetic::Elf_Sym Elf_Sym; auto ESym = new (Alloc) Elf_Sym; memset(ESym, 0, sizeof(Elf_Sym)); ESym->st_value = Value; auto Sym = new (Alloc) DefinedSynthetic(Name, *ESym, Section); - resolve(Sym); + resolve(Sym); } -template void SymbolTable::addIgnoredSym(StringRef Name) { +template void SymbolTable::addIgnoredSym(StringRef Name) { auto Sym = new (Alloc) DefinedAbsolute(Name, DefinedAbsolute::IgnoreUndef); - resolve(Sym); + resolve(Sym); } -template void SymbolTable::init(uint16_t EMachine) { +template void SymbolTable::init(uint16_t EMachine) { Target.reset(createTarget(EMachine)); if (Config->Shared) return; EntrySym = new (Alloc) Undefined( Config->Entry.empty() ? Target->getDefaultEntry() : Config->Entry, Undefined::Required); - resolve(EntrySym); + resolve(EntrySym); // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol is magical // and is used to produce a R_386_GOTPC relocation. @@ -125,10 +108,10 @@ // an undefined symbol in the .o files. // Given that the symbol is effectively unused, we just create a dummy // hidden one to avoid the undefined symbol error. - addIgnoredSym("_GLOBAL_OFFSET_TABLE_"); + addIgnoredSym("_GLOBAL_OFFSET_TABLE_"); } -template void SymbolTable::addELFFile(ELFFileBase *File) { +template void SymbolTable::addELFFile(ELFFileBase *File) { const ELFFileBase *Old = getFirstELF(); if (auto *O = dyn_cast(File)) ObjectFiles.emplace_back(O); @@ -136,40 +119,22 @@ SharedFiles.emplace_back(S); if (!Old) - init(File->getEMachine()); + init(File->getEMachine()); if (auto *O = dyn_cast(File)) { for (SymbolBody *Body : O->getSymbols()) - resolve(Body); + resolve(Body); } if (auto *S = dyn_cast>(File)) { for (SharedSymbol &Body : S->getSharedSymbols()) - resolve(&Body); - } -} - -void SymbolTable::addELFFile(ELFFileBase *File) { - switch (File->getELFKind()) { - case ELF32LEKind: - addELFFile(File); - break; - case ELF32BEKind: - addELFFile(File); - break; - case ELF64LEKind: - addELFFile(File); - break; - case ELF64BEKind: - addELFFile(File); - break; - default: - llvm_unreachable("Invalid kind"); + resolve(&Body); } } template -void SymbolTable::reportConflict(const SymbolBody &Old, const SymbolBody &New) { +void SymbolTable::reportConflict(const SymbolBody &Old, + const SymbolBody &New) { typedef typename ELFFile::Elf_Sym Elf_Sym; typedef typename ELFFile::Elf_Sym_Range Elf_Sym_Range; @@ -198,7 +163,7 @@ // This function resolves conflicts if there's an existing symbol with // the same name. Decisions are made based on symbol type. -template void SymbolTable::resolve(SymbolBody *New) { +template void SymbolTable::resolve(SymbolBody *New) { Symbol *Sym = insert(New); if (Sym->Body == New) return; @@ -229,10 +194,10 @@ if (comp < 0) Sym->Body = New; else if (comp == 0) - reportConflict(*Existing, *New); + reportConflict(*Existing, *New); } -Symbol *SymbolTable::insert(SymbolBody *New) { +template Symbol *SymbolTable::insert(SymbolBody *New) { // Find an existing Symbol or create and insert a new one. StringRef Name = New->getName(); Symbol *&Sym = Symtab[Name]; @@ -245,7 +210,7 @@ return Sym; } -void SymbolTable::addLazy(Lazy *New) { +template void SymbolTable::addLazy(Lazy *New) { Symbol *Sym = insert(New); if (Sym->Body == New) return; @@ -270,7 +235,7 @@ addMemberFile(New); } -void SymbolTable::addMemberFile(Lazy *Body) { +template void SymbolTable::addMemberFile(Lazy *Body) { std::unique_ptr File = Body->getMember(); // getMember returns nullptr if the member was already read from the library. @@ -280,20 +245,7 @@ addFile(std::move(File)); } -namespace lld { -namespace elf2 { -template void SymbolTable::addSyntheticSym(StringRef, OutputSection &, - ELFFile::uintX_t); -template void SymbolTable::addSyntheticSym(StringRef, OutputSection &, - ELFFile::uintX_t); -template void SymbolTable::addSyntheticSym(StringRef, OutputSection &, - ELFFile::uintX_t); -template void SymbolTable::addSyntheticSym(StringRef, OutputSection &, - ELFFile::uintX_t); - -template void SymbolTable::addIgnoredSym(StringRef); -template void SymbolTable::addIgnoredSym(StringRef); -template void SymbolTable::addIgnoredSym(StringRef); -template void SymbolTable::addIgnoredSym(StringRef); -} -} +template class lld::elf2::SymbolTable; +template class lld::elf2::SymbolTable; +template class lld::elf2::SymbolTable; +template class lld::elf2::SymbolTable; Index: ELF/Writer.h =================================================================== --- ELF/Writer.h +++ ELF/Writer.h @@ -13,10 +13,9 @@ namespace lld { namespace elf2 { -class SymbolTable; - -void writeResult(SymbolTable *Symtab); +template class SymbolTable; +template void writeResult(SymbolTable *Symtab); } } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -82,7 +82,7 @@ typedef typename ELFFile::Elf_Sym Elf_Sym; typedef typename ELFFile::Elf_Sym_Range Elf_Sym_Range; typedef typename ELFFile::Elf_Rela Elf_Rela; - Writer(SymbolTable &S) : Symtab(S) {} + Writer(SymbolTable &S) : Symtab(S) {} void run(); private: @@ -111,7 +111,7 @@ unsigned getNumSections() const { return OutputSections.size() + 1; } llvm::BumpPtrAllocator PAlloc; - SymbolTable &Symtab; + SymbolTable &Symtab; std::vector *> PHDRs; ProgramHeader FileHeaderPHDR{PT_LOAD, PF_R, 0, 0}; ProgramHeader InterpPHDR{PT_INTERP, 0, 0, 0}; @@ -123,7 +123,7 @@ }; } // anonymous namespace -template static void doWriteResult(SymbolTable *Symtab) { +template void lld::elf2::writeResult(SymbolTable *Symtab) { // Initialize output sections that are handled by Writer specially. // Don't reorder because the order of initialization matters. InterpSection Interp; @@ -152,25 +152,6 @@ Writer(*Symtab).run(); } -void lld::elf2::writeResult(SymbolTable *Symtab) { - switch (Symtab->getFirstELF()->getELFKind()) { - case ELF32LEKind: - doWriteResult(Symtab); - return; - case ELF32BEKind: - doWriteResult(Symtab); - return; - case ELF64LEKind: - doWriteResult(Symtab); - return; - case ELF64BEKind: - doWriteResult(Symtab); - return; - default: - llvm_unreachable("Invalid kind"); - } -} - // The main function of the writer. template void Writer::run() { createSections(); @@ -267,7 +248,7 @@ } template -static void reportUndefined(const SymbolTable &S, const SymbolBody &Sym) { +static void reportUndefined(const SymbolTable &S, const SymbolBody &Sym) { typedef typename ELFFile::Elf_Sym Elf_Sym; typedef typename ELFFile::Elf_Sym_Range Elf_Sym_Range; @@ -308,14 +289,14 @@ for (StringRef Name : {"__preinit_array_start", "__preinit_array_end", "__init_array_start", "__init_array_end", "__fini_array_start", "__fini_array_end"}) - Symtab.addIgnoredSym(Name); + Symtab.addIgnoredSym(Name); // __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For // static linking the linker is required to optimize away any references to // __tls_get_addr, so it's not defined anywhere. Create a hidden definition // to avoid the undefined symbol error. if (!isOutputDynamic()) - Symtab.addIgnoredSym("__tls_get_addr"); + Symtab.addIgnoredSym("__tls_get_addr"); for (const std::unique_ptr &FileB : Symtab.getObjectFiles()) { auto &File = cast>(*FileB); @@ -354,8 +335,8 @@ auto AddStartEnd = [&](StringRef Start, StringRef End, OutputSection *OS) { if (OS) { - Symtab.addSyntheticSym(Start, *OS, 0); - Symtab.addSyntheticSym(End, *OS, OS->getSize()); + Symtab.addSyntheticSym(Start, *OS, 0); + Symtab.addSyntheticSym(End, *OS, OS->getSize()); } }; @@ -623,3 +604,8 @@ for (OutputSectionBase *Sec : OutputSections) Sec->writeTo(Buf + Sec->getFileOff()); } + +template void lld::elf2::writeResult(SymbolTable *Symtab); +template void lld::elf2::writeResult(SymbolTable *Symtab); +template void lld::elf2::writeResult(SymbolTable *Symtab); +template void lld::elf2::writeResult(SymbolTable *Symtab);