[lld] r179257 - This adds functionality for undefined atoms from dynamic libraries to be added

Shankar Easwaran shankare at codeaurora.org
Wed Apr 10 19:56:31 PDT 2013


Author: shankare
Date: Wed Apr 10 21:56:30 2013
New Revision: 179257

URL: http://llvm.org/viewvc/llvm-project?rev=179257&view=rev
Log:
This adds functionality for undefined atoms from dynamic libraries to be added
to the list of undefined atoms. 

The processing of undefined atoms from dynamic libraries is controlled by
use-shlib-undefines command line option. 

This patch also adds additional command line arguments to allow/disallow
unresolved symbols from shared libraries and mimics GNU ld behavior.


Added:
    lld/trunk/test/elf/dynamic-undef.test
Modified:
    lld/trunk/include/lld/Core/Resolver.h
    lld/trunk/include/lld/Core/TargetInfo.h
    lld/trunk/include/lld/ReaderWriter/ELFTargetInfo.h
    lld/trunk/lib/Core/Resolver.cpp
    lld/trunk/lib/Core/TargetInfo.cpp
    lld/trunk/lib/Driver/GnuLdDriver.cpp
    lld/trunk/lib/Driver/LDOptions.td
    lld/trunk/lib/ReaderWriter/ELF/Atoms.h
    lld/trunk/lib/ReaderWriter/ELF/DynamicFile.h
    lld/trunk/lib/ReaderWriter/ELF/ELFTargetInfo.cpp
    lld/trunk/test/elf/dynamic-segorder.test
    lld/trunk/test/elf/dynamic.test

Modified: lld/trunk/include/lld/Core/Resolver.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/Resolver.h?rev=179257&r1=179256&r2=179257&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/Resolver.h (original)
+++ lld/trunk/include/lld/Core/Resolver.h Wed Apr 10 21:56:30 2013
@@ -12,6 +12,7 @@
 
 #include "lld/Core/File.h"
 #include "lld/Core/InputFiles.h"
+#include "lld/Core/SharedLibraryFile.h"
 #include "lld/Core/SymbolTable.h"
 
 #include "llvm/ADT/DenseSet.h"

Modified: lld/trunk/include/lld/Core/TargetInfo.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/TargetInfo.h?rev=179257&r1=179256&r2=179257&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/TargetInfo.h (original)
+++ lld/trunk/include/lld/Core/TargetInfo.h Wed Apr 10 21:56:30 2013
@@ -35,44 +35,44 @@ class InputFiles;
 
 /// \brief The TargetInfo class encapsulates "what and how" to link.
 ///
-/// The base class TargetInfo contains the options needed by core linking.  
-/// Subclasses of TargetInfo have additional options needed by specific Readers 
-/// and Writers. For example, ELFTargetInfo has methods that supplies options 
+/// The base class TargetInfo contains the options needed by core linking.
+/// Subclasses of TargetInfo have additional options needed by specific Readers
+/// and Writers. For example, ELFTargetInfo has methods that supplies options
 /// to the ELF Reader and Writer.
 ///
