[llvm-commits] [lld] r152874 - in /lld/trunk: include/lld/Core/Pass.h include/lld/Core/Reference.h include/lld/Platform/Platform.h lib/Core/NativeReader.cpp lib/Core/YamlKeyValues.cpp lib/Core/YamlReader.cpp lib/Core/YamlWriter.cpp lib/Passes/CMakeLists.txt lib/Passes/GOTPass.cpp lib/Passes/StubsPass.cpp test/pass-got-basic.objtxt tools/lld-core/lld-core.cpp

Nick Kledzik kledzik at apple.com
Thu Mar 15 16:36:25 PDT 2012


Author: kledzik
Date: Thu Mar 15 18:36:24 2012
New Revision: 152874

URL: http://llvm.org/viewvc/llvm-project?rev=152874&view=rev
Log:
Add Pass to instantiate GOT entries

Added:
    lld/trunk/lib/Passes/GOTPass.cpp
    lld/trunk/test/pass-got-basic.objtxt
Modified:
    lld/trunk/include/lld/Core/Pass.h
    lld/trunk/include/lld/Core/Reference.h
    lld/trunk/include/lld/Platform/Platform.h
    lld/trunk/lib/Core/NativeReader.cpp
    lld/trunk/lib/Core/YamlKeyValues.cpp
    lld/trunk/lib/Core/YamlReader.cpp
    lld/trunk/lib/Core/YamlWriter.cpp
    lld/trunk/lib/Passes/CMakeLists.txt
    lld/trunk/lib/Passes/StubsPass.cpp
    lld/trunk/tools/lld-core/lld-core.cpp

Modified: lld/trunk/include/lld/Core/Pass.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/Pass.h?rev=152874&r1=152873&r2=152874&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/Pass.h (original)
+++ lld/trunk/include/lld/Core/Pass.h Thu Mar 15 18:36:24 2012
@@ -60,6 +60,20 @@
 };
 
 
+///
+/// Pass for adding GOT entries for pointers to functions/data
+/// outside the linkage unit.
+///
+class GOTPass : public Pass {
+public:
+  GOTPass(File& f, Platform& p) : Pass(f, p) {}
+
+  /// Scans all Atoms looking for pointer to SharedLibraryAtoms
+  /// and transfroms them to a pointer to a GOT entry.
+  virtual void perform();
+};
+
+
 } // namespace lld
 
 #endif // LLD_CORE_PASS_H_

Modified: lld/trunk/include/lld/Core/Reference.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/Reference.h?rev=152874&r1=152873&r2=152874&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/Reference.h (original)
+++ lld/trunk/include/lld/Core/Reference.h Thu Mar 15 18:36:24 2012
@@ -39,6 +39,10 @@
   /// What sort of reference this is. 
   virtual Kind kind() const = 0;
   
+  /// During linking, some optimizations may change the code gen and
+  /// hence the reference kind.
+  virtual void setKind(Kind) = 0;
+  
   /// If the reference is a fixup in the Atom, then this returns the 
   /// byte offset into the Atom's content to do the fix up.
   virtual uint64_t offsetInAtom() const = 0;

Modified: lld/trunk/include/lld/Platform/Platform.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Platform/Platform.h?rev=152874&r1=152873&r2=152874&view=diff
==============================================================================
--- lld/trunk/include/lld/Platform/Platform.h (original)
+++ lld/trunk/include/lld/Platform/Platform.h Thu Mar 15 18:36:24 2012
@@ -102,9 +102,6 @@
   /// @brief last chance for platform to tweak atoms
   virtual void postResolveTweaks(std::vector<const Atom *>& all) = 0;
   
-  /// If the output being generated uses needs stubs for external calls
-  virtual bool outputUsesStubs() = 0;
-  
   /// Converts a reference kind string to a in-memory numeric value. 
   /// For use with parsing YAML encoded object files.
   virtual Reference::Kind kindFromString(llvm::StringRef) = 0;
@@ -113,13 +110,34 @@
   /// For use with writing YAML encoded object files.
   virtual llvm::StringRef kindToString(Reference::Kind) = 0;
   
