[lld] r217363 - [ELF] Export strong defined symbol if it coalesces away a weak symbol

Simon Atanasyan simon at atanasyan.com
Mon Sep 8 02:43:38 PDT 2014


Author: atanasyan
Date: Mon Sep  8 04:43:38 2014
New Revision: 217363

URL: http://llvm.org/viewvc/llvm-project?rev=217363&view=rev
Log:
[ELF] Export strong defined symbol if it coalesces away a weak symbol
defined in a shared library.

Now LLD does not export a strong defined symbol if it coalesces away a
weak symbol defined in a shared library. This bug affects all ELF
architectures and leads to segfault:

  % cat foo.c
  extern int __attribute__((weak)) flag;
  int foo() { return flag; }

  % cat main.c
  int flag = 1;
  int foo();
  int main() { return foo() == 1 ? 0 : -1; }

  % clang -c -fPIC foo.c main.c
  % lld -flavor gnu -target x86_64 -shared -o libfoo.so ... foo.o
  % lld -flavor gnu -target x86_64 -o a.out ... main.o libfoo.so
  % ./a.out
  Segmentation fault

The problem is caused by the fact that we lose all information about
coalesced symbols after the `Resolver::resolve()` method is finished.

The patch solves the problem by overriding the
`LinkingContext::notifySymbolTableCoalesce()` method and saving names
of coalesced symbols. Later in the `buildDynamicSymbolTable()` routine
we use this information to export these symbols.

Added:
    lld/trunk/test/elf/X86_64/dynsym-weak.test
Modified:
    lld/trunk/include/lld/Core/LinkingContext.h
    lld/trunk/include/lld/Core/SymbolTable.h
    lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
    lld/trunk/lib/Core/SymbolTable.cpp
    lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
    lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h

Modified: lld/trunk/include/lld/Core/LinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/LinkingContext.h?rev=217363&r1=217362&r2=217363&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/LinkingContext.h (original)
+++ lld/trunk/include/lld/Core/LinkingContext.h Mon Sep  8 04:43:38 2014
@@ -234,9 +234,7 @@ public:
   /// but that can be changed by the LinkingContext.  This is also an
   /// opportunity for flavor specific processing.
   virtual void notifySymbolTableCoalesce(const Atom *existingAtom,
-                                         const Atom *newAtom,
-                                         bool &useNew) const {
-  }
+                                         const Atom *newAtom, bool &useNew) {}
 
   /// This method adds undefined symbols specified by the -u option to the to
   /// the list of undefined symbols known to the linker. This option essentially

Modified: lld/trunk/include/lld/Core/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/SymbolTable.h?rev=217363&r1=217362&r2=217363&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/SymbolTable.h (original)
+++ lld/trunk/include/lld/Core/SymbolTable.h Mon Sep  8 04:43:38 2014
@@ -36,7 +36,7 @@ class UndefinedAtom;
 /// if an atom has been coalesced away.
 class SymbolTable {
 public:
-  explicit SymbolTable(const LinkingContext &);
+  explicit SymbolTable(LinkingContext &);
 
   /// @brief add atom to symbol table
   bool add(const DefinedAtom &);
@@ -108,7 +108,7 @@ private:
   bool addByName(const Atom &);
   bool addByContent(const DefinedAtom &);
 
-  const LinkingContext &_context;
+  LinkingContext &_context;
   AtomToAtom _replacedAtoms;
   NameToAtom _nameTable;
   NameToAtom _groupTable;

Modified: lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h?rev=217363&r1=217362&r2=217363&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h Mon Sep  8 04:43:38 2014
@@ -19,6 +19,7 @@
 #include "lld/ReaderWriter/Reader.h"
 #include "lld/ReaderWriter/Writer.h"
 
+#include "llvm/ADT/StringSet.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/Object/ELF.h"
 #include "llvm/Support/ELF.h"
@@ -69,6 +70,9 @@ public:
   bool mergeCommonStrings() const { return _mergeCommonStrings; }
   virtual uint64_t getBaseAddress() const { return _baseAddress; }
 
+  void notifySymbolTableCoalesce(const Atom *existingAtom, const Atom *newAtom,
+                                 bool &useNew) 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
@@ -258,6 +262,10 @@ public:
 
   void setCreateSeparateROSegment() { _mergeRODataToTextSegment = false; }
 
+  bool hasCoalescedWeakPair(StringRef name) const {
+    return _weakCoalescedSymbols.count(name) != 0;
+  }
+
 private:
   ELFLinkingContext() LLVM_DELETED_FUNCTION;
 
@@ -292,6 +300,7 @@ protected:
   StringRefVector _rpathList;
   StringRefVector _rpathLinkList;
   std::map<std::string, uint64_t> _absoluteSymbols;
+  llvm::StringSet<> _weakCoalescedSymbols;
 };
 } // end namespace lld
 

