[lld] r207769 - [ELF] Fix the file look up algorithm used in the linker script GROUP command.

Simon Atanasyan simon at atanasyan.com
Thu May 1 09:22:08 PDT 2014


Author: atanasyan
Date: Thu May  1 11:22:08 2014
New Revision: 207769

URL: http://llvm.org/viewvc/llvm-project?rev=207769&view=rev
Log:
[ELF] Fix the file look up algorithm used in the linker script GROUP command.

In general the linker scripts's GROUP command works like a pair
of command line options --start-group/--end-group. But there is
a difference in the files look up algorithm.

The --start-group/--end-group commands use a trivial approach:
a) If the path has '-l' prefix, add 'lib' prefix and '.a'/'.so'
   suffix and search the path through library search directories.
b) Otherwise, use the path 'as-is'.

The GROUP command implements more compicated approach:
a) If the path has '-l' prefix, add 'lib' prefix and '.a'/'.so'
   suffix and search the path through library search directories.
b) If the path does not have '-l' prefix, and sysroot is configured,
   and the path starts with the / character, and the script being
   processed is located inside the sysroot, search the path under
   the sysroot. Otherwise, try to open the path in the current
   directory. If it is not found, search through library search
   directories.

https://www.sourceware.org/binutils/docs-2.24/ld/File-Commands.html

The patch reviewed by Shankar Easwaran, Rui Ueyama.

Added:
    lld/trunk/test/elf/Inputs/group-cmd-search-1.ls
    lld/trunk/test/elf/Inputs/group-cmd-search-2.ls
    lld/trunk/test/elf/group-cmd-search.test
Modified:
    lld/trunk/include/lld/Driver/GnuLdInputGraph.h
    lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
    lld/trunk/lib/Driver/GnuLdDriver.cpp
    lld/trunk/lib/Driver/GnuLdInputGraph.cpp
    lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp

Modified: lld/trunk/include/lld/Driver/GnuLdInputGraph.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Driver/GnuLdInputGraph.h?rev=207769&r1=207768&r2=207769&view=diff
==============================================================================
--- lld/trunk/include/lld/Driver/GnuLdInputGraph.h (original)
+++ lld/trunk/include/lld/Driver/GnuLdInputGraph.h Thu May  1 11:22:08 2014
@@ -35,17 +35,20 @@ public:
   class Attributes {
   public:
     Attributes()
-        : _isWholeArchive(false), _asNeeded(false), _isDashlPrefix(false) {}
+        : _isWholeArchive(false), _asNeeded(false), _isDashlPrefix(false),
+          _isSysRooted(false) {}
     void setWholeArchive(bool isWholeArchive) {
       _isWholeArchive = isWholeArchive;
     }
     void setAsNeeded(bool asNeeded) { _asNeeded = asNeeded; }
     void setDashlPrefix(bool isDashlPrefix) { _isDashlPrefix = isDashlPrefix; }
+    void setSysRooted(bool isSysRooted) { _isSysRooted = isSysRooted; }
 
   public:
     bool _isWholeArchive;
     bool _asNeeded;
     bool _isDashlPrefix;
+    bool _isSysRooted;
   };
 
   ELFFileNode(ELFLinkingContext &ctx, StringRef path, Attributes &attributes)

Modified: lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h?rev=207769&r1=207768&r2=207769&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h Thu May  1 11:22:08 2014
@@ -173,6 +173,13 @@ public:
   /// Searches directories for a match on the input File
   ErrorOr<StringRef> searchLibrary(StringRef libName) const;
 
+  /// \brief Searches directories for a match on the input file.
+  /// If \p fileName is an absolute path and \p isSysRooted is true, check
+  /// the file under sysroot directory. If \p fileName is a relative path
+  /// and is not in the current directory, search the file through library
+  /// search directories.
+  ErrorOr<StringRef> searchFile(StringRef fileName, bool isSysRooted) const;
+
   /// Get the entry symbol name
   StringRef entrySymbolName() const override;
 
@@ -207,6 +214,8 @@ public:
 
   StringRef sharedObjectName() const { return _soname; }
 
