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