[llvm-commits] Followon/Preceded-By reference support in lld

Shankar Easwaran shankare at codeaurora.org
Tue Nov 6 10:09:49 PST 2012


Hi Nick, Michael,

I have incorporated your review comments in the attached diff to support 
followon / preceded by reference in lld with

* 2 test cases for testing the Core functionality
* 1 test case for testing ReaderELF

Let me know if its ok to commit this change.

Thanks

Shankar Easwaran

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by the Linux Foundation

-------------- next part --------------
Index: test/followon-basic.objtxt
===================================================================
--- test/followon-basic.objtxt	(revision 0)
+++ test/followon-basic.objtxt	(revision 0)
@@ -0,0 +1,78 @@
+# RUN: lld-core %s -dead-strip | FileCheck %s
+
+#
+# Test follow on references
+#
+
+---
+atoms:
+    - name:              A
+      scope:             global
+      type:              code
+      section-choice:    custom-required
+      section-name:      .text
+
+    - name:              B
+      scope:             global
+      type:              code
+      section-choice:    custom-required
+      section-name:      .text
+      fixups:
+      - offset:            0
+        kind:              follow-on
+        target:            C
+
+    - name:              C
+      scope:             global
+      type:              code
+      section-choice:    custom-required
+      section-name:      .text
+      content:           [ 55, 48, 89, E5, B8, 00, 00, 00, 00, 5D, C3 ]
+
+    - name:              D
+      scope:             global
+      type:              code
+      section-choice:    custom-required
+      section-name:      .text
+      content:           [ 55, 48, 89, E5, B8, 00, 00, 00, 00, 5D, C3 ]
+      dead-strip:        never
+      fixups:
+      - offset:            0
+        kind:              call32
+        target:            B
+
+    - name:              1.c
+      definition:        absolute
+      value:             0x0
+...
+
+
+# CHECK: ---
+# CHECK: atoms:
+# CHECK:     - name:              B
+# CHECK:       scope:             global
+# CHECK:       type:              code
+# CHECK:       section-choice:    custom-required
+# CHECK:       section-name:      .text
+# CHECK:       fixups:
+# CHECK:       - offset:            0
+# CHECK:         kind:              follow-on
+# CHECK:         target:            C
+# CHECK:     - name:              C
+# CHECK:       scope:             global
+# CHECK:       type:              code
+# CHECK:       section-choice:    custom-required
+# CHECK:       section-name:      .text
+# CHECK:       content:           [ 55, 48, 89, E5, B8, 00, 00, 00, 00, 5D, C3 ]
+# CHECK:     - name:              D
+# CHECK:       scope:             global
+# CHECK:       type:              code
+# CHECK:       dead-strip:        never
+# CHECK:       section-choice:    custom-required
+# CHECK:       section-name:      .text
+# CHECK:       content:           [ 55, 48, 89, E5, B8, 00, 00, 00, 00, 5D, C3 ]
+# CHECK:       fixups:
+# CHECK:       - offset:            0
+# CHECK:         kind:              call32
+# CHECK:         target:            B
+# CHECK: ...
Index: test/elf/Inputs/followon-reference-test.elf-i386
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: test/elf/Inputs/followon-reference-test.elf-i386
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: test/elf/followon-reference.objtxt
===================================================================
--- test/elf/followon-reference.objtxt	(revision 0)
+++ test/elf/followon-reference.objtxt	(revision 0)
@@ -0,0 +1,64 @@
+# Test generated by using the following
+#	.file	"1.c"
+#	.text
+#	.globl	fn
+#	.type	fn, @function
+#fn:
+#.LFB0:
+#	.cfi_startproc
+#	pushq	%rbp
+#	.cfi_def_cfa_offset 16
+#	.cfi_offset 6, -16
+#	movq	%rsp, %rbp
+#	.cfi_def_cfa_register 6
+#	movl	$0, %eax
+#	popq	%rbp
+#	.cfi_def_cfa 7, 8
+#	ret
+#	.cfi_endproc
+#.LFE0:
+#	.size	fn, .-fn
+#        .align  32
+#	.globl	fn1
+#	.type	fn1, @function
+#fn1:
+#.LFB1:
+#	.cfi_startproc
+#	pushq	%rbp
+#	.cfi_def_cfa_offset 16
+#	.cfi_offset 6, -16
+#	movq	%rsp, %rbp
+#	.cfi_def_cfa_register 6
+#	movl	$0, %eax
+#	popq	%rbp
+#	.cfi_def_cfa 7, 8
+#	ret
+#	.cfi_endproc
+#.LFE1:
+#	.size	fn1, .-fn1
+#	.section	.note.GNU-stack,"", at progbits
+
+RUN: lld-core -reader ELF %p/Inputs/followon-reference-test.elf-i386 | FileCheck -check-prefix=YAML %s
+
+YAML:    - name:              fn
+YAML:      scope:             global
+YAML:      type:              code
+YAML:      section-choice:    custom-required
+YAML:      section-name:      .text
+YAML:      content:           [ 55, 48, 89, E5, B8, 00, 00, 00, 00, 5D, C3, 66, 
+YAML:                           0F, 1F, 44, 00, 00, 66, 66, 66, 66, 66, 66, 2E, 
+YAML:                           0F, 1F, 84, 00, 00, 00, 00, 00 ]
+YAML:      fixups:
+YAML:      - offset:            0
+YAML:        kind:              follow-on
+YAML:        target:            fn1
+YAML:    - name:              fn1
+YAML:      scope:             global
+YAML:      type:              code
+YAML:      section-choice:    custom-required
+YAML:      section-name:      .text
+YAML:      content:           [ 55, 48, 89, E5, B8, 00, 00, 00, 00, 5D, C3 ]
+YAML:      fixups:
+YAML:      - offset:            0
+YAML:        kind:              preceded-by
+YAML:        target:            fn
Index: test/preceded-by-basic.objtxt
===================================================================
--- test/preceded-by-basic.objtxt	(revision 0)
+++ test/preceded-by-basic.objtxt	(revision 0)
@@ -0,0 +1,68 @@
+# RUN: lld-core %s -dead-strip | FileCheck %s
+
+#
+# Test preceded by references
+#
+
+---
+atoms:
+    - name:              A
+      scope:             global
+      type:              code
+      section-choice:    custom-required
+      section-name:      .text
+
+    - name:              B
+      scope:             global
+      type:              code
+      section-choice:    custom-required
+      section-name:      .text
+      fixups:
+      - offset:            0
+        kind:              preceded-by
+        target:            A
+
+    - name:              C
+      scope:             global
+      type:              code
+      section-choice:    custom-required
+      section-name:      .text
+      dead-strip:        never
+      fixups:
+      - offset:            0
+        kind:              preceded-by
+        target:            B
+
+
+    - name:              1.c
+      definition:        absolute
+      value:             0x0
+...
+
+# CHECK: ---
+# CHECK: atoms:
+# CHECK:     - name:              A
+# CHECK:       scope:             global
+# CHECK:       type:              code
+# CHECK:       section-choice:    custom-required
+# CHECK:       section-name:      .text
+# CHECK:     - name:              B
+# CHECK:       scope:             global
+# CHECK:       type:              code
+# CHECK:       section-choice:    custom-required
+# CHECK:       section-name:      .text
+# CHECK:       fixups:
+# CHECK:       - offset:            0
+# CHECK:         kind:              preceded-by
+# CHECK:         target:            A
+# CHECK:     - name:              C
+# CHECK:       scope:             global
+# CHECK:       type:              code
+# CHECK:       dead-strip:        never
+# CHECK:       section-choice:    custom-required
+# CHECK:       section-name:      .text
+# CHECK:       fixups:
+# CHECK:       - offset:            0
+# CHECK:         kind:              preceded-by
+# CHECK:         target:            B
+# CHECK: ...
Index: tools/lld-core/TestingHelpers.hpp
===================================================================
--- tools/lld-core/TestingHelpers.hpp	(revision 167130)
+++ tools/lld-core/TestingHelpers.hpp	(working copy)
@@ -271,6 +271,8 @@
 // Table of fixup kinds in YAML documents used for testing
 //
 const TestingKindMapping sKinds[] = {
+    { "preceded-by",    -2,   true,  false, false},
+    { "follow-on",      -1,   true,  false, false},
     { "call32",         2,    true,  false, false},
     { "pcrel32",        3,    false, false, false },
     { "gotLoad32",      7,    false, true,  true },
Index: include/lld/Core/Reference.h
===================================================================
--- include/lld/Core/Reference.h	(revision 167130)
+++ include/lld/Core/Reference.h	(working copy)
@@ -11,6 +11,8 @@
 #define LLD_CORE_REFERENCES_H_
 
 #include "llvm/Support/DataTypes.h"
+#include "llvm/ADT/StringRef.h"
+#include <map>
 
 namespace lld {
 
@@ -33,12 +35,29 @@
   /// Negative kind values are architecture independent.
   typedef int32_t Kind;
 
+  enum {
+    FollowOn = -1,
+    PrecededBy = -2,
+    LayoutBefore = -3,
+    LayoutAfter = -4
+  };
+
   // A value to be added to the value of a target
   typedef int64_t Addend;
 
   /// What sort of reference this is.
   virtual Kind kind() const = 0;
 
+  virtual StringRef kindToString() const {
+    if (kind() < 0)
+      return _kindToString.find(kind())->second;
+    return "unknown";
+  }
+
+  virtual int32_t stringToKind(StringRef kindString) const {
+    return _stringToKind.find(kindString)->second;
+  }
+
   /// During linking, some optimizations may change the code gen and
   /// hence the reference kind.
   virtual void setKind(Kind) = 0;
@@ -63,15 +82,27 @@
 
 protected:
   /// Atom is an abstract base class.  Only subclasses can access constructor.
-  Reference() {}
+  Reference() {
+    _kindToString[-1] = "follow-on";
+    _kindToString[-2] = "preceded-by";
+    _kindToString[-3] = "layout-before";
+    _kindToString[-4] = "layout-after";
+    _stringToKind["follow-on"] = -1;
+    _stringToKind["preceded-by"] = -2;    
+    _stringToKind["layout-before"] = -3; 
+    _stringToKind["layout-after"] = -4; 
+  }
 
   /// The memory for Reference objects is always managed by the owning File
   /// object.  Therefore, no one but the owning File object should call
   /// delete on an Reference.  In fact, some File objects may bulk allocate
   /// an array of References, so they cannot be individually deleted by anyone.
   virtual ~Reference() {}
-};
 
+private:
+  std::map<int32_t, StringRef> _kindToString;
+  std::map<StringRef, int32_t> _stringToKind;
+};
 
 } // namespace lld
 
