LLVM: lib/ExecutionEngine/JITLink/x86_64.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

14

15#define DEBUG_TYPE "jitlink"

16

17namespace llvm {

18namespace jitlink {

19namespace x86_64 {

20

22 switch (K) {

24 return "Pointer64";

26 return "Pointer32";

28 return "Pointer32Signed";

30 return "Pointer16";

32 return "Pointer8";

34 return "Delta64";

36 return "Delta32";

38 return "Delta16";

40 return "Delta8";

42 return "NegDelta64";

44 return "NegDelta32";

46 return "Size64";

48 return "Size32";

50 return "Delta64FromGOT";

52 return "PCRel32";

54 return "BranchPCRel32";

56 return "BranchPCRel32ToPtrJumpStub";

58 return "BranchPCRel32ToPtrJumpStubBypassable";

60 return "RequestGOTAndTransformToDelta32";

62 return "RequestGOTAndTransformToDelta64";

64 return "RequestGOTAndTransformToDelta64FromGOT";

66 return "PCRel32GOTLoadREXRelaxable";

68 return "RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable";

70 return "PCRel32GOTLoadRelaxable";

72 return "RequestGOTAndTransformToPCRel32GOTLoadRelaxable";

74 return "PCRel32TLVPLoadREXRelaxable";

76 return "RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable";

77 default:

79 }

80}

81

83 0x00, 0x00, 0x00, 0x00};

84

86 static_cast<char>(0xFFu), 0x25, 0x00, 0x00, 0x00, 0x00};

87

89 static_cast<char>(0xe8), 0x00, 0x00, 0x00, 0x00

90};

91

92void GOTTableManager::registerExistingEntries() {

93 for (auto *EntrySym : GOTSection->symbols()) {

94 assert(EntrySym->getBlock().edges_size() == 1 &&

95 "GOT block edge count != 1");

97 *EntrySym);

98 }

99}

100

102 for (auto *EntrySym : StubsSection->symbols()) {

103 assert(EntrySym->getBlock().edges_size() == 1 &&

104 "PLT block edge count != 1");

105 auto &GOTSym = EntrySym->getBlock().edges().begin()->getTarget();

106 assert(GOTSym.getBlock().edges_size() == 1 && "GOT block edge count != 1");

108 *EntrySym);

109 }

110}

111

113 LLVM_DEBUG(dbgs() << "Optimizing GOT entries and stubs:\n");

114

115 for (auto *B : G.blocks())

116 for (auto &E : B->edges()) {

119#ifndef NDEBUG

121 assert(E.getOffset() >= (REXPrefix ? 3u : 2u) &&

122 "GOT edge occurs too early in block");

123#endif

124 auto *FixupData = reinterpret_cast<uint8_t *>(

125 const_cast<char *>(B->getContent().data())) +

126 E.getOffset();

127 const uint8_t Op = FixupData[-2];

128 const uint8_t ModRM = FixupData[-1];

129

130 auto &GOTEntryBlock = E.getTarget().getBlock();

131 assert(GOTEntryBlock.getSize() == G.getPointerSize() &&

132 "GOT entry block should be pointer sized");

133 assert(GOTEntryBlock.edges_size() == 1 &&

134 "GOT entry should only have one outgoing edge");

135 auto &GOTTarget = GOTEntryBlock.edges().begin()->getTarget();

138 int64_t Displacement = TargetAddr - EdgeAddr + 4;

140 bool DisplacementInRangeForImmS32 = isInt<32>(Displacement);

141

142

143

144 if (!(TargetInRangeForImmU32 || DisplacementInRangeForImmS32))

145 continue;

146

147

148 if (Op == 0x8b && DisplacementInRangeForImmS32) {

149 FixupData[-2] = 0x8d;

151 E.setTarget(GOTTarget);

152 E.setAddend(E.getAddend() - 4);

154 dbgs() << " Replaced GOT load wih LEA:\n ";

156 dbgs() << "\n";

157 });

158 continue;

159 }

160

161

162 if (Op == 0xff && TargetInRangeForImmU32) {

163 if (ModRM == 0x15) {

164

165

166

167 FixupData[-2] = 0x67;

168 FixupData[-1] = 0xe8;

170 dbgs() << " replaced call instruction's memory operand wih imm "

171 "operand:\n ";

173 dbgs() << "\n";

174 });

175 } else {

176

177 assert(ModRM == 0x25 && "Invalid ModRm for call/jmp instructions");

178 FixupData[-2] = 0xe9;

179 FixupData[3] = 0x90;

180 E.setOffset(E.getOffset() - 1);

182 dbgs() << " replaced jmp instruction's memory operand wih imm "

183 "operand:\n ";

185 dbgs() << "\n";

186 });

187 }

189 E.setTarget(GOTTarget);

190 continue;

191 }

193 auto &StubBlock = E.getTarget().getBlock();

195 "Stub block should be stub sized");

