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