[lld] r190625 - Add a fallback mechanism for undefined atom.

Rui Ueyama ruiu at google.com
Thu Sep 12 12:14:06 PDT 2013


Author: ruiu
Date: Thu Sep 12 14:14:05 2013
New Revision: 190625

URL: http://llvm.org/viewvc/llvm-project?rev=190625&view=rev
Log:
Add a fallback mechanism for undefined atom.

In COFF, an undefined symbol can have up to one alternative name. If a symbol
is resolved by its regular name, then it's linked normally. If a symbol is not
found in any input files, all references to the regular name are resolved using
the alternative name. If the alternative name is not found, it's a link error.
This mechanism is called "weak externals".

To support this mechanism, I added a new member function fallback() to undefined
atom. If an undefined atom has the second name, fallback() returns a new undefined
atom that should be used instead of the original one to resolve undefines. If it
does not have the second name, the function returns nullptr.

Differential Revision: http://llvm-reviews.chandlerc.com/D1550

Added:
    lld/trunk/test/core/undef-fallback.objtxt
Modified:
    lld/trunk/include/lld/Core/SymbolTable.h
    lld/trunk/include/lld/Core/UndefinedAtom.h
    lld/trunk/lib/Core/Resolver.cpp
    lld/trunk/lib/Core/SymbolTable.cpp
    lld/trunk/lib/ReaderWriter/Native/NativeFileFormat.h
    lld/trunk/lib/ReaderWriter/Native/ReaderNative.cpp
    lld/trunk/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp

Modified: lld/trunk/include/lld/Core/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/SymbolTable.h?rev=190625&r1=190624&r2=190625&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/SymbolTable.h (original)
+++ lld/trunk/include/lld/Core/SymbolTable.h Thu Sep 12 14:14:05 2013
@@ -67,6 +67,9 @@ public:
   /// @brief count of by-name entries in symbol table
   unsigned int size();
 
+  /// @brief add atom to replacement table
+  void addReplacement(const Atom *replaced, const Atom *replacement);
+
   /// @brief if atom has been coalesced away, return replacement, else return atom
   const Atom *replacement(const Atom *);
 

Modified: lld/trunk/include/lld/Core/UndefinedAtom.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/UndefinedAtom.h?rev=190625&r1=190624&r2=190625&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/UndefinedAtom.h (original)
+++ lld/trunk/include/lld/Core/UndefinedAtom.h Thu Sep 12 14:14:05 2013
@@ -56,6 +56,14 @@ public:
   }
   static inline bool classof(const UndefinedAtom *) { return true; }
 
+  /// Returns an undefined atom if this undefined symbol has a synonym.  This is
+  /// mainly used in COFF. In COFF, an unresolved external symbol can have up to
+  /// one optional name (sym2) in addition to its regular name (sym1). If a
+  /// definition of sym1 exists, sym1 is resolved normally. Otherwise, all
+  /// references to sym1 refer to sym2 instead. In that case sym2 must be
+  /// resolved, or link will fail.
+  virtual const UndefinedAtom *fallback() const { return nullptr; }
+
 protected:
   UndefinedAtom() : Atom(definitionUndefined) {}
   virtual ~UndefinedAtom() {}

