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