diff options
| -rw-r--r-- | lld/include/lld/Core/Pass.h | 14 | ||||
| -rw-r--r-- | lld/include/lld/Core/Reference.h | 4 | ||||
| -rw-r--r-- | lld/include/lld/Platform/Platform.h | 32 | ||||
| -rw-r--r-- | lld/lib/Core/NativeReader.cpp | 18 | ||||
| -rw-r--r-- | lld/lib/Core/YamlKeyValues.cpp | 1 | ||||
| -rw-r--r-- | lld/lib/Core/YamlReader.cpp | 4 | ||||
| -rw-r--r-- | lld/lib/Core/YamlWriter.cpp | 3 | ||||
| -rw-r--r-- | lld/lib/Passes/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | lld/lib/Passes/GOTPass.cpp | 116 | ||||
| -rw-r--r-- | lld/lib/Passes/StubsPass.cpp | 63 | ||||
| -rw-r--r-- | lld/test/pass-got-basic.objtxt | 81 | ||||
| -rw-r--r-- | lld/tools/lld-core/lld-core.cpp | 163 |
12 files changed, 454 insertions, 46 deletions
diff --git a/lld/include/lld/Core/Pass.h b/lld/include/lld/Core/Pass.h index ebbcfcdc36e..8aa9f91736a 100644 --- a/lld/include/lld/Core/Pass.h +++ b/lld/include/lld/Core/Pass.h @@ -60,6 +60,20 @@ public: }; +/// +/// 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_ diff --git a/lld/include/lld/Core/Reference.h b/lld/include/lld/Core/Reference.h index cab931fadcf..1af5fdc9559 100644 --- a/lld/include/lld/Core/Reference.h +++ b/lld/include/lld/Core/Reference.h @@ -39,6 +39,10 @@ public: /// 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; diff --git a/lld/include/lld/Platform/Platform.h b/lld/include/lld/Platform/Platform.h index 3486716f87d..614d55306c4 100644 --- a/lld/include/lld/Platform/Platform.h +++ b/lld/include/lld/Platform/Platform.h @@ -102,9 +102,6 @@ public: /// @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 @@ public: /// 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; }; diff --git a/lld/lib/Core/NativeReader.cpp b/lld/lib/Core/NativeReader.cpp index 0eb95b948d7..41a2823c7b8 100644 --- a/lld/lib/Core/NativeReader.cpp +++ b/lld/lib/Core/NativeReader.cpp @@ -200,11 +200,22 @@ public: 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 @@ inline Reference::Addend NativeReferenceV1::addend() const { 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); } diff --git a/lld/lib/Core/YamlKeyValues.cpp b/lld/lib/Core/YamlKeyValues.cpp index 7ee46cc07fd..99fb95cc1ba 100644 --- a/lld/lib/Core/YamlKeyValues.cpp +++ b/lld/lib/Core/YamlKeyValues.cpp @@ -150,6 +150,7 @@ static const ContentTypeMapping typeMappings[] = { { "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 }, diff --git a/lld/lib/Core/YamlReader.cpp b/lld/lib/Core/YamlReader.cpp index 64192b0ee3f..b02f381c2cf 100644 --- a/lld/lib/Core/YamlReader.cpp +++ b/lld/lib/Core/YamlReader.cpp @@ -271,6 +271,10 @@ public: return _kind; } + virtual void setKind(Kind k) { + _kind = k; + } + virtual const Atom* target() const { return _target; } diff --git a/lld/lib/Core/YamlWriter.cpp b/lld/lib/Core/YamlWriter.cpp index 2a9e05078ea..bd253b42506 100644 --- a/lld/lib/Core/YamlWriter.cpp +++ b/lld/lib/Core/YamlWriter.cpp @@ -305,6 +305,9 @@ public: 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; diff --git a/lld/lib/Passes/CMakeLists.txt b/lld/lib/Passes/CMakeLists.txt index a90164c0449..a96676e2c0b 100644 --- a/lld/lib/Passes/CMakeLists.txt +++ b/lld/lib/Passes/CMakeLists.txt @@ -1,3 +1,4 @@ add_lld_library(lldPasses + GOTPass.cpp StubsPass.cpp ) diff --git a/lld/lib/Passes/GOTPass.cpp b/lld/lib/Passes/GOTPass.cpp new file mode 100644 index 00000000000..84797c0ac71 --- /dev/null +++ b/lld/lib/Passes/GOTPass.cpp @@ -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@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); + } + + +} + + + +} diff --git a/lld/lib/Passes/StubsPass.cpp b/lld/lib/Passes/StubsPass.cpp index 4c0aec4eba3..baeaa76fed2 100644 --- a/lld/lib/Passes/StubsPass.cpp +++ b/lld/lib/Passes/StubsPass.cpp @@ -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 @@ void StubsPass::perform() { 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 @@ void StubsPass::perform() { } // 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); } diff --git a/lld/test/pass-got-basic.objtxt b/lld/test/pass-got-basic.objtxt new file mode 100644 index 00000000000..1309af381c8 --- /dev/null +++ b/lld/test/pass-got-basic.objtxt @@ -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: ... diff --git a/lld/tools/lld-core/lld-core.cpp b/lld/tools/lld-core/lld-core.cpp index 6f6e687b75e..6f200db4ea7 100644 --- a/lld/tools/lld-core/lld-core.cpp +++ b/lld/tools/lld-core/lld-core.cpp @@ -54,11 +54,11 @@ namespace { // -// 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 @@ public: 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 @@ public: // 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 @@ public: 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 @@ public: // 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 @@ llvm::cl::opt<bool> 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 @@ int main(int argc, char *argv[]) { 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; |