Modified: lld/trunk/lib/Core/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/SymbolTable.cpp?rev=217363&r1=217362&r2=217363&view=diff
==============================================================================
--- lld/trunk/lib/Core/SymbolTable.cpp (original)
+++ lld/trunk/lib/Core/SymbolTable.cpp Mon Sep  8 04:43:38 2014
@@ -30,7 +30,7 @@
 #include <vector>
 
 namespace lld {
-SymbolTable::SymbolTable(const LinkingContext &context) : _context(context) {}
+SymbolTable::SymbolTable(LinkingContext &context) : _context(context) {}
 
 bool SymbolTable::add(const UndefinedAtom &atom) { return addByName(atom); }
 

Modified: lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp?rev=217363&r1=217362&r2=217363&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp Mon Sep  8 04:43:38 2014
@@ -241,4 +241,29 @@ std::unique_ptr<File> ELFLinkingContext:
   return std::move(undefinedSymFile);
 }
 
+static bool isSharedWeakAtom(const UndefinedAtom *ua) {
+  return ua->canBeNull() != UndefinedAtom::canBeNullNever &&
+         isa<SharedLibraryFile>(ua->file());
+}
+
+void ELFLinkingContext::notifySymbolTableCoalesce(const Atom *existingAtom,
+                                                  const Atom *newAtom,
+                                                  bool &useNew) {
+  // First suppose that the `existingAtom` is defined
+  // and the `newAtom` is undefined.
+  auto *da = dyn_cast<DefinedAtom>(existingAtom);
+  auto *ua = dyn_cast<UndefinedAtom>(newAtom);
+  if (!da && !ua) {
+    // Then try to reverse the assumption.
+    da = dyn_cast<DefinedAtom>(newAtom);
+    ua = dyn_cast<UndefinedAtom>(existingAtom);
+  }
+
+  if (da && ua && da->scope() == Atom::scopeGlobal && isSharedWeakAtom(ua))
+    // If strong defined atom coalesces away weak atom declared
+    // in the shared object the strong atom needs to be dynamicaly exported.
+    // Save its name.
+    _weakCoalescedSymbols.insert(ua->name());
+}
+
 } // end namespace lld

Modified: lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h?rev=217363&r1=217362&r2=217363&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h Mon Sep  8 04:43:38 2014
@@ -182,7 +182,8 @@ void OutputELFWriter<ELFT>::buildDynamic
     if (auto section = dyn_cast<AtomSection<ELFT>>(sec))
       for (const auto &atom : section->atoms()) {
         const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom->_atom);
-        if (da && da->dynamicExport() == DefinedAtom::dynamicExportAlways)
+        if (da && (da->dynamicExport() == DefinedAtom::dynamicExportAlways ||
+                   _context.hasCoalescedWeakPair(da->name())))
           _dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
                                          atom->_virtualAddr, atom);
       }

Added: lld/trunk/test/elf/X86_64/dynsym-weak.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/X86_64/dynsym-weak.test?rev=217363&view=auto
==============================================================================
--- lld/trunk/test/elf/X86_64/dynsym-weak.test (added)
+++ lld/trunk/test/elf/X86_64/dynsym-weak.test Mon Sep  8 04:43:38 2014
@@ -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
+...





More information about the llvm-commits mailing list