1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 11:02:59 +02:00

[JITLink] Factor basic common GOT and stub creation code into its own class.

llvm-svn: 358838
This commit is contained in:
Lang Hames 2019-04-21 03:14:42 +00:00
parent 292476a361
commit 3cfa631a3b
2 changed files with 132 additions and 74 deletions

View File

@ -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 <typename BuilderImpl> 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<DefinedAtom *> 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<BuilderImpl &>(*this); }
DenseMap<StringRef, DefinedAtom *> GOTEntries;
DenseMap<StringRef, DefinedAtom *> Stubs;
};
} // end namespace jitlink
} // end namespace llvm
#endif // LLVM_LIB_EXECUTIONENGINE_JITLINK_BASICGOTANDSTUBSBUILDER_H

View File

@ -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<MachO_x86_64_GOTAndStubsBuilder> {
public:
MachOInPlaceGOTAndStubsBuilder(AtomGraph &G) : G(G) {}
MachO_x86_64_GOTAndStubsBuilder(AtomGraph &G)
: BasicGOTAndStubsBuilder<MachO_x86_64_GOTAndStubsBuilder>(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<DefinedAtom *> 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);
bool isGOTEdge(Edge &E) const {
return E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad;
}
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<const char *>(NullGOTEntryContent), 8));
GOTEntryAtom.addEdge(Pointer64, 0, Target, 0);
GOTEntryI =
GOTEntries.insert(std::make_pair(Target.getName(), &GOTEntryAtom))
.first;
}
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<const char *>(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::ProtectionFlags>(
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<const char *>(StubContent), 6));
// Re-use GOT entries for stub targets.
auto &GOTEntryAtom = getGOTEntryAtom(Target);
StubAtom.addEdge(PCRel32, 2, GOTEntryAtom, 0);
StubI = Stubs.insert(std::make_pair(Target.getName(), &StubAtom)).first;
}
assert(StubI != Stubs.end() && "Count not get stub atom");
return *StubI->second;
bool isExternalBranchEdge(Edge &E) {
return E.getKind() == Branch32 && !E.getTarget().isDefined();
}
void fixExternalBranchEdge(Edge &E) {
DefinedAtom &createStub(Atom &Target) {
auto &StubAtom = G.addAnonymousAtom(getStubsSection(), 0x0, 2);
StubAtom.setContent(
StringRef(reinterpret_cast<const char *>(StubContent), 6));
// Re-use GOT entries for stub targets.
auto &GOTEntryAtom = getGOTEntryAtom(Target);
StubAtom.addEdge(PCRel32, 2, GOTEntryAtom, 0);
return StubAtom;
}
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::ProtectionFlags>(
sys::Memory::MF_READ | sys::Memory::MF_EXEC);
StubsSection = &G.createSection("$__STUBS", StubsProt, false);
}
return *StubsSection;
}
AtomGraph &G;
DenseMap<StringRef, DefinedAtom *> GOTEntries;
DenseMap<StringRef, DefinedAtom *> 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<JITLinkContext> 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();
});
}