[lld] r239719 - [LinkerScript] Add matching of output sections to segments

Denis Protivensky dprotivensky at accesssoftek.com
Mon Jun 15 01:00:52 PDT 2015


Author: denis-protivensky
Date: Mon Jun 15 03:00:51 2015
New Revision: 239719

URL: http://llvm.org/viewvc/llvm-project?rev=239719&view=rev
Log:
[LinkerScript] Add matching of output sections to segments

Add method to query segments for specified output section name.
Return error if the section is assigned to unknown segment.
Check matching of sections to segments during layout on the subject of correctness.
NOTE: no actual functionality of using custom segments is implemented.

Differential Revision: http://reviews.llvm.org/D10359

Added:
    lld/trunk/test/elf/linkerscript/phdrs/
    lld/trunk/test/elf/linkerscript/phdrs-default.test
    lld/trunk/test/elf/linkerscript/phdrs-invalid.test
    lld/trunk/test/elf/linkerscript/phdrs/sections-empty-phdrs.script
    lld/trunk/test/elf/linkerscript/phdrs/sections-no-phdrs.script
    lld/trunk/test/elf/linkerscript/phdrs/sections-none-phdrs.script
    lld/trunk/test/elf/linkerscript/phdrs/undef-empty-phdrs.script
    lld/trunk/test/elf/linkerscript/phdrs/undef-id-phdrs.script
    lld/trunk/test/elf/linkerscript/phdrs/undef-no-phdrs.script
Modified:
    lld/trunk/include/lld/Core/Error.h
    lld/trunk/include/lld/ReaderWriter/LinkerScript.h
    lld/trunk/lib/Core/Error.cpp
    lld/trunk/lib/ReaderWriter/ELF/TargetLayout.cpp
    lld/trunk/lib/ReaderWriter/ELF/TargetLayout.h
    lld/trunk/lib/ReaderWriter/LinkerScript.cpp

Modified: lld/trunk/include/lld/Core/Error.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/Error.h?rev=239719&r1=239718&r2=239719&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/Error.h (original)
+++ lld/trunk/include/lld/Core/Error.h Mon Jun 15 03:00:51 2015
@@ -36,7 +36,8 @@ enum class LinkerScriptReaderError {
   success = 0,
   parse_error,
   unknown_symbol_in_expr,
-  unrecognized_function_in_expr
+  unrecognized_function_in_expr,
+  unknown_phdr_ids,
 };
 
 inline std::error_code make_error_code(LinkerScriptReaderError e) {

Modified: lld/trunk/include/lld/ReaderWriter/LinkerScript.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/LinkerScript.h?rev=239719&r1=239718&r2=239719&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/LinkerScript.h (original)
+++ lld/trunk/include/lld/ReaderWriter/LinkerScript.h Mon Jun 15 03:00:51 2015
@@ -20,6 +20,7 @@
 #include "lld/Core/range.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/ADT/StringSwitch.h"
@@ -777,6 +778,8 @@ public:
   const_iterator begin() const { return _outputSectionCommands.begin(); }
   const_iterator end() const { return _outputSectionCommands.end(); }
   StringRef name() const { return _sectionName; }
+  bool isDiscarded() const { return _discard; }
+  ArrayRef<StringRef> PHDRs() const { return _phdrs; }
 
 private:
   StringRef _sectionName;
@@ -814,9 +817,13 @@ public:
         _includePHDRs(includePHDRs), _at(at), _flags(flags) {}
 
   ~PHDR() = delete;
+  StringRef name() const { return _name; }
 
   void dump(raw_ostream &os) const;
 
+  /// Special header that discards output sections assigned to it.
+  static const PHDR *NONE;
+
 private:
   StringRef _name;
   uint64_t _type;
@@ -1320,6 +1327,13 @@ public:
   /// has been performed (by calling evalExpr() for all expressions).
   uint64_t getLinkerScriptExprValue(StringRef name) const;
 
+  /// Retrieve all the headers the given output section is assigned to.
+  /// Error is returned if the output section is assigned to headers with
+  /// missing declarations.
+  std::error_code
+  getPHDRsForOutputSection(StringRef name,
+                           std::vector<const PHDR *> &phdrs) const;
+
   void dump() const;
 
 private:
@@ -1361,6 +1375,9 @@ private:
   bool localCompare(int order, const SectionKey &lhs,
                     const SectionKey &rhs) const;
 
+  /// Build map that matches output section names to segments they should be
+  /// put into.
+  std::error_code buildSectionToPHDR();
 
   /// Our goal with all linearizeAST overloaded functions is to
   /// traverse the linker script AST while putting nodes in a vector and
@@ -1428,6 +1445,9 @@ private:
   llvm::DenseSet<int> _deliveredExprs;
   mutable llvm::StringSet<> _definedSymbols;
 
+  bool _parsedPHDRS;
+  llvm::StringMap<llvm::SmallVector<const PHDR *, 2>> _sectionToPHDR;
+
   Expression::SymbolTableTy _symbolTable;
 };
 