+  StringRef getSysroot() const { return _sysrootPath; }
+
   /// \brief Set path to the system root
   void setSysroot(StringRef path) {
     _sysrootPath = path;

Modified: lld/trunk/lib/Driver/GnuLdDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/GnuLdDriver.cpp?rev=207769&r1=207768&r2=207769&view=diff
==============================================================================
--- lld/trunk/lib/Driver/GnuLdDriver.cpp (original)
+++ lld/trunk/lib/Driver/GnuLdDriver.cpp Thu May  1 11:22:08 2014
@@ -153,9 +153,9 @@ static bool parseDefsymAsAlias(StringRef
 }
 
 llvm::ErrorOr<StringRef> ELFFileNode::getPath(const LinkingContext &) const {
-  if (!_attributes._isDashlPrefix)
-    return _path;
-  return _elfLinkingContext.searchLibrary(_path);
+  if (_attributes._isDashlPrefix)
+    return _elfLinkingContext.searchLibrary(_path);
+  return _elfLinkingContext.searchFile(_path, _attributes._isSysRooted);
 }
 
 std::string ELFFileNode::errStr(error_code errc) {

Modified: lld/trunk/lib/Driver/GnuLdInputGraph.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/GnuLdInputGraph.cpp?rev=207769&r1=207768&r2=207769&view=diff
==============================================================================
--- lld/trunk/lib/Driver/GnuLdInputGraph.cpp (original)
+++ lld/trunk/lib/Driver/GnuLdInputGraph.cpp Thu May  1 11:22:08 2014
@@ -10,6 +10,9 @@
 #include "lld/Driver/GnuLdInputGraph.h"
 #include "lld/ReaderWriter/LinkerScript.h"
 
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
 using namespace lld;
 
 /// \brief Parse the input file to lld::File.
@@ -70,12 +73,27 @@ error_code GNULdScript::parse(const Link
   return error_code::success();
 }
 
+static bool isPathUnderSysroot(StringRef sysroot, StringRef path) {
+  // TODO: Handle the case when 'sysroot' and/or 'path' are symlinks.
+  if (sysroot.empty() || sysroot.size() >= path.size())
+    return false;
+  if (llvm::sys::path::is_separator(sysroot.back()))
+    sysroot = sysroot.substr(0, sysroot.size() - 1);
+  if (!llvm::sys::path::is_separator(path[sysroot.size()]))
+    return false;
+
+  return llvm::sys::fs::equivalent(sysroot, path.substr(0, sysroot.size()));
+}
+
 /// \brief Handle GnuLD script for ELF.
 error_code ELFGNULdScript::parse(const LinkingContext &ctx,
                                  raw_ostream &diagnostics) {
   ELFFileNode::Attributes attributes;
   if (error_code ec = GNULdScript::parse(ctx, diagnostics))
     return ec;
+  StringRef sysRoot = _elfLinkingContext.getSysroot();
+  if (!sysRoot.empty() && isPathUnderSysroot(sysRoot, *getPath(ctx)))
+    attributes.setSysRooted(true);
   for (const script::Command *c : _linkerScript->_commands) {
     auto *group = dyn_cast<script::Group>(c);
     if (!group)

Modified: lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp?rev=207769&r1=207768&r2=207769&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp Thu May  1 11:22:08 2014
@@ -247,6 +247,29 @@ ErrorOr<StringRef> ELFLinkingContext::se
   return libName;
 }
 
+ErrorOr<StringRef> ELFLinkingContext::searchFile(StringRef fileName,
+                                                 bool isSysRooted) const {
+  SmallString<128> path;
+  if (llvm::sys::path::is_absolute(fileName) && isSysRooted) {
+    path.assign(_sysrootPath);
+    path.append(fileName);
+    if (llvm::sys::fs::exists(path.str()))
+      return StringRef(*new (_allocator) std::string(path.str()));
+  } else if (llvm::sys::fs::exists(fileName))
+    return fileName;
+
+  if (llvm::sys::path::is_absolute(fileName))
+    return llvm::make_error_code(llvm::errc::no_such_file_or_directory);
+
+  for (StringRef dir : _inputSearchPaths) {
+    buildSearchPath(path, dir, _sysrootPath);
+    llvm::sys::path::append(path, fileName);
+    if (llvm::sys::fs::exists(path.str()))
+      return StringRef(*new (_allocator) std::string(path.str()));
+  }
+  return llvm::make_error_code(llvm::errc::no_such_file_or_directory);
+}
+
 void ELFLinkingContext::createInternalFiles(
     std::vector<std::unique_ptr<File>> &files) const {
   std::unique_ptr<SimpleFile> file(

Added: lld/trunk/test/elf/Inputs/group-cmd-search-1.ls
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/Inputs/group-cmd-search-1.ls?rev=207769&view=auto
==============================================================================
--- lld/trunk/test/elf/Inputs/group-cmd-search-1.ls (added)
+++ lld/trunk/test/elf/Inputs/group-cmd-search-1.ls Thu May  1 11:22:08 2014
@@ -0,0 +1 @@
+GROUP ( shared.so-x86-64 )

Added: lld/trunk/test/elf/Inputs/group-cmd-search-2.ls
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/Inputs/group-cmd-search-2.ls?rev=207769&view=auto
==============================================================================
--- lld/trunk/test/elf/Inputs/group-cmd-search-2.ls (added)
+++ lld/trunk/test/elf/Inputs/group-cmd-search-2.ls Thu May  1 11:22:08 2014
@@ -0,0 +1 @@
+GROUP ( /shared.so-x86-64 )

Added: lld/trunk/test/elf/group-cmd-search.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/group-cmd-search.test?rev=207769&view=auto
==============================================================================
--- lld/trunk/test/elf/group-cmd-search.test (added)
+++ lld/trunk/test/elf/group-cmd-search.test Thu May  1 11:22:08 2014
@@ -0,0 +1,95 @@
+/*
+  In general the linker scripts's GROUP command works like a pair
+  of command line options --start-group/--end-group. But there is
+  a difference in the files look up algorithm.
+
+  The --start-group/--end-group commands use a trivial approach:
+  a) If the path has '-l' prefix, add 'lib' prefix and '.a'/'.so'
+     suffix and search the path through library search directories.
+  b) Otherwise, use the path 'as-is'.
+
+  The GROUP command implements more compicated approach:
+  a) If the path has '-l' prefix, add 'lib' prefix and '.a'/'.so'
+     suffix and search the path through library search directories.
+  b) If the path does not have '-l' prefix, and sysroot is configured,
+     and the path starts with the / character, and the script being
+     processed is located inside the sysroot, search the path under
+     the sysroot. Otherwise, try to open the path in the current
+     directory. If it is not found, search through library search
+     directories.
+*/
+
+/*
+  This link should finish successfully. The --start-group/--end-group
+  contains an existing absolute path to the file.
+
+RUN: lld -flavor gnu -target x86_64 -shared \
+RUN:     -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN:     --start-group %p/Inputs/shared.so-x86-64 --end-group -o %t1
+*/
+
+/*
+  This link should fail with unknown input file format error.
+  There is no shared.so-x86-64 file in the current directory.
+
+RUN: not \
+RUN: lld -flavor gnu -target x86_64 -shared \
+RUN:     -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN:     --start-group shared.so-x86-64 --end-group -o %t2
+*/
+
+/*
+  This link should fail with unknown input file format error.
+  The absolute path /shared.so-x86-64 does not exist and the linker
+  should not attempt to search it under the sysroot directory.
+
+RUN: not \
+RUN: lld -flavor gnu -target x86_64 -shared --sysroot=%p/Inputs \
+RUN:     -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN:     --start-group /shared.so-x86-64 --end-group -o %t3
+*/
+
+/*
+  This link should finish successfully. The group-cmd-search-1.ls
+  script contains "GROUP ( shared.so-x86-64 )" command and the linker
+  has to search shared.so-x86-64 through the library search paths.
+
+RUN: lld -flavor gnu -target x86_64 -shared \
+RUN:     -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN:     %p/Inputs/group-cmd-search-1.ls -o %t4
+*/
+
+/*
+  This link should fail with unknown input file format error.
+  The group-cmd-search-2.ls script contains GROUP command with
+  a non-existing absolute path but there is no --sysroot argument.
+
+RUN: not \
+RUN: lld -flavor gnu -target x86_64 -shared \
+RUN:     -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN:     %p/Inputs/group-cmd-search-2.ls -o %t5
+*/
+
+/*
+  This link should finish successfully. The group-cmd-search-2.ls
+  script contains GROUP command with an absolute path and the sysroot
+  directory is provided. The linker has to search the absolute path
+  under the sysroot directory.
+
+RUN: lld -flavor gnu -target x86_64 -shared --sysroot=%p/Inputs \
+RUN:     -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN:     %p/Inputs/group-cmd-search-2.ls -o %t6
+*/
+
+/*
+  This link should fail with unknown input file format error.
+  The linker script from this file contains GROUP with an absolute
+  path which can be found under provided sysroot directory.
+  But the linker script itself is not under the sysroot.
+
+RUN: not \
+RUN: lld -flavor gnu -target x86_64 -shared --sysroot=%p/Inputs \
+RUN:     -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN:     %s -o %t7
+*/
+GROUP ( /shared.so-x86-64 )





More information about the llvm-commits mailing list