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