Index: include/lld/Core/Reference.h =================================================================== --- include/lld/Core/Reference.h +++ include/lld/Core/Reference.h @@ -93,6 +93,8 @@ // kindGroupChild is treated as a bidirected edge too. kindGroupChild = 4, kindAssociate = 5, + // kindDynExport marks an ELF atom which needs to be dynamically exported. + kindDynExport = 6, }; // A value to be added to the value of a target Index: include/lld/ReaderWriter/ELFLinkingContext.h =================================================================== --- include/lld/ReaderWriter/ELFLinkingContext.h +++ include/lld/ReaderWriter/ELFLinkingContext.h @@ -44,6 +44,9 @@ virtual std::unique_ptr getDSOReader(bool) = 0; virtual std::unique_ptr getWriter() = 0; + + virtual void createEdge(DefinedAtom *from, const Atom *to, + uint32_t edgeKind) const = 0; }; class ELFLinkingContext : public LinkingContext { @@ -69,6 +72,9 @@ bool mergeCommonStrings() const { return _mergeCommonStrings; } virtual uint64_t getBaseAddress() const { return _baseAddress; } + void notifySymbolTableCoalesce(const Atom *existingAtom, const Atom *newAtom, + bool &useNew) const override; + /// This controls if undefined atoms need to be created for undefines that are /// present in a SharedLibrary. If this option is set, undefined atoms are /// created for every undefined symbol that are present in the dynamic table 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; } @@ -390,7 +399,7 @@ } DefinedAtom::reference_iterator end() const override { - uintptr_t index = _referenceEndIndex; + uintptr_t index = _referenceEndIndex + _markerReferenceList.size(); const void *it = reinterpret_cast(index); return reference_iterator(*this, it); } @@ -398,8 +407,11 @@ const Reference *derefIterator(const void *It) const override { uintptr_t index = reinterpret_cast(It); assert(index >= _referenceStartIndex); - assert(index < _referenceEndIndex); - return ((_referenceList)[index]); + if (index < _referenceEndIndex) + return ((_referenceList)[index]); + index -= _referenceEndIndex; + assert(index < _markerReferenceList.size()); + return _markerReferenceList[index]; } void incrementIterator(const void *&It) const override { @@ -413,6 +425,10 @@ _referenceEndIndex = _referenceList.size(); } + void addMarkerReference(ELFReference *reference) { + _markerReferenceList.push_back(reference); + } + virtual void setOrdinal(uint64_t ord) { _ordinal = ord; } protected: @@ -428,6 +444,7 @@ unsigned int _referenceStartIndex; unsigned int _referenceEndIndex; std::vector *> &_referenceList; + std::vector *> _markerReferenceList; mutable ContentType _contentType; mutable ContentPermissions _permissions; }; Index: lib/ReaderWriter/ELF/DefaultTargetHandler.h =================================================================== --- lib/ReaderWriter/ELF/DefaultTargetHandler.h +++ lib/ReaderWriter/ELF/DefaultTargetHandler.h @@ -42,8 +42,19 @@ } virtual std::unique_ptr getWriter() = 0; + + void createEdge(DefinedAtom *from, const Atom *to, + uint32_t edgeKind) const override; }; +template +void DefaultTargetHandler::createEdge(DefinedAtom *from, const Atom *to, + uint32_t edgeKind) const { + auto *atom = static_cast *>(from); + auto &file = const_cast &>(atom->file()); + file.createEdge(atom, to, edgeKind); +} + } // end namespace elf } // end namespace lld #endif Index: lib/ReaderWriter/ELF/ELFFile.h =================================================================== --- lib/ReaderWriter/ELF/ELFFile.h +++ lib/ReaderWriter/ELF/ELFFile.h @@ -136,6 +136,10 @@ /// Undefined symbols, absolute symbols virtual std::error_code createSymbolsFromAtomizableSections(); + /// \brief Create reference between two atoms. + virtual void createEdge(ELFDefinedAtom *from, const Atom *to, + uint32_t edgeKind); + /// \brief Create individual atoms virtual std::error_code createAtoms(); @@ -210,9 +214,6 @@ const Elf_Sym *symbol, const Elf_Sym *nextSymbol); - virtual void createEdge(ELFDefinedAtom *from, ELFDefinedAtom *to, - uint32_t edgeKind); - /// Determines if the reader needs to create atoms for the section. virtual bool ignoreCreateAtomsForSection(const Elf_Shdr *shdr) { return false; @@ -901,11 +902,11 @@ } template -void ELFFile::createEdge(ELFDefinedAtom *from, - ELFDefinedAtom *to, uint32_t edgeKind) { +void ELFFile::createEdge(ELFDefinedAtom *from, const Atom *to, + uint32_t edgeKind) { auto reference = new (_readerStorage) ELFReference(edgeKind); reference->setTarget(to); - from->addReference(reference); + from->addMarkerReference(reference); } } // end namespace elf Index: lib/ReaderWriter/ELF/ELFLinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ lib/ReaderWriter/ELF/ELFLinkingContext.cpp @@ -241,4 +241,29 @@ return std::move(undefinedSymFile); } +static bool isSharedWeakAtom(const UndefinedAtom *ua) { + return ua->canBeNull() != UndefinedAtom::canBeNullNever && + isa(ua->file()); +} + +void ELFLinkingContext::notifySymbolTableCoalesce(const Atom *existingAtom, + const Atom *newAtom, + bool &useNew) const { + // First suppose that the `existingAtom` is defined + // and the `newAtom` is undefined. + auto *da = dyn_cast(existingAtom); + auto *ua = dyn_cast(newAtom); + if (!da && !ua) { + // Then try to reverse the assumption. + da = dyn_cast(newAtom); + ua = dyn_cast(existingAtom); + } + + if (da && ua && isSharedWeakAtom(ua)) + // If strong defined atom coalesces away weak atom declared + // in the shared object the strong atom needs to be dynamicaly exported. + targetHandler()->createEdge(const_cast(da), ua, + lld::Reference::kindDynExport); +} + } // end namespace lld 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 %t1.exe %t.main.o %t.so +# RUN: llvm-readobj -dyn-symbols %t1.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 %t2.exe %t.main.o %t.foo.o +# RUN: llvm-readobj -dyn-symbols %t2.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 +...