Modified: lld/trunk/lib/Core/Error.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/Error.cpp?rev=239719&r1=239718&r2=239719&view=diff
==============================================================================
--- lld/trunk/lib/Core/Error.cpp (original)
+++ lld/trunk/lib/Core/Error.cpp Mon Jun 15 03:00:51 2015
@@ -56,6 +56,8 @@ public:
     case LinkerScriptReaderError::unrecognized_function_in_expr:
       return "Unrecognized function call when evaluating linker script "
              "expression";
+    case LinkerScriptReaderError::unknown_phdr_ids:
+      return "Unknown header identifiers (missing in PHDRS command) are used";
     }
     llvm_unreachable("An enumerator of LinkerScriptReaderError does not have a "
                      "message defined.");

Modified: lld/trunk/lib/ReaderWriter/ELF/TargetLayout.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/TargetLayout.cpp?rev=239719&r1=239718&r2=239719&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/TargetLayout.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/TargetLayout.cpp Mon Jun 15 03:00:51 2015
@@ -320,6 +320,7 @@ template <class ELFT> void TargetLayout<
     } else {
       outputSection = new (_allocator.Allocate<OutputSection<ELFT>>())
           OutputSection<ELFT>(section->outputSectionName());
+      checkOutputSectionSegment(outputSection);
       _outputSections.push_back(outputSection);
       outputSectionInsert.first->second = outputSection;
     }
@@ -327,6 +328,17 @@ template <class ELFT> void TargetLayout<
   }
 }
 
