Index: include/lld/Core/LinkingContext.h =================================================================== --- include/lld/Core/LinkingContext.h +++ include/lld/Core/LinkingContext.h @@ -30,6 +30,7 @@ class Writer; class InputGraph; class InputElement; +class Resolver; class SharedLibraryFile; /// \brief The LinkingContext class encapsulates "what and how" to link. @@ -244,6 +245,8 @@ /// the actual input files. virtual void createInternalFiles(std::vector > &) const; + virtual std::unique_ptr getResolver(); + /// Return the list of undefined symbols that are specified in the /// linker command line, using the -u option. range initialUndefinedSymbols() const { Index: include/lld/Core/Reference.h =================================================================== --- include/lld/Core/Reference.h +++ include/lld/Core/Reference.h @@ -92,6 +92,8 @@ // kindGroupChild is treated as a bidirected edge too. kindGroupChild = 4, kindAssociate = 5, + // kindDynExport marks an ELF atom which needs to have a .dynsym record. + kindDynExport = 6, }; // A value to be added to the value of a target Index: include/lld/Core/Resolver.h =================================================================== --- include/lld/Core/Resolver.h +++ include/lld/Core/Resolver.h @@ -30,7 +30,9 @@ class Resolver { public: Resolver(LinkingContext &context) - : _context(context), _symbolTable(context), _result(new MergedFile()) {} + : _symbolTable(context), _context(context), _result(new MergedFile()) {} + + virtual ~Resolver() {} // InputFiles::Handler methods void doDefinedAtom(const DefinedAtom&); @@ -53,6 +55,16 @@ std::unique_ptr resultFile() { return std::move(_result); } +protected: + std::vector _atoms; + SymbolTable _symbolTable; + + virtual bool checkUndefines(); + + template T *makeReference(Args &&... args) { + return new (_result->_allocator) T(std::forward(args)...); + } + private: typedef std::function UndefCallback; @@ -63,7 +75,6 @@ bool resolveUndefines(); void updateReferences(); void deadStripOptimize(); - bool checkUndefines(); void removeCoalescedAwayAtoms(); void checkDylibSymbolCollisions(); void forEachUndefines(bool searchForOverrides, UndefCallback callback); @@ -73,6 +84,8 @@ class MergedFile : public MutableFile { public: + llvm::BumpPtrAllocator _allocator; + MergedFile() : MutableFile("") {} const atom_collection &defined() const override { @@ -101,8 +114,6 @@ }; LinkingContext &_context; - SymbolTable _symbolTable; - std::vector _atoms; std::set _deadStripRoots; llvm::DenseSet _liveAtoms; llvm::DenseSet _deadAtoms; Index: include/lld/ReaderWriter/ELFLinkingContext.h =================================================================== --- include/lld/ReaderWriter/ELFLinkingContext.h +++ include/lld/ReaderWriter/ELFLinkingContext.h @@ -44,6 +44,8 @@ virtual std::unique_ptr getDSOReader(bool) = 0; virtual std::unique_ptr getWriter() = 0; + + virtual std::unique_ptr getResolver() = 0; }; class ELFLinkingContext : public LinkingContext { @@ -155,6 +157,8 @@ void createInternalFiles(std::vector> &) const override; + std::unique_ptr getResolver() override; + /// \brief Set the dynamic linker path void setInterpreter(StringRef dynamicLinker) { _dynamicLinkerArg = true; Index: lib/Core/LinkingContext.cpp =================================================================== --- lib/Core/LinkingContext.cpp +++ lib/Core/LinkingContext.cpp @@ -99,6 +99,10 @@ result.push_back(std::move(file)); } +std::unique_ptr LinkingContext::getResolver() { + return llvm::make_unique(*this); +} + void LinkingContext::addPasses(PassManager &pm) {} } // end namespace lld Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ lib/Driver/Driver.cpp @@ -105,10 +105,10 @@ // Do core linking. ScopedTask resolveTask(getDefaultDomain(), "Resolve"); - Resolver resolver(context); - if (!resolver.resolve()) + auto resolver = context.getResolver(); + if (!resolver->resolve()) return false; - std::unique_ptr merged = resolver.resultFile(); + std::unique_ptr merged = resolver->resultFile(); resolveTask.end(); // Run passes on linked atoms. Index: lib/ReaderWriter/ELF/Atoms.h =================================================================== --- lib/ReaderWriter/ELF/Atoms.h +++ lib/ReaderWriter/ELF/Atoms.h @@ -192,6 +192,15 @@ return scopeTranslationUnit; } + DynamicExport dynamicExport() const override { + for (const auto &r : *this) + if (r->kindNamespace() == lld::Reference::KindNamespace::all && + r->kindArch() == lld::Reference::KindArch::all && + r->kindValue() == Reference::kindDynExport) + return dynamicExportAlways; + return dynamicExportNormal; + } + // FIXME: Need to revisit this in future. Interposable interposable() const override { return interposeNo; } Index: lib/ReaderWriter/ELF/DefaultTargetHandler.h =================================================================== --- lib/ReaderWriter/ELF/DefaultTargetHandler.h +++ lib/ReaderWriter/ELF/DefaultTargetHandler.h @@ -13,6 +13,7 @@ #include "DefaultLayout.h" #include "TargetHandler.h" #include "ELFReader.h" +#include "ELFResolver.h" #include "DynamicLibraryWriter.h" #include "ExecutableWriter.h" @@ -42,6 +43,10 @@ } virtual std::unique_ptr getWriter() = 0; + + virtual std::unique_ptr getResolver() { + return llvm::make_unique>(this->_context); + } }; } // end namespace elf Index: lib/ReaderWriter/ELF/ELFLinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ lib/ReaderWriter/ELF/ELFLinkingContext.cpp @@ -225,6 +225,10 @@ LinkingContext::createInternalFiles(files); } +std::unique_ptr ELFLinkingContext::getResolver() { + return _targetHandler->getResolver(); +} + std::unique_ptr ELFLinkingContext::createUndefinedSymbolFile() const { if (_initialUndefinedSymbols.empty()) return nullptr; Index: lib/ReaderWriter/ELF/ELFResolver.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/ELFResolver.h @@ -0,0 +1,57 @@ +//===- lib/ReaderWriter/ELF/Resolver.h - Resolves Atom References ---------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_ELF_RESOLVER_H +#define LLD_READER_WRITER_ELF_RESOLVER_H + +#include "Atoms.h" + +#include "lld/Core/Resolver.h" + +namespace lld { +namespace elf { + +template class ELFResolver : public Resolver { +public: + ELFResolver(LinkingContext &context) : Resolver(context) {} + +protected: + bool checkUndefines() override; +}; + +template +bool ELFResolver::checkUndefines() { + if (Resolver::checkUndefines()) + return true; + + for (const Atom *a : _atoms) { + auto *ua = dyn_cast>(a); + // Skip non-weak symbols. + if (!ua || ua->canBeNull() == UndefinedAtom::canBeNullNever) + continue; + // Skip weak symbols from non-shared libraries. + if (!isa(ua->file())) + continue; + auto *da = dyn_cast>(_symbolTable.replacement(ua)); + if (!da) + continue; + // Request dynamic export for coalesced symbols replaced + // by strong defined atoms. + auto *r = this->makeReference>(Reference::kindDynExport); + r->setTarget(ua); + const_cast *>(da)->addReference(r); + } + + return false; +} + +} // namespace elf +} // namespace lld + +#endif // LLD_READER_WRITER_ELF_RESOLVER_H Index: lib/ReaderWriter/ELF/TargetHandler.h =================================================================== --- lib/ReaderWriter/ELF/TargetHandler.h +++ lib/ReaderWriter/ELF/TargetHandler.h @@ -73,7 +73,7 @@ /// How does the target deal with writing ELF output. virtual std::unique_ptr getWriter() = 0; -private: +protected: ELFLinkingContext &_context; }; } // end namespace elf Index: lib/ReaderWriter/Reader.cpp =================================================================== --- lib/ReaderWriter/Reader.cpp +++ lib/ReaderWriter/Reader.cpp @@ -52,6 +52,7 @@ {Reference::kindLayoutBefore, "layout-before"}, {Reference::kindGroupChild, "group-child"}, {Reference::kindAssociate, "associate"}, + {Reference::kindDynExport, "dyn-export"}, LLD_KIND_STRING_END}; Registry::Registry() { Index: test/elf/X86_64/dynsym-weak.test =================================================================== --- /dev/null +++ test/elf/X86_64/dynsym-weak.test @@ -0,0 +1,118 @@ +# Check that a symbol declared as a week in a shared library gets a dynamic +# symbol table record in an executable file if this executabe file declares the +# symbol as strong. + +# RUN: yaml2obj -format=elf -docnum 1 %s > %t.foo.o +# RUN: lld -flavor gnu -target x86_64 -shared -o %t.so %t.foo.o +# RUN: yaml2obj -format=elf -docnum 2 %s > %t.main.o +# +# Link executable file with strong symbol. Weak symbol is in the shared lib. +# RUN: lld -flavor gnu -target x86_64 -e main -o %t.exe %t.main.o %t.so +# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck -check-prefix=EXE %s +# +# Link executable file. Strong and weak symbol come from different object files. +# RUN: lld -flavor gnu -target x86_64 -e main -o %t.exe %t.main.o %t.foo.o +# RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck -check-prefix=OBJ %s +# +# Link shared library. Weak symbol is in the another shared lib. +# RUN: lld -flavor gnu -target x86_64 -shared -o %t.res.so %t.main.o %t.so +# RUN: llvm-readobj -dyn-symbols %t.res.so | FileCheck -check-prefix=SO %s + +# EXE: Symbol { +# EXE: Name: flag@ ({{[0-9]+}}) +# EXE-NEXT: Value: 0x{{[0-9A-F]+}} +# EXE-NEXT: Size: 4 +# EXE-NEXT: Binding: Global (0x1) +# EXE-NEXT: Type: Object (0x1) +# EXE-NEXT: Other: 0 +# EXE-NEXT: Section: .data (0x{{[0-9A-F]+}}) +# EXE-NEXT: } + +# OBJ-NOT: Name: flag@ ({{[0-9]+}}) + +# SO: Symbol { +# SO: Name: flag@ ({{[0-9]+}}) +# SO-NEXT: Value: 0x{{[0-9A-F]+}} +# SO-NEXT: Size: 4 +# SO-NEXT: Binding: Global (0x1) +# SO-NEXT: Type: Object (0x1) +# SO-NEXT: Other: 0 +# SO-NEXT: Section: .data (0x{{[0-9A-F]+}}) +# SO-NEXT: } + +# foo.o +--- +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 + +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x04 + Size: 0x08 + - Name: .rela.text + Type: SHT_RELA + Link: .symtab + AddressAlign: 0x08 + Info: .text + Relocations: + - Offset: 0x00 + Symbol: flag + Type: R_X86_64_GOTPCREL + Addend: -4 + +Symbols: + Global: + - Name: foo + Type: STT_FUNC + Section: .text + Size: 0x08 + Weak: + - Name: flag + +# main.o +--- +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 + +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x04 + Size: 0x08 + - Name: .rela.text + Type: SHT_RELA + Link: .symtab + AddressAlign: 0x08 + Info: .text + Relocations: + - Offset: 0x00 + Symbol: foo + Type: R_X86_64_PLT32 + Addend: -4 + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x04 + Size: 0x04 + +Symbols: + Global: + - Name: flag + Type: STT_OBJECT + Section: .data + Size: 0x04 + - Name: main + Type: STT_FUNC + Section: .text + Size: 0x08 + - Name: foo +...