Index: lib/ReaderWriter/ELF/ReaderELF.cpp
===================================================================
--- lib/ReaderWriter/ELF/ReaderELF.cpp	(revision 167130)
+++ lib/ReaderWriter/ELF/ReaderELF.cpp	(working copy)
@@ -58,14 +58,21 @@
     , _targetSymbolIndex(rela->getSymbol())
     , _offsetInAtom(offset)
     , _addend(rela->r_addend)
-    , _kind(rela->getType()) {}
+    , _kind((Kind)rela->getType()) {}
 
   ELFReference(const Elf_Rel *rel, uint64_t offset, const Atom *target)
     : _target(target)
     , _targetSymbolIndex(rel->getSymbol())
     , _offsetInAtom(offset)
     , _addend(0)
-    , _kind(rel->getType()) {}
+    , _kind((Kind)rel->getType()) {}
+
+  ELFReference(Kind kind)
+    : _target(nullptr)
+    , _targetSymbolIndex(0)
+    , _offsetInAtom(0)
+    , _addend(0)
+    , _kind(kind) {}
 
 
   virtual uint64_t offsetInAtom() const {
@@ -428,6 +435,12 @@
     It = reinterpret_cast<const void*>(index);
   }
 
+  void updateReferences(std::vector<ELFReference<target_endianness, is64Bits> *>
+                        &_references) {
+    _referenceList = _references;
+    _referenceEndIndex = _referenceList.size();
+  }
+
 private:
 
   const File &_owningFile;