-  /// If Reference is a branch instruction that might need to be changed
-  /// to target a stub (PLT entry). 
-  virtual bool isBranch(const Reference*) = 0;
+  /// If true, the linker will use stubs and GOT entries for
+  /// references to shared library symbols. If false, the linker
+  /// will generate relocations on the text segment which the
+  /// runtime loader will use to patch the program at runtime.
+  virtual bool noTextRelocs() = 0;
+  
+  /// Returns if the Reference kind is for a call site.  The "stubs" Pass uses
+  /// this to find calls that need to be indirected through a stub.
+  virtual bool isCallSite(Reference::Kind) = 0;
+
+  /// Returns if the Reference kind is a pre-instantiated GOT access.
+  /// The "got" Pass uses this to figure out what GOT entries to instantiate.
+  virtual bool isGOTAccess(Reference::Kind, bool& canBypassGOT) = 0;
+  
+  /// The platform needs to alter the reference kind from a pre-instantiated 
+  /// GOT access to an actual access.  If targetIsNowGOT is true, the "got" 
+  /// Pass has instantiated a GOT atom and altered the reference's target
+  /// to point to that atom.  If targetIsNowGOT is false, the "got" Pass 
+  /// determined a GOT entry is not needed because the reference site can 
+  /// directly access the target.
+  virtual void updateReferenceToGOT(const Reference*, bool targetIsNowGOT) = 0;
   
   /// Create a platform specific atom which contains a stub/PLT entry 
   /// targeting the specified shared library atom.
-  virtual const Atom* makeStub(const SharedLibraryAtom&, File&) = 0;
+  virtual const DefinedAtom* makeStub(const Atom&, File&) = 0;
+
+  /// Create a platform specific GOT atom. 
+  virtual const DefinedAtom* makeGOTEntry(const Atom&, File&) = 0;
 
 };
 

Modified: lld/trunk/lib/Core/NativeReader.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/NativeReader.cpp?rev=152874&r1=152873&r2=152874&view=diff
==============================================================================
--- lld/trunk/lib/Core/NativeReader.cpp (original)
+++ lld/trunk/lib/Core/NativeReader.cpp Thu Mar 15 18:36:24 2012
@@ -200,11 +200,22 @@
     return _ivarData->kind;
   }
   
+  virtual void setKind(Kind);
   virtual const Atom* target() const;
   virtual Addend addend() const;
   virtual void setTarget(const Atom* newAtom);
-   
+
 private:
+  // Used in rare cases when Reference is modified, 
+  // since ivar data is mapped read-only.
+  void cloneIvarData() {
+    // TODO: do nothing on second call
+   NativeReferenceIvarsV1* niv = reinterpret_cast<NativeReferenceIvarsV1*>
+                                (operator new(sizeof(NativeReferenceIvarsV1), 
+                                                                std::nothrow));
+    memcpy(niv, _ivarData, sizeof(NativeReferenceIvarsV1));
+  }
+
   const NativeFile*                 _file;
   const NativeReferenceIvarsV1*     _ivarData;
 };
@@ -785,6 +796,11 @@
   return _file->addend(_ivarData->addendIndex);
 }
 
+inline void NativeReferenceV1::setKind(Kind k) {
+  this->cloneIvarData();
+  const_cast<NativeReferenceIvarsV1*>(_ivarData)->kind = k;
+}
+
 inline void NativeReferenceV1::setTarget(const Atom* newAtom) {
   return _file->setTarget(_ivarData->targetIndex, newAtom);
 }

Modified: lld/trunk/lib/Core/YamlKeyValues.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/YamlKeyValues.cpp?rev=152874&r1=152873&r2=152874&view=diff
==============================================================================
--- lld/trunk/lib/Core/YamlKeyValues.cpp (original)
+++ lld/trunk/lib/Core/YamlKeyValues.cpp Thu Mar 15 18:36:24 2012
@@ -150,6 +150,7 @@
   { "data",           DefinedAtom::typeData },
   { "zero-fill",      DefinedAtom::typeZeroFill },
   { "cf-string",      DefinedAtom::typeCFString },
+  { "got",            DefinedAtom::typeGOT },
   { "initializer-ptr",DefinedAtom::typeInitializerPtr },
   { "terminator-ptr", DefinedAtom::typeTerminatorPtr },
   { "c-string-ptr",   DefinedAtom::typeCStringPtr },

