1 //===------------- JITLink.cpp - Core Run-time JIT linker APIs ------------===// 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 #include "llvm/ExecutionEngine/JITLink/JITLink.h" 11 12 #include "llvm/BinaryFormat/Magic.h" 13 #include "llvm/ExecutionEngine/JITLink/MachO.h" 14 #include "llvm/Support/Format.h" 15 #include "llvm/Support/ManagedStatic.h" 16 #include "llvm/Support/MemoryBuffer.h" 17 #include "llvm/Support/Process.h" 18 #include "llvm/Support/raw_ostream.h" 19 20 using namespace llvm; 21 using namespace llvm::object; 22 23 #define DEBUG_TYPE "jitlink" 24 25 namespace { 26 27 enum JITLinkErrorCode { GenericJITLinkError = 1 }; 28 29 // FIXME: This class is only here to support the transition to llvm::Error. It 30 // will be removed once this transition is complete. Clients should prefer to 31 // deal with the Error value directly, rather than converting to error_code. 32 class JITLinkerErrorCategory : public std::error_category { 33 public: 34 const char *name() const noexcept override { return "runtimedyld"; } 35 36 std::string message(int Condition) const override { 37 switch (static_cast<JITLinkErrorCode>(Condition)) { 38 case GenericJITLinkError: 39 return "Generic JITLink error"; 40 } 41 llvm_unreachable("Unrecognized JITLinkErrorCode"); 42 } 43 }; 44 45 static ManagedStatic<JITLinkerErrorCategory> JITLinkerErrorCategory; 46 47 } // namespace 48 49 namespace llvm { 50 namespace jitlink { 51 52 char JITLinkError::ID = 0; 53 54 void JITLinkError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; } 55 56 std::error_code JITLinkError::convertToErrorCode() const { 57 return std::error_code(GenericJITLinkError, *JITLinkerErrorCategory); 58 } 59 60 JITLinkMemoryManager::~JITLinkMemoryManager() = default; 61 62 JITLinkMemoryManager::Allocation::~Allocation() = default; 63 64 const StringRef getGenericEdgeKindName(Edge::Kind K) { 65 switch (K) { 66 case Edge::Invalid: 67 return "INVALID RELOCATION"; 68 case Edge::KeepAlive: 69 return "Keep-Alive"; 70 case Edge::LayoutNext: 71 return "Layout-Next"; 72 default: 73 llvm_unreachable("Unrecognized relocation kind"); 74 } 75 } 76 77 raw_ostream &operator<<(raw_ostream &OS, const Atom &A) { 78 OS << "<"; 79 if (A.getName().empty()) 80 OS << "anon@" << format("0x%016" PRIx64, A.getAddress()); 81 else 82 OS << A.getName(); 83 OS << " ["; 84 if (A.isDefined()) { 85 auto &DA = static_cast<const DefinedAtom &>(A); 86 OS << " section=" << DA.getSection().getName(); 87 if (DA.isLive()) 88 OS << " live"; 89 if (DA.shouldDiscard()) 90 OS << " should-discard"; 91 } else 92 OS << " external"; 93 OS << " ]>"; 94 return OS; 95 } 96 97 void printEdge(raw_ostream &OS, const Atom &FixupAtom, const Edge &E, 98 StringRef EdgeKindName) { 99 OS << "edge@" << formatv("{0:x16}", FixupAtom.getAddress() + E.getOffset()) 100 << ": " << FixupAtom << " + " << E.getOffset() << " -- " << EdgeKindName 101 << " -> " << E.getTarget() << " + " << E.getAddend(); 102 } 103 104 Section::~Section() { 105 for (auto *DA : DefinedAtoms) 106 DA->~DefinedAtom(); 107 } 108 109 void AtomGraph::dump(raw_ostream &OS, 110 std::function<StringRef(Edge::Kind)> EdgeKindToName) { 111 if (!EdgeKindToName) 112 EdgeKindToName = [](Edge::Kind K) { return StringRef(); }; 113 114 OS << "Defined atoms:\n"; 115 for (auto *DA : defined_atoms()) { 116 OS << " " << format("0x%016" PRIx64, DA->getAddress()) << ": " << *DA 117 << "\n"; 118 for (auto &E : DA->edges()) { 119 OS << " "; 120 StringRef EdgeName = (E.getKind() < Edge::FirstRelocation 121 ? getGenericEdgeKindName(E.getKind()) 122 : EdgeKindToName(E.getKind())); 123 124 if (!EdgeName.empty()) 125 printEdge(OS, *DA, E, EdgeName); 126 else { 127 auto EdgeNumberString = std::to_string(E.getKind()); 128 printEdge(OS, *DA, E, EdgeNumberString); 129 } 130 OS << "\n"; 131 } 132 } 133 134 OS << "Absolute atoms:\n"; 135 for (auto *A : absolute_atoms()) 136 OS << " " << format("0x%016" PRIx64, A->getAddress()) << ": " << *A 137 << "\n"; 138 139 OS << "External atoms:\n"; 140 for (auto *A : external_atoms()) 141 OS << " " << format("0x%016" PRIx64, A->getAddress()) << ": " << *A 142 << "\n"; 143 } 144 145 Expected<std::unique_ptr<JITLinkMemoryManager::Allocation>> 146 InProcessMemoryManager::allocate(const SegmentsRequestMap &Request) { 147 148 using AllocationMap = DenseMap<unsigned, sys::MemoryBlock>; 149 150 // Local class for allocation. 151 class IPMMAlloc : public Allocation { 152 public: 153 IPMMAlloc(AllocationMap SegBlocks) : SegBlocks(std::move(SegBlocks)) {} 154 MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg) override { 155 assert(SegBlocks.count(Seg) && "No allocation for segment"); 156 return {static_cast<char *>(SegBlocks[Seg].base()), 157 SegBlocks[Seg].size()}; 158 } 159 JITTargetAddress getTargetMemory(ProtectionFlags Seg) override { 160 assert(SegBlocks.count(Seg) && "No allocation for segment"); 161 return reinterpret_cast<JITTargetAddress>(SegBlocks[Seg].base()); 162 } 163 void finalizeAsync(FinalizeContinuation OnFinalize) override { 164 OnFinalize(applyProtections()); 165 } 166 Error deallocate() override { 167 for (auto &KV : SegBlocks) 168 if (auto EC = sys::Memory::releaseMappedMemory(KV.second)) 169 return errorCodeToError(EC); 170 return Error::success(); 171 } 172 173 private: 174 Error applyProtections() { 175 for (auto &KV : SegBlocks) { 176 auto &Prot = KV.first; 177 auto &Block = KV.second; 178 if (auto EC = sys::Memory::protectMappedMemory(Block, Prot)) 179 return errorCodeToError(EC); 180 if (Prot & sys::Memory::MF_EXEC) 181 sys::Memory::InvalidateInstructionCache(Block.base(), Block.size()); 182 } 183 return Error::success(); 184 } 185 186 AllocationMap SegBlocks; 187 }; 188 189 AllocationMap Blocks; 190 const sys::Memory::ProtectionFlags ReadWrite = 191 static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ | 192 sys::Memory::MF_WRITE); 193 194 for (auto &KV : Request) { 195 auto &Seg = KV.second; 196 197 if (Seg.getContentAlignment() > sys::Process::getPageSize()) 198 return make_error<StringError>("Cannot request higher than page " 199 "alignment", 200 inconvertibleErrorCode()); 201 202 if (sys::Process::getPageSize() % Seg.getContentAlignment() != 0) 203 return make_error<StringError>("Page size is not a multiple of " 204 "alignment", 205 inconvertibleErrorCode()); 206 207 uint64_t ZeroFillStart = 208 alignTo(Seg.getContentSize(), Seg.getZeroFillAlignment()); 209 uint64_t SegmentSize = ZeroFillStart + Seg.getZeroFillSize(); 210 211 std::error_code EC; 212 auto SegMem = 213 sys::Memory::allocateMappedMemory(SegmentSize, nullptr, ReadWrite, EC); 214 215 if (EC) 216 return errorCodeToError(EC); 217 218 // Zero out the zero-fill memory. 219 memset(static_cast<char *>(SegMem.base()) + ZeroFillStart, 0, 220 Seg.getZeroFillSize()); 221 222 // Record the block for this segment. 223 Blocks[KV.first] = std::move(SegMem); 224 } 225 return std::unique_ptr<InProcessMemoryManager::Allocation>( 226 new IPMMAlloc(std::move(Blocks))); 227 } 228 229 JITLinkContext::~JITLinkContext() {} 230 231 bool JITLinkContext::shouldAddDefaultTargetPasses(const Triple &TT) const { 232 return true; 233 } 234 235 AtomGraphPassFunction JITLinkContext::getMarkLivePass(const Triple &TT) const { 236 return AtomGraphPassFunction(); 237 } 238 239 Error JITLinkContext::modifyPassConfig(const Triple &TT, 240 PassConfiguration &Config) { 241 return Error::success(); 242 } 243 244 Error markAllAtomsLive(AtomGraph &G) { 245 for (auto *DA : G.defined_atoms()) 246 DA->setLive(true); 247 return Error::success(); 248 } 249 250 void jitLink(std::unique_ptr<JITLinkContext> Ctx) { 251 auto Magic = identify_magic(Ctx->getObjectBuffer().getBuffer()); 252 switch (Magic) { 253 case file_magic::macho_object: 254 return jitLink_MachO(std::move(Ctx)); 255 default: 256 Ctx->notifyFailed(make_error<JITLinkError>("Unsupported file format")); 257 }; 258 } 259 260 } // end namespace jitlink 261 } // end namespace llvm 262