Index: include/lld/Core/LinkingContext.h =================================================================== --- include/lld/Core/LinkingContext.h +++ include/lld/Core/LinkingContext.h @@ -308,7 +308,7 @@ // This function is called just before the Resolver kicks in. // Derived classes may use that chance to rearrange the input files. - virtual void maybeSortInputFiles() {} + virtual void finalizeInputFiles() {} TaskGroup &getTaskGroup() { return _taskGroup; } Index: include/lld/Core/Simple.h =================================================================== --- include/lld/Core/Simple.h +++ include/lld/Core/Simple.h @@ -17,6 +17,7 @@ #include "lld/Core/DefinedAtom.h" #include "lld/Core/File.h" +#include "lld/Core/ArchiveLibraryFile.h" #include "lld/Core/LinkingContext.h" #include "lld/Core/Reference.h" #include "lld/Core/UndefinedAtom.h" @@ -77,6 +78,48 @@ atom_collection_vector _absoluteAtoms; }; +/// \brief Archive library file that may be used as a virtual container +/// for symbols that should be added dynamically in response to +/// call to find() method. +class SimpleArchiveLibraryFile : public ArchiveLibraryFile { +public: + SimpleArchiveLibraryFile(StringRef filename) + : ArchiveLibraryFile(filename) {} + + const atom_collection &defined() const override { + return _definedAtoms; + } + + const atom_collection &undefined() const override { + return _undefinedAtoms; + } + + const atom_collection &sharedLibrary() const override { + return _sharedLibraryAtoms; + } + + const atom_collection &absolute() const override { + return _absoluteAtoms; + } + + File *find(StringRef sym, bool dataSymbolOnly) override { + // For descendants: + // do some checks here and return dynamically generated files with atoms. + return nullptr; + } + + std::error_code + parseAllMembers(std::vector> &result) override { + return std::error_code(); + } + +private: + atom_collection_vector _definedAtoms; + atom_collection_vector _undefinedAtoms; + atom_collection_vector _sharedLibraryAtoms; + atom_collection_vector _absoluteAtoms; +}; + class SimpleReference : public Reference { public: SimpleReference(Reference::KindNamespace ns, Reference::KindArch arch, Index: include/lld/ReaderWriter/ELFLinkingContext.h =================================================================== --- include/lld/ReaderWriter/ELFLinkingContext.h +++ include/lld/ReaderWriter/ELFLinkingContext.h @@ -29,6 +29,7 @@ namespace lld { class DefinedAtom; class Reference; +class File; namespace elf { template class TargetHandler; @@ -170,6 +171,8 @@ void createInternalFiles(std::vector> &) const override; + void finalizeInputFiles() override; + /// \brief Set the dynamic linker path void setInterpreter(StringRef dynamicLinker) { _dynamicLinkerArg = true; @@ -306,6 +309,8 @@ const llvm::StringSet<> &wrapCalls() const { return _wrapCalls; } + void setUndefinesResolver(std::unique_ptr resolver); + private: ELFLinkingContext() = delete; @@ -350,6 +355,7 @@ std::map _absoluteSymbols; llvm::StringSet<> _dynamicallyExportedSymbols; std::vector> _scripts; + std::unique_ptr _resolver; }; } // end namespace lld Index: include/lld/ReaderWriter/MachOLinkingContext.h =================================================================== --- include/lld/ReaderWriter/MachOLinkingContext.h +++ include/lld/ReaderWriter/MachOLinkingContext.h @@ -291,7 +291,7 @@ /// bits are xxxx.yy.zz. Largest number is 65535.255.255 static bool parsePackedVersion(StringRef str, uint32_t &result); - void maybeSortInputFiles() override; + void finalizeInputFiles() override; bool customAtomOrderer(const DefinedAtom *left, const DefinedAtom *right, bool &leftBeforeRight) const; Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ lib/Driver/Driver.cpp @@ -96,9 +96,10 @@ members.insert(members.begin(), llvm::make_unique(std::move(*i))); } - // Give target a chance to sort the input files. + // Give target a chance to postprocess input files. // Mach-O uses this chance to move all object files before library files. - context.maybeSortInputFiles(); + // ELF adds specific undefined symbols resolver. + context.finalizeInputFiles(); // Do core linking. ScopedTask resolveTask(getDefaultDomain(), "Resolve"); Index: lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h =================================================================== --- lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h +++ lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h @@ -27,10 +27,7 @@ // Add any runtime files and their atoms to the output bool createImplicitFiles(std::vector> &) override; - void finalizeDefaultAtomValues() override { - // Finalize the atom values that are part of the parent. - ExecutableWriter::finalizeDefaultAtomValues(); - } + void finalizeDefaultAtomValues() override; void addDefaultAtoms() override { ExecutableWriter::addDefaultAtoms(); @@ -39,12 +36,19 @@ /// \brief Create symbol table. LLD_UNIQUE_BUMP_PTR(SymbolTable) createSymbolTable() override; + void processUndefinedSymbol(StringRef symName, + CRuntimeFile *file) const override; private: ARMLinkingContext &_context; ARMTargetLayout &_armLayout; + + static const StringRef gotSymbol; }; template +const StringRef ARMExecutableWriter::gotSymbol = "_GLOBAL_OFFSET_TABLE_"; + +template ARMExecutableWriter::ARMExecutableWriter(ARMLinkingContext &context, ARMTargetLayout &layout) : ExecutableWriter(context, layout), _context(context), @@ -58,12 +62,34 @@ } template +void ARMExecutableWriter::finalizeDefaultAtomValues() { + // Finalize the atom values that are part of the parent. + ExecutableWriter::finalizeDefaultAtomValues(); + auto gotAtomIter = _armLayout.findAbsoluteAtom(gotSymbol); + if (auto *gotAtom = *gotAtomIter) { + if (auto gotpltSection = _armLayout.findOutputSection(".got.plt")) + gotAtom->_virtualAddr = gotpltSection->virtualAddr(); + else + gotAtom->_virtualAddr = 0; + } +} + +template LLD_UNIQUE_BUMP_PTR(SymbolTable) ARMExecutableWriter::createSymbolTable() { return LLD_UNIQUE_BUMP_PTR(SymbolTable)( new (this->_alloc) ARMSymbolTable(this->_context)); } +template +void ARMExecutableWriter::processUndefinedSymbol( + StringRef symName, CRuntimeFile *file) const { + + if (symName == gotSymbol) { + file->addAbsoluteAtom(gotSymbol); + } +} + } // namespace elf } // namespace lld Index: lib/ReaderWriter/ELF/ELFLinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ lib/ReaderWriter/ELF/ELFLinkingContext.cpp @@ -203,6 +203,12 @@ LinkingContext::createInternalFiles(files); } +void ELFLinkingContext::finalizeInputFiles() { + // Add virtual archive that resolves undefined symbols. + if (_resolver) + getNodes().push_back(llvm::make_unique(std::move(_resolver))); +} + std::unique_ptr ELFLinkingContext::createUndefinedSymbolFile() const { if (_initialUndefinedSymbols.empty()) return nullptr; @@ -260,4 +266,9 @@ return symbolName; } +void ELFLinkingContext::setUndefinesResolver(std::unique_ptr resolver) { + assert(isa(resolver.get()) && "Wrong resolver type"); + _resolver = std::move(resolver); +} + } // end namespace lld Index: lib/ReaderWriter/ELF/OutputELFWriter.h =================================================================== --- lib/ReaderWriter/ELF/OutputELFWriter.h +++ lib/ReaderWriter/ELF/OutputELFWriter.h @@ -16,7 +16,9 @@ #include "lld/Core/Parallel.h" #include "lld/Core/SharedLibraryFile.h" #include "lld/ReaderWriter/ELFLinkingContext.h" +#include "lld/Core/Simple.h" #include "lld/Core/Writer.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Path.h" @@ -28,6 +30,64 @@ template class OutputELFWriter; template class TargetLayout; +namespace { + +template +class SymbolFile : public CRuntimeFile { +public: + SymbolFile(ELFLinkingContext &context) + : CRuntimeFile(context, "Dynamic absolute symbols"), + _atomsAdded(false) {} + + Atom *addAbsoluteAtom(StringRef symbolName) override { + auto *a = CRuntimeFile::addAbsoluteAtom(symbolName); + if (a) _atomsAdded = true; + return a; + } + + Atom *addUndefinedAtom(StringRef) override { + llvm_unreachable("Cannot add undefined atoms to resolve undefined symbols"); + } + + bool hasAtoms() const { return _atomsAdded; } + +private: + bool _atomsAdded; +}; + +template +class DynamicSymbolFile : public SimpleArchiveLibraryFile { + typedef std::function *)> Resolver; +public: + DynamicSymbolFile(ELFLinkingContext &context, Resolver resolver) + : SimpleArchiveLibraryFile("Dynamic symbols for executable"), + _context(context), _resolver(resolver) {} + + File *find(StringRef sym, bool dataSymbolOnly) override { + if (!_file.hasValue()) + _file = new (_alloc) SymbolFile(_context); + + SymbolFile *file = _file.getValue(); + assert (!file->hasAtoms() && "The file shouldn't have atoms yet"); + _resolver(sym, file); + // If atoms were added - throw the file to the caller and prepare + // to create new one by resetting the holder. + if (file->hasAtoms()) { + _file.reset(); + return file; + } + return nullptr; + } + +private: + ELFLinkingContext &_context; + Resolver _resolver; + llvm::Optional *> _file; + llvm::BumpPtrAllocator _alloc; +}; + +} // end anon namespace + //===----------------------------------------------------------------------===// // OutputELFWriter Class //===----------------------------------------------------------------------===// @@ -121,6 +181,10 @@ return false; } + /// \brief Process undefined symbols that left after resolution step. + virtual void processUndefinedSymbol(StringRef symName, + CRuntimeFile *file) const {} + llvm::BumpPtrAllocator _alloc; const ELFLinkingContext &_context; @@ -305,6 +369,14 @@ template bool OutputELFWriter::createImplicitFiles( std::vector> &) { + // Add the virtual archive to resolve undefined symbols. + // The file will be added later in the linking context. + auto callback = [this](StringRef sym, CRuntimeFile *file) { + processUndefinedSymbol(sym, file); + }; + auto &ctx = const_cast(_context); + ctx.setUndefinesResolver( + llvm::make_unique>(ctx, std::move(callback))); return true; } Index: lib/ReaderWriter/MachO/MachOLinkingContext.cpp =================================================================== --- lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -955,7 +955,7 @@ // comes before any library file. We also make a group for the library files // so that the Resolver will reiterate over the libraries as long as we find // new undefines from libraries. -void MachOLinkingContext::maybeSortInputFiles() { +void MachOLinkingContext::finalizeInputFiles() { std::vector> &elements = getNodes(); std::stable_sort(elements.begin(), elements.end(), [](const std::unique_ptr &a, Index: lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h =================================================================== --- lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h +++ lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "Atoms.h" -#include "lld/Core/ArchiveLibraryFile.h" #include "lld/Core/Simple.h" #include "lld/ReaderWriter/PECOFFLinkingContext.h" #include "llvm/Support/Allocator.h" @@ -65,39 +64,6 @@ ImpPointerAtom _defined; }; -class VirtualArchiveLibraryFile : public ArchiveLibraryFile { -public: - VirtualArchiveLibraryFile(StringRef filename) - : ArchiveLibraryFile(filename) {} - - const atom_collection &defined() const override { - return _definedAtoms; - } - - const atom_collection &undefined() const override { - return _undefinedAtoms; - } - - const atom_collection &sharedLibrary() const override { - return _sharedLibraryAtoms; - } - - const atom_collection &absolute() const override { - return _absoluteAtoms; - } - - std::error_code - parseAllMembers(std::vector> &result) override { - return std::error_code(); - } - -private: - atom_collection_vector _definedAtoms; - atom_collection_vector _undefinedAtoms; - atom_collection_vector _sharedLibraryAtoms; - atom_collection_vector _absoluteAtoms; -}; - // A file to make Resolver to resolve a symbol TO instead of a symbol FROM, // using fallback mechanism for an undefined symbol. One can virtually rename an // undefined symbol using this file. @@ -153,10 +119,10 @@ // } // // This odd feature is for the compatibility with MSVC link.exe. -class LocallyImportedSymbolFile : public impl::VirtualArchiveLibraryFile { +class LocallyImportedSymbolFile : public SimpleArchiveLibraryFile { public: LocallyImportedSymbolFile(const PECOFFLinkingContext &ctx) - : VirtualArchiveLibraryFile("__imp_"), _is64(ctx.is64Bit()), + : SimpleArchiveLibraryFile("__imp_"), _is64(ctx.is64Bit()), _ordinal(0) {} File *find(StringRef sym, bool dataSymbolOnly) override { @@ -169,8 +135,8 @@ private: bool _is64; - mutable uint64_t _ordinal; - mutable llvm::BumpPtrAllocator _alloc; + uint64_t _ordinal; + llvm::BumpPtrAllocator _alloc; }; // A ExportedSymbolRenameFile is a virtual archive file for dllexported symbols. @@ -203,10 +169,10 @@ // prefix, it returns an atom to rename the dllexported symbol, hoping that // Resolver will find the new symbol with atsign from an archive file at the // next visit. -class ExportedSymbolRenameFile : public impl::VirtualArchiveLibraryFile { +class ExportedSymbolRenameFile : public SimpleArchiveLibraryFile { public: ExportedSymbolRenameFile(const PECOFFLinkingContext &ctx) - : VirtualArchiveLibraryFile(""), + : SimpleArchiveLibraryFile(""), _ctx(const_cast(&ctx)) { for (PECOFFLinkingContext::ExportDesc &desc : _ctx->getDllExports()) _exportedSyms.insert(desc.name); @@ -230,8 +196,8 @@ private: std::set _exportedSyms; - mutable llvm::BumpPtrAllocator _alloc; - mutable PECOFFLinkingContext *_ctx; + llvm::BumpPtrAllocator _alloc; + PECOFFLinkingContext *_ctx; }; // Windows has not only one but many entry point functions. The Index: test/elf/ARM/got-symbol.test =================================================================== --- /dev/null +++ test/elf/ARM/got-symbol.test @@ -0,0 +1,46 @@ +# Check that _GLOBAL_OFFSET_TABLE_ symbol is resolved + +# RUN: yaml2obj -format=elf %s > %t-o.o +# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \ +# RUN: --noinhibit-exec %t-o.o -o %t +# RUN: llvm-readobj -symbols %t | FileCheck %s + +# CHECK: Name: _GLOBAL_OFFSET_TABLE_ (185) +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global (0x1) +# CHECK-NEXT: Type: Object (0x1) +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Absolute (0xFFF1) + +--- +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_ARM + Flags: [ EF_ARM_EABI_VER5 ] +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000004 + Content: 80B483B000AF40F20003C0F200037B60002318460C37BD465DF8047B704700BF + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' + - Name: .bss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' +Symbols: + Global: + - Name: main + Type: STT_FUNC + Section: .text + Value: 0x0000000000000001 + - Name: _GLOBAL_OFFSET_TABLE_ +... Index: test/elf/ARM/missing-symbol.test =================================================================== --- /dev/null +++ test/elf/ARM/missing-symbol.test @@ -0,0 +1,39 @@ +# Check that _MISSING_SYMBOL_ symbol is not resolved + +# RUN: yaml2obj -format=elf %s > %t-o.o +# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \ +# RUN: --noinhibit-exec %t-o.o -o %t 2>&1 | FileCheck %s + +# CHECK: Undefined symbol: {{.*}}: _MISSING_SYMBOL_ + +--- +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_ARM + Flags: [ EF_ARM_EABI_VER5 ] +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000004 + Content: 80B483B000AF40F20003C0F200037B60002318460C37BD465DF8047B704700BF + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' + - Name: .bss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000001 + Content: '' +Symbols: + Global: + - Name: main + Type: STT_FUNC + Section: .text + Value: 0x0000000000000001 + - Name: _MISSING_SYMBOL_ +...