Modified: lld/trunk/lib/Core/YamlReader.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/YamlReader.cpp?rev=152874&r1=152873&r2=152874&view=diff
==============================================================================
--- lld/trunk/lib/Core/YamlReader.cpp (original)
+++ lld/trunk/lib/Core/YamlReader.cpp Thu Mar 15 18:36:24 2012
@@ -271,6 +271,10 @@
     return _kind;
   }
   
+  virtual void setKind(Kind k) {
+    _kind = k;
+  }
+
   virtual const Atom* target() const {
     return _target;
   }

Modified: lld/trunk/lib/Core/YamlWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/YamlWriter.cpp?rev=152874&r1=152873&r2=152874&view=diff
==============================================================================
--- lld/trunk/lib/Core/YamlWriter.cpp (original)
+++ lld/trunk/lib/Core/YamlWriter.cpp Thu Mar 15 18:36:24 2012
@@ -305,6 +305,9 @@
       for (unsigned int i=0; i < arr.size(); ++i) {
         if ( needComma )
           out  << ", ";
+        if ( ((i % 12) == 0) && (i != 0) ) {
+          out << "\n                           ";
+        }
         out  << hexdigit(arr[i] >> 4);
         out  << hexdigit(arr[i] & 0x0F);
         needComma = true;

Modified: lld/trunk/lib/Passes/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Passes/CMakeLists.txt?rev=152874&r1=152873&r2=152874&view=diff
==============================================================================
--- lld/trunk/lib/Passes/CMakeLists.txt (original)
+++ lld/trunk/lib/Passes/CMakeLists.txt Thu Mar 15 18:36:24 2012
@@ -1,3 +1,4 @@
 add_lld_library(lldPasses
+  GOTPass.cpp
   StubsPass.cpp
   )

Added: lld/trunk/lib/Passes/GOTPass.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Passes/GOTPass.cpp?rev=152874&view=auto
==============================================================================
--- lld/trunk/lib/Passes/GOTPass.cpp (added)
+++ lld/trunk/lib/Passes/GOTPass.cpp Thu Mar 15 18:36:24 2012
@@ -0,0 +1,116 @@
+//===- Passes/GOTPass.cpp - Adds GOT entries ------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//
+// This linker pass transforms all GOT kind references to real references.
+// That is, in assembly you can write something like:
+//     movq	foo at GOTPCREL(%rip), %rax 
+// which means you want to load a pointer to "foo" out of the GOT (global
+// Offsets Table). In the object file, the Atom containing this instruction
+// has a Reference whose target is an Atom named "foo" and the Reference
+// kind is a GOT load.  The linker needs to instantiate a pointer sized
+// GOT entry.  This is done be creating a GOT Atom to represent that pointer
+// sized data in this pass, and altering the Atom graph so the Reference now
+// points to the GOT Atom entry (corresponding to "foo") and changing the
+// Reference Kind to reflect it is now pointing to a GOT entry (rather
+// then needing a GOT entry). 
+// 
+// There is one optimization the linker can do here.  If the target of the GOT
+// is in the same linkage unit and does not need to be interposable, and 
+// the GOT use is just a load (not some other operation), this pass can 
+// transform that load into an LEA (add).  This optimizes away one memory load
+// at runtime that could stall the pipeline.  This optimization only works
+// for architectures in which a (GOT) load instruction can be change to an 
+// LEA instruction that is the same size.  The platform method isGOTAccess()
+// should only return true for "canBypassGOT" if this optimization is supported.
+//
+
+#include "llvm/ADT/DenseMap.h"
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/Pass.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Reference.h"
+#include "lld/Platform/Platform.h"
+
+
+namespace lld {
+
+void GOTPass::perform() {
+  // Use map so all pointers to same symbol use same GOT entry.
+  llvm::DenseMap<const Atom*, const DefinedAtom*> targetToGOT;
+  
+  // Scan all references in all atoms.
+  for(auto ait=_file.definedAtomsBegin(), aend=_file.definedAtomsEnd(); 
+                                                      ait != aend; ++ait) {
+    const DefinedAtom* atom = *ait;
+    for (auto rit=atom->referencesBegin(), rend=atom->referencesEnd(); 
+                                                      rit != rend; ++rit) {
+      const Reference* ref = *rit;
+      // Look at instructions accessing the GOT.
+      bool canBypassGOT;
+      if ( _platform.isGOTAccess(ref->kind(), canBypassGOT) ) {
+        const Atom* target = ref->target();
+        assert(target != NULL);
+        const DefinedAtom* defTarget = target->definedAtom();
+        bool replaceTargetWithGOTAtom = false;
+        if ( target->definition() == Atom::definitionSharedLibrary ) {
+          // Accesses to shared library symbols must go through GOT.
+          replaceTargetWithGOTAtom = true;
+        }
+        else if ( (defTarget != NULL)
+               && (defTarget->interposable() != DefinedAtom::interposeNo) ) {
+          // Accesses to interposable symbols in same linkage unit 
+          // must also go through GOT.
+          assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
+          replaceTargetWithGOTAtom = true;
+        }
+        else {
+          // Target does not require indirection.  So, if instruction allows
+          // GOT to be by-passed, do that optimization and don't create
+          // GOT entry.
+          replaceTargetWithGOTAtom = !canBypassGOT;
+        } 
+        if ( replaceTargetWithGOTAtom ) {
+          // Replace the target with a reference to a GOT entry.
+          const DefinedAtom* gotEntry = NULL;
+          auto pos = targetToGOT.find(target);
+          if ( pos == targetToGOT.end() ) {
+            // This is no existing GOT entry.  Create a new one.
+            gotEntry = _platform.makeGOTEntry(*target, _file);
+            assert(gotEntry != NULL);
+            assert(gotEntry->contentType() == DefinedAtom::typeGOT);
+            targetToGOT[target] = gotEntry;
+          }
+          else {
+            // Reuse an existing GOT entry.
+            gotEntry = pos->second;
+            assert(gotEntry != NULL);
+          }
+          // Switch reference to GOT atom.
+          (const_cast<Reference*>(ref))->setTarget(gotEntry);
+        }
+        // Platform needs to update reference kind to reflect
+        // that target is a GOT entry or a direct accesss.
+        _platform.updateReferenceToGOT(ref, replaceTargetWithGOTAtom);
+      }
+    }
+  }
+  
+  // add all created GOT Atoms to master file
+  for (auto it=targetToGOT.begin(), end=targetToGOT.end(); it != end; ++it) {
+    _file.addAtom(*it->second);
+  }
+  
+
+}
+
+
+
+}

Modified: lld/trunk/lib/Passes/StubsPass.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Passes/StubsPass.cpp?rev=152874&r1=152873&r2=152874&view=diff
==============================================================================
--- lld/trunk/lib/Passes/StubsPass.cpp (original)
+++ lld/trunk/lib/Passes/StubsPass.cpp Thu Mar 15 18:36:24 2012
@@ -8,15 +8,16 @@
 //===----------------------------------------------------------------------===//
 
 //
-// This linker pass is 
-//
-//
-//
+// This linker pass updates call sites which have references to shared library
+// atoms to instead have a reference to a stub (PLT entry) for the specified
+// symbol.  The platform object does the work of creating the platform-specific
+// StubAtom.
 //
 
 
 #include "llvm/ADT/DenseMap.h"
 
+#include "lld/Core/DefinedAtom.h"
 #include "lld/Core/Pass.h"
 #include "lld/Core/File.h"
 #include "lld/Core/Reference.h"
@@ -26,12 +27,12 @@
 namespace lld {
 
 void StubsPass::perform() {
-  // Skip this pass if output format does not need stubs.
-  if ( !_platform.outputUsesStubs() )
+  // Skip this pass if output format uses text relocations instead of stubs.
+  if ( !_platform.noTextRelocs() )
     return;
   
-  // Use map so all call sites to same shlib symbol use same stub
-  llvm::DenseMap<const SharedLibraryAtom*, const Atom*> shlibToStub;
+  // Use map so all call sites to same shlib symbol use same stub.
+  llvm::DenseMap<const Atom*, const DefinedAtom*> targetToStub;
   
   // Scan all references in all atoms.
   for(auto ait=_file.definedAtomsBegin(), aend=_file.definedAtomsEnd(); 
@@ -40,26 +41,40 @@
     for (auto rit=atom->referencesBegin(), rend=atom->referencesEnd(); 
                                                       rit != rend; ++rit) {
       const Reference* ref = *rit;
-      const Atom* target = ref->target();
-      assert(target != NULL);
-      // If the target of this reference is in a shared library
-      if ( const SharedLibraryAtom* shlbTarget = target->sharedLibraryAtom() ) {
-        // and this is a call to that shared library symbol.
-        if ( _platform.isBranch(ref) ) {
-          const Atom* stub;
-          // Replace the target with a reference to a stub
-          auto pos = shlibToStub.find(shlbTarget);
-          if ( pos == shlibToStub.end() ) {
+      // Look at call-sites.
+      if ( _platform.isCallSite(ref->kind()) ) {
+        const Atom* target = ref->target();
+        assert(target != NULL);
+        bool replaceCalleeWithStub = false;
+        if ( target->definition() == Atom::definitionSharedLibrary ) {
+          // Calls to shared libraries go through stubs.
+          replaceCalleeWithStub = true;
+        }
+        else if ( const DefinedAtom* defTarget = target->definedAtom() ) {
+          if ( defTarget->interposable() != DefinedAtom::interposeNo ) {
+            // Calls to interposable functions in same linkage unit 
+            // must also go through a stub.
+            assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
+            replaceCalleeWithStub = true;
+          }
+        }
+        if ( replaceCalleeWithStub ) {
+          // Replace the reference's target with a stub.
+          const DefinedAtom* stub;
+          auto pos = targetToStub.find(target);
+          if ( pos == targetToStub.end() ) {
             // This is no existing stub.  Create a new one.
-            stub = _platform.makeStub(*shlbTarget, _file);
-            shlibToStub[shlbTarget] = stub;
+            stub = _platform.makeStub(*target, _file);
+            assert(stub != NULL);
+            assert(stub->contentType() == DefinedAtom::typeStub);
+            targetToStub[target] = stub;
           }
           else {
-            // Reuse and existing stub
+            // Reuse an existing stub.
             stub = pos->second;
+            assert(stub != NULL);
           }
-          assert(stub != NULL);
-          // Switch call site in atom to refrence stub instead of shlib atom.
+          // Switch call site to reference stub atom.
           (const_cast<Reference*>(ref))->setTarget(stub);
         }
       }
@@ -67,7 +82,7 @@
   }
   
   // add all created stubs to file
-  for (auto it=shlibToStub.begin(), end=shlibToStub.end(); it != end; ++it) {
+  for (auto it=targetToStub.begin(), end=targetToStub.end(); it != end; ++it) {
     _file.addAtom(*it->second);
   }
   

Added: lld/trunk/test/pass-got-basic.objtxt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pass-got-basic.objtxt?rev=152874&view=auto
==============================================================================
--- lld/trunk/test/pass-got-basic.objtxt (added)
+++ lld/trunk/test/pass-got-basic.objtxt Thu Mar 15 18:36:24 2012
@@ -0,0 +1,81 @@
+# RUN: lld-core %s -got_pass  | FileCheck %s
+
+#
+# Test that GOT pass instantiates GOT entires and alters references
+#
+
+---
+atoms:
+    - name:              foo
+      type:              code
+      content:           [ 48, 8B, 0D, 00, 00, 00, 00, 
+                           48, 8B, 0D, 00, 00, 00, 00, 
+                           48, 8B, 0D, 00, 00, 00, 00, 
+                           48, 83, 3D, 00, 00, 00, 00, 00,
+                           48, 83, 3D, 00, 00, 00, 00, 00, 
+                           48, 83, 3D, 00, 00, 00, 00, 00,
+                           48, 83, 3D, 00, 00, 00, 00, 00 ]
+      fixups:
+      - offset:          3
+        kind:            gotLoad32
+        target:          malloc
+      - offset:          10
+        kind:            gotLoad32
+        target:          myPrivate
+      - offset:          17
+        kind:            gotLoad32
+        target:          myInterposable
+      - offset:          24
+        kind:            gotUse32
+        target:          malloc
+      - offset:          32
+        kind:            gotUse32
+        target:          myPrivate
+      - offset:          40
+        kind:            gotUse32
+        target:          myInterposable
+
+    - name:              myPrivate
+      scope:             global
+      interposable:      no
+
+    - name:              myInterposable
+      scope:             global
+      interposable:      yes
+
+    - name:              malloc
+      definition:        shared-library
+      load-name:         libc.so
+      
+...
+
+# CHECK:       name:         foo
+# CHECK:       fixups: 
+# CHECK:       offset:       3
+# CHECK:       kind:         pcrel32
+# CHECK:       target:       L
+# CHECK:       offset:       10
+# CHECK:       kind:         lea32wasGot
+# CHECK:       target:       myPrivate
+# CHECK:       offset:       17
+# CHECK:       kind:         pcrel32
+# CHECK:       target:       L
+# CHECK:       offset:       24
+# CHECK:       kind:         pcrel32
+# CHECK:       target:       L
+# CHECK:       offset:       32
+# CHECK:       kind:         pcrel32
+# CHECK:       target:       L
+# CHECK:       offset:       40
+# CHECK:       kind:         pcrel32
+# CHECK:       target:       L
+# CHECK:       name:         myPrivate
+# CHECK:       name:         myInterposable
+# CHECK:       interposable: yes
+# CHECK:       name:         L
+# CHECK:       type:         got
+# CHECK:       type:         got
+# CHECK:       type:         got
+# CHECK:       name:         malloc
+# CHECK:       definition:   shared-library
+# CHECK:       ...

Modified: lld/trunk/tools/lld-core/lld-core.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/tools/lld-core/lld-core.cpp?rev=152874&r1=152873&r2=152874&view=diff
==============================================================================
--- lld/trunk/tools/lld-core/lld-core.cpp (original)
+++ lld/trunk/tools/lld-core/lld-core.cpp Thu Mar 15 18:36:24 2012
@@ -54,11 +54,11 @@
 
 
 //
-// Simple atoms created by the stubs pass.
+// Simple atom created by the stubs pass.
 //
 class TestingStubAtom : public DefinedAtom {
 public:
-        TestingStubAtom(const File& f, const SharedLibraryAtom& shlib) :
+        TestingStubAtom(const File& f, const Atom& shlib) :
                         _file(f), _shlib(shlib) {
           static uint32_t lastOrdinal = 0;
           _ordinal = lastOrdinal++; 
@@ -145,11 +145,109 @@
   
 private:
   const File&               _file;
-  const SharedLibraryAtom&  _shlib;
+  const Atom&               _shlib;
   uint32_t                  _ordinal;
 };
 
 
+
+
+//
+// Simple atom created by the GOT pass.
+//
+class TestingGOTAtom : public DefinedAtom {
+public:
+        TestingGOTAtom(const File& f, const Atom& shlib) :
+                        _file(f), _shlib(shlib) {
+          static uint32_t lastOrdinal = 0;
+          _ordinal = lastOrdinal++; 
+        }
+
+  virtual const File& file() const {
+    return _file;
+  }
+
+  virtual llvm::StringRef name() const {
+    return llvm::StringRef();
+  }
+  
+  virtual uint64_t ordinal() const {
+    return _ordinal;
+  }
+
+  virtual uint64_t size() const {
+    return 0;
+  }
+
+  virtual Scope scope() const {
+    return DefinedAtom::scopeLinkageUnit;
+  }
+  
+  virtual Interposable interposable() const {
+    return DefinedAtom::interposeNo;
+  }
+  
+  virtual Merge merge() const {
+    return DefinedAtom::mergeNo;
+  }
+  
+  virtual ContentType contentType() const  {
+    return DefinedAtom::typeGOT;
+  }
+
+  virtual Alignment alignment() const {
+    return Alignment(3,0);
+  }
+  
+  virtual SectionChoice sectionChoice() const {
+    return DefinedAtom::sectionBasedOnContent;
+  }
+    
+  virtual llvm::StringRef customSectionName() const {
+    return llvm::StringRef();
+  }
+  virtual DeadStripKind deadStrip() const {
+    return DefinedAtom::deadStripNormal;
+  }
+    
+  virtual ContentPermissions permissions() const  {
+    return DefinedAtom::permRW_;
+  }
+  
+  virtual bool isThumb() const {
+    return false;
+  }
+    
+  virtual bool isAlias() const {
+    return false;
+  }
+  
+  virtual llvm::ArrayRef<uint8_t> rawContent() const {
+    return llvm::ArrayRef<uint8_t>();
+  }
+  
+  virtual reference_iterator referencesBegin() const {
+    return reference_iterator(*this, NULL);
+  }
+  
+  virtual reference_iterator referencesEnd() const {
+    return reference_iterator(*this, NULL);
+  }
+  
+  virtual const Reference* derefIterator(const void* iter) const {
+    return NULL;
+  }
+  
+  virtual void incrementIterator(const void*& iter) const {
+  
+  }
+  
+private:
+  const File&               _file;
+  const Atom&               _shlib;
+  uint32_t                  _ordinal;
+};
+
 //
 // A simple platform for testing.
 //
@@ -251,14 +349,14 @@
 
   // last chance for platform to tweak atoms
   virtual void postResolveTweaks(std::vector<const Atom *> &all) {}
-
-  virtual bool outputUsesStubs() { return true; };
   
 
   struct KindMapping {
     const char*           string;
     Reference::Kind       value;
     bool                  isBranch;
+    bool                  isGotLoad;
+    bool                  isGotUse;
   };
 
   static const KindMapping _s_kindMappings[]; 
@@ -282,19 +380,45 @@
     return llvm::StringRef("???");
   }
 
-
-  virtual bool isBranch(const Reference* ref) { 
-    Reference::Kind value = ref->kind();
+  virtual bool noTextRelocs() {
+    return true;
+  }
+  
+  virtual bool isCallSite(Reference::Kind kind) {
     for (const KindMapping* p = _s_kindMappings; p->string != NULL; ++p) {
-      if ( value == p->value )
+      if ( kind == p->value )
         return p->isBranch;
     }
     return false;
   }
+
+  virtual bool isGOTAccess(Reference::Kind kind, bool& canBypassGOT) {
+    for (const KindMapping* p = _s_kindMappings; p->string != NULL; ++p) {
+      if ( kind == p->value ) {
+        canBypassGOT = p->isGotLoad;
+        return p->isGotUse;
+      }
+    }
+    return false;
+  }
   
-  virtual const Atom* makeStub(const SharedLibraryAtom& shlibAtom, File& file) {
+  virtual void updateReferenceToGOT(const Reference* ref, bool targetIsNowGOT) {
+    if ( targetIsNowGOT )
+      (const_cast<Reference*>(ref))->setKind(kindFromString("pcrel32"));
+    else
+      (const_cast<Reference*>(ref))->setKind(kindFromString("lea32wasGot"));
+  }
+
+
+
+  virtual const DefinedAtom* makeStub(const Atom& shlibAtom, File& file) {
     return new TestingStubAtom(file, shlibAtom);
   }
+  
+  virtual const DefinedAtom* makeGOTEntry(const Atom& shlibAtom, File& file) {
+    return new TestingGOTAtom(file, shlibAtom);
+  }
+
 };
 
 
@@ -302,13 +426,16 @@
 // Table of fixup kinds in YAML documents used for testing
 //
 const TestingPlatform::KindMapping TestingPlatform::_s_kindMappings[] = {
-    { "call32",         1,    true },
-    { "pcrel32",        2,    false },
-    { "gotLoad32",      3,    false },
-    { NULL,             0,    false }
+    { "call32",         1,    true,  false, false},
+    { "pcrel32",        2,    false, false, false },
+    { "gotLoad32",      3,    false, true,  true },
+    { "gotUse32",       4,    false, false, true },
+    { "lea32wasGot",    5,    false, false, false },
+    { NULL,             0,    false, false, false }
   };
 
 
+
 //
 // A simple input files wrapper for testing.
 //
@@ -372,6 +499,9 @@
 gDoStubsPass("stubs_pass", 
           llvm::cl::desc("Run pass to create stub atoms"));
 
+llvm::cl::opt<bool> 
+gDoGotPass("got_pass", 
+          llvm::cl::desc("Run pass to create GOT atoms"));
 
 int main(int argc, char *argv[]) {
   // Print a stack trace if we signal out.
@@ -400,10 +530,15 @@
   resolver.resolve();
 
   // run passes
+  if ( gDoGotPass ) {
+    GOTPass  addGot(resolver.resultFile(), testingPlatform);
+    addGot.perform();
+  }
   if ( gDoStubsPass ) {
     StubsPass  addStubs(resolver.resultFile(), testingPlatform);
     addStubs.perform();
   }
+
   
   // write new atom graph out as YAML doc
   std::string errorInfo;





More information about the llvm-commits mailing list