xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/COFF.cpp (revision a90b9d0159070121c221b966469c3e36d912bf82)
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