196 assert(StubBlock.edges_size() == 1 &&

197 "Stub block should only have one outgoing edge");

198

199 auto &GOTBlock = StubBlock.edges().begin()->getTarget().getBlock();

200 assert(GOTBlock.getSize() == G.getPointerSize() &&

201 "GOT block should be pointer sized");

202 assert(GOTBlock.edges_size() == 1 &&

203 "GOT block should only have one outgoing edge");

204

205 auto &GOTTarget = GOTBlock.edges().begin()->getTarget();

208

209 int64_t Displacement = TargetAddr - EdgeAddr + 4;

212 E.setTarget(GOTTarget);

214 dbgs() << " Replaced stub branch with direct branch:\n ";

216 dbgs() << "\n";

217 });

218 }

219 }

220 }

221

223}

224

225}

226}

227}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

Lightweight error class with error context and mandatory checking.

static ErrorSuccess success()

Create a success value.

iterator_range< symbol_iterator > symbols()

Returns an iterator over the symbols defined in this section.

bool registerPreExistingEntry(Symbol &Target, Symbol &Entry)

LLVM_ABI void registerExistingEntries()

Definition x86_64.cpp:101

Represents an address in the executor process.

uint64_t getValue() const

LLVM_ABI const char * getEdgeKindName(Edge::Kind K)

Returns a string name for the given x86-64 edge.

Definition x86_64.cpp:21

constexpr uint64_t PointerSize

x86_64 pointer size.

LLVM_ABI const char NullPointerContent[PointerSize]

x86-64 null pointer content.

Definition x86_64.cpp:82

LLVM_ABI Error optimizeGOTAndStubAccesses(LinkGraph &G)

Optimize the GOT and Stub relocations if the edge target address is in range.

Definition x86_64.cpp:112

LLVM_ABI const char ReentryTrampolineContent[5]

x86-64 reentry trampoline.

Definition x86_64.cpp:88

LLVM_ABI const char PointerJumpStubContent[6]

x86-64 pointer jump stub content.

Definition x86_64.cpp:85

@ Delta64FromGOT

A 64-bit GOT delta.

@ Pointer32

A plain 32-bit pointer value relocation.

@ RequestGOTAndTransformToDelta32

A GOT entry getter/constructor, transformed to Delta32 pointing at the GOT entry for the original tar...

@ Pointer8

A plain 8-bit pointer value relocation.

@ PCRel32GOTLoadRelaxable

A PC-relative load of a GOT entry, relaxable if GOT entry target is in-range of the fixup.

@ Pointer32Signed

A signed 32-bit pointer value relocation.

@ BranchPCRel32

A 32-bit PC-relative branch.

@ RequestGOTAndTransformToDelta64

A GOT entry getter/constructor, transformed to Delta64 pointing at the GOT entry for the original tar...

@ RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable

A TLVP entry getter/constructor, transformed to Delta32ToTLVPLoadREXRelaxable.

@ RequestGOTAndTransformToDelta64FromGOT

A GOT entry offset within GOT getter/constructor, transformed to Delta64FromGOT pointing at the GOT e...

@ PCRel32TLVPLoadREXRelaxable

A PC-relative REX load of a Thread Local Variable Pointer (TLVP) entry, relaxable if the TLVP entry t...

@ PCRel32

A 32-bit PC-relative relocation.

@ PCRel32GOTLoadREXRelaxable

A PC-relative REX load of a GOT entry, relaxable if GOT entry target is in-range of the fixup.

@ Size64

A 64-bit size relocation.

@ NegDelta64

A 64-bit negative delta.

@ Pointer16

A plain 16-bit pointer value relocation.

@ RequestGOTAndTransformToPCRel32GOTLoadRelaxable

A GOT entry getter/constructor, transformed to PCRel32ToGOTLoadRelaxable pointing at the GOT entry fo...

@ Pointer64

A plain 64-bit pointer value relocation.

@ Size32

A 32-bit size relocation.

@ BranchPCRel32ToPtrJumpStub

A 32-bit PC-relative branch to a pointer jump stub.

@ RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable

A GOT entry getter/constructor, transformed to PCRel32ToGOTLoadREXRelaxable pointing at the GOT entry...

@ BranchPCRel32ToPtrJumpStubBypassable

A relaxable version of BranchPCRel32ToPtrJumpStub.

@ NegDelta32

A 32-bit negative delta.

LLVM_ABI const char * getGenericEdgeKindName(Edge::Kind K)

Returns the string name of the given generic edge kind, or "unknown" otherwise.

LLVM_ABI void printEdge(raw_ostream &OS, const Block &B, const Edge &E, StringRef EdgeKindName)

This is an optimization pass for GlobalISel generic memory operations.

constexpr bool isInt(int64_t x)

Checks if an integer fits into the given bit width.

LLVM_ABI raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

constexpr bool isUInt(uint64_t x)

Checks if an unsigned integer fits into the given bit width.

DWARFExpression::Operation Op