@@ -606,6 +619,9 @@
         return A->st_value < B->st_value;
       }));
 
+      ELFDefinedAtom<target_endianness, is64Bits> *previous_atom = nullptr;
+      const Elf_Sym *previous_sym = nullptr;
+
       // i.first is the section the symbol lives in
       for (auto si = symbols.begin(), se = symbols.end(); si != se; ++si) {
 
@@ -640,6 +656,30 @@
         symbolData = llvm::ArrayRef<uint8_t>((uint8_t *)symbolContents.data()
                                     + (*si)->st_value, contentSize);
 
+        // Check to see if we need to add the FollowOn Reference
+        // We dont want to do for symbols that are
+        // a) common symbols
+        // b) the atoms have the merge attribute set
+        // We add a follow on reference only if there is a gap
+        // in between two atoms, we dont know what the gap is
+        // so, lets add a follow-on reference from the previous atom to the 
+        // current atom as well as lets add a preceded-by reference from the 
+        // current atom to the previous atom, so that the previous atom 
+        // is not removed in any case
+        ELFReference<target_endianness, is64Bits> *followOn = nullptr;
+        if (!isCommon && 
+            previous_atom && 
+            previous_atom->merge() == DefinedAtom::mergeNo) {
+          if (((*si)->st_value - (previous_sym->st_value +
+                                  previous_sym->st_size)) > 0) {
+            followOn = new (_readerStorage.Allocate
+                         <ELFReference<target_endianness, is64Bits> > ())
+                          ELFReference<target_endianness, is64Bits> (
+                          lld::Reference::FollowOn);
+            _references.push_back(followOn);
+            previous_atom->updateReferences(_references);
+          }
+        }
 
         unsigned int referenceStart = _references.size();
 
@@ -674,6 +714,18 @@
           }
         }
 