Modified: lld/trunk/lib/Core/Resolver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/Resolver.cpp?rev=190625&r1=190624&r2=190625&view=diff
==============================================================================
--- lld/trunk/lib/Core/Resolver.cpp (original)
+++ lld/trunk/lib/Core/Resolver.cpp Thu Sep 12 14:14:05 2013
@@ -198,7 +198,7 @@ void Resolver::resolveUndefines() {
     undefineGenCount = _symbolTable.size();
     std::vector<const UndefinedAtom *> undefines;
     _symbolTable.undefines(undefines);
-    for ( const Atom *undefAtom : undefines ) {
+    for (const UndefinedAtom *undefAtom : undefines) {
       StringRef undefName = undefAtom->name();
       // load for previous undefine may also have loaded this undefine
       if (!_symbolTable.isDefined(undefName)) {
@@ -208,6 +208,13 @@ void Resolver::resolveUndefines() {
                                     false,  // dataSymbolOnly
                                     *this);
       }
+      // If the undefined symbol has an alternative name, try to resolve the
+      // symbol with the name to give it a second chance. This feature is used
+      // for COFF "weak external" symbol.
+      if (const UndefinedAtom *fallbackUndefAtom = undefAtom->fallback()) {
+        _symbolTable.addReplacement(undefAtom, fallbackUndefAtom);
+        _symbolTable.add(*fallbackUndefAtom);
+      }
     }
     // search libraries for overrides of common symbols
     if (searchArchives || searchSharedLibs) {

Modified: lld/trunk/lib/Core/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/SymbolTable.cpp?rev=190625&r1=190624&r2=190625&view=diff
==============================================================================
--- lld/trunk/lib/Core/SymbolTable.cpp (original)
+++ lld/trunk/lib/Core/SymbolTable.cpp Thu Sep 12 14:14:05 2013
@@ -311,6 +311,11 @@ bool SymbolTable::isDefined(StringRef sy
   return true;
 }
 
+void SymbolTable::addReplacement(const Atom *replaced,
+                                 const Atom *replacement) {
+  _replacedAtoms[replaced] = replacement;
+}
+
 const Atom *SymbolTable::replacement(const Atom *atom) {
   AtomToAtom::iterator pos = _replacedAtoms.find(atom);
   if (pos == _replacedAtoms.end())
@@ -328,8 +333,12 @@ void SymbolTable::undefines(std::vector<
        end = _nameTable.end(); it != end; ++it) {
     const Atom *atom = it->second;
     assert(atom != nullptr);
-    if (const auto undef = dyn_cast<const UndefinedAtom>(atom))
+    if (const auto undef = dyn_cast<const UndefinedAtom>(atom)) {
+      AtomToAtom::iterator pos = _replacedAtoms.find(undef);
+      if (pos != _replacedAtoms.end())
+        continue;
       undefs.push_back(undef);
+    }
   }
 }
 

Modified: lld/trunk/lib/ReaderWriter/Native/NativeFileFormat.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/Native/NativeFileFormat.h?rev=190625&r1=190624&r2=190625&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/Native/NativeFileFormat.h (original)
+++ lld/trunk/lib/ReaderWriter/Native/NativeFileFormat.h Thu Sep 12 14:14:05 2013
@@ -164,10 +164,10 @@ struct NativeAtomAttributesV1 {
 struct NativeUndefinedAtomIvarsV1 {
   uint32_t  nameOffset;
   uint32_t  flags;
+  uint32_t  fallbackNameOffset;
 };
 
 
-
 //
 // The NCS_SharedLibraryAtomsV1 chunk contains an array of these structs
 //

Modified: lld/trunk/lib/ReaderWriter/Native/ReaderNative.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/Native/ReaderNative.cpp?rev=190625&r1=190624&r2=190625&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/Native/ReaderNative.cpp (original)
+++ lld/trunk/lib/ReaderWriter/Native/ReaderNative.cpp Thu Sep 12 14:14:05 2013
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "lld/ReaderWriter/Reader.h"
+#include "lld/ReaderWriter/Simple.h"
 
 #include "lld/Core/Atom.h"
 #include "lld/Core/Error.h"
@@ -134,10 +135,12 @@ public:
     return (CanBeNull)(_ivarData->flags & 0x3);
   }
 
+  virtual const UndefinedAtom *fallback() const;
 
 private:
   const File                        *_file;
   const NativeUndefinedAtomIvarsV1  *_ivarData;
+  mutable std::unique_ptr<const SimpleUndefinedAtom> _fallback;
 };
 
 
@@ -860,8 +863,14 @@ inline StringRef NativeUndefinedAtomV1::
   return _file->string(_ivarData->nameOffset);
 }
 
-
-
+inline const UndefinedAtom *NativeUndefinedAtomV1::fallback() const {
+  if (!_ivarData->fallbackNameOffset)
+    return nullptr;
+  if (!_fallback)
+    _fallback.reset(new SimpleUndefinedAtom(
+        *_file, _file->string(_ivarData->fallbackNameOffset)));
+  return _fallback.get();
+}
 
 inline const lld::File& NativeSharedLibraryAtomV1::file() const {
   return *_file;

Modified: lld/trunk/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp?rev=190625&r1=190624&r2=190625&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp (original)
+++ lld/trunk/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp Thu Sep 12 14:14:05 2013
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "lld/ReaderWriter/Reader.h"
+#include "lld/ReaderWriter/Simple.h"
 #include "lld/ReaderWriter/Writer.h"
 
 #include "lld/Core/ArchiveLibraryFile.h"
@@ -957,10 +958,13 @@ template <> struct MappingTraits<const l
   class NormalizedAtom : public lld::UndefinedAtom {
   public:
     NormalizedAtom(IO &io)
-        : _file(fileFromContext(io)), _name(), _canBeNull(canBeNullNever) {}
+        : _file(fileFromContext(io)), _name(), _canBeNull(canBeNullNever),
+          _fallback(nullptr) {}
+
     NormalizedAtom(IO &io, const lld::UndefinedAtom *atom)
         : _file(fileFromContext(io)), _name(atom->name()),
-          _canBeNull(atom->canBeNull()) {}
+          _canBeNull(atom->canBeNull()), _fallback(atom->fallback()) {}
+
     const lld::UndefinedAtom *denormalize(IO &io) {
       ContextInfo *info = reinterpret_cast<ContextInfo *>(io.getContext());
       assert(info != nullptr);
@@ -972,10 +976,11 @@ template <> struct MappingTraits<const l
 
       DEBUG_WITH_TYPE("WriterYAML",
                       llvm::dbgs() << "created UndefinedAtom named: '" << _name
-                                   << "' (" << (void *)_name.data() << ", "
-                                   << _name.size() << ")\n");
+                      << "' (" << (void *)_name.data() << ", "
+                      << _name.size() << ")\n");
       return this;
     }
+
     // Extract current File object from YAML I/O parsing context
     const lld::File &fileFromContext(IO &io) {
       ContextInfo *info = reinterpret_cast<ContextInfo *>(io.getContext());
@@ -987,10 +992,12 @@ template <> struct MappingTraits<const l
     virtual const lld::File &file() const { return _file; }
     virtual StringRef name() const { return _name; }
     virtual CanBeNull canBeNull() const { return _canBeNull; }
+    virtual const UndefinedAtom *fallback() const { return _fallback; }
 
     const lld::File &_file;
     StringRef _name;
     CanBeNull _canBeNull;
+    const UndefinedAtom *_fallback;
   };
 
   static void mapping(IO &io, const lld::UndefinedAtom *&atom) {
@@ -1000,6 +1007,8 @@ template <> struct MappingTraits<const l
     io.mapRequired("name", keys->_name);
     io.mapOptional("can-be-null", keys->_canBeNull,
                    lld::UndefinedAtom::canBeNullNever);
+    io.mapOptional("fallback", keys->_fallback,
+                   (const lld::UndefinedAtom *)nullptr);
   }
 };
 

Added: lld/trunk/test/core/undef-fallback.objtxt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/core/undef-fallback.objtxt?rev=190625&view=auto
==============================================================================
--- lld/trunk/test/core/undef-fallback.objtxt (added)
+++ lld/trunk/test/core/undef-fallback.objtxt Thu Sep 12 14:14:05 2013
@@ -0,0 +1,18 @@
+# RUN: lld -core %s | FileCheck %s
+
+# Test that fallback atoms can be parsed by YAML reader and processed by the
+# core linker.
+
+---
+defined-atoms:
+  - name: bar
+    type: code
+
+undefined-atoms:
+  - name: foo
+    fallback:
+      name: bar
+...
+
+# CHECK:      defined-atoms:
+# CHECK-NEXT:   - name: bar





More information about the llvm-commits mailing list