From 0191531a76c7824c330e9de499164b5be5690634 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Sun, 21 Apr 2019 03:14:42 +0000 Subject: [PATCH] [JITLink] Factor basic common GOT and stub creation code into its own class. llvm-svn: 358838 --- .../JITLink/BasicGOTAndStubsBuilder.h | 82 ++++++++++++++ .../JITLink/JITLink_MachO_x86_64.cpp | 120 +++++++++------------ 2 files changed, 130 insertions(+), 72 deletions(-) create mode 100644 llvm/lib/ExecutionEngine/JITLink/BasicGOTAndStubsBuilder.h diff --git a/llvm/lib/ExecutionEngine/JITLink/BasicGOTAndStubsBuilder.h b/llvm/lib/ExecutionEngine/JITLink/BasicGOTAndStubsBuilder.h new file mode 100644 index 0000000..1271ad9 --- /dev/null +++ b/llvm/lib/ExecutionEngine/JITLink/BasicGOTAndStubsBuilder.h @@ -0,0 +1,82 @@ +//===--- BasicGOTAndStubsBuilder.h - Generic GOT/Stub creation --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// A base for simple GOT and stub creation. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_JITLINK_BASICGOTANDSTUBSBUILDER_H +#define LLVM_LIB_EXECUTIONENGINE_JITLINK_BASICGOTANDSTUBSBUILDER_H + +#include "llvm/ExecutionEngine/JITLink/JITLink.h" + +namespace llvm { +namespace jitlink { + +template class BasicGOTAndStubsBuilder { +public: + BasicGOTAndStubsBuilder(AtomGraph &G) : G(G) {} + + void run() { + // We're going to be adding new atoms, but we don't want to iterate over + // the newly added ones, so just copy the existing atoms out. + std::vector DAs(G.defined_atoms().begin(), + G.defined_atoms().end()); + + for (auto *DA : DAs) + for (auto &E : DA->edges()) + if (impl().isGOTEdge(E)) + impl().fixGOTEdge(E, getGOTEntryAtom(E.getTarget())); + else if (impl().isExternalBranchEdge(E)) + impl().fixExternalBranchEdge(E, getStubAtom(E.getTarget())); + } + +protected: + Atom &getGOTEntryAtom(Atom &Target) { + assert(Target.hasName() && "GOT edge cannot point to anonymous target"); + + auto GOTEntryI = GOTEntries.find(Target.getName()); + + // Build the entry if it doesn't exist. + if (GOTEntryI == GOTEntries.end()) { + auto &GOTEntry = impl().createGOTEntry(Target); + GOTEntryI = + GOTEntries.insert(std::make_pair(Target.getName(), &GOTEntry)).first; + } + + assert(GOTEntryI != GOTEntries.end() && "Could not get GOT entry atom"); + return *GOTEntryI->second; + } + + Atom &getStubAtom(Atom &Target) { + assert(Target.hasName() && + "External branch edge can not point to an anonymous target"); + auto StubI = Stubs.find(Target.getName()); + + if (StubI == Stubs.end()) { + auto &StubAtom = impl().createStub(Target); + StubI = Stubs.insert(std::make_pair(Target.getName(), &StubAtom)).first; + } + + assert(StubI != Stubs.end() && "Count not get stub atom"); + return *StubI->second; + } + + AtomGraph &G; + +private: + BuilderImpl &impl() { return static_cast(*this); } + + DenseMap GOTEntries; + DenseMap Stubs; +}; + +} // end namespace jitlink +} // end namespace llvm + +#endif // LLVM_LIB_EXECUTIONENGINE_JITLINK_BASICGOTANDSTUBSBUILDER_H diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLink_MachO_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLink_MachO_x86_64.cpp index 50bbe4b..9db129d 100644 --- a/llvm/lib/ExecutionEngine/JITLink/JITLink_MachO_x86_64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/JITLink_MachO_x86_64.cpp @@ -12,6 +12,7 @@ #include "llvm/ExecutionEngine/JITLink/JITLink_MachO_x86_64.h" +#include "BasicGOTAndStubsBuilder.h" #include "MachOAtomGraphBuilder.h" #define DEBUG_TYPE "jitlink" @@ -346,104 +347,79 @@ private: unsigned NumSymbols = 0; }; -class MachOInPlaceGOTAndStubsBuilder { +class MachO_x86_64_GOTAndStubsBuilder + : public BasicGOTAndStubsBuilder { public: - MachOInPlaceGOTAndStubsBuilder(AtomGraph &G) : G(G) {} - - void run() { - // We're going to be adding new atoms, but we don't want to iterate over - // the newly added ones, so just copy the existing atoms out. - std::vector DAs(G.defined_atoms().begin(), - G.defined_atoms().end()); - - for (auto *DA : DAs) - for (auto &E : DA->edges()) - if (E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad) - fixGOTEdge(E); - else if (E.getKind() == Branch32 && !E.getTarget().isDefined()) - fixExternalBranchEdge(E); - } + MachO_x86_64_GOTAndStubsBuilder(AtomGraph &G) + : BasicGOTAndStubsBuilder(G) {} - Atom &getGOTEntryAtom(Atom &Target) { - assert(!Target.getName().empty() && - "GOT load edge cannot point to anonymous target"); - - auto GOTEntryI = GOTEntries.find(Target.getName()); - - // Build the entry if it doesn't exist. - if (GOTEntryI == GOTEntries.end()) { - // Build a GOT section if we don't have one already. - if (!GOTSection) - GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ, false); - - auto &GOTEntryAtom = G.addAnonymousAtom(*GOTSection, 0x0, 8); - GOTEntryAtom.setContent( - StringRef(reinterpret_cast(NullGOTEntryContent), 8)); - GOTEntryAtom.addEdge(Pointer64, 0, Target, 0); - GOTEntryI = - GOTEntries.insert(std::make_pair(Target.getName(), &GOTEntryAtom)) - .first; - } + bool isGOTEdge(Edge &E) const { + return E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad; + } - assert(GOTEntryI != GOTEntries.end() && "Could not get GOT entry atom"); - return *GOTEntryI->second; + DefinedAtom &createGOTEntry(Atom &Target) { + auto &GOTEntryAtom = G.addAnonymousAtom(getGOTSection(), 0x0, 8); + GOTEntryAtom.setContent( + StringRef(reinterpret_cast(NullGOTEntryContent), 8)); + GOTEntryAtom.addEdge(Pointer64, 0, Target, 0); + return GOTEntryAtom; } - void fixGOTEdge(Edge &E) { + void fixGOTEdge(Edge &E, Atom &GOTEntry) { assert((E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad) && "Not a GOT edge?"); - auto &GOTEntryAtom = getGOTEntryAtom(E.getTarget()); E.setKind(PCRel32); - E.setTarget(GOTEntryAtom); + E.setTarget(GOTEntry); // Leave the edge addend as-is. } - Atom &getStubAtom(Atom &Target) { - assert(!Target.getName().empty() && - "Branch edge can not point to an anonymous target"); - auto StubI = Stubs.find(Target.getName()); - - if (StubI == Stubs.end()) { - // Build a Stubs section if we don't have one already. - if (!StubsSection) { - auto StubsProt = static_cast( - sys::Memory::MF_READ | sys::Memory::MF_EXEC); - StubsSection = &G.createSection("$__STUBS", StubsProt, false); - } - - auto &StubAtom = G.addAnonymousAtom(*StubsSection, 0x0, 2); - StubAtom.setContent( - StringRef(reinterpret_cast(StubContent), 6)); + bool isExternalBranchEdge(Edge &E) { + return E.getKind() == Branch32 && !E.getTarget().isDefined(); + } - // Re-use GOT entries for stub targets. - auto &GOTEntryAtom = getGOTEntryAtom(Target); - StubAtom.addEdge(PCRel32, 2, GOTEntryAtom, 0); + DefinedAtom &createStub(Atom &Target) { + auto &StubAtom = G.addAnonymousAtom(getStubsSection(), 0x0, 2); + StubAtom.setContent( + StringRef(reinterpret_cast(StubContent), 6)); - StubI = Stubs.insert(std::make_pair(Target.getName(), &StubAtom)).first; - } + // Re-use GOT entries for stub targets. + auto &GOTEntryAtom = getGOTEntryAtom(Target); + StubAtom.addEdge(PCRel32, 2, GOTEntryAtom, 0); - assert(StubI != Stubs.end() && "Count not get stub atom"); - return *StubI->second; + return StubAtom; } - void fixExternalBranchEdge(Edge &E) { + void fixExternalBranchEdge(Edge &E, Atom &Stub) { assert(E.getKind() == Branch32 && "Not a Branch32 edge?"); assert(E.getAddend() == 0 && "Branch32 edge has non-zero addend?"); - E.setTarget(getStubAtom(E.getTarget())); + E.setTarget(Stub); + } + +private: + Section &getGOTSection() { + if (!GOTSection) + GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ, false); + return *GOTSection; + } + + Section &getStubsSection() { + if (!StubsSection) { + auto StubsProt = static_cast( + sys::Memory::MF_READ | sys::Memory::MF_EXEC); + StubsSection = &G.createSection("$__STUBS", StubsProt, false); + } + return *StubsSection; } - AtomGraph &G; - DenseMap GOTEntries; - DenseMap Stubs; static const uint8_t NullGOTEntryContent[8]; static const uint8_t StubContent[6]; Section *GOTSection = nullptr; Section *StubsSection = nullptr; }; -const uint8_t MachOInPlaceGOTAndStubsBuilder::NullGOTEntryContent[8] = { +const uint8_t MachO_x86_64_GOTAndStubsBuilder::NullGOTEntryContent[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -const uint8_t MachOInPlaceGOTAndStubsBuilder::StubContent[6] = { +const uint8_t MachO_x86_64_GOTAndStubsBuilder::StubContent[6] = { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00}; } // namespace @@ -570,7 +546,7 @@ void jitLink_MachO_x86_64(std::unique_ptr Ctx) { // Add an in-place GOT/Stubs pass. Config.PostPrunePasses.push_back([](AtomGraph &G) -> Error { - MachOInPlaceGOTAndStubsBuilder(G).run(); + MachO_x86_64_GOTAndStubsBuilder(G).run(); return Error::success(); }); } -- 2.7.4