1*753f127fSDimitry Andric //===-------------- COFF.cpp - JIT linker function for COFF -------------===// 2*753f127fSDimitry Andric // 3*753f127fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*753f127fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*753f127fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*753f127fSDimitry Andric // 7*753f127fSDimitry Andric //===----------------------------------------------------------------------===// 8*753f127fSDimitry Andric // 9*753f127fSDimitry Andric // COFF jit-link function. 10*753f127fSDimitry Andric // 11*753f127fSDimitry Andric //===----------------------------------------------------------------------===// 12*753f127fSDimitry Andric 13*753f127fSDimitry Andric #include "llvm/ExecutionEngine/JITLink/COFF.h" 14*753f127fSDimitry Andric 15*753f127fSDimitry Andric #include "llvm/BinaryFormat/COFF.h" 16*753f127fSDimitry Andric #include "llvm/ExecutionEngine/JITLink/COFF_x86_64.h" 17*753f127fSDimitry Andric #include "llvm/Object/COFF.h" 18*753f127fSDimitry Andric #include "llvm/Support/Format.h" 19*753f127fSDimitry Andric #include "llvm/Support/MemoryBuffer.h" 20*753f127fSDimitry Andric #include <cstring> 21*753f127fSDimitry Andric 22*753f127fSDimitry Andric using namespace llvm; 23*753f127fSDimitry Andric 24*753f127fSDimitry Andric #define DEBUG_TYPE "jitlink" 25*753f127fSDimitry Andric 26*753f127fSDimitry Andric namespace llvm { 27*753f127fSDimitry Andric namespace jitlink { 28*753f127fSDimitry Andric 29*753f127fSDimitry Andric static StringRef getMachineName(uint16_t Machine) { 30*753f127fSDimitry Andric switch (Machine) { 31*753f127fSDimitry Andric case COFF::IMAGE_FILE_MACHINE_I386: 32*753f127fSDimitry Andric return "i386"; 33*753f127fSDimitry Andric case COFF::IMAGE_FILE_MACHINE_AMD64: 34*753f127fSDimitry Andric return "x86_64"; 35*753f127fSDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARMNT: 36*753f127fSDimitry Andric return "ARM"; 37*753f127fSDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64: 38*753f127fSDimitry Andric return "ARM64"; 39*753f127fSDimitry Andric default: 40*753f127fSDimitry Andric return "unknown"; 41*753f127fSDimitry Andric } 42*753f127fSDimitry Andric } 43*753f127fSDimitry Andric 44*753f127fSDimitry Andric Expected<std::unique_ptr<LinkGraph>> 45*753f127fSDimitry Andric createLinkGraphFromCOFFObject(MemoryBufferRef ObjectBuffer) { 46*753f127fSDimitry Andric StringRef Data = ObjectBuffer.getBuffer(); 47*753f127fSDimitry Andric 48*753f127fSDimitry Andric // Check magic 49*753f127fSDimitry Andric auto Magic = identify_magic(ObjectBuffer.getBuffer()); 50*753f127fSDimitry Andric if (Magic != file_magic::coff_object) 51*753f127fSDimitry Andric return make_error<JITLinkError>("Invalid COFF buffer"); 52*753f127fSDimitry Andric 53*753f127fSDimitry Andric if (Data.size() < sizeof(object::coff_file_header)) 54*753f127fSDimitry Andric return make_error<JITLinkError>("Truncated COFF buffer"); 55*753f127fSDimitry Andric 56*753f127fSDimitry Andric uint64_t CurPtr = 0; 57*753f127fSDimitry Andric bool IsPE = false; 58*753f127fSDimitry Andric 59*753f127fSDimitry Andric // Check if this is a PE/COFF file. 60*753f127fSDimitry Andric if (Data.size() >= sizeof(object::dos_header) + sizeof(COFF::PEMagic)) { 61*753f127fSDimitry Andric const auto *DH = 62*753f127fSDimitry Andric reinterpret_cast<const object::dos_header *>(Data.data() + CurPtr); 63*753f127fSDimitry Andric if (DH->Magic[0] == 'M' && DH->Magic[1] == 'Z') { 64*753f127fSDimitry Andric // Check the PE magic bytes. ("PE\0\0") 65*753f127fSDimitry Andric CurPtr = DH->AddressOfNewExeHeader; 66*753f127fSDimitry Andric if (memcmp(Data.data() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != 67*753f127fSDimitry Andric 0) { 68*753f127fSDimitry Andric return make_error<JITLinkError>("Incorrect PE magic"); 69*753f127fSDimitry Andric } 70*753f127fSDimitry Andric CurPtr += sizeof(COFF::PEMagic); 71*753f127fSDimitry Andric IsPE = true; 72*753f127fSDimitry Andric } 73*753f127fSDimitry Andric } 74*753f127fSDimitry Andric if (Data.size() < CurPtr + sizeof(object::coff_file_header)) 75*753f127fSDimitry Andric return make_error<JITLinkError>("Truncated COFF buffer"); 76*753f127fSDimitry Andric 77*753f127fSDimitry Andric const object::coff_file_header *COFFHeader = 78*753f127fSDimitry Andric reinterpret_cast<const object::coff_file_header *>(Data.data() + CurPtr); 79*753f127fSDimitry Andric const object::coff_bigobj_file_header *COFFBigObjHeader = nullptr; 80*753f127fSDimitry Andric 81*753f127fSDimitry Andric // Deal with bigobj file 82*753f127fSDimitry Andric if (!IsPE && COFFHeader->Machine == COFF::IMAGE_FILE_MACHINE_UNKNOWN && 83*753f127fSDimitry Andric COFFHeader->NumberOfSections == uint16_t(0xffff) && 84*753f127fSDimitry Andric Data.size() >= sizeof(object::coff_bigobj_file_header)) { 85*753f127fSDimitry Andric if (Data.size() < sizeof(object::coff_file_header)) { 86*753f127fSDimitry Andric return make_error<JITLinkError>("Truncated COFF buffer"); 87*753f127fSDimitry Andric } 88*753f127fSDimitry Andric COFFBigObjHeader = 89*753f127fSDimitry Andric reinterpret_cast<const object::coff_bigobj_file_header *>(Data.data() + 90*753f127fSDimitry Andric CurPtr); 91*753f127fSDimitry Andric 92*753f127fSDimitry Andric // Verify that we are dealing with bigobj. 93*753f127fSDimitry Andric if (COFFBigObjHeader->Version >= COFF::BigObjHeader::MinBigObjectVersion && 94*753f127fSDimitry Andric std::memcmp(COFFBigObjHeader->UUID, COFF::BigObjMagic, 95*753f127fSDimitry Andric sizeof(COFF::BigObjMagic)) == 0) { 96*753f127fSDimitry Andric COFFHeader = nullptr; 97*753f127fSDimitry Andric CurPtr += sizeof(object::coff_bigobj_file_header); 98*753f127fSDimitry Andric } else 99*753f127fSDimitry Andric COFFBigObjHeader = nullptr; 100*753f127fSDimitry Andric } 101*753f127fSDimitry Andric 102*753f127fSDimitry Andric uint16_t Machine = 103*753f127fSDimitry Andric COFFHeader ? COFFHeader->Machine : COFFBigObjHeader->Machine; 104*753f127fSDimitry Andric LLVM_DEBUG({ 105*753f127fSDimitry Andric dbgs() << "jitLink_COFF: PE = " << (IsPE ? "yes" : "no") 106*753f127fSDimitry Andric << ", bigobj = " << (COFFBigObjHeader ? "yes" : "no") 107*753f127fSDimitry Andric << ", identifier = \"" << ObjectBuffer.getBufferIdentifier() << "\" " 108*753f127fSDimitry Andric << "machine = " << getMachineName(Machine) << "\n"; 109*753f127fSDimitry Andric }); 110*753f127fSDimitry Andric 111*753f127fSDimitry Andric switch (Machine) { 112*753f127fSDimitry Andric case COFF::IMAGE_FILE_MACHINE_AMD64: 113*753f127fSDimitry Andric return createLinkGraphFromCOFFObject_x86_64(ObjectBuffer); 114*753f127fSDimitry Andric default: 115*753f127fSDimitry Andric return make_error<JITLinkError>( 116*753f127fSDimitry Andric "Unsupported target machine architecture in COFF object " + 117*753f127fSDimitry Andric ObjectBuffer.getBufferIdentifier() + ": " + getMachineName(Machine)); 118*753f127fSDimitry Andric } 119*753f127fSDimitry Andric } 120*753f127fSDimitry Andric 121*753f127fSDimitry Andric void link_COFF(std::unique_ptr<LinkGraph> G, 122*753f127fSDimitry Andric std::unique_ptr<JITLinkContext> Ctx) { 123*753f127fSDimitry Andric switch (G->getTargetTriple().getArch()) { 124*753f127fSDimitry Andric case Triple::x86_64: 125*753f127fSDimitry Andric link_COFF_x86_64(std::move(G), std::move(Ctx)); 126*753f127fSDimitry Andric return; 127*753f127fSDimitry Andric default: 128*753f127fSDimitry Andric Ctx->notifyFailed(make_error<JITLinkError>( 129*753f127fSDimitry Andric "Unsupported target machine architecture in COFF link graph " + 130*753f127fSDimitry Andric G->getName())); 131*753f127fSDimitry Andric return; 132*753f127fSDimitry Andric } 133*753f127fSDimitry Andric } 134*753f127fSDimitry Andric 135*753f127fSDimitry Andric } // end namespace jitlink 136*753f127fSDimitry Andric } // end namespace llvm 137