Skip to content

Commit ec6b71d

Browse files
committed
[JITLink][ORC] Enable creation / linking of raw jitlink::LinkGraphs.
Separates link graph creation from linking. This allows raw LinkGraphs to be created and passed to a link. ObjectLinkingLayer is updated to support emission of raw LinkGraphs in addition to object buffers. Raw LinkGraphs can be created by in-memory compilers to bypass object encoding / decoding (though this prevents caching, as LinkGraphs have do not have an on-disk representation), and by utility code to add programatically generated data structures to the JIT target process.
1 parent 15ce0ab commit ec6b71d

File tree

19 files changed

+254
-158
lines changed

19 files changed

+254
-158
lines changed

llvm/include/llvm/ExecutionEngine/JITLink/ELF.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,20 @@
1919
namespace llvm {
2020
namespace jitlink {
2121

22-
/// jit-link the given ObjBuffer, which must be a ELF object file.
22+
/// Create a LinkGraph from an ELF relocatable object.
23+
///
24+
/// Note: The graph does not take ownership of the underlying buffer, nor copy
25+
/// its contents. The caller is responsible for ensuring that the object buffer
26+
/// outlives the graph.
27+
Expected<std::unique_ptr<LinkGraph>>
28+
createLinkGraphFromELFObject(MemoryBufferRef ObjectBuffer);
29+
30+
/// Link the given graph.
2331
///
2432
/// Uses conservative defaults for GOT and stub handling based on the target
2533
/// platform.
26-
void jitLink_ELF(std::unique_ptr<JITLinkContext> Ctx);
34+
void link_ELF(std::unique_ptr<LinkGraph> G,
35+
std::unique_ptr<JITLinkContext> Ctx);
2736

2837
} // end namespace jitlink
2938
} // end namespace llvm

llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,18 @@ enum ELFX86RelocationKind : Edge::Kind {
4444

4545
} // end namespace ELF_x86_64_Edges
4646

47+
/// Create a LinkGraph from an ELF/x86-64 relocatable object.
48+
///
49+
/// Note: The graph does not take ownership of the underlying buffer, nor copy
50+
/// its contents. The caller is responsible for ensuring that the object buffer
51+
/// outlives the graph.
52+
Expected<std::unique_ptr<LinkGraph>>
53+
createLinkGraphFromELFObject_x86_64(MemoryBufferRef ObjectBuffer);
54+
4755
/// jit-link the given object buffer, which must be a ELF x86-64 object file.
48-
void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx);
56+
void link_ELF_x86_64(std::unique_ptr<LinkGraph> G,
57+
std::unique_ptr<JITLinkContext> Ctx);
58+
4959
/// Return the string name of the given ELF x86-64 edge kind.
5060
StringRef getELFX86RelocationKindName(Edge::Kind R);
5161
} // end namespace jitlink

llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -786,24 +786,40 @@ class LinkGraph {
786786
Section::const_block_iterator, const Block *,
787787
getSectionConstBlocks>;
788788

789-
LinkGraph(std::string Name, unsigned PointerSize,
789+
LinkGraph(std::string Name, const Triple &TT, unsigned PointerSize,
790790
support::endianness Endianness)
791-
: Name(std::move(Name)), PointerSize(PointerSize),
791+
: Name(std::move(Name)), TT(TT), PointerSize(PointerSize),
792792
Endianness(Endianness) {}
793793

794794
/// Returns the name of this graph (usually the name of the original
795795
/// underlying MemoryBuffer).
796796
const std::string &getName() { return Name; }
797797

798+
/// Returns the target triple for this Graph.
799+
const Triple &getTargetTriple() const { return TT; }
800+
798801
/// Returns the pointer size for use in this graph.
799802
unsigned getPointerSize() const { return PointerSize; }
800803

801804
/// Returns the endianness of content in this graph.
802805
support::endianness getEndianness() const { return Endianness; }
803806

804-
/// Allocate a copy of the given String using the LinkGraph's allocator.
807+
/// Allocate a copy of the given string using the LinkGraph's allocator.
805808
/// This can be useful when renaming symbols or adding new content to the
806809
/// graph.
810+
StringRef allocateString(StringRef Source) {
811+
auto *AllocatedBuffer = Allocator.Allocate<char>(Source.size());
812+
llvm::copy(Source, AllocatedBuffer);
813+
return StringRef(AllocatedBuffer, Source.size());
814+
}
815+
816+
/// Allocate a copy of the given string using the LinkGraph's allocator.
817+
/// This can be useful when renaming symbols or adding new content to the
818+
/// graph.
819+
///
820+
/// Note: This Twine-based overload requires an extra string copy and an
821+
/// extra heap allocation for large strings. The StringRef overload should
822+
/// be preferred where possible.
807823
StringRef allocateString(Twine Source) {
808824
SmallString<256> TmpBuffer;
809825
auto SourceStr = Source.toStringRef(TmpBuffer);
@@ -1034,6 +1050,7 @@ class LinkGraph {
10341050
BumpPtrAllocator Allocator;
10351051

10361052
std::string Name;
1053+
Triple TT;
10371054
unsigned PointerSize;
10381055
support::endianness Endianness;
10391056
SectionList Sections;
@@ -1282,10 +1299,6 @@ class JITLinkContext {
12821299
/// Return the MemoryManager to be used for this link.
12831300
virtual JITLinkMemoryManager &getMemoryManager() = 0;
12841301

1285-
/// Returns a StringRef for the object buffer.
1286-
/// This method can not be called once takeObjectBuffer has been called.
1287-
virtual MemoryBufferRef getObjectBuffer() const = 0;
1288-
12891302
/// Notify this context that linking failed.
12901303
/// Called by JITLink if linking cannot be completed.
12911304
virtual void notifyFailed(Error Err) = 0;
@@ -1339,10 +1352,16 @@ class JITLinkContext {
13391352
/// conservative mark-live implementation.
13401353
Error markAllSymbolsLive(LinkGraph &G);
13411354

1342-
/// Basic JITLink implementation.
1355+
/// Create a LinkGraph from the given object buffer.
13431356
///
1344-
/// This function will use sensible defaults for GOT and Stub handling.
1345-
void jitLink(std::unique_ptr<JITLinkContext> Ctx);
1357+
/// Note: The graph does not take ownership of the underlying buffer, nor copy
1358+
/// its contents. The caller is responsible for ensuring that the object buffer
1359+
/// outlives the graph.
1360+
Expected<std::unique_ptr<LinkGraph>>
1361+
createLinkGraphFromObject(MemoryBufferRef ObjectBuffer);
1362+
1363+
/// Link the given graph.
1364+
void link(std::unique_ptr<LinkGraph> G, std::unique_ptr<JITLinkContext> Ctx);
13461365

13471366
} // end namespace jitlink
13481367
} // end namespace llvm

llvm/include/llvm/ExecutionEngine/JITLink/MachO.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,20 @@
1818
namespace llvm {
1919
namespace jitlink {
2020

21+
/// Create a LinkGraph from a MachO relocatable object.
22+
///
23+
/// Note: The graph does not take ownership of the underlying buffer, nor copy
24+
/// its contents. The caller is responsible for ensuring that the object buffer
25+
/// outlives the graph.
26+
Expected<std::unique_ptr<LinkGraph>>
27+
createLinkGraphFromMachOObject(MemoryBufferRef ObjectBuffer);
28+
2129
/// jit-link the given ObjBuffer, which must be a MachO object file.
2230
///
2331
/// Uses conservative defaults for GOT and stub handling based on the target
2432
/// platform.
25-
void jitLink_MachO(std::unique_ptr<JITLinkContext> Ctx);
33+
void link_MachO(std::unique_ptr<LinkGraph> G,
34+
std::unique_ptr<JITLinkContext> Ctx);
2635

2736
} // end namespace jitlink
2837
} // end namespace llvm

llvm/include/llvm/ExecutionEngine/JITLink/MachO_arm64.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ enum MachOARM64RelocationKind : Edge::Kind {
4040

4141
} // namespace MachO_arm64_Edges
4242

43+
/// Create a LinkGraph from a MachO/arm64 relocatable object.
44+
///
45+
/// Note: The graph does not take ownership of the underlying buffer, nor copy
46+
/// its contents. The caller is responsible for ensuring that the object buffer
47+
/// outlives the graph.
48+
Expected<std::unique_ptr<LinkGraph>>
49+
createLinkGraphFromMachOObject_arm64(MemoryBufferRef ObjectBuffer);
50+
4351
/// jit-link the given object buffer, which must be a MachO arm64 object file.
4452
///
4553
/// If PrePrunePasses is empty then a default mark-live pass will be inserted
@@ -49,7 +57,8 @@ enum MachOARM64RelocationKind : Edge::Kind {
4957
/// If PostPrunePasses is empty then a default GOT-and-stubs insertion pass will
5058
/// be inserted. If PostPrunePasses is not empty then the caller is responsible
5159
/// for including a pass to insert GOT and stub edges.
52-
void jitLink_MachO_arm64(std::unique_ptr<JITLinkContext> Ctx);
60+
void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
61+
std::unique_ptr<JITLinkContext> Ctx);
5362

5463
/// Return the string name of the given MachO arm64 edge kind.
5564
StringRef getMachOARM64RelocationKindName(Edge::Kind R);

llvm/include/llvm/ExecutionEngine/JITLink/MachO_x86_64.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,15 @@ enum MachOX86RelocationKind : Edge::Kind {
4545

4646
} // namespace MachO_x86_64_Edges
4747

48-
/// jit-link the given object buffer, which must be a MachO x86-64 object file.
48+
/// Create a LinkGraph from a MachO/x86-64 relocatable object.
49+
///
50+
/// Note: The graph does not take ownership of the underlying buffer, nor copy
51+
/// its contents. The caller is responsible for ensuring that the object buffer
52+
/// outlives the graph.
53+
Expected<std::unique_ptr<LinkGraph>>
54+
createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer);
55+
56+
/// jit-link the given LinkGraph.
4957
///
5058
/// If PrePrunePasses is empty then a default mark-live pass will be inserted
5159
/// that will mark all exported atoms live. If PrePrunePasses is not empty, the
@@ -54,7 +62,8 @@ enum MachOX86RelocationKind : Edge::Kind {
5462
/// If PostPrunePasses is empty then a default GOT-and-stubs insertion pass will
5563
/// be inserted. If PostPrunePasses is not empty then the caller is responsible
5664
/// for including a pass to insert GOT and stub edges.
57-
void jitLink_MachO_x86_64(std::unique_ptr<JITLinkContext> Ctx);
65+
void link_MachO_x86_64(std::unique_ptr<LinkGraph> G,
66+
std::unique_ptr<JITLinkContext> Ctx);
5867

5968
/// Return the string name of the given MachO x86-64 edge kind.
6069
StringRef getMachOX86RelocationKindName(Edge::Kind R);

llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ namespace llvm {
3535

3636
namespace jitlink {
3737
class EHFrameRegistrar;
38+
class LinkGraph;
3839
class Symbol;
3940
} // namespace jitlink
4041

@@ -118,10 +119,14 @@ class ObjectLinkingLayer : public ObjectLayer, private ResourceManager {
118119
return *this;
119120
}
120121

121-
/// Emit the object.
122+
/// Emit an object file.
122123
void emit(std::unique_ptr<MaterializationResponsibility> R,
123124
std::unique_ptr<MemoryBuffer> O) override;
124125

126+
/// Emit a LinkGraph.
127+
void emit(std::unique_ptr<MaterializationResponsibility> R,
128+
std::unique_ptr<jitlink::LinkGraph> G);
129+
125130
/// Instructs this ObjectLinkingLayer instance to override the symbol flags
126131
/// found in the AtomGraph with the flags supplied by the
127132
/// MaterializationResponsibility instance. This is a workaround to support

llvm/lib/ExecutionEngine/JITLink/ELF.cpp

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -50,32 +50,39 @@ Expected<uint16_t> readTargetMachineArch(StringRef Buffer) {
5050
return ELF::EM_NONE;
5151
}
5252

53-
void jitLink_ELF(std::unique_ptr<JITLinkContext> Ctx) {
54-
StringRef Buffer = Ctx->getObjectBuffer().getBuffer();
55-
if (Buffer.size() < ELF::EI_MAG3 + 1) {
56-
Ctx->notifyFailed(make_error<JITLinkError>("Truncated ELF buffer"));
57-
return;
58-
}
53+
Expected<std::unique_ptr<LinkGraph>>
54+
createLinkGraphFromELFObject(MemoryBufferRef ObjectBuffer) {
55+
StringRef Buffer = ObjectBuffer.getBuffer();
56+
if (Buffer.size() < ELF::EI_MAG3 + 1)
57+
return make_error<JITLinkError>("Truncated ELF buffer");
5958

60-
if (memcmp(Buffer.data(), ELF::ElfMagic, strlen(ELF::ElfMagic)) != 0) {
61-
Ctx->notifyFailed(make_error<JITLinkError>("ELF magic not valid"));
62-
return;
63-
}
59+
if (memcmp(Buffer.data(), ELF::ElfMagic, strlen(ELF::ElfMagic)) != 0)
60+
return make_error<JITLinkError>("ELF magic not valid");
6461

6562
Expected<uint16_t> TargetMachineArch = readTargetMachineArch(Buffer);
66-
if (!TargetMachineArch) {
67-
Ctx->notifyFailed(TargetMachineArch.takeError());
68-
return;
69-
}
63+
if (!TargetMachineArch)
64+
return TargetMachineArch.takeError();
7065

7166
switch (*TargetMachineArch) {
7267
case ELF::EM_X86_64:
73-
jitLink_ELF_x86_64(std::move(Ctx));
68+
return createLinkGraphFromELFObject_x86_64(std::move(ObjectBuffer));
69+
default:
70+
return make_error<JITLinkError>(
71+
"Unsupported target machine architecture in ELF object " +
72+
ObjectBuffer.getBufferIdentifier());
73+
}
74+
}
75+
76+
void link_ELF(std::unique_ptr<LinkGraph> G,
77+
std::unique_ptr<JITLinkContext> Ctx) {
78+
switch (G->getTargetTriple().getArch()) {
79+
case Triple::x86_64:
80+
link_ELF_x86_64(std::move(G), std::move(Ctx));
7481
return;
7582
default:
7683
Ctx->notifyFailed(make_error<JITLinkError>(
77-
"Unsupported target machine architecture in ELF object " +
78-
Ctx->getObjectBuffer().getBufferIdentifier()));
84+
"Unsupported target machine architecture in ELF link graph " +
85+
G->getName()));
7986
return;
8087
}
8188
}

llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -571,10 +571,11 @@ class ELFLinkGraphBuilder_x86_64 {
571571
}
572572

573573
public:
574-
ELFLinkGraphBuilder_x86_64(std::string filename,
574+
ELFLinkGraphBuilder_x86_64(StringRef FileName,
575575
const object::ELFFile<object::ELF64LE> &Obj)
576-
: G(std::make_unique<LinkGraph>(filename, getPointerSize(Obj),
577-
getEndianness(Obj))),
576+
: G(std::make_unique<LinkGraph>(FileName.str(),
577+
Triple("x86_64-unknown-linux"),
578+
getPointerSize(Obj), getEndianness(Obj))),
578579
Obj(Obj) {}
579580

580581
Expected<std::unique_ptr<LinkGraph>> buildGraph() {
@@ -610,27 +611,15 @@ class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> {
610611

611612
public:
612613
ELFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
614+
std::unique_ptr<LinkGraph> G,
613615
PassConfiguration PassConfig)
614-
: JITLinker(std::move(Ctx), std::move(PassConfig)) {}
616+
: JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
615617

616618
private:
617619
StringRef getEdgeKindName(Edge::Kind R) const override {
618620
return getELFX86RelocationKindName(R);
619621
}
620622

621-
Expected<std::unique_ptr<LinkGraph>>
622-
buildGraph(MemoryBufferRef ObjBuffer) override {
623-
auto ELFObj = object::ObjectFile::createELFObjectFile(ObjBuffer);
624-
if (!ELFObj)
625-
return ELFObj.takeError();
626-
627-
auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
628-
std::string fileName(ELFObj->get()->getFileName());
629-
return ELFLinkGraphBuilder_x86_64(std::move(fileName),
630-
ELFObjFile.getELFFile())
631-
.buildGraph();
632-
}
633-
634623
Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const {
635624
using namespace ELF_x86_64_Edges;
636625
using namespace llvm::support;
@@ -655,12 +644,30 @@ class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> {
655644
}
656645
};
657646

658-
void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
647+
Expected<std::unique_ptr<LinkGraph>>
648+
createLinkGraphFromELFObject_x86_64(MemoryBufferRef ObjectBuffer) {
649+
LLVM_DEBUG({
650+
dbgs() << "Building jitlink graph for new input "
651+
<< ObjectBuffer.getBufferIdentifier() << "...\n";
652+
});
653+
654+
auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
655+
if (!ELFObj)
656+
return ELFObj.takeError();
657+
658+
auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
659+
return ELFLinkGraphBuilder_x86_64((*ELFObj)->getFileName(),
660+
ELFObjFile.getELFFile())
661+
.buildGraph();
662+
}
663+
664+
void link_ELF_x86_64(std::unique_ptr<LinkGraph> G,
665+
std::unique_ptr<JITLinkContext> Ctx) {
659666
PassConfiguration Config;
660-
Triple TT("x86_64-linux");
667+
661668
// Construct a JITLinker and run the link function.
662669
// Add a mark-live pass.
663-
if (auto MarkLive = Ctx->getMarkLivePass(TT))
670+
if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
664671
Config.PrePrunePasses.push_back(std::move(MarkLive));
665672
else
666673
Config.PrePrunePasses.push_back(markAllSymbolsLive);
@@ -674,10 +681,10 @@ void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
674681
// Add GOT/Stubs optimizer pass.
675682
Config.PostAllocationPasses.push_back(optimizeELF_x86_64_GOTAndStubs);
676683

677-
if (auto Err = Ctx->modifyPassConfig(TT, Config))
684+
if (auto Err = Ctx->modifyPassConfig(G->getTargetTriple(), Config))
678685
return Ctx->notifyFailed(std::move(Err));
679686

680-
ELFJITLinker_x86_64::link(std::move(Ctx), std::move(Config));
687+
ELFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
681688
}
682689
StringRef getELFX86RelocationKindName(Edge::Kind R) {
683690
switch (R) {

0 commit comments

Comments
 (0)