+        // If we are inserting a followOn reference, lets add a precededBy 
+        // reference too
+        ELFReference<target_endianness, is64Bits> *precededBy = nullptr;
+        if (followOn) {
+          precededBy = new (_readerStorage.Allocate
+                         <ELFReference<target_endianness, is64Bits> > ())
+                          ELFReference<target_endianness, is64Bits> (
+                          lld::Reference::PrecededBy);
+          precededBy->setTarget(previous_atom);
+          _references.push_back(precededBy);
+        }
+
         // Create the DefinedAtom and add it to the list of DefinedAtoms.
         auto *newAtom = new (_readerStorage.Allocate
                        <ELFDefinedAtom<target_endianness, is64Bits> > ()) 
@@ -682,6 +734,12 @@
                              *si, i.first, symbolData,
                              referenceStart, _references.size(), _references);
 
+        if (followOn) {
+          followOn->setTarget(newAtom);
+        }
+        previous_atom = newAtom;
+        previous_sym = *si;
+
         _definedAtoms._atoms.push_back(newAtom);
         _symbolToAtomMapping.insert(std::make_pair((*si), newAtom));
 
@@ -691,10 +749,12 @@
 // All the Atoms and References are created.  Now update each Reference's
 // target with the Atom pointer it refers to.
     for (auto &ri : _references) {
+      if (ri->kind() > lld::Reference::FollowOn) {
       const Elf_Sym  *Symbol  = _objFile->getElfSymbol(ri->targetSymbolIndex());
       ri->setTarget(findAtom (Symbol));
     }
   }
+  }
 
   virtual void addAtom(const Atom&) {
     llvm_unreachable("cannot add atoms to native .o files");


More information about the llvm-commits mailing list