1633ea072SLang Hames //===--------------- LLJITWithCustomObjectLinkingLayer.cpp ----------------===// 2633ea072SLang Hames // 3633ea072SLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4633ea072SLang Hames // See https://llvm.org/LICENSE.txt for license information. 5633ea072SLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6633ea072SLang Hames // 7633ea072SLang Hames //===----------------------------------------------------------------------===// 8633ea072SLang Hames // 9633ea072SLang Hames // This file shows how to switch LLJIT to use a custom object linking layer (we 10633ea072SLang Hames // use ObjectLinkingLayer, which is backed by JITLink, as an example). 11633ea072SLang Hames // 12633ea072SLang Hames //===----------------------------------------------------------------------===// 13633ea072SLang Hames 14633ea072SLang Hames #include "llvm/ADT/StringMap.h" 15633ea072SLang Hames #include "llvm/ExecutionEngine/JITLink/JITLink.h" 16633ea072SLang Hames #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" 17*4e30b20bSLang Hames #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" 18633ea072SLang Hames #include "llvm/ExecutionEngine/Orc/LLJIT.h" 19633ea072SLang Hames #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" 20633ea072SLang Hames #include "llvm/Support/InitLLVM.h" 21633ea072SLang Hames #include "llvm/Support/TargetSelect.h" 22633ea072SLang Hames #include "llvm/Support/raw_ostream.h" 23633ea072SLang Hames 24633ea072SLang Hames #include "../ExampleModules.h" 25633ea072SLang Hames 26633ea072SLang Hames using namespace llvm; 27633ea072SLang Hames using namespace llvm::orc; 28633ea072SLang Hames 29633ea072SLang Hames ExitOnError ExitOnErr; 30633ea072SLang Hames 31633ea072SLang Hames const llvm::StringRef TestMod = 32633ea072SLang Hames R"( 33633ea072SLang Hames define i32 @callee() { 34633ea072SLang Hames entry: 35633ea072SLang Hames ret i32 7 36633ea072SLang Hames } 37633ea072SLang Hames 38633ea072SLang Hames define i32 @entry() { 39633ea072SLang Hames entry: 40633ea072SLang Hames %0 = call i32 @callee() 41633ea072SLang Hames ret i32 %0 42633ea072SLang Hames } 43633ea072SLang Hames )"; 44633ea072SLang Hames 45633ea072SLang Hames class MyPlugin : public ObjectLinkingLayer::Plugin { 46633ea072SLang Hames public: 47633ea072SLang Hames // The modifyPassConfig callback gives us a chance to inspect the 48633ea072SLang Hames // MaterializationResponsibility and target triple for the object being 49633ea072SLang Hames // linked, then add any JITLink passes that we would like to run on the 50633ea072SLang Hames // link graph. A pass is just a function object that is callable as 51633ea072SLang Hames // Error(jitlink::LinkGraph&). In this case we will add two passes 52633ea072SLang Hames // defined as lambdas that call the printLinkerGraph method on our 53633ea072SLang Hames // plugin: One to run before the linker applies fixups and another to 54633ea072SLang Hames // run afterwards. 55*4e30b20bSLang Hames void modifyPassConfig(MaterializationResponsibility &MR, 56*4e30b20bSLang Hames jitlink::LinkGraph &LG, 57633ea072SLang Hames jitlink::PassConfiguration &Config) override { 58*4e30b20bSLang Hames 59*4e30b20bSLang Hames outs() << "MyPlugin -- Modifying pass config for " << LG.getName() << " (" 60*4e30b20bSLang Hames << LG.getTargetTriple().str() << "):\n"; 61*4e30b20bSLang Hames 62*4e30b20bSLang Hames // Print sections, symbol names and addresses, and any edges for the 63*4e30b20bSLang Hames // associated blocks. 64*4e30b20bSLang Hames Config.PostPrunePasses.push_back(printGraph); 65*4e30b20bSLang Hames 66*4e30b20bSLang Hames // Print graph contents before and after fixups: 67*4e30b20bSLang Hames // 68*4e30b20bSLang Hames // Config.PostPrunePasses.push_back([this](jitlink::LinkGraph &G) -> Error { 69*4e30b20bSLang Hames // printLinkGraphContent(G, "Before fixup:"); 70*4e30b20bSLang Hames // return Error::success(); 71*4e30b20bSLang Hames // }); 72*4e30b20bSLang Hames // Config.PostFixupPasses.push_back([this](jitlink::LinkGraph &G) -> Error { 73*4e30b20bSLang Hames // printLinkGraphContent(G, "After fixup:"); 74*4e30b20bSLang Hames // return Error::success(); 75*4e30b20bSLang Hames // }); 76633ea072SLang Hames } 77633ea072SLang Hames 78633ea072SLang Hames void notifyLoaded(MaterializationResponsibility &MR) override { 79*4e30b20bSLang Hames outs() << "Loading object defining " << MR.getSymbols() << "\n"; 80633ea072SLang Hames } 81633ea072SLang Hames 82633ea072SLang Hames Error notifyEmitted(MaterializationResponsibility &MR) override { 83*4e30b20bSLang Hames outs() << "Emitted object defining " << MR.getSymbols() << "\n"; 84633ea072SLang Hames return Error::success(); 85633ea072SLang Hames } 86633ea072SLang Hames 870aec49c8SLang Hames Error notifyFailed(MaterializationResponsibility &MR) override { 880aec49c8SLang Hames return Error::success(); 890aec49c8SLang Hames } 900aec49c8SLang Hames 910aec49c8SLang Hames Error notifyRemovingResources(ResourceKey K) override { 920aec49c8SLang Hames return Error::success(); 930aec49c8SLang Hames } 940aec49c8SLang Hames 950aec49c8SLang Hames void notifyTransferringResources(ResourceKey DstKey, 960aec49c8SLang Hames ResourceKey SrcKey) override {} 970aec49c8SLang Hames 98633ea072SLang Hames private: 99*4e30b20bSLang Hames static void printBlockContent(jitlink::Block &B) { 100633ea072SLang Hames constexpr JITTargetAddress LineWidth = 16; 101633ea072SLang Hames 102*4e30b20bSLang Hames if (B.isZeroFill()) { 103*4e30b20bSLang Hames outs() << " " << formatv("{0:x16}", B.getAddress()) << ": " 104*4e30b20bSLang Hames << B.getSize() << " bytes of zero-fill.\n"; 105*4e30b20bSLang Hames return; 106*4e30b20bSLang Hames } 107633ea072SLang Hames 108*4e30b20bSLang Hames JITTargetAddress InitAddr = B.getAddress() & ~(LineWidth - 1); 109*4e30b20bSLang Hames JITTargetAddress StartAddr = B.getAddress(); 110*4e30b20bSLang Hames JITTargetAddress EndAddr = B.getAddress() + B.getSize(); 111*4e30b20bSLang Hames auto *Data = reinterpret_cast<const uint8_t *>(B.getContent().data()); 112633ea072SLang Hames 113*4e30b20bSLang Hames for (JITTargetAddress CurAddr = InitAddr; CurAddr != EndAddr; ++CurAddr) { 114633ea072SLang Hames if (CurAddr % LineWidth == 0) 115*4e30b20bSLang Hames outs() << " " << formatv("{0:x16}", CurAddr) << ": "; 116633ea072SLang Hames if (CurAddr < StartAddr) 117*4e30b20bSLang Hames outs() << " "; 118633ea072SLang Hames else 119*4e30b20bSLang Hames outs() << formatv("{0:x-2}", Data[CurAddr - StartAddr]) << " "; 120633ea072SLang Hames if (CurAddr % LineWidth == LineWidth - 1) 121*4e30b20bSLang Hames outs() << "\n"; 122633ea072SLang Hames } 123633ea072SLang Hames if (EndAddr % LineWidth != 0) 124*4e30b20bSLang Hames outs() << "\n"; 125*4e30b20bSLang Hames } 126*4e30b20bSLang Hames 127*4e30b20bSLang Hames static Error printGraph(jitlink::LinkGraph &G) { 128*4e30b20bSLang Hames 129*4e30b20bSLang Hames DenseSet<jitlink::Block *> BlocksAlreadyVisited; 130*4e30b20bSLang Hames 131*4e30b20bSLang Hames outs() << "Graph \"" << G.getName() << "\"\n"; 132*4e30b20bSLang Hames // Loop over all sections... 133*4e30b20bSLang Hames for (auto &S : G.sections()) { 134*4e30b20bSLang Hames outs() << " Section " << S.getName() << ":\n"; 135*4e30b20bSLang Hames 136*4e30b20bSLang Hames // Loop over all symbols in the current section... 137*4e30b20bSLang Hames for (auto *Sym : S.symbols()) { 138*4e30b20bSLang Hames 139*4e30b20bSLang Hames // Print the symbol's address. 140*4e30b20bSLang Hames outs() << " " << formatv("{0:x16}", Sym->getAddress()) << ": "; 141*4e30b20bSLang Hames 142*4e30b20bSLang Hames // Print the symbol's name, or "<anonymous symbol>" if it doesn't have 143*4e30b20bSLang Hames // one. 144*4e30b20bSLang Hames if (Sym->hasName()) 145*4e30b20bSLang Hames outs() << Sym->getName() << "\n"; 146*4e30b20bSLang Hames else 147*4e30b20bSLang Hames outs() << "<anonymous symbol>\n"; 148*4e30b20bSLang Hames 149*4e30b20bSLang Hames // Get the content block for this symbol. 150*4e30b20bSLang Hames auto &B = Sym->getBlock(); 151*4e30b20bSLang Hames 152*4e30b20bSLang Hames if (BlocksAlreadyVisited.count(&B)) { 153*4e30b20bSLang Hames outs() << " Block " << formatv("{0:x16}", B.getAddress()) 154*4e30b20bSLang Hames << " already printed.\n"; 155*4e30b20bSLang Hames continue; 156*4e30b20bSLang Hames } else 157*4e30b20bSLang Hames outs() << " Block " << formatv("{0:x16}", B.getAddress()) 158*4e30b20bSLang Hames << ":\n"; 159*4e30b20bSLang Hames 160*4e30b20bSLang Hames outs() << " Content:\n"; 161*4e30b20bSLang Hames printBlockContent(B); 162*4e30b20bSLang Hames BlocksAlreadyVisited.insert(&B); 163*4e30b20bSLang Hames 164*4e30b20bSLang Hames if (!llvm::empty(B.edges())) { 165*4e30b20bSLang Hames outs() << " Edges:\n"; 166*4e30b20bSLang Hames for (auto &E : B.edges()) { 167*4e30b20bSLang Hames outs() << " " 168*4e30b20bSLang Hames << formatv("{0:x16}", B.getAddress() + E.getOffset()) 169*4e30b20bSLang Hames << ": kind = " << formatv("{0:d}", E.getKind()) 170*4e30b20bSLang Hames << ", addend = " << formatv("{0:x}", E.getAddend()) 171*4e30b20bSLang Hames << ", target = "; 172*4e30b20bSLang Hames jitlink::Symbol &TargetSym = E.getTarget(); 173*4e30b20bSLang Hames if (TargetSym.hasName()) 174*4e30b20bSLang Hames outs() << TargetSym.getName() << "\n"; 175*4e30b20bSLang Hames else 176*4e30b20bSLang Hames outs() << "<anonymous target>\n"; 177633ea072SLang Hames } 178633ea072SLang Hames } 179*4e30b20bSLang Hames outs() << "\n"; 180*4e30b20bSLang Hames } 181*4e30b20bSLang Hames } 182*4e30b20bSLang Hames return Error::success(); 183633ea072SLang Hames } 184633ea072SLang Hames }; 185633ea072SLang Hames 186*4e30b20bSLang Hames static cl::opt<std::string> 187*4e30b20bSLang Hames EntryPointName("entry", cl::desc("Symbol to call as main entry point"), 188*4e30b20bSLang Hames cl::init("entry")); 189*4e30b20bSLang Hames 190*4e30b20bSLang Hames static cl::list<std::string> InputObjects(cl::Positional, cl::ZeroOrMore, 191*4e30b20bSLang Hames cl::desc("input objects")); 192*4e30b20bSLang Hames 193633ea072SLang Hames int main(int argc, char *argv[]) { 194633ea072SLang Hames // Initialize LLVM. 195633ea072SLang Hames InitLLVM X(argc, argv); 196633ea072SLang Hames 197633ea072SLang Hames InitializeNativeTarget(); 198633ea072SLang Hames InitializeNativeTargetAsmPrinter(); 199633ea072SLang Hames 200633ea072SLang Hames cl::ParseCommandLineOptions(argc, argv, "LLJITWithObjectLinkingLayerPlugin"); 201633ea072SLang Hames ExitOnErr.setBanner(std::string(argv[0]) + ": "); 202633ea072SLang Hames 203633ea072SLang Hames // Detect the host and set code model to small. 204633ea072SLang Hames auto JTMB = ExitOnErr(JITTargetMachineBuilder::detectHost()); 205633ea072SLang Hames JTMB.setCodeModel(CodeModel::Small); 206633ea072SLang Hames 207633ea072SLang Hames // Create an LLJIT instance with an ObjectLinkingLayer as the base layer. 208633ea072SLang Hames // We attach our plugin in to the newly created ObjectLinkingLayer before 209633ea072SLang Hames // returning it. 210633ea072SLang Hames auto J = ExitOnErr( 211633ea072SLang Hames LLJITBuilder() 212633ea072SLang Hames .setJITTargetMachineBuilder(std::move(JTMB)) 213633ea072SLang Hames .setObjectLinkingLayerCreator( 214633ea072SLang Hames [&](ExecutionSession &ES, const Triple &TT) { 215633ea072SLang Hames // Create ObjectLinkingLayer. 216633ea072SLang Hames auto ObjLinkingLayer = std::make_unique<ObjectLinkingLayer>( 217633ea072SLang Hames ES, std::make_unique<jitlink::InProcessMemoryManager>()); 218633ea072SLang Hames // Add an instance of our plugin. 219633ea072SLang Hames ObjLinkingLayer->addPlugin(std::make_unique<MyPlugin>()); 2206edc3fe5SStefan Gränitz return ObjLinkingLayer; 221633ea072SLang Hames }) 222633ea072SLang Hames .create()); 223633ea072SLang Hames 224*4e30b20bSLang Hames if (!InputObjects.empty()) { 225633ea072SLang Hames 226*4e30b20bSLang Hames // If we have input objects then reflect process symbols so the input 227*4e30b20bSLang Hames // objects can do interesting things, like call printf. 228*4e30b20bSLang Hames J->getMainJITDylib().addGenerator( 229*4e30b20bSLang Hames ExitOnErr(DynamicLibrarySearchGenerator::GetForCurrentProcess( 230*4e30b20bSLang Hames J->getDataLayout().getGlobalPrefix()))); 231*4e30b20bSLang Hames 232*4e30b20bSLang Hames // Load the input objects. 233*4e30b20bSLang Hames for (auto InputObject : InputObjects) { 234*4e30b20bSLang Hames auto ObjBuffer = 235*4e30b20bSLang Hames ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputObject))); 236*4e30b20bSLang Hames ExitOnErr(J->addObjectFile(std::move(ObjBuffer))); 237*4e30b20bSLang Hames } 238*4e30b20bSLang Hames } else { 239*4e30b20bSLang Hames auto M = ExitOnErr(parseExampleModule(TestMod, "test-module")); 240*4e30b20bSLang Hames M.withModuleDo([](Module &MP) { 241*4e30b20bSLang Hames outs() << "No input objects specified. Using demo module:\n" 242*4e30b20bSLang Hames << MP << "\n"; 243*4e30b20bSLang Hames }); 244633ea072SLang Hames ExitOnErr(J->addIRModule(std::move(M))); 245*4e30b20bSLang Hames } 246633ea072SLang Hames 247633ea072SLang Hames // Look up the JIT'd function, cast it to a function pointer, then call it. 248*4e30b20bSLang Hames auto EntrySym = ExitOnErr(J->lookup(EntryPointName)); 249633ea072SLang Hames auto *Entry = (int (*)())EntrySym.getAddress(); 250633ea072SLang Hames 251633ea072SLang Hames int Result = Entry(); 252633ea072SLang Hames outs() << "---Result---\n" 253*4e30b20bSLang Hames << EntryPointName << "() = " << Result << "\n"; 254633ea072SLang Hames 255633ea072SLang Hames return 0; 256633ea072SLang Hames } 257