summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter
diff options
context:
space:
mode:
authorNick Kledzik <kledzik@apple.com>2014-07-09 21:04:24 +0000
committerNick Kledzik <kledzik@apple.com>2014-07-09 21:04:24 +0000
commit0edfdeb0be83dc9fac8d11c51fc59eb1ab73512e (patch)
tree0ddd2e9aeae75654568baabe5cf9654bdd1d75a4 /lld/lib/ReaderWriter
parent79d4ffbc8fb57a6362da83868952fbe3cb591260 (diff)
downloadbcm5719-llvm-0edfdeb0be83dc9fac8d11c51fc59eb1ab73512e.tar.gz
bcm5719-llvm-0edfdeb0be83dc9fac8d11c51fc59eb1ab73512e.zip
Move GOTPass and StubsPass from Core to MachO
llvm-svn: 212652
Diffstat (limited to 'lld/lib/ReaderWriter')
-rw-r--r--lld/lib/ReaderWriter/CoreLinkingContext.cpp65
-rw-r--r--lld/lib/ReaderWriter/MachO/CMakeLists.txt2
-rw-r--r--lld/lib/ReaderWriter/MachO/GOTPass.cpp108
-rw-r--r--lld/lib/ReaderWriter/MachO/GOTPass.hpp1
-rw-r--r--lld/lib/ReaderWriter/MachO/MachOPasses.h101
-rw-r--r--lld/lib/ReaderWriter/MachO/StubsPass.cpp67
-rw-r--r--lld/lib/ReaderWriter/MachO/StubsPass.hpp1
7 files changed, 280 insertions, 65 deletions
diff --git a/lld/lib/ReaderWriter/CoreLinkingContext.cpp b/lld/lib/ReaderWriter/CoreLinkingContext.cpp
index 0adaa017672..9fd97ed067a 100644
--- a/lld/lib/ReaderWriter/CoreLinkingContext.cpp
+++ b/lld/lib/ReaderWriter/CoreLinkingContext.cpp
@@ -184,67 +184,6 @@ private:
};
-class TestingStubsPass : public StubsPass {
-public:
- TestingStubsPass(const LinkingContext &ctx) : _file(ctx) {}
-
- bool noTextRelocs() override { return true; }
-
- bool isCallSite(const Reference &ref) override {
- if (ref.kindNamespace() != Reference::KindNamespace::testing)
- return false;
- return (ref.kindValue() == CoreLinkingContext::TEST_RELOC_CALL32);
- }
-
- const DefinedAtom *getStub(const Atom &target) override {
- const DefinedAtom *result = new TestingStubAtom(_file, target);
- _file.addAtom(*result);
- return result;
- }
-
- void addStubAtoms(MutableFile &mergedFile) override {
- for (const DefinedAtom *stub : _file.defined()) {
- mergedFile.addAtom(*stub);
- }
- }
-
-private:
- TestingPassFile _file;
-};
-
-class TestingGOTPass : public GOTPass {
-public:
- TestingGOTPass(const LinkingContext &ctx) : _file(ctx) {}
-
- bool noTextRelocs() override { return true; }
-
- bool isGOTAccess(const Reference &ref, bool &canBypassGOT) override {
- if (ref.kindNamespace() != Reference::KindNamespace::testing)
- return false;
- switch (ref.kindValue()) {
- case CoreLinkingContext::TEST_RELOC_GOT_LOAD32:
- canBypassGOT = true;
- return true;
- case CoreLinkingContext::TEST_RELOC_GOT_USE32:
- canBypassGOT = false;
- return true;
- }
- return false;
- }
-
- void updateReferenceToGOT(const Reference *ref, bool targetIsNowGOT) override {
- const_cast<Reference *>(ref)->setKindValue(
- targetIsNowGOT ? CoreLinkingContext::TEST_RELOC_PCREL32
- : CoreLinkingContext::TEST_RELOC_LEA32_WAS_GOT);
- }
-
- const DefinedAtom *makeGOTEntry(const Atom &target) override {
- return new TestingGOTAtom(_file, target);
- }
-
-private:
- TestingPassFile _file;
-};
} // anonymous namespace
@@ -259,10 +198,6 @@ void CoreLinkingContext::addPasses(PassManager &pm) {
for (StringRef name : _passNames) {
if (name.equals("layout"))
pm.add(std::unique_ptr<Pass>(new LayoutPass(registry())));
- else if (name.equals("GOT"))
- pm.add(std::unique_ptr<Pass>(new TestingGOTPass(*this)));
- else if (name.equals("stubs"))
- pm.add(std::unique_ptr<Pass>(new TestingStubsPass(*this)));
else
llvm_unreachable("bad pass name");
}
diff --git a/lld/lib/ReaderWriter/MachO/CMakeLists.txt b/lld/lib/ReaderWriter/MachO/CMakeLists.txt
index 0b9b13545e0..51a1f2077a2 100644
--- a/lld/lib/ReaderWriter/MachO/CMakeLists.txt
+++ b/lld/lib/ReaderWriter/MachO/CMakeLists.txt
@@ -1,4 +1,5 @@
add_lld_library(lldMachO
+ GOTPass.cpp
MachOLinkingContext.cpp
MachONormalizedFileBinaryReader.cpp
MachONormalizedFileBinaryWriter.cpp
@@ -6,6 +7,7 @@ add_lld_library(lldMachO
MachONormalizedFileToAtoms.cpp
MachONormalizedFileYAML.cpp
ReferenceKinds.cpp
+ StubsPass.cpp
WriterMachO.cpp
)
diff --git a/lld/lib/ReaderWriter/MachO/GOTPass.cpp b/lld/lib/ReaderWriter/MachO/GOTPass.cpp
new file mode 100644
index 00000000000..1d5c6eeeb85
--- /dev/null
+++ b/lld/lib/ReaderWriter/MachO/GOTPass.cpp
@@ -0,0 +1,108 @@
+//===- lib/ReaderWriter/MachO/GOTPass.cpp ---------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// 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
+/// which 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 method isGOTAccess() should
+/// only return true for "canBypassGOT" if this optimization is supported.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "llvm/ADT/DenseMap.h"
+
+#include "MachOPasses.h"
+
+namespace lld {
+
+static bool shouldReplaceTargetWithGOTAtom(const Atom *target,
+ bool canBypassGOT) {
+ // Accesses to shared library symbols must go through GOT.
+ if (target->definition() == Atom::definitionSharedLibrary)
+ return true;
+ // Accesses to interposable symbols in same linkage unit must also go
+ // through GOT.
+ const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target);
+ if (defTarget != nullptr &&
+ defTarget->interposable() != DefinedAtom::interposeNo) {
+ assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
+ return true;
+ }
+ // Target does not require indirection. So, if instruction allows GOT to be
+ // by-passed, do that optimization and don't create GOT entry.
+ return !canBypassGOT;
+}
+
+static const DefinedAtom *
+findGOTAtom(const Atom *target,
+ llvm::DenseMap<const Atom *, const DefinedAtom *> &targetToGOT) {
+ auto pos = targetToGOT.find(target);
+ return (pos == targetToGOT.end()) ? nullptr : pos->second;
+}
+
+void GOTPass::perform(std::unique_ptr<MutableFile> &mergedFile) {
+ // 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 (const DefinedAtom *atom : mergedFile->defined()) {
+ for (const Reference *ref : *atom) {
+ // Look at instructions accessing the GOT.
+ bool canBypassGOT;
+ if (!isGOTAccess(*ref, canBypassGOT))
+ continue;
+ const Atom *target = ref->target();
+ assert(target != nullptr);
+
+ if (!shouldReplaceTargetWithGOTAtom(target, canBypassGOT)) {
+ // Update reference kind to reflect that target is a direct accesss.
+ updateReferenceToGOT(ref, false);
+ continue;
+ }
+ // Replace the target with a reference to a GOT entry.
+ const DefinedAtom *gotEntry = findGOTAtom(target, targetToGOT);
+ if (!gotEntry) {
+ gotEntry = makeGOTEntry(*target);
+ assert(gotEntry != nullptr);
+ assert(gotEntry->contentType() == DefinedAtom::typeGOT);
+ targetToGOT[target] = gotEntry;
+ }
+ const_cast<Reference *>(ref)->setTarget(gotEntry);
+ // Update reference kind to reflect that target is now a GOT entry.
+ updateReferenceToGOT(ref, true);
+ }
+ }
+
+ // add all created GOT Atoms to master file
+ for (auto &it : targetToGOT)
+ mergedFile->addAtom(*it.second);
+}
+
+} // end namesapce lld
diff --git a/lld/lib/ReaderWriter/MachO/GOTPass.hpp b/lld/lib/ReaderWriter/MachO/GOTPass.hpp
index f66d6a76de8..a7ab2543555 100644
--- a/lld/lib/ReaderWriter/MachO/GOTPass.hpp
+++ b/lld/lib/ReaderWriter/MachO/GOTPass.hpp
@@ -16,6 +16,7 @@
#include "lld/Core/Reference.h"
#include "lld/Core/Pass.h"
+#include "MachOPasses.h"
#include "ReferenceKinds.h"
#include "StubAtoms.hpp"
diff --git a/lld/lib/ReaderWriter/MachO/MachOPasses.h b/lld/lib/ReaderWriter/MachO/MachOPasses.h
new file mode 100644
index 00000000000..d55fdf5fac8
--- /dev/null
+++ b/lld/lib/ReaderWriter/MachO/MachOPasses.h
@@ -0,0 +1,101 @@
+//===- lib/ReaderWriter/MachO/MachOPasses.h -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_MACHO_PASSES_H
+#define LLD_READER_WRITER_MACHO_PASSES_H
+
+#include "lld/Core/Atom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/Pass.h"
+#include "lld/Core/range.h"
+#include "lld/Core/Reference.h"
+
+#include <vector>
+
+namespace lld {
+class DefinedAtom;
+class MutableFile;
+
+
+/// Pass for adding stubs (PLT entries) for calls to functions
+/// outside the linkage unit. This class is subclassed by each
+/// file format Writer which implements the pure virtual methods.
+class StubsPass : public Pass {
+public:
+ StubsPass() : Pass() {}
+
+ /// Scans all Atoms looking for call-site uses of SharedLibraryAtoms
+ /// and transfroms the call-site to call a stub instead using the
+ /// helper methods below.
+ void perform(std::unique_ptr<MutableFile> &mergedFile) override;
+
+ /// If true, the pass should use stubs for references
+ /// to shared library symbols. If false, the pass
+ /// will generate relocations on the text segment which the
+ /// runtime loader will use to patch the program at runtime.
+ virtual bool noTextRelocs() = 0;
+
+ /// Returns whether the Reference kind is for a call site. The pass
+ /// uses this to find calls that need to be indirected through a stub.
+ virtual bool isCallSite(const Reference &) = 0;
+
+ /// Returns a file format specific atom for a stub/PLT entry which contains
+ /// instructions which jump to the specified atom. May be called multiple
+ /// times for the same target atom, in which case this method should return
+ /// the same stub atom.
+ virtual const DefinedAtom *getStub(const Atom &target) = 0;
+
+ /// After the default implementation of perform() is done calling getStub(),
+ /// it will call this method to add all the stub (and support) atoms to the
+ /// master file object.
+ virtual void addStubAtoms(MutableFile &masterFile) = 0;
+
+private:
+ void replaceCalleeWithStub(const Atom *target, const Reference *ref);
+};
+
+/// Pass for adding GOT entries for pointers to functions/data
+/// outside the linkage unit. This class is subclassed by each
+/// file format Writer which implements the pure virtual methods.
+class GOTPass : public Pass {
+public:
+ GOTPass() : Pass() {}
+
+ /// Scans all Atoms looking for pointer to SharedLibraryAtoms
+ /// and transfroms them to a pointer to a GOT entry using the
+ /// helper methods below.
+ void perform(std::unique_ptr<MutableFile> &mergedFile) override;
+
+ /// If true, the pass will use GOT entries for references
+ /// to shared library symbols. If false, the pass
+ /// will generate relocations on the text segment which the
+ /// runtime loader will use to patch the program at runtime.
+ virtual bool noTextRelocs() = 0;
+
+ /// Returns whether the Reference kind is a pre-instantiated GOT access.
+ /// The default implementation of perform() uses this to figure out
+ /// what GOT entries to instantiate.
+ virtual bool isGOTAccess(const Reference &, bool &canBypassGOT) = 0;
+
+ /// The file format Writer needs to alter the reference kind from a
+ /// pre-instantiated GOT access to an actual access. If targetIsNowGOT is
+ /// true, the pass has instantiated a GOT atom and altered the reference's
+ /// target to point to that atom. If targetIsNowGOT is false, the 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;
+
+ /// Returns a file format specific atom for a GOT entry targeting
+ /// the specified atom.
+ virtual const DefinedAtom *makeGOTEntry(const Atom &target) = 0;
+};
+
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_PASSES_H
diff --git a/lld/lib/ReaderWriter/MachO/StubsPass.cpp b/lld/lib/ReaderWriter/MachO/StubsPass.cpp
new file mode 100644
index 00000000000..630e00be179
--- /dev/null
+++ b/lld/lib/ReaderWriter/MachO/StubsPass.cpp
@@ -0,0 +1,67 @@
+//===- lib/ReaderWriter/MachO/StubsPass.cpp -------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// 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. Each file format defines a subclass of StubsPass which implements
+// the abstract methods for creating the file format specific StubAtoms.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Core/DefinedAtom.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "llvm/ADT/DenseMap.h"
+
+#include "MachOPasses.h"
+
+namespace lld {
+
+void StubsPass::perform(std::unique_ptr<MutableFile> &mergedFile) {
+ // Skip this pass if output format uses text relocations instead of stubs.
+ if (!this->noTextRelocs())
+ return;
+
+ // Scan all references in all atoms.
+ for (const DefinedAtom *atom : mergedFile->defined()) {
+ for (const Reference *ref : *atom) {
+ // Look at call-sites.
+ if (!this->isCallSite(*ref))
+ continue;
+ const Atom *target = ref->target();
+ assert(target != nullptr);
+ if (target->definition() == Atom::definitionSharedLibrary) {
+ // Calls to shared libraries go through stubs.
+ replaceCalleeWithStub(target, ref);
+ continue;
+ }
+ const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target);
+ if (defTarget && defTarget->interposable() != DefinedAtom::interposeNo) {
+ // Calls to interposable functions in same linkage unit must also go
+ // through a stub.
+ assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
+ replaceCalleeWithStub(target, ref);
+ }
+ }
+ }
+ // Add all created stubs and support Atoms.
+ this->addStubAtoms(*mergedFile);
+}
+
+void StubsPass::replaceCalleeWithStub(const Atom *target,
+ const Reference *ref) {
+ // Make file-format specific stub and other support atoms.
+ const DefinedAtom *stub = this->getStub(*target);
+ assert(stub != nullptr);
+ // Switch call site to reference stub atom instead.
+ const_cast<Reference *>(ref)->setTarget(stub);
+}
+
+} // end namespace lld
diff --git a/lld/lib/ReaderWriter/MachO/StubsPass.hpp b/lld/lib/ReaderWriter/MachO/StubsPass.hpp
index 8dac613f0b0..0e705896c7f 100644
--- a/lld/lib/ReaderWriter/MachO/StubsPass.hpp
+++ b/lld/lib/ReaderWriter/MachO/StubsPass.hpp
@@ -19,6 +19,7 @@
#include "lld/Core/SharedLibraryAtom.h"
#include "lld/Core/Simple.h"
+#include "MachOPasses.h"
#include "ReferenceKinds.h"
#include "StubAtoms.hpp"
OpenPOWER on IntegriCloud