136 lines · cpp
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-exception6//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 20using namespace llvm;21 22#define DEBUG_TYPE "jitlink"23 24namespace llvm {25namespace jitlink {26 27static 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 42Expected<std::unique_ptr<LinkGraph>>43createLinkGraphFromCOFFObject(MemoryBufferRef ObjectBuffer,44 std::shared_ptr<orc::SymbolStringPool> SSP) {45 StringRef Data = ObjectBuffer.getBuffer();46 47 // Check magic48 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 file81 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 } else98 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 120void 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 jitlink135} // end namespace llvm136