xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/i386.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1bdd1243dSDimitry Andric //===---- i386.cpp - Generic JITLink i386 edge kinds, utilities -----===//
2bdd1243dSDimitry Andric //
3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bdd1243dSDimitry Andric //
7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
8bdd1243dSDimitry Andric //
9bdd1243dSDimitry Andric // Generic utilities for graphs representing i386 objects.
10bdd1243dSDimitry Andric //
11bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
12bdd1243dSDimitry Andric 
13bdd1243dSDimitry Andric #include "llvm/ExecutionEngine/JITLink/i386.h"
14bdd1243dSDimitry Andric 
15bdd1243dSDimitry Andric #define DEBUG_TYPE "jitlink"
16bdd1243dSDimitry Andric 
17bdd1243dSDimitry Andric namespace llvm::jitlink::i386 {
18bdd1243dSDimitry Andric 
getEdgeKindName(Edge::Kind K)19bdd1243dSDimitry Andric const char *getEdgeKindName(Edge::Kind K) {
20bdd1243dSDimitry Andric   switch (K) {
21bdd1243dSDimitry Andric   case None:
22bdd1243dSDimitry Andric     return "None";
23bdd1243dSDimitry Andric   case Pointer32:
24bdd1243dSDimitry Andric     return "Pointer32";
25bdd1243dSDimitry Andric   case PCRel32:
26bdd1243dSDimitry Andric     return "PCRel32";
27bdd1243dSDimitry Andric   case Pointer16:
28bdd1243dSDimitry Andric     return "Pointer16";
29bdd1243dSDimitry Andric   case PCRel16:
30bdd1243dSDimitry Andric     return "PCRel16";
31bdd1243dSDimitry Andric   case Delta32:
32bdd1243dSDimitry Andric     return "Delta32";
33bdd1243dSDimitry Andric   case Delta32FromGOT:
34bdd1243dSDimitry Andric     return "Delta32FromGOT";
35bdd1243dSDimitry Andric   case RequestGOTAndTransformToDelta32FromGOT:
36bdd1243dSDimitry Andric     return "RequestGOTAndTransformToDelta32FromGOT";
37*06c3fb27SDimitry Andric   case BranchPCRel32:
38*06c3fb27SDimitry Andric     return "BranchPCRel32";
39*06c3fb27SDimitry Andric   case BranchPCRel32ToPtrJumpStub:
40*06c3fb27SDimitry Andric     return "BranchPCRel32ToPtrJumpStub";
41*06c3fb27SDimitry Andric   case BranchPCRel32ToPtrJumpStubBypassable:
42*06c3fb27SDimitry Andric     return "BranchPCRel32ToPtrJumpStubBypassable";
43bdd1243dSDimitry Andric   }
44bdd1243dSDimitry Andric 
45bdd1243dSDimitry Andric   return getGenericEdgeKindName(K);
46bdd1243dSDimitry Andric }
47bdd1243dSDimitry Andric 
48bdd1243dSDimitry Andric const char NullPointerContent[PointerSize] = {0x00, 0x00, 0x00, 0x00};
49*06c3fb27SDimitry Andric 
50*06c3fb27SDimitry Andric const char PointerJumpStubContent[6] = {
51*06c3fb27SDimitry Andric     static_cast<char>(0xFFu), 0x25, 0x00, 0x00, 0x00, 0x00};
52*06c3fb27SDimitry Andric 
optimizeGOTAndStubAccesses(LinkGraph & G)53*06c3fb27SDimitry Andric Error optimizeGOTAndStubAccesses(LinkGraph &G) {
54*06c3fb27SDimitry Andric   LLVM_DEBUG(dbgs() << "Optimizing GOT entries and stubs:\n");
55*06c3fb27SDimitry Andric 
56*06c3fb27SDimitry Andric   for (auto *B : G.blocks())
57*06c3fb27SDimitry Andric     for (auto &E : B->edges()) {
58*06c3fb27SDimitry Andric       if (E.getKind() == i386::BranchPCRel32ToPtrJumpStubBypassable) {
59*06c3fb27SDimitry Andric         auto &StubBlock = E.getTarget().getBlock();
60*06c3fb27SDimitry Andric         assert(StubBlock.getSize() == sizeof(PointerJumpStubContent) &&
61*06c3fb27SDimitry Andric                "Stub block should be stub sized");
62*06c3fb27SDimitry Andric         assert(StubBlock.edges_size() == 1 &&
63*06c3fb27SDimitry Andric                "Stub block should only have one outgoing edge");
64*06c3fb27SDimitry Andric 
65*06c3fb27SDimitry Andric         auto &GOTBlock = StubBlock.edges().begin()->getTarget().getBlock();
66*06c3fb27SDimitry Andric         assert(GOTBlock.getSize() == G.getPointerSize() &&
67*06c3fb27SDimitry Andric                "GOT block should be pointer sized");
68*06c3fb27SDimitry Andric         assert(GOTBlock.edges_size() == 1 &&
69*06c3fb27SDimitry Andric                "GOT block should only have one outgoing edge");
70*06c3fb27SDimitry Andric 
71*06c3fb27SDimitry Andric         auto &GOTTarget = GOTBlock.edges().begin()->getTarget();
72*06c3fb27SDimitry Andric         orc::ExecutorAddr EdgeAddr = B->getAddress() + E.getOffset();
73*06c3fb27SDimitry Andric         orc::ExecutorAddr TargetAddr = GOTTarget.getAddress();
74*06c3fb27SDimitry Andric 
75*06c3fb27SDimitry Andric         int64_t Displacement = TargetAddr - EdgeAddr + 4;
76*06c3fb27SDimitry Andric         if (isInt<32>(Displacement)) {
77*06c3fb27SDimitry Andric           E.setKind(i386::BranchPCRel32);
78*06c3fb27SDimitry Andric           E.setTarget(GOTTarget);
79*06c3fb27SDimitry Andric           LLVM_DEBUG({
80*06c3fb27SDimitry Andric             dbgs() << "  Replaced stub branch with direct branch:\n    ";
81*06c3fb27SDimitry Andric             printEdge(dbgs(), *B, E, getEdgeKindName(E.getKind()));
82*06c3fb27SDimitry Andric             dbgs() << "\n";
83*06c3fb27SDimitry Andric           });
84*06c3fb27SDimitry Andric         }
85*06c3fb27SDimitry Andric       }
86*06c3fb27SDimitry Andric     }
87*06c3fb27SDimitry Andric 
88*06c3fb27SDimitry Andric   return Error::success();
89*06c3fb27SDimitry Andric }
90*06c3fb27SDimitry Andric 
91bdd1243dSDimitry Andric } // namespace llvm::jitlink::i386
92