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