|  | //===-------------- MachO.cpp - JIT linker function for MachO -------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // MachO jit-link function. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/ExecutionEngine/JITLink/MachO.h" | 
|  |  | 
|  | #include "llvm/BinaryFormat/MachO.h" | 
|  | #include "llvm/ExecutionEngine/JITLink/MachO_arm64.h" | 
|  | #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h" | 
|  | #include "llvm/Support/Format.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | #define DEBUG_TYPE "jitlink" | 
|  |  | 
|  | namespace llvm { | 
|  | namespace jitlink { | 
|  |  | 
|  | Expected<std::unique_ptr<LinkGraph>> | 
|  | createLinkGraphFromMachOObject(MemoryBufferRef ObjectBuffer, | 
|  | std::shared_ptr<orc::SymbolStringPool> SSP) { | 
|  | StringRef Data = ObjectBuffer.getBuffer(); | 
|  | if (Data.size() < 4) | 
|  | return make_error<JITLinkError>("Truncated MachO buffer \"" + | 
|  | ObjectBuffer.getBufferIdentifier() + "\""); | 
|  |  | 
|  | uint32_t Magic; | 
|  | memcpy(&Magic, Data.data(), sizeof(uint32_t)); | 
|  | LLVM_DEBUG({ | 
|  | dbgs() << "jitLink_MachO: magic = " << format("0x%08" PRIx32, Magic) | 
|  | << ", identifier = \"" << ObjectBuffer.getBufferIdentifier() | 
|  | << "\"\n"; | 
|  | }); | 
|  |  | 
|  | if (Magic == MachO::MH_MAGIC || Magic == MachO::MH_CIGAM) | 
|  | return make_error<JITLinkError>("MachO 32-bit platforms not supported"); | 
|  | else if (Magic == MachO::MH_MAGIC_64 || Magic == MachO::MH_CIGAM_64) { | 
|  |  | 
|  | if (Data.size() < sizeof(MachO::mach_header_64)) | 
|  | return make_error<JITLinkError>("Truncated MachO buffer \"" + | 
|  | ObjectBuffer.getBufferIdentifier() + | 
|  | "\""); | 
|  |  | 
|  | // Read the CPU type from the header. | 
|  | uint32_t CPUType; | 
|  | memcpy(&CPUType, Data.data() + 4, sizeof(uint32_t)); | 
|  | if (Magic == MachO::MH_CIGAM_64) | 
|  | CPUType = llvm::byteswap<uint32_t>(CPUType); | 
|  |  | 
|  | LLVM_DEBUG({ | 
|  | dbgs() << "jitLink_MachO: cputype = " << format("0x%08" PRIx32, CPUType) | 
|  | << "\n"; | 
|  | }); | 
|  |  | 
|  | switch (CPUType) { | 
|  | case MachO::CPU_TYPE_ARM64: | 
|  | return createLinkGraphFromMachOObject_arm64(ObjectBuffer, std::move(SSP)); | 
|  | case MachO::CPU_TYPE_X86_64: | 
|  | return createLinkGraphFromMachOObject_x86_64(ObjectBuffer, | 
|  | std::move(SSP)); | 
|  | } | 
|  | return make_error<JITLinkError>("MachO-64 CPU type not valid"); | 
|  | } else | 
|  | return make_error<JITLinkError>("Unrecognized MachO magic value"); | 
|  | } | 
|  |  | 
|  | void link_MachO(std::unique_ptr<LinkGraph> G, | 
|  | std::unique_ptr<JITLinkContext> Ctx) { | 
|  |  | 
|  | switch (G->getTargetTriple().getArch()) { | 
|  | case Triple::aarch64: | 
|  | return link_MachO_arm64(std::move(G), std::move(Ctx)); | 
|  | case Triple::x86_64: | 
|  | return link_MachO_x86_64(std::move(G), std::move(Ctx)); | 
|  | default: | 
|  | Ctx->notifyFailed(make_error<JITLinkError>("MachO-64 CPU type not valid")); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | template <typename MachOHeaderType> | 
|  | static Expected<Block &> createLocalHeaderBlock(LinkGraph &G, Section &Sec) { | 
|  | auto &B = G.createMutableContentBlock(Sec, sizeof(MachOHeaderType), | 
|  | orc::ExecutorAddr(), 8, 0, true); | 
|  | MachOHeaderType Hdr; | 
|  | Hdr.magic = G.getPointerSize() == 4 ? MachO::MH_MAGIC : MachO::MH_MAGIC_64; | 
|  | if (auto CPUType = MachO::getCPUType(G.getTargetTriple())) | 
|  | Hdr.cputype = *CPUType; | 
|  | else | 
|  | return CPUType.takeError(); | 
|  | if (auto CPUSubType = MachO::getCPUSubType(G.getTargetTriple())) | 
|  | Hdr.cpusubtype = *CPUSubType; | 
|  | else | 
|  | return CPUSubType.takeError(); | 
|  | Hdr.filetype = MachO::MH_OBJECT; | 
|  |  | 
|  | if (G.getEndianness() != endianness::native) | 
|  | MachO::swapStruct(Hdr); | 
|  |  | 
|  | memcpy(B.getAlreadyMutableContent().data(), &Hdr, sizeof(Hdr)); | 
|  |  | 
|  | return B; | 
|  | } | 
|  |  | 
|  | Expected<Symbol &> getOrCreateLocalMachOHeader(LinkGraph &G) { | 
|  | StringRef LocalHeaderSectionName("__TEXT,__lcl_macho_hdr"); | 
|  | Section *Sec = G.findSectionByName(LocalHeaderSectionName); | 
|  | if (Sec) { | 
|  | assert(Sec->blocks_size() == 1 && "Unexpected number of blocks"); | 
|  | assert(Sec->symbols_size() == 1 && "Unexpected number of symbols"); | 
|  | auto &Sym = **Sec->symbols().begin(); | 
|  | assert(Sym.getOffset() == 0 && "Symbol not at start of header block"); | 
|  | return Sym; | 
|  | } | 
|  |  | 
|  | // Create the local header section, move all other sections up in the | 
|  | // section ordering to ensure that it's laid out first. | 
|  | for (auto &Sec : G.sections()) | 
|  | Sec.setOrdinal(Sec.getOrdinal() + 1); | 
|  |  | 
|  | Sec = &G.createSection(LocalHeaderSectionName, orc::MemProt::Read); | 
|  |  | 
|  | Sec->setOrdinal(0); | 
|  |  | 
|  | Block *B = nullptr; | 
|  | switch (G.getTargetTriple().getArch()) { | 
|  | case Triple::aarch64: | 
|  | case Triple::x86_64: | 
|  | if (auto BOrErr = createLocalHeaderBlock<MachO::mach_header_64>(G, *Sec)) | 
|  | B = &*BOrErr; | 
|  | else | 
|  | return BOrErr.takeError(); | 
|  | break; | 
|  | default: | 
|  | return make_error<JITLinkError>("Cannot create local Mach-O header for " + | 
|  | G.getName() + ": unsupported triple " + | 
|  | G.getTargetTriple().str()); | 
|  | } | 
|  |  | 
|  | return G.addAnonymousSymbol(*B, 0, B->getSize(), false, false); | 
|  | } | 
|  |  | 
|  | } // end namespace jitlink | 
|  | } // end namespace llvm |