[lld] r219349 - [ELF] Fix inclusion of weak symbols in the dynamic symbol table

Rafael Auler rafaelauler at gmail.com
Wed Oct 8 15:38:11 PDT 2014


Author: rafauler
Date: Wed Oct  8 17:38:10 2014
New Revision: 219349

URL: http://llvm.org/viewvc/llvm-project?rev=219349&view=rev
Log:
[ELF] Fix inclusion of weak symbols in the dynamic symbol table

This commit implements in the X86_64 ELF lld backend yet another feature that
was only available in the MIPS backend. However, this patch changes generic ELF
classes to make it trivial for other ELF backends to use this logic too. When
creating a dynamic executable that has dynamic relocations against weak
undefined symbols, these symbols must be exported to the dynamic symbol table
to seek a possible resolution at run time.

A common use case is the __gmon_start__ weak glibc undefined symbol.

Reviewer: shankarke

http://reviews.llvm.org/D5571

Added:
    lld/trunk/test/elf/X86_64/weaksym.test
Modified:
    lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h
    lld/trunk/lib/ReaderWriter/ELF/ExecutableWriter.h
    lld/trunk/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h
    lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp

Modified: lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h?rev=219349&r1=219348&r2=219349&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h Wed Oct  8 17:38:10 2014
@@ -170,6 +170,8 @@ public:
 
   typedef typename std::vector<lld::AtomLayout *>::iterator AbsoluteAtomIterT;
 
+  typedef llvm::DenseSet<const Atom *> AtomSetT;
+
   DefaultLayout(const ELFLinkingContext &context) : _context(context) {}
 
   /// \brief Return the section order for a input section
@@ -297,8 +299,8 @@ public:
     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 @@ protected:
   LLD_UNIQUE_BUMP_PTR(RelocationTable<ELFT>) _dynamicRelocationTable;
   LLD_UNIQUE_BUMP_PTR(RelocationTable<ELFT>) _pltRelocationTable;
   std::vector<lld::AtomLayout *> _absoluteAtoms;
-  llvm::DenseSet<const SharedLibraryAtom *> _referencedDynAtoms;
+  AtomSetT _referencedDynAtoms;
   const ELFLinkingContext &_context;
 };
 
@@ -561,15 +563,28 @@ ErrorOr<const lld::AtomLayout &> Default
     StringRef sectionName = getSectionName(definedAtom);
     AtomSection<ELFT> *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<SharedLibraryAtom>(reloc->target()))
-        _referencedDynAtoms.insert(sla);
+        isLocalReloc = false;
+      }
+
+      if (!reloc->target())
+        continue;
+
+      //Ignore undefined atoms that are not target of dynamic relocations
+      if (isa<UndefinedAtom>(reloc->target()) && isLocalReloc)
+        continue;
+
+      _referencedDynAtoms.insert(reloc->target());
     }
+
     return section->appendAtom(atom);
   } else if (const AbsoluteAtom *absoluteAtom = dyn_cast<AbsoluteAtom>(atom)) {
     // Absolute atoms are not part of any section, they are global for the whole

Modified: lld/trunk/lib/ReaderWriter/ELF/ExecutableWriter.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ExecutableWriter.h?rev=219349&r1=219348&r2=219349&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ExecutableWriter.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/ExecutableWriter.h Wed Oct  8 17:38:10 2014
@@ -59,6 +59,15 @@ void ExecutableWriter<ELFT>::buildDynami
                                              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<ELFT>::buildDynamicSymbolTable(file);
 }
 

Modified: lld/trunk/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h?rev=219349&r1=219348&r2=219349&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h Wed Oct  8 17:38:10 2014
@@ -65,9 +65,24 @@ void MipsExecutableWriter<ELFT>::buildDy
   for (auto sec : this->_layout.sections())
     if (auto section = dyn_cast<AtomSection<ELFT>>(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<const DefinedAtom>(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 @@ void MipsExecutableWriter<ELFT>::buildDy
     if (_writeHelper.hasGlobalGOTEntry(a))
       this->_dynamicSymbolTable->addSymbol(a, ELF::SHN_UNDEF);
 
-  ExecutableWriter<ELFT>::buildDynamicSymbolTable(file);
+  // Skip our immediate parent class method
+  // ExecutableWriter<ELFT>::buildDynamicSymbolTable because we replaced it
+  // with our own version. Call OutputELFWriter directly.
+  OutputELFWriter<ELFT>::buildDynamicSymbolTable(file);
 }
 
 template <class ELFT>

Modified: lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp?rev=219349&r1=219348&r2=219349&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp Wed Oct  8 17:38:10 2014
@@ -471,16 +471,16 @@ public:
     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 @@ public:
   }
 
   std::error_code handleGOT(const Reference &ref) {
-    if (isa<UndefinedAtom>(ref.target()))
-      const_cast<Reference &>(ref).setTarget(getNullGOT());
-    else if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target()))
+    if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(ref.target()))
       const_cast<Reference &>(ref).setTarget(getGOT(da));
-    else if (const auto sla = dyn_cast<const SharedLibraryAtom>(ref.target()))
-      const_cast<Reference &>(ref).setTarget(getSharedGOT(sla));
+    // Handle undefined atoms in the same way as shared lib atoms: to be
+    // resolved at run time.
+    else if (isa<SharedLibraryAtom>(ref.target()) ||
+             isa<UndefinedAtom>(ref.target()))
+      const_cast<Reference &>(ref).setTarget(getSharedGOT(ref.target()));
     return std::error_code();
   }
 };

Added: lld/trunk/test/elf/X86_64/weaksym.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/X86_64/weaksym.test?rev=219349&view=auto
==============================================================================
--- lld/trunk/test/elf/X86_64/weaksym.test (added)
+++ lld/trunk/test/elf/X86_64/weaksym.test Wed Oct  8 17:38:10 2014
@@ -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





More information about the llvm-commits mailing list