Index: lld/trunk/include/lld/Core/LinkingContext.h =================================================================== --- lld/trunk/include/lld/Core/LinkingContext.h +++ lld/trunk/include/lld/Core/LinkingContext.h @@ -307,8 +307,8 @@ virtual uint64_t getNextOrdinalAndIncrement() const { return _nextOrdinal++; } // This function is called just before the Resolver kicks in. - // Derived classes may use that chance to rearrange the input files. - virtual void maybeSortInputFiles() {} + // Derived classes may use it to change the list of input files. + virtual void finalizeInputFiles() {} TaskGroup &getTaskGroup() { return _taskGroup; } Index: lld/trunk/include/lld/Core/Simple.h =================================================================== --- lld/trunk/include/lld/Core/Simple.h +++ lld/trunk/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: lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h =================================================================== --- lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h +++ lld/trunk/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; @@ -310,6 +313,8 @@ const llvm::StringSet<> &wrapCalls() const { return _wrapCalls; } + void setUndefinesResolver(std::unique_ptr resolver); + private: ELFLinkingContext() = delete; @@ -354,6 +359,7 @@ std::map _absoluteSymbols; llvm::StringSet<> _dynamicallyExportedSymbols; std::vector> _scripts; + std::unique_ptr _resolver; }; } // end namespace lld Index: lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h =================================================================== --- lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h +++ lld/trunk/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: lld/trunk/lib/Driver/Driver.cpp =================================================================== --- lld/trunk/lib/Driver/Driver.cpp +++ lld/trunk/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: lld/trunk/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h +++ lld/trunk/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. unique_bump_ptr> createSymbolTable() override; + void processUndefinedSymbol(StringRef symName, + CRuntimeFile &file) const override; private: ARMLinkingContext &_context; ARMTargetLayout &_armLayout; + + static StringRef gotSymbol; }; template +StringRef ARMExecutableWriter::gotSymbol = "_GLOBAL_OFFSET_TABLE_"; + +template ARMExecutableWriter::ARMExecutableWriter(ARMLinkingContext &context, ARMTargetLayout &layout) : ExecutableWriter(context, layout), _context(context), @@ -58,12 +62,40 @@ } template +void ARMExecutableWriter::finalizeDefaultAtomValues() { + // Finalize the atom values that are part of the parent. + ExecutableWriter::finalizeDefaultAtomValues(); + auto gotAtomIter = _armLayout.findAbsoluteAtom(gotSymbol); + if (gotAtomIter != _armLayout.absoluteAtoms().end()) { + auto *gotAtom = *gotAtomIter; + if (auto gotpltSection = _armLayout.findOutputSection(".got.plt")) + gotAtom->_virtualAddr = gotpltSection->virtualAddr(); + else if (auto gotSection = _armLayout.findOutputSection(".got")) + gotAtom->_virtualAddr = gotSection->virtualAddr(); + else + gotAtom->_virtualAddr = 0; + } + // TODO: resolve addresses of __exidx_start/_end atoms +} + +template unique_bump_ptr> ARMExecutableWriter::createSymbolTable() { return unique_bump_ptr>( new (this->_alloc) ARMSymbolTable(this->_context)); } +template +void ARMExecutableWriter::processUndefinedSymbol( + StringRef symName, CRuntimeFile &file) const { + if (symName == gotSymbol) { + file.addAbsoluteAtom(gotSymbol); + } else if (symName.startswith("__exidx")) { + file.addAbsoluteAtom("__exidx_start"); + file.addAbsoluteAtom("__exidx_end"); + } +} + } // namespace elf } // namespace lld Index: lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp @@ -188,6 +188,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; @@ -245,4 +251,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: lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h +++ lld/trunk/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,61 @@ 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("Dynamically added runtime symbols"), + _context(context), _resolver(resolver) {} + + File *find(StringRef sym, bool dataSymbolOnly) override { + if (!_file) + _file.reset(new (_alloc) SymbolFile(_context)); + + assert(!_file->hasAtoms() && "The file shouldn't have atoms yet"); + _resolver(sym, *_file); + // If atoms were added - release the file to the caller. + return _file->hasAtoms() ? _file.release() : nullptr; + } + +private: + ELFLinkingContext &_context; + Resolver _resolver; + + // The allocator should go before bump pointers because of + // reversed destruction order. + llvm::BumpPtrAllocator _alloc; + unique_bump_ptr> _file; +}; + +} // end anon namespace + //===----------------------------------------------------------------------===// // OutputELFWriter Class //===----------------------------------------------------------------------===// @@ -121,6 +178,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 +366,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: lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp =================================================================== --- lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ lld/trunk/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: lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h =================================================================== --- lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h +++ lld/trunk/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" @@ -71,39 +70,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. @@ -159,10 +125,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 { @@ -175,8 +141,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. @@ -209,10 +175,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); @@ -236,8 +202,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: lld/trunk/test/elf/ARM/missing-symbol.test =================================================================== --- lld/trunk/test/elf/ARM/missing-symbol.test +++ lld/trunk/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_ +... Index: lld/trunk/test/elf/ARM/undef-lazy-symbol.test =================================================================== --- lld/trunk/test/elf/ARM/undef-lazy-symbol.test +++ lld/trunk/test/elf/ARM/undef-lazy-symbol.test @@ -0,0 +1,135 @@ +# Check that _GLOBAL_OFFSET_TABLE_ symbol is resolved + +# RUN: yaml2obj -format=elf -docnum 1 %s > %t-got.o +# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \ +# RUN: --noinhibit-exec %t-got.o -o %t +# RUN: llvm-readobj -symbols %t | FileCheck -check-prefix=GOT %s + +# GOT: Name: _GLOBAL_OFFSET_TABLE_ (185) +# GOT-NEXT: Value: {{[0-9]+}} +# GOT-NEXT: Size: 0 +# GOT-NEXT: Binding: Global (0x1) +# GOT-NEXT: Type: Object (0x1) +# GOT-NEXT: Other: 0 +# GOT-NEXT: Section: Absolute (0xFFF1) + +# Check that __exidx_start/_end symbols are resolved + +# RUN: yaml2obj -format=elf -docnum 2 %s > %t-exidx.o +# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \ +# RUN: --defsym=main=fn --noinhibit-exec %t-exidx.o -o %t +# RUN: llvm-readobj -symbols %t | FileCheck -check-prefix=EXIDX %s + +# EXIDX: Name: __exidx_start (188) +# EXIDX-NEXT: Value: {{[0-9]+}} +# EXIDX-NEXT: Size: 0 +# EXIDX-NEXT: Binding: Global (0x1) +# EXIDX-NEXT: Type: Object (0x1) +# EXIDX-NEXT: Other: 0 +# EXIDX-NEXT: Section: Absolute (0xFFF1) +# +# EXIDX: Name: __exidx_end (202) +# EXIDX-NEXT: Value: {{[0-9]+}} +# EXIDX-NEXT: Size: 0 +# EXIDX-NEXT: Binding: Global (0x1) +# EXIDX-NEXT: Type: Object (0x1) +# EXIDX-NEXT: Other: 0 +# EXIDX-NEXT: Section: Absolute (0xFFF1) + +# Check that all symbols are resolved + +# RUN: yaml2obj -format=elf -docnum 1 %s > %t-got.o +# RUN: yaml2obj -format=elf -docnum 2 %s > %t-exidx.o +# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \ +# RUN: --noinhibit-exec %t-got.o %t-exidx.o -o %t +# RUN: llvm-readobj -symbols %t | FileCheck -check-prefix=SYMS %s + +# SYMS: Name: _GLOBAL_OFFSET_TABLE_ (188) +# SYMS-NEXT: Value: {{[0-9]+}} +# SYMS-NEXT: Size: 0 +# SYMS-NEXT: Binding: Global (0x1) +# SYMS-NEXT: Type: Object (0x1) +# SYMS-NEXT: Other: 0 +# SYMS-NEXT: Section: Absolute (0xFFF1) +# +# SYMS: Name: __exidx_start (210) +# SYMS-NEXT: Value: {{[0-9]+}} +# SYMS-NEXT: Size: 0 +# SYMS-NEXT: Binding: Global (0x1) +# SYMS-NEXT: Type: Object (0x1) +# SYMS-NEXT: Other: 0 +# SYMS-NEXT: Section: Absolute (0xFFF1) +# +# SYMS: Name: __exidx_end (224) +# SYMS-NEXT: Value: {{[0-9]+}} +# SYMS-NEXT: Size: 0 +# SYMS-NEXT: Binding: Global (0x1) +# SYMS-NEXT: Type: Object (0x1) +# SYMS-NEXT: Other: 0 +# SYMS-NEXT: Section: Absolute (0xFFF1) + +# got.o +--- +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_ + +# exidx.o +--- +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: fn + Type: STT_FUNC + Section: .text + Value: 0x0000000000000001 + - Name: __exidx_start + - Name: __exidx_end +...