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