xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===----- COFF_x86_64.cpp - JIT linker implementation for COFF/x86_64 ----===//
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/x86_64 jit-link implementation.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/ExecutionEngine/JITLink/COFF_x86_64.h"
14 #include "COFFLinkGraphBuilder.h"
15 #include "JITLinkGeneric.h"
16 #include "SEHFrameSupport.h"
17 #include "llvm/BinaryFormat/COFF.h"
18 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
19 #include "llvm/Object/COFF.h"
20 #include "llvm/Support/Endian.h"
21 
22 #define DEBUG_TYPE "jitlink"
23 
24 using namespace llvm;
25 using namespace llvm::jitlink;
26 
27 namespace {
28 
29 enum EdgeKind_coff_x86_64 : Edge::Kind {
30   PCRel32 = x86_64::FirstPlatformRelocation,
31   Pointer32NB,
32   Pointer64,
33   SectionIdx16,
34   SecRel32,
35 };
36 
37 class COFFJITLinker_x86_64 : public JITLinker<COFFJITLinker_x86_64> {
38   friend class JITLinker<COFFJITLinker_x86_64>;
39 
40 public:
COFFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,std::unique_ptr<LinkGraph> G,PassConfiguration PassConfig)41   COFFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
42                        std::unique_ptr<LinkGraph> G,
43                        PassConfiguration PassConfig)
44       : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
45 
46 private:
applyFixup(LinkGraph & G,Block & B,const Edge & E) const47   Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
48     return x86_64::applyFixup(G, B, E, nullptr);
49   }
50 };
51 
52 class COFFLinkGraphBuilder_x86_64 : public COFFLinkGraphBuilder {
53 private:
addRelocations()54   Error addRelocations() override {
55     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
56 
57     for (const auto &RelSect : sections())
58       if (Error Err = COFFLinkGraphBuilder::forEachRelocation(
59               RelSect, this, &COFFLinkGraphBuilder_x86_64::addSingleRelocation))
60         return Err;
61 
62     return Error::success();
63   }
64 
addSingleRelocation(const object::RelocationRef & Rel,const object::SectionRef & FixupSect,Block & BlockToFix)65   Error addSingleRelocation(const object::RelocationRef &Rel,
66                             const object::SectionRef &FixupSect,
67                             Block &BlockToFix) {
68     const object::coff_relocation *COFFRel = getObject().getCOFFRelocation(Rel);
69     auto SymbolIt = Rel.getSymbol();
70     if (SymbolIt == getObject().symbol_end()) {
71       return make_error<StringError>(
72           formatv("Invalid symbol index in relocation entry. "
73                   "index: {0}, section: {1}",
74                   COFFRel->SymbolTableIndex, FixupSect.getIndex()),
75           inconvertibleErrorCode());
76     }
77 
78     object::COFFSymbolRef COFFSymbol = getObject().getCOFFSymbol(*SymbolIt);
79     COFFSymbolIndex SymIndex = getObject().getSymbolIndex(COFFSymbol);
80 
81     Symbol *GraphSymbol = getGraphSymbol(SymIndex);
82     if (!GraphSymbol)
83       return make_error<StringError>(
84           formatv("Could not find symbol at given index, did you add it to "
85                   "JITSymbolTable? index: {0}, section: {1}",
86                   SymIndex, FixupSect.getIndex()),
87           inconvertibleErrorCode());
88 
89     int64_t Addend = 0;
90     orc::ExecutorAddr FixupAddress =
91         orc::ExecutorAddr(FixupSect.getAddress()) + Rel.getOffset();
92     Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
93 
94     Edge::Kind Kind = Edge::Invalid;
95     const char *FixupPtr = BlockToFix.getContent().data() + Offset;
96     Symbol *ImageBase = GetImageBaseSymbol()(getGraph());
97 
98     switch (Rel.getType()) {
99     case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR32NB: {
100       if (!ImageBase)
101         ImageBase = &addImageBaseSymbol();
102       Kind = EdgeKind_coff_x86_64::Pointer32NB;
103       Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
104       break;
105     }
106     case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32: {
107       Kind = EdgeKind_coff_x86_64::PCRel32;
108       Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
109       break;
110     }
111     case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_1: {
112       Kind = EdgeKind_coff_x86_64::PCRel32;
113       Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
114       Addend -= 1;
115       break;
116     }
117     case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_2: {
118       Kind = EdgeKind_coff_x86_64::PCRel32;
119       Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
120       Addend -= 2;
121       break;
122     }
123     case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_3: {
124       Kind = EdgeKind_coff_x86_64::PCRel32;
125       Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
126       Addend -= 3;
127       break;
128     }
129     case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_4: {
130       Kind = EdgeKind_coff_x86_64::PCRel32;
131       Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
132       Addend -= 4;
133       break;
134     }
135     case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_5: {
136       Kind = EdgeKind_coff_x86_64::PCRel32;
137       Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
138       Addend -= 5;
139       break;
140     }
141     case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR64: {
142       Kind = EdgeKind_coff_x86_64::Pointer64;
143       Addend = *reinterpret_cast<const support::little64_t *>(FixupPtr);
144       break;
145     }
146     case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECTION: {
147       Kind = EdgeKind_coff_x86_64::SectionIdx16;
148       Addend = *reinterpret_cast<const support::little16_t *>(FixupPtr);
149       uint64_t SectionIdx = 0;
150       if (COFFSymbol.isAbsolute())
151         SectionIdx = getObject().getNumberOfSections() + 1;
152       else
153         SectionIdx = COFFSymbol.getSectionNumber();
154 
155       auto *AbsSym = &getGraph().addAbsoluteSymbol(
156           "secidx", orc::ExecutorAddr(SectionIdx), 2, Linkage::Strong,
157           Scope::Local, false);
158       GraphSymbol = AbsSym;
159       break;
160     }
161     case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECREL: {
162       // FIXME: SECREL to external symbol should be handled
163       if (!GraphSymbol->isDefined())
164         return Error::success();
165       Kind = EdgeKind_coff_x86_64::SecRel32;
166       Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
167       break;
168     }
169     default: {
170       return make_error<JITLinkError>("Unsupported x86_64 relocation:" +
171                                       formatv("{0:d}", Rel.getType()));
172     }
173     };
174 
175     Edge GE(Kind, Offset, *GraphSymbol, Addend);
176     LLVM_DEBUG({
177       dbgs() << "    ";
178       printEdge(dbgs(), BlockToFix, GE, getCOFFX86RelocationKindName(Kind));
179       dbgs() << "\n";
180     });
181 
182     BlockToFix.addEdge(std::move(GE));
183 
184     return Error::success();
185   }
186 
187 public:
COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile & Obj,std::shared_ptr<orc::SymbolStringPool> SSP,const Triple T,const SubtargetFeatures Features)188   COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile &Obj,
189                               std::shared_ptr<orc::SymbolStringPool> SSP,
190                               const Triple T, const SubtargetFeatures Features)
191       : COFFLinkGraphBuilder(Obj, std::move(SSP), std::move(T),
192                              std::move(Features),
193                              getCOFFX86RelocationKindName) {}
194 };
195 
196 class COFFLinkGraphLowering_x86_64 {
197 public:
198   // Lowers COFF x86_64 specific edges to generic x86_64 edges.
operator ()(LinkGraph & G)199   Error operator()(LinkGraph &G) {
200     for (auto *B : G.blocks()) {
201       for (auto &E : B->edges()) {
202         switch (E.getKind()) {
203         case EdgeKind_coff_x86_64::Pointer32NB: {
204           auto ImageBase = GetImageBase(G);
205           assert(ImageBase && "__ImageBase symbol must be defined");
206           E.setAddend(E.getAddend() - ImageBase->getAddress().getValue());
207           E.setKind(x86_64::Pointer32);
208           break;
209         }
210         case EdgeKind_coff_x86_64::PCRel32: {
211           E.setKind(x86_64::PCRel32);
212           break;
213         }
214         case EdgeKind_coff_x86_64::Pointer64: {
215           E.setKind(x86_64::Pointer64);
216           break;
217         }
218         case EdgeKind_coff_x86_64::SectionIdx16: {
219           E.setKind(x86_64::Pointer16);
220           break;
221         }
222         case EdgeKind_coff_x86_64::SecRel32: {
223           E.setAddend(E.getAddend() -
224                       getSectionStart(E.getTarget().getSection()).getValue());
225           E.setKind(x86_64::Pointer32);
226           break;
227         }
228         default:
229           break;
230         }
231       }
232     }
233     return Error::success();
234   }
235 
236 private:
getSectionStart(Section & Sec)237   orc::ExecutorAddr getSectionStart(Section &Sec) {
238     auto [It, Inserted] = SectionStartCache.try_emplace(&Sec);
239     if (Inserted) {
240       SectionRange Range(Sec);
241       It->second = Range.getStart();
242     }
243     return It->second;
244   }
245 
246   GetImageBaseSymbol GetImageBase;
247   DenseMap<Section *, orc::ExecutorAddr> SectionStartCache;
248 };
249 } // namespace
250 
251 namespace llvm {
252 namespace jitlink {
253 
254 /// Return the string name of the given COFF x86_64 edge kind.
getCOFFX86RelocationKindName(Edge::Kind R)255 const char *getCOFFX86RelocationKindName(Edge::Kind R) {
256   switch (R) {
257   case PCRel32:
258     return "PCRel32";
259   case Pointer32NB:
260     return "Pointer32NB";
261   case Pointer64:
262     return "Pointer64";
263   case SectionIdx16:
264     return "SectionIdx16";
265   case SecRel32:
266     return "SecRel32";
267   default:
268     return x86_64::getEdgeKindName(R);
269   }
270 }
271 
createLinkGraphFromCOFFObject_x86_64(MemoryBufferRef ObjectBuffer,std::shared_ptr<orc::SymbolStringPool> SSP)272 Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromCOFFObject_x86_64(
273     MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) {
274   LLVM_DEBUG({
275     dbgs() << "Building jitlink graph for new input "
276            << ObjectBuffer.getBufferIdentifier() << "...\n";
277   });
278 
279   auto COFFObj = object::ObjectFile::createCOFFObjectFile(ObjectBuffer);
280   if (!COFFObj)
281     return COFFObj.takeError();
282 
283   auto Features = (*COFFObj)->getFeatures();
284   if (!Features)
285     return Features.takeError();
286 
287   return COFFLinkGraphBuilder_x86_64(**COFFObj, std::move(SSP),
288                                      (*COFFObj)->makeTriple(),
289                                      std::move(*Features))
290       .buildGraph();
291 }
292 
link_COFF_x86_64(std::unique_ptr<LinkGraph> G,std::unique_ptr<JITLinkContext> Ctx)293 void link_COFF_x86_64(std::unique_ptr<LinkGraph> G,
294                       std::unique_ptr<JITLinkContext> Ctx) {
295   PassConfiguration Config;
296   const Triple &TT = G->getTargetTriple();
297   if (Ctx->shouldAddDefaultTargetPasses(TT)) {
298     // Add a mark-live pass.
299     if (auto MarkLive = Ctx->getMarkLivePass(TT)) {
300       Config.PrePrunePasses.push_back(std::move(MarkLive));
301       Config.PrePrunePasses.push_back(SEHFrameKeepAlivePass(".pdata"));
302     } else
303       Config.PrePrunePasses.push_back(markAllSymbolsLive);
304 
305     // Add COFF edge lowering passes.
306     Config.PreFixupPasses.push_back(COFFLinkGraphLowering_x86_64());
307   }
308 
309   if (auto Err = Ctx->modifyPassConfig(*G, Config))
310     return Ctx->notifyFailed(std::move(Err));
311 
312   COFFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
313 }
314 
315 } // namespace jitlink
316 } // namespace llvm
317