+// Check that output section has proper segment set
+template <class ELFT>
+void TargetLayout<ELFT>::checkOutputSectionSegment(
+    const OutputSection<ELFT> *sec) {
+  std::vector<const script::PHDR *> phdrs;
+  if (_linkerScriptSema.getPHDRsForOutputSection(sec->name(), phdrs)) {
+    llvm::report_fatal_error(
+        "Linker script has wrong segments set for output sections");
+  }
+}
+
 template <class ELFT>
 uint64_t
 TargetLayout<ELFT>::getLookupSectionFlags(const OutputSection<ELFT> *os) const {

Modified: lld/trunk/lib/ReaderWriter/ELF/TargetLayout.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/TargetLayout.h?rev=239719&r1=239718&r2=239719&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/TargetLayout.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/TargetLayout.h Mon Jun 15 03:00:51 2015
@@ -209,6 +209,9 @@ public:
   // Output sections with the same name into a OutputSection
   void createOutputSections();
 
+  // Check that output section has proper segment set
+  void checkOutputSectionSegment(const OutputSection<ELFT> *sec);
+
   /// \brief Sort the sections by their order as defined by the layout,
   /// preparing all sections to be assigned to a segment.
   virtual void sortInputSections();

Modified: lld/trunk/lib/ReaderWriter/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/LinkerScript.cpp?rev=239719&r1=239718&r2=239719&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/LinkerScript.cpp (original)
+++ lld/trunk/lib/ReaderWriter/LinkerScript.cpp Mon Jun 15 03:00:51 2015
@@ -953,6 +953,9 @@ void PHDR::dump(raw_ostream &os) const {
   os << ";\n";
 }
 
+static PHDR none("NONE", 0, false, false, NULL, 0);
+const PHDR *PHDR::NONE = &none;
+
 void PHDRS::dump(raw_ostream &os) const {
   os << "PHDRS\n{\n";
   for (auto &&phdr : _phdrs) {
@@ -2353,10 +2356,7 @@ Extern *Parser::parseExtern() {
 }
 
 // Sema member functions
-Sema::Sema()
-    : _scripts(), _layoutCommands(), _memberToLayoutOrder(),
-      _memberNameWildcards(), _cacheSectionOrder(), _cacheExpressionOrder(),
-      _deliveredExprs(), _symbolTable() {}
+Sema::Sema() : _parsedPHDRS(false) {}
 
 void Sema::perform() {
   for (auto &parser : _scripts)
@@ -2465,6 +2465,18 @@ uint64_t Sema::getLinkerScriptExprValue(
   return it->second;
 }
 
+std::error_code
+Sema::getPHDRsForOutputSection(StringRef name,
+                               std::vector<const PHDR *> &phdrs) const {
+  // Cache results if not done yet.
+  if (auto ec = const_cast<Sema *>(this)->buildSectionToPHDR())
+    return ec;
+
+  auto vec = _sectionToPHDR.lookup(name);
+  std::copy(std::begin(vec), std::end(vec), std::back_inserter(phdrs));
+  return std::error_code();
+}
+
 void Sema::dump() const {
   raw_ostream &os = llvm::outs();
   os << "Linker script semantics dump\n";
@@ -2701,6 +2713,64 @@ bool Sema::localCompare(int order, const
   return false;
 }
 
+std::error_code Sema::buildSectionToPHDR() {
+  if (_parsedPHDRS)
+    return std::error_code();
+  _parsedPHDRS = true;
+
+  // No scripts - nothing to do.
+  if (_scripts.empty() || _layoutCommands.empty())
+    return std::error_code();
+
+  // Collect all header declarations.
+  llvm::StringMap<const PHDR *> phdrs;
+  for (auto &parser : _scripts) {
+    for (auto *cmd : parser->get()->_commands) {
+      if (auto *ph = dyn_cast<PHDRS>(cmd)) {
+        for (auto *p : *ph)
+          phdrs[p->name()] = p;
+      }
+    }
+  }
+  const bool noPhdrs = phdrs.empty();
+
+  // Add NONE header to the map provided there's no user-defined
+  // header with the same name.
+  if (!_sectionToPHDR.count(PHDR::NONE->name()))
+    phdrs[PHDR::NONE->name()] = PHDR::NONE;
+
+  // Match output sections to available headers.
+  llvm::SmallVector<const PHDR *, 2> phdrsCur, phdrsLast { PHDR::NONE };
+  for (const Command *cmd : _layoutCommands) {
+    auto osd = dyn_cast<OutputSectionDescription>(cmd);
+    if (!osd || osd->isDiscarded())
+      continue;
+
+    phdrsCur.clear();
+    for (StringRef name : osd->PHDRs()) {
+      auto it = phdrs.find(name);
+      if (it == phdrs.end()) {
+        return LinkerScriptReaderError::unknown_phdr_ids;
+      }
+      phdrsCur.push_back(it->second);
+    }
+
+    // If no headers and no errors - insert empty headers set.
+    // If the current set of headers is empty, then use the last non-empty
+    // set. Otherwise mark the current set to be the last non-empty set for
+    // successors.
+    if (noPhdrs)
+      phdrsCur.clear();
+    else if (phdrsCur.empty())
+      phdrsCur = phdrsLast;
+    else
+      phdrsLast = phdrsCur;
+
+    _sectionToPHDR[osd->name()] = phdrsCur;
+  }
+  return std::error_code();
+}
+
 static bool hasWildcard(StringRef name) {
   for (auto ch : name)
     if (ch == '*' || ch == '?' || ch == '[' || ch == '\\')

Added: lld/trunk/test/elf/linkerscript/phdrs-default.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/linkerscript/phdrs-default.test?rev=239719&view=auto
==============================================================================
--- lld/trunk/test/elf/linkerscript/phdrs-default.test (added)
+++ lld/trunk/test/elf/linkerscript/phdrs-default.test Mon Jun 15 03:00:51 2015
@@ -0,0 +1,82 @@
+/*
+This group of tests checks usage of default headers during linking,
+when PHDRS command is not defined or defined empty in linker scripts.
+
+This test uses a single X86-64 input object, simple.o, created with the
+following X86-64 assembly code:
+
+*** simple.S:
+
+(command line clang -c simple.S -o simple.o)
+
+      .text
+      main:
+        mov $1, %eax
+        movq $1, %rdi
+        movq $msg, %rsi
+        movq $14, %rdx
+        syscall
+        ret
+
+        .globl _start
+      _start:
+        call  main
+        mov $60, %eax
+        syscall
+        ret
+
+      .data
+      msg: .asciz "Hello, World!\n"
+*/
+
+/*
+Prepare the object file to test on.
+
+RUN: yaml2obj -format=elf %p/Inputs/simple.o.yaml -o=%t.o
+*/
+
+/*
+Test when no linker script passed.
+
+RUN: lld -flavor gnu -target x86_64 %t.o -static -o %t1
+RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix SECTIONS %s
+RUN: llvm-readobj -program-headers %t1 | FileCheck -check-prefix HEADERS %s
+
+SECTIONS: .text {{[0-9a-f]+}} 00000000004000b0
+SECTIONS: .data {{[0-9a-f]+}} 0000000000401000
+
+HEADERS: ProgramHeader {
+HEADERS: Type: PT_LOAD (0x1)
+HEADERS: VirtualAddress: 0x400000
+HEADERS: }
+HEADERS: ProgramHeader {
+HEADERS: Type: PT_LOAD (0x1)
+HEADERS: VirtualAddress: 0x401000
+HEADERS: }
+*/
+
+/*
+Test when linker script doesn't contain PHDRS and sections are not assigned to any segments.
+
+RUN: lld -flavor gnu -target x86_64 -T %p/phdrs/sections-no-phdrs.script %t.o -static -o %t2
+RUN: llvm-objdump -section-headers %t2 | FileCheck -check-prefix SECTIONS %s
+RUN: llvm-readobj -program-headers %t2 | FileCheck -check-prefix HEADERS %s
+*/
+
+/*
+Test when linker script contains empty PHDRS and sections are not assigned to any segments.
+
+RUN: lld -flavor gnu -target x86_64 -T %p/phdrs/sections-empty-phdrs.script %t.o -static -o %t3
+RUN: llvm-objdump -section-headers %t3 | FileCheck -check-prefix SECTIONS %s
+RUN: llvm-readobj -program-headers %t3 | FileCheck -check-prefix HEADERS %s
+*/
+
+/*
+Test when linker script contains empty PHDRS and sections are only assigned to NONE segments
+or not assigned at all.
+NOTE: Segments with the name NONE are ignored in such a case.
+
+RUN: lld -flavor gnu -target x86_64 -T %p/phdrs/sections-none-phdrs.script %t.o -static -o %t4
+RUN: llvm-objdump -section-headers %t4 | FileCheck -check-prefix SECTIONS %s
+RUN: llvm-readobj -program-headers %t4 | FileCheck -check-prefix HEADERS %s
+*/

Added: lld/trunk/test/elf/linkerscript/phdrs-invalid.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/linkerscript/phdrs-invalid.test?rev=239719&view=auto
==============================================================================
--- lld/trunk/test/elf/linkerscript/phdrs-invalid.test (added)
+++ lld/trunk/test/elf/linkerscript/phdrs-invalid.test Mon Jun 15 03:00:51 2015
@@ -0,0 +1,63 @@
+/*
+This group of tests checks invalid cases of defining and using PHDRS
+command in linker scripts.
+
+This test uses a single X86-64 input object, simple.o, created with the
+following X86-64 assembly code:
+
+*** simple.S:
+
+(command line clang -c simple.S -o simple.o)
+
+      .text
+      main:
+        mov $1, %eax
+        movq $1, %rdi
+        movq $msg, %rsi
+        movq $14, %rdx
+        syscall
+        ret
+
+        .globl _start
+      _start:
+        call  main
+        mov $60, %eax
+        syscall
+        ret
+
+      .data
+      msg: .asciz "Hello, World!\n"
+*/
+
+/*
+Prepare the object file to test on.
+
+RUN: yaml2obj -format=elf %p/Inputs/simple.o.yaml -o=%t.o
+*/
+
+/*
+Test undefined header used when no PHDRS defined.
+
+RUN: not lld -flavor gnu -target x86_64 -T %p/phdrs/undef-no-phdrs.script %t.o -static -o %t1 &> %t1-error
+RUN: FileCheck -check-prefix UNDEF-NO-PHDRS %s < %t1-error
+
+UNDEF-NO-PHDRS: Linker script has wrong segments set for output sections
+*/
+
+/*
+Test undefined header used when PHDRS is empty.
+
+RUN: not lld -flavor gnu -target x86_64 -T %p/phdrs/undef-empty-phdrs.script %t.o -static -o %t2 &> %t2-error
+RUN: FileCheck -check-prefix UNDEF-EMPTY-PHDRS %s < %t2-error
+
+UNDEF-EMPTY-PHDRS: Linker script has wrong segments set for output sections
+*/
+
+/*
+Test undefined header used when PHDRS contains definitions.
+
+RUN: not lld -flavor gnu -target x86_64 -T %p/phdrs/undef-id-phdrs.script %t.o -static -o %t3 &> %t3-error
+RUN: FileCheck -check-prefix UNDEF-ID-PHDRS %s < %t3-error
+
+UNDEF-ID-PHDRS: Linker script has wrong segments set for output sections
+*/

Added: lld/trunk/test/elf/linkerscript/phdrs/sections-empty-phdrs.script
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/linkerscript/phdrs/sections-empty-phdrs.script?rev=239719&view=auto
==============================================================================
--- lld/trunk/test/elf/linkerscript/phdrs/sections-empty-phdrs.script (added)
+++ lld/trunk/test/elf/linkerscript/phdrs/sections-empty-phdrs.script Mon Jun 15 03:00:51 2015
@@ -0,0 +1,11 @@
+ENTRY(_start)
+
+PHDRS
+{
+}
+
+SECTIONS
+{
+  .text : { *(.text) }
+  .data : { *(.data) }
+}

Added: lld/trunk/test/elf/linkerscript/phdrs/sections-no-phdrs.script
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/linkerscript/phdrs/sections-no-phdrs.script?rev=239719&view=auto
==============================================================================
--- lld/trunk/test/elf/linkerscript/phdrs/sections-no-phdrs.script (added)
+++ lld/trunk/test/elf/linkerscript/phdrs/sections-no-phdrs.script Mon Jun 15 03:00:51 2015
@@ -0,0 +1,7 @@
+ENTRY(_start)
+
+SECTIONS
+{
+  .text : { *(.text) }
+  .data : { *(.data) }
+}

Added: lld/trunk/test/elf/linkerscript/phdrs/sections-none-phdrs.script
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/linkerscript/phdrs/sections-none-phdrs.script?rev=239719&view=auto
==============================================================================
--- lld/trunk/test/elf/linkerscript/phdrs/sections-none-phdrs.script (added)
+++ lld/trunk/test/elf/linkerscript/phdrs/sections-none-phdrs.script Mon Jun 15 03:00:51 2015
@@ -0,0 +1,11 @@
+ENTRY(_start)
+
+PHDRS
+{
+}
+
+SECTIONS
+{
+  .text : { *(.text) } :NONE
+  .data : { *(.data) }
+}

Added: lld/trunk/test/elf/linkerscript/phdrs/undef-empty-phdrs.script
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/linkerscript/phdrs/undef-empty-phdrs.script?rev=239719&view=auto
==============================================================================
--- lld/trunk/test/elf/linkerscript/phdrs/undef-empty-phdrs.script (added)
+++ lld/trunk/test/elf/linkerscript/phdrs/undef-empty-phdrs.script Mon Jun 15 03:00:51 2015
@@ -0,0 +1,11 @@
+ENTRY(_start)
+
+PHDRS
+{
+}
+
+SECTIONS
+{
+  .text : { *(.text) }
+  .data : { *(.data) } :phdr
+}

Added: lld/trunk/test/elf/linkerscript/phdrs/undef-id-phdrs.script
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/linkerscript/phdrs/undef-id-phdrs.script?rev=239719&view=auto
==============================================================================
--- lld/trunk/test/elf/linkerscript/phdrs/undef-id-phdrs.script (added)
+++ lld/trunk/test/elf/linkerscript/phdrs/undef-id-phdrs.script Mon Jun 15 03:00:51 2015
@@ -0,0 +1,12 @@
+ENTRY(_start)
+
+PHDRS
+{
+  phdr PT_LOAD;
+}
+
+SECTIONS
+{
+  .text : { *(.text) } :phdr_wrong
+  .data : { *(.data) }
+}

Added: lld/trunk/test/elf/linkerscript/phdrs/undef-no-phdrs.script
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/linkerscript/phdrs/undef-no-phdrs.script?rev=239719&view=auto
==============================================================================
--- lld/trunk/test/elf/linkerscript/phdrs/undef-no-phdrs.script (added)
+++ lld/trunk/test/elf/linkerscript/phdrs/undef-no-phdrs.script Mon Jun 15 03:00:51 2015
@@ -0,0 +1,7 @@
+ENTRY(_start)
+
+SECTIONS
+{
+  .text : { *(.text) } :phdr
+  .data : { *(.data) }
+}





More information about the llvm-commits mailing list