//===-------------- COFF.cpp - JIT linker function for COFF -------------===// // // 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 // //===----------------------------------------------------------------------===// // // COFF jit-link function. // //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/JITLink/COFF.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/ExecutionEngine/JITLink/COFF_x86_64.h" #include "llvm/Object/COFF.h" #include "llvm/Support/Format.h" #include "llvm/Support/MemoryBuffer.h" #include using namespace llvm; #define DEBUG_TYPE "jitlink" namespace llvm { namespace jitlink { static StringRef getMachineName(uint16_t Machine) { switch (Machine) { case COFF::IMAGE_FILE_MACHINE_I386: return "i386"; case COFF::IMAGE_FILE_MACHINE_AMD64: return "x86_64"; case COFF::IMAGE_FILE_MACHINE_ARMNT: return "ARM"; case COFF::IMAGE_FILE_MACHINE_ARM64: return "ARM64"; default: return "unknown"; } } Expected> createLinkGraphFromCOFFObject(MemoryBufferRef ObjectBuffer) { StringRef Data = ObjectBuffer.getBuffer(); // Check magic auto Magic = identify_magic(ObjectBuffer.getBuffer()); if (Magic != file_magic::coff_object) return make_error("Invalid COFF buffer"); if (Data.size() < sizeof(object::coff_file_header)) return make_error("Truncated COFF buffer"); uint64_t CurPtr = 0; bool IsPE = false; // Check if this is a PE/COFF file. if (Data.size() >= sizeof(object::dos_header) + sizeof(COFF::PEMagic)) { const auto *DH = reinterpret_cast(Data.data() + CurPtr); if (DH->Magic[0] == 'M' && DH->Magic[1] == 'Z') { // Check the PE magic bytes. ("PE\0\0") CurPtr = DH->AddressOfNewExeHeader; if (memcmp(Data.data() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != 0) { return make_error("Incorrect PE magic"); } CurPtr += sizeof(COFF::PEMagic); IsPE = true; } } if (Data.size() < CurPtr + sizeof(object::coff_file_header)) return make_error("Truncated COFF buffer"); const object::coff_file_header *COFFHeader = reinterpret_cast(Data.data() + CurPtr); const object::coff_bigobj_file_header *COFFBigObjHeader = nullptr; // Deal with bigobj file if (!IsPE && COFFHeader->Machine == COFF::IMAGE_FILE_MACHINE_UNKNOWN && COFFHeader->NumberOfSections == uint16_t(0xffff) && Data.size() >= sizeof(object::coff_bigobj_file_header)) { if (Data.size() < sizeof(object::coff_file_header)) { return make_error("Truncated COFF buffer"); } COFFBigObjHeader = reinterpret_cast(Data.data() + CurPtr); // Verify that we are dealing with bigobj. if (COFFBigObjHeader->Version >= COFF::BigObjHeader::MinBigObjectVersion && std::memcmp(COFFBigObjHeader->UUID, COFF::BigObjMagic, sizeof(COFF::BigObjMagic)) == 0) { COFFHeader = nullptr; CurPtr += sizeof(object::coff_bigobj_file_header); } else COFFBigObjHeader = nullptr; } uint16_t Machine = COFFHeader ? COFFHeader->Machine : COFFBigObjHeader->Machine; LLVM_DEBUG({ dbgs() << "jitLink_COFF: PE = " << (IsPE ? "yes" : "no") << ", bigobj = " << (COFFBigObjHeader ? "yes" : "no") << ", identifier = \"" << ObjectBuffer.getBufferIdentifier() << "\" " << "machine = " << getMachineName(Machine) << "\n"; }); switch (Machine) { case COFF::IMAGE_FILE_MACHINE_AMD64: return createLinkGraphFromCOFFObject_x86_64(ObjectBuffer); default: return make_error( "Unsupported target machine architecture in COFF object " + ObjectBuffer.getBufferIdentifier() + ": " + getMachineName(Machine)); } } void link_COFF(std::unique_ptr G, std::unique_ptr Ctx) { switch (G->getTargetTriple().getArch()) { case Triple::x86_64: link_COFF_x86_64(std::move(G), std::move(Ctx)); return; default: Ctx->notifyFailed(make_error( "Unsupported target machine architecture in COFF link graph " + G->getName())); return; } } } // end namespace jitlink } // end namespace llvm