Index: lib/ReaderWriter/ELF/DefaultLayout.h =================================================================== --- lib/ReaderWriter/ELF/DefaultLayout.h +++ lib/ReaderWriter/ELF/DefaultLayout.h @@ -170,6 +170,8 @@ typedef typename std::vector::iterator AbsoluteAtomIterT; + typedef llvm::DenseSet AtomSetT; + DefaultLayout(const ELFLinkingContext &context) : _context(context) {} /// \brief Return the section order for a input section @@ -297,8 +299,8 @@ return 0; } - bool isReferencedByDefinedAtom(const SharedLibraryAtom *sla) const { - return _referencedDynAtoms.count(sla); + bool isReferencedByDefinedAtom(const Atom *a) const { + return _referencedDynAtoms.count(a); } protected: @@ -322,7 +324,7 @@ LLD_UNIQUE_BUMP_PTR(RelocationTable) _dynamicRelocationTable; LLD_UNIQUE_BUMP_PTR(RelocationTable) _pltRelocationTable; std::vector _absoluteAtoms; - llvm::DenseSet _referencedDynAtoms; + AtomSetT _referencedDynAtoms; const ELFLinkingContext &_context; }; @@ -561,15 +563,28 @@ StringRef sectionName = getSectionName(definedAtom); AtomSection *section = getSection(sectionName, contentType, permissions); + // Add runtime relocations to the .rela section. for (const auto &reloc : *definedAtom) { - if (_context.isDynamicRelocation(*definedAtom, *reloc)) + bool isLocalReloc = true; + if (_context.isDynamicRelocation(*definedAtom, *reloc)) { getDynamicRelocationTable()->addRelocation(*definedAtom, *reloc); - else if (_context.isPLTRelocation(*definedAtom, *reloc)) + isLocalReloc = false; + } else if (_context.isPLTRelocation(*definedAtom, *reloc)) { getPLTRelocationTable()->addRelocation(*definedAtom, *reloc); - if (const auto *sla = dyn_cast(reloc->target())) - _referencedDynAtoms.insert(sla); + isLocalReloc = false; + } + + if (!reloc->target()) + continue; + + //Ignore undefined atoms that are not target of dynamic relocations + if (isa(reloc->target()) && isLocalReloc) + continue; + + _referencedDynAtoms.insert(reloc->target()); } + return section->appendAtom(atom); } else if (const AbsoluteAtom *absoluteAtom = dyn_cast(atom)) { // Absolute atoms are not part of any section, they are global for the whole Index: lib/ReaderWriter/ELF/ExecutableWriter.h =================================================================== --- lib/ReaderWriter/ELF/ExecutableWriter.h +++ lib/ReaderWriter/ELF/ExecutableWriter.h @@ -59,6 +59,15 @@ atom->_virtualAddr, atom); } + // Put weak symbols in the dynamic symbol table. + if (this->_context.isDynamic()) { + for (const UndefinedAtom *a : file.undefined()) { + if (this->_layout.isReferencedByDefinedAtom(a) && + a->canBeNull() != UndefinedAtom::canBeNullNever) + this->_dynamicSymbolTable->addSymbol(a, ELF::SHN_UNDEF); + } + } + OutputELFWriter::buildDynamicSymbolTable(file); } Index: lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h =================================================================== --- lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h +++ lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h @@ -65,9 +65,24 @@ for (auto sec : this->_layout.sections()) if (auto section = dyn_cast>(sec)) for (const auto &atom : section->atoms()) { - if (_writeHelper.hasGlobalGOTEntry(atom->_atom)) + if (_writeHelper.hasGlobalGOTEntry(atom->_atom)) { this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(), atom->_virtualAddr, atom); + continue; + } + + const DefinedAtom *da = dyn_cast(atom->_atom); + if (!da) + continue; + + if (da->dynamicExport() != DefinedAtom::dynamicExportAlways && + !this->_context.isDynamicallyExportedSymbol(da->name()) && + !(this->_context.shouldExportDynamic() && + da->scope() == Atom::Scope::scopeGlobal)) + continue; + + this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(), + atom->_virtualAddr, atom); } for (const UndefinedAtom *a : file.undefined()) @@ -77,7 +92,10 @@ if (_writeHelper.hasGlobalGOTEntry(a)) this->_dynamicSymbolTable->addSymbol(a, ELF::SHN_UNDEF); - ExecutableWriter::buildDynamicSymbolTable(file); + // Skip our immediate parent class method + // ExecutableWriter::buildDynamicSymbolTable because we replaced it + // with our own version. Call OutputELFWriter directly. + OutputELFWriter::buildDynamicSymbolTable(file); } template Index: lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp +++ lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp @@ -471,16 +471,16 @@ return std::error_code(); } - const GOTAtom *getSharedGOT(const SharedLibraryAtom *sla) { - auto got = _gotMap.find(sla); + const GOTAtom *getSharedGOT(const Atom *a) { + auto got = _gotMap.find(a); if (got == _gotMap.end()) { auto g = new (_file._alloc) X86_64GOTAtom(_file, ".got.dyn"); - g->addReferenceELF_x86_64(R_X86_64_GLOB_DAT, 0, sla, 0); + g->addReferenceELF_x86_64(R_X86_64_GLOB_DAT, 0, a, 0); #ifndef NDEBUG g->_name = "__got_"; - g->_name += sla->name(); + g->_name += a->name(); #endif - _gotMap[sla] = g; + _gotMap[a] = g; _gotVector.push_back(g); return g; } @@ -488,12 +488,13 @@ } std::error_code handleGOT(const Reference &ref) { - if (isa(ref.target())) - const_cast(ref).setTarget(getNullGOT()); - else if (const DefinedAtom *da = dyn_cast(ref.target())) + if (const DefinedAtom *da = dyn_cast(ref.target())) const_cast(ref).setTarget(getGOT(da)); - else if (const auto sla = dyn_cast(ref.target())) - const_cast(ref).setTarget(getSharedGOT(sla)); + // Handle undefined atoms in the same way as shared lib atoms: to be + // resolved at run time. + else if (isa(ref.target()) || + isa(ref.target())) + const_cast(ref).setTarget(getSharedGOT(ref.target())); return std::error_code(); } }; Index: test/elf/X86_64/weaksym.test =================================================================== --- /dev/null +++ test/elf/X86_64/weaksym.test @@ -0,0 +1,78 @@ +# Tests that an executable with a weak undefine will put this symbol in the +# dynamic symbol table if the executable has a dynamic relocation against this +# symbol. + +#RUN: yaml2obj --format elf %s -o %t.o +#RUN: lld -flavor gnu -target x86_64 -e main %t.o -o %t1 +#RUN: llvm-readobj -dt %t1 | FileCheck -check-prefix CHECKSYMS %s + +#CHECKSYMS: Name: x@ +#CHECKSYMS-NEXT: Value: 0x0 +#CHECKSYMS-NEXT: Size: 0 +#CHECKSYMS-NEXT: Binding: Weak (0x2) +#CHECKSYMS-NEXT: Type: None (0x0) +#CHECKSYMS-NEXT: Other: 0 +#CHECKSYMS-NEXT: Section: Undefined (0x0) + +# The object file above corresponds to the following C program compiled with +# -fPIC: +# extern int *x __attribute__((weak)); +# +# int main() { +# if (x) +# return 1; +# return 0; +# } + +--- +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + OSABI: ELFOSABI_GNU + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000010 + Content: 554889E5488B0500000000C745FC00000000488138000000000F840C000000C745FC01000000E907000000C745FC000000008B45FC5DC3 + - Name: .rela.text + Type: SHT_RELA + Link: .symtab + AddressAlign: 0x0000000000000008 + Info: .text + Relocations: + - Offset: 0x0000000000000007 + Symbol: x + Type: R_X86_64_GOTPCREL + Addend: -4 + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000004 + Content: '' + - Name: .bss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000004 + Content: '' +Symbols: + Local: + - Name: .text + Type: STT_SECTION + Section: .text + - Name: .data + Type: STT_SECTION + Section: .data + - Name: .bss + Type: STT_SECTION + Section: .bss + Global: + - Name: main + Type: STT_FUNC + Section: .text + Size: 0x0000000000000037 + - Name: _GLOBAL_OFFSET_TABLE_ + Weak: + - Name: x