-/// \todo Consider renaming to something like "LinkingOptions".  
+/// \todo Consider renaming to something like "LinkingOptions".
 class TargetInfo : public Reader {
 public:
   virtual ~TargetInfo();
 
   /// \name Methods needed by core linking
   /// @{
-  
-  /// Name of symbol linker should use as "entry point" to program, 
+
+  /// Name of symbol linker should use as "entry point" to program,
   /// usually "main" or "start".
-  StringRef entrySymbolName() const { 
-    return _entrySymbolName; 
+  StringRef entrySymbolName() const {
+    return _entrySymbolName;
   }
-  
-  /// Whether core linking should remove Atoms not reachable by following 
+
+  /// Whether core linking should remove Atoms not reachable by following
   /// References from the entry point Atom or from all global scope Atoms
   /// if globalsAreDeadStripRoots() is true.
-  bool deadStrip() const { 
-    return _deadStrip; 
+  bool deadStrip() const {
+    return _deadStrip;
   }
-  
+
   /// Only used if deadStrip() returns true.  Means all global scope Atoms
   /// should be marked live (along with all Atoms they reference).  Usually
   /// this method returns false for main executables, but true for dynamic
   /// shared libraries.
   bool globalsAreDeadStripRoots() const {
     assert(_deadStrip && "only applicable when deadstripping enabled");
-    return _globalsAreDeadStripRoots; 
+    return _globalsAreDeadStripRoots;
   }
-  
+
   /// Only used if deadStrip() returns true.  This method returns the names
-  /// of DefinedAtoms that should be marked live (along with all Atoms they 
-  /// reference). Only Atoms with scope scopeLinkageUnit or scopeGlobal can 
+  /// of DefinedAtoms that should be marked live (along with all Atoms they
+  /// reference). Only Atoms with scope scopeLinkageUnit or scopeGlobal can
   /// be kept live using this method.
   const std::vector<StringRef> &deadStripRoots() const {
     return _deadStripRoots;
@@ -80,51 +80,51 @@ public:
 
   /// Archive files (aka static libraries) are normally lazily loaded.  That is,
   /// object files within an archive are only loaded and linked in, if the
-  /// object file contains a DefinedAtom which will replace an existing  
+  /// object file contains a DefinedAtom which will replace an existing
   /// UndefinedAtom.  If this method returns true, core linking will actively
   /// load every member object file from every archive.
-  bool forceLoadAllArchives() const { 
-    return _forceLoadAllArchives; 
+  bool forceLoadAllArchives() const {
+    return _forceLoadAllArchives;
   }
-  
+
   /// Archive files (aka static libraries) are normally lazily loaded.  That is,
   /// object files within an archive are only loaded and linked in, if the
-  /// object file contains a DefinedAtom which will replace an existing  
+  /// object file contains a DefinedAtom which will replace an existing
   /// UndefinedAtom.  If this method returns true, core linking will also look
   /// for archive members to replace existing tentative definitions in addition
   /// to replacing undefines. Note: a "tentative definition" (also called a
   /// "common" symbols) is a C (but not C++) concept. They are modeled in lld
   /// as a DefinedAtom with merge() of mergeAsTentative.
-  bool searchArchivesToOverrideTentativeDefinitions() const { 
-    return _searchArchivesToOverrideTentativeDefinitions; 
+  bool searchArchivesToOverrideTentativeDefinitions() const {
+    return _searchArchivesToOverrideTentativeDefinitions;
   }
-  
+
   /// Normally core linking will turn a tentative definition into a real
   /// definition if not replaced by a real DefinedAtom from some object file.
   /// If this method returns true, core linking will search all supplied
   /// dynamic shared libraries for symbol names that match remaining tentative
   /// definitions.  If any are found, the corresponding tentative definition
-  /// atom is replaced with SharedLibraryAtom. 
-  bool searchSharedLibrariesToOverrideTentativeDefinitions() const { 
-    return _searchSharedLibrariesToOverrideTentativeDefinitions; 
+  /// atom is replaced with SharedLibraryAtom.
+  bool searchSharedLibrariesToOverrideTentativeDefinitions() const {
+    return _searchSharedLibrariesToOverrideTentativeDefinitions;
   }
-  
+
   /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
   /// SharedLibraryAtom for the link to be successful.  This method controls
   /// whether core linking prints out a list of remaining UndefinedAtoms.
   ///
-  /// \todo This should be a method core linking calls with a list of the 
+  /// \todo This should be a method core linking calls with a list of the
   /// UndefinedAtoms so that different drivers can format the error message
   /// as needed.
-  bool printRemainingUndefines() const { 
-    return _printRemainingUndefines; 
+  bool printRemainingUndefines() const {
+    return _printRemainingUndefines;
   }
 
   /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
   /// SharedLibraryAtom for the link to be successful.  This method controls
   /// whether core linking considers remaining undefines to be an error.
-  bool allowRemainingUndefines() const { 
-    return _allowRemainingUndefines; 
+  bool allowRemainingUndefines() const {
+    return _allowRemainingUndefines;
   }
 
   /// In the lld model, a SharedLibraryAtom is a proxy atom for something
@@ -135,48 +135,56 @@ public:
   /// when merging core linking will also verify that they both have the same
   /// loadName() and if not print a warning.
   ///
-  /// \todo This should be a method core linking calls so that drivers can 
+  /// \todo This should be a method core linking calls so that drivers can
   /// format the warning as needed.
-  bool warnIfCoalesableAtomsHaveDifferentLoadName() const { 
-    return _warnIfCoalesableAtomsHaveDifferentLoadName; 
+  bool warnIfCoalesableAtomsHaveDifferentLoadName() const {
+    return _warnIfCoalesableAtomsHaveDifferentLoadName;
   }
-  
-  /// In C/C++ you can mark a function's prototype with 
-  /// __attribute__((weak_import)) or __attribute__((weak)) to say the function 
+
+  /// In C/C++ you can mark a function's prototype with
+  /// __attribute__((weak_import)) or __attribute__((weak)) to say the function
   /// may not be available at runtime and/or build time and in which case its
-  /// address will evaluate to NULL. In lld this is modeled using the 
+  /// address will evaluate to NULL. In lld this is modeled using the
   /// UndefinedAtom::canBeNull() method.  During core linking, UndefinedAtom
   /// with the same name are automatically merged.  If this method returns
   /// true, core link also verfies that the canBeNull() value for merged
   /// UndefinedAtoms are the same and warns if not.
   ///
-  /// \todo This should be a method core linking calls so that drivers can 
+  /// \todo This should be a method core linking calls so that drivers can
   /// format the warning as needed.
-  bool warnIfCoalesableAtomsHaveDifferentCanBeNull() const { 
-    return _warnIfCoalesableAtomsHaveDifferentCanBeNull; 
+  bool warnIfCoalesableAtomsHaveDifferentCanBeNull() const {
+    return _warnIfCoalesableAtomsHaveDifferentCanBeNull;
+  }
+
+  /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
+  /// SharedLibraryAtom for the link to be successful.  This method controls
+  /// whether core linking considers remaining undefines from the shared library
+  /// to be an error.
+  bool allowShlibUndefines() const {
+    return _allowShlibUndefines;
   }
-  
+
   /// If true, core linking will write the path to each input file to stdout
   /// (i.e. llvm::outs()) as it is used.  This is used to implement the -t
   /// linker option.
   ///
-  /// \todo This should be a method core linking calls so that drivers can 
+  /// \todo This should be a method core linking calls so that drivers can
   /// format the line as needed.
   bool logInputFiles() const {
-    return _logInputFiles; 
+    return _logInputFiles;
   }
-  
+
   /// Parts of LLVM use global variables which are bound to command line
   /// options (see llvm::cl::Options). This method returns "command line"
-  /// options which are used to configure LLVM's command line settings.  
+  /// options which are used to configure LLVM's command line settings.
   /// For instance the -debug-only XXX option can be used to dynamically
   /// trace different parts of LLVM and lld.
   const std::vector<const char*> &llvmOptions() const {
     return _llvmOptions;
   }
-  
+
   /// This method returns the sequence of input files for core linking to
-  /// process.  
+  /// process.
   ///
   /// \todo Consider moving this out of TargetInfo so that the same TargetInfo
   /// object can be reused for different links.
@@ -184,85 +192,88 @@ public:
     return _inputFiles;
   }
   /// @}
-  
-  
+
+
   /// \name Methods used by Drivers to configure TargetInfo
   /// @{
   void setOutputPath(StringRef str) { _outputPath = str; }
   void setEntrySymbolName(StringRef name) { _entrySymbolName = name; }
   void setDeadStripping(bool enable) { _deadStrip = enable; }
   void setGlobalsAreDeadStripRoots(bool v) { _globalsAreDeadStripRoots = v; }
-  void setSearchArchivesToOverrideTentativeDefinitions(bool search) { 
-    _searchArchivesToOverrideTentativeDefinitions = search; 
+  void setSearchArchivesToOverrideTentativeDefinitions(bool search) {
+    _searchArchivesToOverrideTentativeDefinitions = search;
   }
-  void setSearchSharedLibrariesToOverrideTentativeDefinitions(bool search) { 
-    _searchSharedLibrariesToOverrideTentativeDefinitions = search; 
+  void setSearchSharedLibrariesToOverrideTentativeDefinitions(bool search) {
+    _searchSharedLibrariesToOverrideTentativeDefinitions = search;
   }
-  void setWarnIfCoalesableAtomsHaveDifferentCanBeNull(bool warn) { 
-    _warnIfCoalesableAtomsHaveDifferentCanBeNull = warn; 
+  void setWarnIfCoalesableAtomsHaveDifferentCanBeNull(bool warn) {
+    _warnIfCoalesableAtomsHaveDifferentCanBeNull = warn;
   }
-  void setWarnIfCoalesableAtomsHaveDifferentLoadName(bool warn) { 
-    _warnIfCoalesableAtomsHaveDifferentLoadName = warn; 
+  void setWarnIfCoalesableAtomsHaveDifferentLoadName(bool warn) {
+    _warnIfCoalesableAtomsHaveDifferentLoadName = warn;
   }
-  void setForceLoadAllArchives(bool force) { 
-    _forceLoadAllArchives = force; 
+  void setForceLoadAllArchives(bool force) {
+    _forceLoadAllArchives = force;
   }
-  void setPrintRemainingUndefines(bool print) { 
-    _printRemainingUndefines = print; 
+  void setPrintRemainingUndefines(bool print) {
+    _printRemainingUndefines = print;
   }
-  void setAllowRemainingUndefines(bool allow) { 
-    _allowRemainingUndefines = allow; 
+  void setAllowRemainingUndefines(bool allow) {
+    _allowRemainingUndefines = allow;
   }
-  void setLogInputFiles(bool log) { 
-    _logInputFiles = log; 
+  void setAllowShlibUndefines(bool allow) {
+    _allowShlibUndefines = allow;
   }
-  void appendInputFile(StringRef path) { 
+  void setLogInputFiles(bool log) {
+    _logInputFiles = log;
+  }
+  void appendInputFile(StringRef path) {
     _inputFiles.emplace_back(LinkerInput(path));
   }
-  void appendInputFile(std::unique_ptr<llvm::MemoryBuffer> buffer) { 
+  void appendInputFile(std::unique_ptr<llvm::MemoryBuffer> buffer) {
     _inputFiles.emplace_back(LinkerInput(std::move(buffer)));
   }
-  void appendLLVMOption(const char *opt) { 
+  void appendLLVMOption(const char *opt) {
     _llvmOptions.push_back(opt);
   }
-  
+
   /// After all set* methods are called, the Driver calls this method
   /// to validate that there are no missing options or invalid combinations
   /// of options.  If there is a problem, a description of the problem
   /// is written to the supplied stream.
   ///
-  /// \returns true if there is an error with the current settings.  
+  /// \returns true if there is an error with the current settings.
   virtual bool validate(raw_ostream &diagnostics) = 0;
 
 
   /// @}
   /// \name Methods used by Driver::link()
   /// @{
-  
+
   /// Returns the file system path to which the linked output should be written.
   ///
   /// \todo To support in-memory linking, we need an abstraction that allows
   /// the linker to write to an in-memory buffer.
-  StringRef outputPath() const { 
-    return _outputPath; 
+  StringRef outputPath() const {
+    return _outputPath;
   }
-  
+
   /// Abstract method to parse a supplied input file buffer into one or
-  /// more lld::File objects. Subclasses of TargetInfo must implement this 
-  /// method. 
+  /// more lld::File objects. Subclasses of TargetInfo must implement this
+  /// method.
   ///
   /// \param inputBuff This is an in-memory read-only copy of the input file.
   /// If the resulting lld::File object will contain pointers into
   /// this memory buffer, the lld::File object should take ownership
-  /// of the buffer.  Otherwise core linking will maintain ownership of the 
-  /// buffer and delete it at some point. 
+  /// of the buffer.  Otherwise core linking will maintain ownership of the
+  /// buffer and delete it at some point.
   ///
   /// \param [out] result The instantiated lld::File object is returned here.
   /// The \p result is a vector because some input files parse into more than
-  /// one lld::File (e.g. YAML). 
+  /// one lld::File (e.g. YAML).
   virtual error_code parseFile(std::unique_ptr<MemoryBuffer> &inputBuff,
                         std::vector<std::unique_ptr<File>> &result) const = 0;
-  
+
   /// This is a wrapper around parseFile() where the input file is specified
   /// by file system path.  The default implementation reads the input file
   /// into a memory buffer and calls parseFile().
@@ -276,12 +287,12 @@ public:
   /// to add file format specific "files" to set of files to be linked. This is
   /// how file format specific atoms can be added to the link.
   virtual void addImplicitFiles(InputFiles&) const;
-  
+
   /// This method is called by core linking to build the list of Passes to be
   /// run on the merged/linked graph of all input files.
   virtual void addPasses(PassManager &pm) const;
 
-  /// Calls through to the writeFile() method on the specified Writer. 
+  /// Calls through to the writeFile() method on the specified Writer.
   ///
   /// \param linkedFile This is the merged/linked graph of all input file Atoms.
   virtual error_code writeFile(const File &linkedFile) const;
@@ -289,18 +300,18 @@ public:
   /// @}
 
 
-  /// \name Methods needed by YAML I/O and error messages to convert Kind values 
+  /// \name Methods needed by YAML I/O and error messages to convert Kind values
   /// to and from strings.
   /// @{
-  
-  /// Abstract method to parse a kind name string into an integral 
+
+  /// Abstract method to parse a kind name string into an integral
   /// Reference::Kind
   virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const = 0;
 
-  /// Abstract method to return the name for a given integral 
+  /// Abstract method to return the name for a given integral
   /// Reference::Kind.
   virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind k) const = 0;
-  
+
   /// @}
 
 
@@ -310,7 +321,7 @@ protected:
 
   /// Abstract method to lazily instantiate the Writer.
   virtual Writer &writer() const = 0;
-  
+
 
   StringRef                _outputPath;
   StringRef                _entrySymbolName;
@@ -324,6 +335,7 @@ protected:
   bool                     _printRemainingUndefines;
   bool                     _allowRemainingUndefines;
   bool                     _logInputFiles;
+  bool                     _allowShlibUndefines;
   std::vector<StringRef>   _deadStripRoots;
   std::vector<LinkerInput> _inputFiles;
   std::vector<const char*> _llvmOptions;

Modified: lld/trunk/include/lld/ReaderWriter/ELFTargetInfo.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/ELFTargetInfo.h?rev=179257&r1=179256&r2=179257&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/ELFTargetInfo.h (original)
+++ lld/trunk/include/lld/ReaderWriter/ELFTargetInfo.h Wed Apr 10 21:56:30 2013
@@ -45,6 +45,13 @@ public:
   bool mergeCommonStrings() const { return _mergeCommonStrings; }
   virtual uint64_t getBaseAddress() const { return _baseAddress; }
 
+  /// 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
+  /// in the shared library
+  bool useShlibUndefines() const { return _useShlibUndefines; }
+  /// @}
+
   /// \brief Does this relocation belong in the dynamic relocation table?
   ///
   /// This table is evaluated at loadtime by the dynamic loader and is
@@ -60,7 +67,7 @@ public:
 
   virtual error_code parseFile(std::unique_ptr<MemoryBuffer> &mb,
                         std::vector<std::unique_ptr<File>> &result) const;
-   
+
   static std::unique_ptr<ELFTargetInfo> create(llvm::Triple);
 
   /// \brief Does this relocation belong in the dynamic plt relocation table?
@@ -79,7 +86,7 @@ public:
   }
 
   /// \brief Does the output have dynamic sections.
-  bool isDynamic() const; 
+  bool isDynamic() const;
 
   template <typename ELFT>
   lld::elf::TargetHandler<ELFT> &getTargetHandler() const {
@@ -95,16 +102,17 @@ public:
   void setNoInhibitExec(bool v) { _noInhibitExec = v; }
   void setIsStaticExecutable(bool v) { _isStaticExecutable = v; }
   void setMergeCommonStrings(bool v) { _mergeCommonStrings = v; }
-  void appendSearchPath(StringRef dirPath) { 
+  void setUseShlibUndefines(bool use) { _useShlibUndefines = use; }
+  void appendSearchPath(StringRef dirPath) {
     _inputSearchPaths.push_back(dirPath);
   }
   /// Searches directories then calls appendInputFile()
   bool appendLibrary(StringRef libName);
-  
+
 private:
   ELFTargetInfo() LLVM_DELETED_FUNCTION;
 protected:
-  ELFTargetInfo(llvm::Triple); 
+  ELFTargetInfo(llvm::Triple);
 
   virtual Writer &writer() const;
 
@@ -117,6 +125,7 @@ protected:
   bool                               _noInhibitExec;
   bool                               _mergeCommonStrings;
   bool                               _runLayoutPass;
+  bool                               _useShlibUndefines;
   std::vector<StringRef>             _inputSearchPaths;
   llvm::BumpPtrAllocator             _extraStrings;
   mutable std::unique_ptr<Reader>    _elfReader;

Modified: lld/trunk/lib/Core/Resolver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/Resolver.cpp?rev=179257&r1=179256&r2=179257&view=diff
==============================================================================
--- lld/trunk/lib/Core/Resolver.cpp (original)
+++ lld/trunk/lib/Core/Resolver.cpp Wed Apr 10 21:56:30 2013
@@ -181,11 +181,11 @@ void Resolver::addAtoms(const std::vecto
 // ask symbol table if any definitionUndefined atoms still exist
 // if so, keep searching libraries until no more atoms being added
 void Resolver::resolveUndefines() {
-  const bool searchArchives   = 
-                    _targetInfo.searchArchivesToOverrideTentativeDefinitions();
-  const bool searchSharedLibs = 
-             _targetInfo.searchSharedLibrariesToOverrideTentativeDefinitions();
-  
+  const bool searchArchives =
+      _targetInfo.searchArchivesToOverrideTentativeDefinitions();
+  const bool searchSharedLibs =
+      _targetInfo.searchSharedLibrariesToOverrideTentativeDefinitions();
+
   // keep looping until no more undefines were added in last loop
   unsigned int undefineGenCount = 0xFFFFFFFF;
   while (undefineGenCount != _symbolTable.size()) {
@@ -311,15 +311,23 @@ bool Resolver::checkUndefines(bool final
 
   // error message about missing symbols
   if (!undefinedAtoms.empty()) {
-    // FIXME: need diagonstics interface for writing error messages
+    // FIXME: need diagnostics interface for writing error messages
     bool foundUndefines = false;
     for (const UndefinedAtom *undefAtom : undefinedAtoms) {
-      if (undefAtom->canBeNull() == UndefinedAtom::canBeNullNever) {
-        foundUndefines = true;
-        if (_targetInfo.printRemainingUndefines()) {
-          llvm::errs() << "Undefined Symbol: " << undefAtom->file().path()
-                       << " : " << undefAtom->name() << "\n";
+      const File &f = undefAtom->file();
+      bool isAtomUndefined = false;
+      if (isa<SharedLibraryFile>(f)) {
+        if (!_targetInfo.allowShlibUndefines()) {
+          foundUndefines = true;
+          isAtomUndefined = true;
         }
+      } else if (undefAtom->canBeNull() == UndefinedAtom::canBeNullNever) {
+        foundUndefines = true;
+        isAtomUndefined = true;
+      }
+      if (isAtomUndefined && _targetInfo.printRemainingUndefines()) {
+        llvm::errs() << "Undefined Symbol: " << undefAtom->file().path()
+                     << " : " << undefAtom->name() << "\n";
       }
     }
     if (foundUndefines) {

Modified: lld/trunk/lib/Core/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/TargetInfo.cpp?rev=179257&r1=179256&r2=179257&view=diff
==============================================================================
--- lld/trunk/lib/Core/TargetInfo.cpp (original)
+++ lld/trunk/lib/Core/TargetInfo.cpp Wed Apr 10 21:56:30 2013
@@ -15,23 +15,17 @@
 namespace lld {
 
 TargetInfo::TargetInfo()
-  : Reader(*this)
-  , _deadStrip(false)
-  , _globalsAreDeadStripRoots(false)
-  , _searchArchivesToOverrideTentativeDefinitions(false)
-  , _searchSharedLibrariesToOverrideTentativeDefinitions(false)
-  , _warnIfCoalesableAtomsHaveDifferentCanBeNull(false)
-  , _warnIfCoalesableAtomsHaveDifferentLoadName(false)
-  , _forceLoadAllArchives(false)
-  , _printRemainingUndefines(true)
-  , _allowRemainingUndefines(false)
-  , _logInputFiles(false)
-{
-}
+    : Reader(*this), _deadStrip(false), _globalsAreDeadStripRoots(false),
+      _searchArchivesToOverrideTentativeDefinitions(false),
+      _searchSharedLibrariesToOverrideTentativeDefinitions(false),
+      _warnIfCoalesableAtomsHaveDifferentCanBeNull(false),
+      _warnIfCoalesableAtomsHaveDifferentLoadName(false),
+      _forceLoadAllArchives(false), _printRemainingUndefines(true),
+      _allowRemainingUndefines(false), _logInputFiles(false),
+      _allowShlibUndefines(false) {}
 
 TargetInfo::~TargetInfo() {}
 
-
 error_code TargetInfo::readFile(StringRef path,
                         std::vector<std::unique_ptr<File>> &result) const {
   OwningPtr<llvm::MemoryBuffer> opmb;

Modified: lld/trunk/lib/Driver/GnuLdDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/GnuLdDriver.cpp?rev=179257&r1=179256&r2=179257&view=diff
==============================================================================
--- lld/trunk/lib/Driver/GnuLdDriver.cpp (original)
+++ lld/trunk/lib/Driver/GnuLdDriver.cpp Wed Apr 10 21:56:30 2013
@@ -77,33 +77,33 @@ bool GnuLdDriver::linkELF(int argc, cons
   std::unique_ptr<ELFTargetInfo> options(parse(argc, argv, diagnostics));
   if (!options)
     return true;
-    
+
   return link(*options, diagnostics);
 }
 
-
-std::unique_ptr<ELFTargetInfo> GnuLdDriver::parse(int argc, const char *argv[],  
-                                                  raw_ostream &diagnostics) {
+std::unique_ptr<ELFTargetInfo>
+GnuLdDriver::parse(int argc, const char *argv[], raw_ostream &diagnostics) {
   // Parse command line options using LDOptions.td
   std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
   GnuLdOptTable table;
   unsigned missingIndex;
   unsigned missingCount;
-  parsedArgs.reset(table.ParseArgs(&argv[1], &argv[argc], 
-                                                missingIndex, missingCount));
+  parsedArgs.reset(
+      table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
   if (missingCount) {
-    diagnostics  << "error: missing arg value for '"
-                 << parsedArgs->getArgString(missingIndex)
-                 << "' expected " << missingCount << " argument(s).\n";
+    diagnostics << "error: missing arg value for '"
+                << parsedArgs->getArgString(missingIndex) << "' expected "
+                << missingCount << " argument(s).\n";
     return nullptr;
   }
 
   for (auto it = parsedArgs->filtered_begin(OPT_UNKNOWN),
             ie = parsedArgs->filtered_end(); it != ie; ++it) {
-    diagnostics  << "warning: ignoring unknown argument: "
-                 << (*it)->getAsString(*parsedArgs) << "\n";
+    diagnostics << "warning: ignoring unknown argument: " << (*it)->getAsString(
+                                                                 *parsedArgs)
+                << "\n";
   }
-  
+
   // Handle --help
   if (parsedArgs->getLastArg(OPT_help)) {
     table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
@@ -112,37 +112,36 @@ std::unique_ptr<ELFTargetInfo> GnuLdDriv
 
   // Use -target or use default target triple to instantiate TargetInfo
   llvm::Triple triple;
-  if (llvm::opt::Arg *trip = parsedArgs->getLastArg(OPT_target)) 
+  if (llvm::opt::Arg *trip = parsedArgs->getLastArg(OPT_target))
     triple = llvm::Triple(trip->getValue());
   else
     triple = getDefaultTarget(argv[0]);
   std::unique_ptr<ELFTargetInfo> options(ELFTargetInfo::create(triple));
-  
+
   if (!options) {
     diagnostics << "unknown target triple\n";
     return nullptr;
   }
-  
+
   // Handle -e xxx
   if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry))
     options->setEntrySymbolName(entry->getValue());
-    
+
   // Handle -emit-yaml
   if (parsedArgs->getLastArg(OPT_emit_yaml))
     options->setOutputYAML(true);
-  
+
   // Handle -o xxx
-  if (llvm::opt::Arg *output = parsedArgs->getLastArg(OPT_output)) 
+  if (llvm::opt::Arg *output = parsedArgs->getLastArg(OPT_output))
     options->setOutputPath(output->getValue());
   else if (options->outputYAML())
-    options->setOutputPath("-");  // yaml writes to stdout by default
+    options->setOutputPath("-"); // yaml writes to stdout by default
   else
     options->setOutputPath("a.out");
-    
+
   // Handle -r, -shared, or -static
-  if ( llvm::opt::Arg *kind = parsedArgs->getLastArg(OPT_relocatable, 
-                                                     OPT_shared,
-                                                     OPT_static)) {
+  if (llvm::opt::Arg *kind =
+          parsedArgs->getLastArg(OPT_relocatable, OPT_shared, OPT_static)) {
     switch (kind->getOption().getID()) {
     case OPT_relocatable:
       options->setOutputFileType(llvm::ELF::ET_REL);
@@ -151,60 +150,76 @@ std::unique_ptr<ELFTargetInfo> GnuLdDriv
       break;
     case OPT_shared:
       options->setOutputFileType(llvm::ELF::ET_DYN);
+      options->setAllowShlibUndefines(true);
+      options->setUseShlibUndefines(false);
       break;
     case OPT_static:
       options->setOutputFileType(llvm::ELF::ET_EXEC);
       options->setIsStaticExecutable(true);
       break;
     }
+  } else {
+    options->setOutputFileType(llvm::ELF::ET_EXEC);
+    options->setIsStaticExecutable(false);
+    options->setAllowShlibUndefines(false);
+    options->setUseShlibUndefines(true);
   }
-  else {
-      options->setOutputFileType(llvm::ELF::ET_EXEC);
-      options->setIsStaticExecutable(false);
-  }
-  
+
   // Handle --noinhibit-exec
-  if (parsedArgs->getLastArg(OPT_noinhibit_exec)) 
+  if (parsedArgs->getLastArg(OPT_noinhibit_exec))
     options->setAllowRemainingUndefines(true);
-    
+
   // Handle --force-load
   if (parsedArgs->getLastArg(OPT_force_load))
     options->setForceLoadAllArchives(true);
-  
+
   // Handle --merge-strings
   if (parsedArgs->getLastArg(OPT_merge_strings))
     options->setMergeCommonStrings(true);
-  
+
   // Handle -t
   if (parsedArgs->getLastArg(OPT_t))
     options->setLogInputFiles(true);
-  
+
+  // Handle --no-allow-shlib-undefined
+  if (parsedArgs->getLastArg(OPT_no_allow_shlib_undefs))
+    options->setAllowShlibUndefines(false);
+
+  // Handle --allow-shlib-undefined
+  if (parsedArgs->getLastArg(OPT_allow_shlib_undefs))
+    options->setAllowShlibUndefines(true);
+
+  // Handle --use-shlib-undefs
+  if (parsedArgs->getLastArg(OPT_use_shlib_undefs))
+    options->setUseShlibUndefines(true);
+
   // Handle -Lxxx
   for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_L),
                                ie = parsedArgs->filtered_end();
-                               it != ie; ++it) {
+       it != ie; ++it) {
     options->appendSearchPath((*it)->getValue());
   }
-  
+
   // Copy mllvm
   for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_mllvm),
                                ie = parsedArgs->filtered_end();
-                               it != ie; ++it) {
-      options->appendLLVMOption((*it)->getValue());
+       it != ie; ++it) {
+    options->appendLLVMOption((*it)->getValue());
   }
-  
+
   // Handle input files (full paths and -lxxx)
-  for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT,OPT_l),
-                               ie = parsedArgs->filtered_end();
-                              it != ie; ++it) {
+  for (llvm::opt::arg_iterator
+           it = parsedArgs->filtered_begin(OPT_INPUT, OPT_l),
+           ie = parsedArgs->filtered_end();
+       it != ie; ++it) {
     switch ((*it)->getOption().getID()) {
     case OPT_INPUT:
       options->appendInputFile((*it)->getValue());
       break;
     case OPT_l:
       if (options->appendLibrary((*it)->getValue())) {
-        diagnostics << "Failed to find library for " 
-                    << (*it)->getValue() << "\n";
+        diagnostics << "Failed to find library for " << (*it)->getValue()
+                    << "\n";
         return nullptr;
       }
       break;
@@ -212,7 +227,7 @@ std::unique_ptr<ELFTargetInfo> GnuLdDriv
       llvm_unreachable("input option type not handled");
     }
   }
-  
+
   // Validate the combination of options used.
   if (options->validate(diagnostics))
     return nullptr;
@@ -220,22 +235,20 @@ std::unique_ptr<ELFTargetInfo> GnuLdDriv
   return options;
 }
 
-
-/// Get the default target triple based on either the program name 
+/// Get the default target triple based on either the program name
 /// (e.g. "x86-ibm-linux-lld") or the primary target llvm was configured for.
 llvm::Triple GnuLdDriver::getDefaultTarget(const char *progName) {
   SmallVector<StringRef, 4> components;
   llvm::SplitString(llvm::sys::path::stem(progName), components, "-");
   // If has enough parts to be start with a triple.
   if (components.size() >= 4) {
-    llvm::Triple triple(components[0], components[1], components[2], 
-                                                      components[3]);
+    llvm::Triple triple(components[0], components[1], components[2],
+                        components[3]);
     // If first component looks like an arch.
     if (triple.getArch() != llvm::Triple::UnknownArch)
       return triple;
   }
-  
+
   // Fallback to use whatever default triple llvm was configured for.
   return llvm::Triple(llvm::sys::getDefaultTargetTriple());
 }
-

Modified: lld/trunk/lib/Driver/LDOptions.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/LDOptions.td?rev=179257&r1=179256&r2=179257&view=diff
==============================================================================
--- lld/trunk/lib/Driver/LDOptions.td (original)
+++ lld/trunk/lib/Driver/LDOptions.td Wed Apr 10 21:56:30 2013
@@ -51,6 +51,15 @@ def merge_strings : Flag<["--"], "merge-
     HelpText<"Merge common strings across mergeable sections">;
 
 
+def no_allow_shlib_undefs : Flag<["--"], "no-allow-shlib-undefined">,
+    HelpText<"Donot allow undefined symbols from dynamic library when creating executables">;
+
+def allow_shlib_undefs : Flag<["--"], "allow-shlib-undefined">,
+    HelpText<"Allow undefined symbols from dynamic library when creating executables">;
+
+def use_shlib_undefs: Flag<["--"], "use-shlib-undefines">,
+    HelpText<"Resolve undefined symbols from dynamic libraries">;
+
 // extensions
 def emit_yaml : Flag<["-"], "emit-yaml">, 
     HelpText<"Write YAML instead of ELF">;

Modified: lld/trunk/lib/ReaderWriter/ELF/Atoms.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Atoms.h?rev=179257&r1=179256&r2=179257&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Atoms.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/Atoms.h Wed Apr 10 21:56:30 2013
@@ -126,17 +126,12 @@ class ELFUndefinedAtom LLVM_FINAL : publ
   typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
 
 public:
-  ELFUndefinedAtom(const ELFFile<ELFT> &file, StringRef name,
-                   const Elf_Sym *symbol)
+  ELFUndefinedAtom(const File &file, StringRef name, const Elf_Sym *symbol)
       : _owningFile(file), _name(name), _symbol(symbol) {}
 
-  virtual const ELFFile<ELFT> &file() const {
-    return _owningFile;
-  }
+  virtual const File &file() const { return _owningFile; }
 
-  virtual StringRef name() const {
-    return _name;
-  }
+  virtual StringRef name() const { return _name; }
 
   // FIXME: What distinguishes a symbol in ELF that can help decide if the
   // symbol is undefined only during build and not runtime? This will make us
@@ -149,7 +144,7 @@ public:
   }
 
 private:
-  const ELFFile<ELFT> &_owningFile;
+  const File &_owningFile;
   StringRef _name;
   const Elf_Sym *_symbol;
 };

Modified: lld/trunk/lib/ReaderWriter/ELF/DynamicFile.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/DynamicFile.h?rev=179257&r1=179256&r2=179257&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/DynamicFile.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/DynamicFile.h Wed Apr 10 21:56:30 2013
@@ -10,6 +10,8 @@
 #ifndef LLD_READER_WRITER_ELF_DYNAMIC_FILE_H
 #define LLD_READER_WRITER_ELF_DYNAMIC_FILE_H
 
+#include "Atoms.h"
+
 #include "lld/Core/SharedLibraryFile.h"
 #include "lld/ReaderWriter/ELFTargetInfo.h"
 
@@ -27,6 +29,8 @@ public:
     std::unique_ptr<DynamicFile> file(
         new DynamicFile(ti, mb->getBufferIdentifier()));
     llvm::OwningPtr<llvm::object::Binary> binaryFile;
+    bool useShlibUndefines = ti.useShlibUndefines();
+
     if (error_code ec = createBinary(mb.release(), binaryFile))
       return ec;
 
@@ -51,18 +55,25 @@ public:
     for (auto i = obj.begin_elf_dynamic_symbols(),
               e = obj.end_elf_dynamic_symbols();
          i != e; ++i) {
-      // Don't expose undefined or absolute symbols to export.
-      if (i->st_shndx == llvm::ELF::SHN_ABS ||
-          i->st_shndx == llvm::ELF::SHN_UNDEF)
-        continue;
       StringRef name;
-      if (error_code ec =
-              obj.getSymbolName(obj.getDynamicSymbolTableSectionHeader(), &*i,
-                                name))
+      if (error_code ec = obj.getSymbolName(
+              obj.getDynamicSymbolTableSectionHeader(), &*i, name))
         return ec;
-      file->_nameToSym[name]._symbol = &*i;
 
-      // TODO: Read undefined dynamic symbols into _undefinedAtoms.
+      // TODO: Add absolute symbols
+      if (i->st_shndx == llvm::ELF::SHN_ABS)
+        continue;
+
+      if (useShlibUndefines && (i->st_shndx == llvm::ELF::SHN_UNDEF)) {
+        // Create an undefined atom.
+        if (!name.empty()) {
+          auto *newAtom =
+              new (file->_alloc) ELFUndefinedAtom<ELFT>(*file.get(), name, &*i);
+          file->_undefinedAtoms._atoms.push_back(newAtom);
+        }
+        continue;
+      }
+      file->_nameToSym[name]._symbol = &*i;
     }
 
     return std::move(file);

Modified: lld/trunk/lib/ReaderWriter/ELF/ELFTargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFTargetInfo.cpp?rev=179257&r1=179256&r2=179257&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFTargetInfo.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFTargetInfo.cpp Wed Apr 10 21:56:30 2013
@@ -29,7 +29,8 @@ ELFTargetInfo::ELFTargetInfo(llvm::Tripl
  , _outputYAML(false)
  , _noInhibitExec(false)
  , _mergeCommonStrings(false)
- , _runLayoutPass(true) {
+ , _runLayoutPass(true)
+ , _useShlibUndefines(false) {
 }
 
 bool ELFTargetInfo::is64Bits() const {

Modified: lld/trunk/test/elf/dynamic-segorder.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/dynamic-segorder.test?rev=179257&r1=179256&r2=179257&view=diff
==============================================================================
--- lld/trunk/test/elf/dynamic-segorder.test (original)
+++ lld/trunk/test/elf/dynamic-segorder.test Wed Apr 10 21:56:30 2013
@@ -1,5 +1,5 @@
 RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/tls.x86-64 \
-RUN:   %p/Inputs/shared.so-x86-64 -o %t -e main 
+RUN:   %p/Inputs/shared.so-x86-64 -o %t -e main --allow-shlib-undefined
 RUN: llvm-objdump -p %t | FileCheck %s
 
 CHECK: PHDR

Added: lld/trunk/test/elf/dynamic-undef.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/dynamic-undef.test?rev=179257&view=auto
==============================================================================
--- lld/trunk/test/elf/dynamic-undef.test (added)
+++ lld/trunk/test/elf/dynamic-undef.test Wed Apr 10 21:56:30 2013
@@ -0,0 +1,27 @@
+#
+# This test creates a executable and tests the options that are used to 
+# to create an executable and a shared library
+#
+# This test will fail because there are unresolved symbols from the shared
+# library and we are not passing --allow-shlib-undefined
+RUN: not lld -flavor gnu -target x86_64-linux %p/Inputs/tls.x86-64 \
+RUN:   %p/Inputs/shared.so-x86-64 -o %t -e main 2> %t1
+RUN: FileCheck -check-prefix=EXEC %s < %t1
+# This test will pass because of --allow-shlib-undefined
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/tls.x86-64 \
+RUN:   %p/Inputs/shared.so-x86-64 -o %t -e main --allow-shlib-undefined
+# Test creation of shared library, this should pass because we are using 
+# shared option and by default, dynamic library wouldnot create undefined atoms
+# from the input shared library
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/tls.x86-64 \
+RUN:   %p/Inputs/shared.so-x86-64 -o %t -e main -shared
+# Test creation of shared library, this should fail because we are using 
+# shared option setting the options to use the shared library undefines to
+# create undefined atoms from the input shared library 
+RUN: not lld -flavor gnu -target x86_64-linux %p/Inputs/tls.x86-64 \
+RUN:   %p/Inputs/shared.so-x86-64 -o %t -e main -shared \
+RUN: --use-shlib-undefines --no-allow-shlib-undefined  2> %t2
+RUN: FileCheck -check-prefix=SHLIB %s < %t2
+
+EXEC: Undefined Symbol: {{[Ia-z.\/]+}}shared.so-x86-64 : puts
+SHLIB: Undefined Symbol: {{[Ia-z.\/]+}}shared.so-x86-64 : puts

Modified: lld/trunk/test/elf/dynamic.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/dynamic.test?rev=179257&r1=179256&r2=179257&view=diff
==============================================================================
--- lld/trunk/test/elf/dynamic.test (original)
+++ lld/trunk/test/elf/dynamic.test Wed Apr 10 21:56:30 2013
@@ -1,7 +1,8 @@
 RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/use-shared.x86-64 \
-RUN:   %p/Inputs/shared.so-x86-64 -o %t -e main 
+RUN:   %p/Inputs/shared.so-x86-64 -o %t -e main --allow-shlib-undefined
 RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/use-shared.x86-64 \
-RUN:   %p/Inputs/shared.so-x86-64 -emit-yaml -o %t2 --noinhibit-exec
+RUN:   %p/Inputs/shared.so-x86-64 -emit-yaml -o %t2 --allow-shlib-undefined \
+RUN: --noinhibit-exec
 RUN: llvm-objdump -p %t >> %t2
 RUN: llvm-readobj -s -dyn-symbols -dynamic-table %t >> %t2
 RUN: FileCheck %s < %t2





More information about the llvm-commits mailing list