1 //===-------------- MachO.cpp - JIT linker function for MachO -------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // MachO jit-link function. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/ExecutionEngine/JITLink/MachO.h" 14 15 #include "llvm/BinaryFormat/MachO.h" 16 #include "llvm/ExecutionEngine/JITLink/MachO_arm64.h" 17 #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h" 18 #include "llvm/Support/Format.h" 19 20 using namespace llvm; 21 22 #define DEBUG_TYPE "jitlink" 23 24 namespace llvm { 25 namespace jitlink { 26 27 Expected<std::unique_ptr<LinkGraph>> 28 createLinkGraphFromMachOObject(MemoryBufferRef ObjectBuffer, 29 std::shared_ptr<orc::SymbolStringPool> SSP) { 30 StringRef Data = ObjectBuffer.getBuffer(); 31 if (Data.size() < 4) 32 return make_error<JITLinkError>("Truncated MachO buffer \"" + 33 ObjectBuffer.getBufferIdentifier() + "\""); 34 35 uint32_t Magic; 36 memcpy(&Magic, Data.data(), sizeof(uint32_t)); 37 LLVM_DEBUG({ 38 dbgs() << "jitLink_MachO: magic = " << format("0x%08" PRIx32, Magic) 39 << ", identifier = \"" << ObjectBuffer.getBufferIdentifier() 40 << "\"\n"; 41 }); 42 43 if (Magic == MachO::MH_MAGIC || Magic == MachO::MH_CIGAM) 44 return make_error<JITLinkError>("MachO 32-bit platforms not supported"); 45 else if (Magic == MachO::MH_MAGIC_64 || Magic == MachO::MH_CIGAM_64) { 46 47 if (Data.size() < sizeof(MachO::mach_header_64)) 48 return make_error<JITLinkError>("Truncated MachO buffer \"" + 49 ObjectBuffer.getBufferIdentifier() + 50 "\""); 51 52 // Read the CPU type from the header. 53 uint32_t CPUType; 54 memcpy(&CPUType, Data.data() + 4, sizeof(uint32_t)); 55 if (Magic == MachO::MH_CIGAM_64) 56 CPUType = llvm::byteswap<uint32_t>(CPUType); 57 58 LLVM_DEBUG({ 59 dbgs() << "jitLink_MachO: cputype = " << format("0x%08" PRIx32, CPUType) 60 << "\n"; 61 }); 62 63 switch (CPUType) { 64 case MachO::CPU_TYPE_ARM64: 65 return createLinkGraphFromMachOObject_arm64(ObjectBuffer, std::move(SSP)); 66 case MachO::CPU_TYPE_X86_64: 67 return createLinkGraphFromMachOObject_x86_64(ObjectBuffer, 68 std::move(SSP)); 69 } 70 return make_error<JITLinkError>("MachO-64 CPU type not valid"); 71 } else 72 return make_error<JITLinkError>("Unrecognized MachO magic value"); 73 } 74 75 void link_MachO(std::unique_ptr<LinkGraph> G, 76 std::unique_ptr<JITLinkContext> Ctx) { 77 78 switch (G->getTargetTriple().getArch()) { 79 case Triple::aarch64: 80 return link_MachO_arm64(std::move(G), std::move(Ctx)); 81 case Triple::x86_64: 82 return link_MachO_x86_64(std::move(G), std::move(Ctx)); 83 default: 84 Ctx->notifyFailed(make_error<JITLinkError>("MachO-64 CPU type not valid")); 85 return; 86 } 87 } 88 89 template <typename MachOHeaderType> 90 static Expected<Block &> createLocalHeaderBlock(LinkGraph &G, Section &Sec) { 91 auto &B = G.createMutableContentBlock(Sec, sizeof(MachOHeaderType), 92 orc::ExecutorAddr(), 8, 0, true); 93 MachOHeaderType Hdr; 94 Hdr.magic = G.getPointerSize() == 4 ? MachO::MH_MAGIC : MachO::MH_MAGIC_64; 95 if (auto CPUType = MachO::getCPUType(G.getTargetTriple())) 96 Hdr.cputype = *CPUType; 97 else 98 return CPUType.takeError(); 99 if (auto CPUSubType = MachO::getCPUSubType(G.getTargetTriple())) 100 Hdr.cpusubtype = *CPUSubType; 101 else 102 return CPUSubType.takeError(); 103 Hdr.filetype = MachO::MH_OBJECT; 104 105 if (G.getEndianness() != endianness::native) 106 MachO::swapStruct(Hdr); 107 108 memcpy(B.getAlreadyMutableContent().data(), &Hdr, sizeof(Hdr)); 109 110 return B; 111 } 112 113 Expected<Symbol &> getOrCreateLocalMachOHeader(LinkGraph &G) { 114 StringRef LocalHeaderSectionName("__TEXT,__lcl_macho_hdr"); 115 Section *Sec = G.findSectionByName(LocalHeaderSectionName); 116 if (Sec) { 117 assert(Sec->blocks_size() == 1 && "Unexpected number of blocks"); 118 assert(Sec->symbols_size() == 1 && "Unexpected number of symbols"); 119 auto &Sym = **Sec->symbols().begin(); 120 assert(Sym.getOffset() == 0 && "Symbol not at start of header block"); 121 return Sym; 122 } 123 124 // Create the local header section, move all other sections up in the 125 // section ordering to ensure that it's laid out first. 126 for (auto &Sec : G.sections()) 127 Sec.setOrdinal(Sec.getOrdinal() + 1); 128 129 Sec = &G.createSection(LocalHeaderSectionName, orc::MemProt::Read); 130 131 Sec->setOrdinal(0); 132 133 Block *B = nullptr; 134 switch (G.getTargetTriple().getArch()) { 135 case Triple::aarch64: 136 case Triple::x86_64: 137 if (auto BOrErr = createLocalHeaderBlock<MachO::mach_header_64>(G, *Sec)) 138 B = &*BOrErr; 139 else 140 return BOrErr.takeError(); 141 break; 142 default: 143 return make_error<JITLinkError>("Cannot create local Mach-O header for " + 144 G.getName() + ": unsupported triple " + 145 G.getTargetTriple().str()); 146 } 147 148 return G.addAnonymousSymbol(*B, 0, B->getSize(), false, false); 149 } 150 151 } // end namespace jitlink 152 } // end namespace llvm 153