1//===-- llvm-rtdyld.cpp - MCJIT Testing Tool ------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This is a testing tool for use with the MC-JIT LLVM components.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/ADT/StringMap.h"
15#include "llvm/ADT/OwningPtr.h"
16#include "llvm/ExecutionEngine/RuntimeDyld.h"
17#include "llvm/Object/MachOObject.h"
18#include "llvm/Support/CommandLine.h"
19#include "llvm/Support/ManagedStatic.h"
20#include "llvm/Support/Memory.h"
21#include "llvm/Support/MemoryBuffer.h"
22#include "llvm/Support/raw_ostream.h"
23#include "llvm/Support/system_error.h"
24using namespace llvm;
25using namespace llvm::object;
26
27static cl::list<std::string>
28InputFileList(cl::Positional, cl::ZeroOrMore,
29              cl::desc("<input file>"));
30
31enum ActionType {
32  AC_Execute
33};
34
35static cl::opt<ActionType>
36Action(cl::desc("Action to perform:"),
37       cl::init(AC_Execute),
38       cl::values(clEnumValN(AC_Execute, "execute",
39                             "Load, link, and execute the inputs."),
40                  clEnumValEnd));
41
42static cl::opt<std::string>
43EntryPoint("entry",
44           cl::desc("Function to call as entry point."),
45           cl::init("_main"));
46
47/* *** */
48
49// A trivial memory manager that doesn't do anything fancy, just uses the
50// support library allocation routines directly.
51class TrivialMemoryManager : public RTDyldMemoryManager {
52public:
53  SmallVector<sys::MemoryBlock, 16> FunctionMemory;
54
55  uint8_t *startFunctionBody(const char *Name, uintptr_t &Size);
56  void endFunctionBody(const char *Name, uint8_t *FunctionStart,
57                       uint8_t *FunctionEnd);
58};
59
60uint8_t *TrivialMemoryManager::startFunctionBody(const char *Name,
61                                                 uintptr_t &Size) {
62  return (uint8_t*)sys::Memory::AllocateRWX(Size, 0, 0).base();
63}
64
65void TrivialMemoryManager::endFunctionBody(const char *Name,
66                                           uint8_t *FunctionStart,
67                                           uint8_t *FunctionEnd) {
68  uintptr_t Size = FunctionEnd - FunctionStart + 1;
69  FunctionMemory.push_back(sys::MemoryBlock(FunctionStart, Size));
70}
71
72static const char *ProgramName;
73
74static void Message(const char *Type, const Twine &Msg) {
75  errs() << ProgramName << ": " << Type << ": " << Msg << "\n";
76}
77
78static int Error(const Twine &Msg) {
79  Message("error", Msg);
80  return 1;
81}
82
83/* *** */
84
85static int executeInput() {
86  // Instantiate a dynamic linker.
87  TrivialMemoryManager *MemMgr = new TrivialMemoryManager;
88  RuntimeDyld Dyld(MemMgr);
89
90  // If we don't have any input files, read from stdin.
91  if (!InputFileList.size())
92    InputFileList.push_back("-");
93  for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) {
94    // Load the input memory buffer.
95    OwningPtr<MemoryBuffer> InputBuffer;
96    if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFileList[i],
97                                                     InputBuffer))
98      return Error("unable to read input: '" + ec.message() + "'");
99
100    // Load the object file into it.
101    if (Dyld.loadObject(InputBuffer.take())) {
102      return Error(Dyld.getErrorString());
103    }
104  }
105
106  // Resolve all the relocations we can.
107  Dyld.resolveRelocations();
108
109  // FIXME: Error out if there are unresolved relocations.
110
111  // Get the address of the entry point (_main by default).
112  void *MainAddress = Dyld.getSymbolAddress(EntryPoint);
113  if (MainAddress == 0)
114    return Error("no definition for '" + EntryPoint + "'");
115
116  // Invalidate the instruction cache for each loaded function.
117  for (unsigned i = 0, e = MemMgr->FunctionMemory.size(); i != e; ++i) {
118    sys::MemoryBlock &Data = MemMgr->FunctionMemory[i];
119    // Make sure the memory is executable.
120    std::string ErrorStr;
121    sys::Memory::InvalidateInstructionCache(Data.base(), Data.size());
122    if (!sys::Memory::setExecutable(Data, &ErrorStr))
123      return Error("unable to mark function executable: '" + ErrorStr + "'");
124  }
125
126  // Dispatch to _main().
127  errs() << "loaded '" << EntryPoint << "' at: " << (void*)MainAddress << "\n";
128
129  int (*Main)(int, const char**) =
130    (int(*)(int,const char**)) uintptr_t(MainAddress);
131  const char **Argv = new const char*[2];
132  // Use the name of the first input object module as argv[0] for the target.
133  Argv[0] = InputFileList[0].c_str();
134  Argv[1] = 0;
135  return Main(1, Argv);
136}
137
138int main(int argc, char **argv) {
139  ProgramName = argv[0];
140  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
141
142  cl::ParseCommandLineOptions(argc, argv, "llvm MC-JIT tool\n");
143
144  switch (Action) {
145  default:
146  case AC_Execute:
147    return executeInput();
148  }
149
150  return 0;
151}
152