1 //===--------- ELF_x86.cpp - JIT linker implementation for ELF/x86 --------===//
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 // ELF/x86 jit-link implementation.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "llvm/ExecutionEngine/JITLink/ELF_x86.h"
14 #include "DefineExternalSectionStartAndEndSymbols.h"
15 #include "ELFLinkGraphBuilder.h"
16 #include "JITLinkGeneric.h"
17 #include "llvm/BinaryFormat/ELF.h"
18 #include "llvm/ExecutionEngine/JITLink/x86.h"
19 #include "llvm/Object/ELFObjectFile.h"
20
21 #define DEBUG_TYPE "jitlink"
22
23 using namespace llvm;
24 using namespace llvm::jitlink;
25
26 namespace {
27 constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_";
28
buildTables_ELF_x86(LinkGraph & G)29 Error buildTables_ELF_x86(LinkGraph &G) {
30 LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
31
32 x86::GOTTableManager GOT;
33 x86::PLTTableManager PLT(GOT);
34 visitExistingEdges(G, GOT, PLT);
35 return Error::success();
36 }
37 } // namespace
38
39 namespace llvm::jitlink {
40
41 class ELFJITLinker_x86 : public JITLinker<ELFJITLinker_x86> {
42 friend class JITLinker<ELFJITLinker_x86>;
43
44 public:
ELFJITLinker_x86(std::unique_ptr<JITLinkContext> Ctx,std::unique_ptr<LinkGraph> G,PassConfiguration PassConfig)45 ELFJITLinker_x86(std::unique_ptr<JITLinkContext> Ctx,
46 std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)
47 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {
48 getPassConfig().PostAllocationPasses.push_back(
49 [this](LinkGraph &G) { return getOrCreateGOTSymbol(G); });
50 }
51
52 private:
53 Symbol *GOTSymbol = nullptr;
54
getOrCreateGOTSymbol(LinkGraph & G)55 Error getOrCreateGOTSymbol(LinkGraph &G) {
56 auto DefineExternalGOTSymbolIfPresent =
57 createDefineExternalSectionStartAndEndSymbolsPass(
58 [&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc {
59 if (Sym.getName() != nullptr &&
60 *Sym.getName() == ELFGOTSymbolName)
61 if (auto *GOTSection = G.findSectionByName(
62 x86::GOTTableManager::getSectionName())) {
63 GOTSymbol = &Sym;
64 return {*GOTSection, true};
65 }
66 return {};
67 });
68
69 // Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an
70 // external.
71 if (auto Err = DefineExternalGOTSymbolIfPresent(G))
72 return Err;
73
74 // If we succeeded then we're done.
75 if (GOTSymbol)
76 return Error::success();
77
78 // Otherwise look for a GOT section: If it already has a start symbol we'll
79 // record it, otherwise we'll create our own.
80 // If there's a GOT section but we didn't find an external GOT symbol...
81 if (auto *GOTSection =
82 G.findSectionByName(x86::GOTTableManager::getSectionName())) {
83
84 // Check for an existing defined symbol.
85 for (auto *Sym : GOTSection->symbols())
86 if (Sym->getName() != nullptr && *Sym->getName() == ELFGOTSymbolName) {
87 GOTSymbol = Sym;
88 return Error::success();
89 }
90
91 // If there's no defined symbol then create one.
92 SectionRange SR(*GOTSection);
93
94 if (SR.empty()) {
95 GOTSymbol =
96 &G.addAbsoluteSymbol(ELFGOTSymbolName, orc::ExecutorAddr(), 0,
97 Linkage::Strong, Scope::Local, true);
98 } else {
99 GOTSymbol =
100 &G.addDefinedSymbol(*SR.getFirstBlock(), 0, ELFGOTSymbolName, 0,
101 Linkage::Strong, Scope::Local, false, true);
102 }
103 }
104
105 return Error::success();
106 }
107
applyFixup(LinkGraph & G,Block & B,const Edge & E) const108 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
109 return x86::applyFixup(G, B, E, GOTSymbol);
110 }
111 };
112
113 class ELFLinkGraphBuilder_x86 : public ELFLinkGraphBuilder<object::ELF32LE> {
114 private:
115 using ELFT = object::ELF32LE;
116
getRelocationKind(const uint32_t Type)117 Expected<x86::EdgeKind_x86> getRelocationKind(const uint32_t Type) {
118 switch (Type) {
119 case ELF::R_386_32:
120 return x86::Pointer32;
121 case ELF::R_386_PC32:
122 return x86::PCRel32;
123 case ELF::R_386_16:
124 return x86::Pointer16;
125 case ELF::R_386_PC16:
126 return x86::PCRel16;
127 case ELF::R_386_GOT32:
128 return x86::RequestGOTAndTransformToDelta32FromGOT;
129 case ELF::R_386_GOT32X:
130 // TODO: Add a relaxable edge kind and update relaxation optimization.
131 return x86::RequestGOTAndTransformToDelta32FromGOT;
132 case ELF::R_386_GOTPC:
133 return x86::Delta32;
134 case ELF::R_386_GOTOFF:
135 return x86::Delta32FromGOT;
136 case ELF::R_386_PLT32:
137 return x86::BranchPCRel32;
138 }
139
140 return make_error<JITLinkError>(
141 "In " + G->getName() + ": Unsupported x86 relocation type " +
142 object::getELFRelocationTypeName(ELF::EM_386, Type));
143 }
144
addRelocations()145 Error addRelocations() override {
146 LLVM_DEBUG(dbgs() << "Adding relocations\n");
147 using Base = ELFLinkGraphBuilder<ELFT>;
148 using Self = ELFLinkGraphBuilder_x86;
149
150 for (const auto &RelSect : Base::Sections) {
151 // Validate the section to read relocation entries from.
152 if (RelSect.sh_type == ELF::SHT_RELA)
153 return make_error<StringError>(
154 "No SHT_RELA in valid x86 ELF object files",
155 inconvertibleErrorCode());
156
157 if (Error Err = Base::forEachRelRelocation(RelSect, this,
158 &Self::addSingleRelocation))
159 return Err;
160 }
161
162 return Error::success();
163 }
164
addSingleRelocation(const typename ELFT::Rel & Rel,const typename ELFT::Shdr & FixupSection,Block & BlockToFix)165 Error addSingleRelocation(const typename ELFT::Rel &Rel,
166 const typename ELFT::Shdr &FixupSection,
167 Block &BlockToFix) {
168 using Base = ELFLinkGraphBuilder<ELFT>;
169
170 auto ELFReloc = Rel.getType(false);
171
172 // R_386_NONE is a no-op.
173 if (LLVM_UNLIKELY(ELFReloc == ELF::R_386_NONE))
174 return Error::success();
175
176 uint32_t SymbolIndex = Rel.getSymbol(false);
177 auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
178 if (!ObjSymbol)
179 return ObjSymbol.takeError();
180
181 Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
182 if (!GraphSymbol)
183 return make_error<StringError>(
184 formatv("Could not find symbol at given index, did you add it to "
185 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
186 SymbolIndex, (*ObjSymbol)->st_shndx,
187 Base::GraphSymbols.size()),
188 inconvertibleErrorCode());
189
190 Expected<x86::EdgeKind_x86> Kind = getRelocationKind(ELFReloc);
191 if (!Kind)
192 return Kind.takeError();
193
194 auto FixupAddress = orc::ExecutorAddr(FixupSection.sh_addr) + Rel.r_offset;
195 int64_t Addend = 0;
196
197 switch (*Kind) {
198 case x86::Pointer32:
199 case x86::PCRel32:
200 case x86::RequestGOTAndTransformToDelta32FromGOT:
201 case x86::Delta32:
202 case x86::Delta32FromGOT:
203 case x86::BranchPCRel32:
204 case x86::BranchPCRel32ToPtrJumpStub:
205 case x86::BranchPCRel32ToPtrJumpStubBypassable: {
206 const char *FixupContent = BlockToFix.getContent().data() +
207 (FixupAddress - BlockToFix.getAddress());
208 Addend = *(const support::little32_t *)FixupContent;
209 break;
210 }
211 case x86::Pointer16:
212 case x86::PCRel16: {
213 const char *FixupContent = BlockToFix.getContent().data() +
214 (FixupAddress - BlockToFix.getAddress());
215 Addend = *(const support::little16_t *)FixupContent;
216 break;
217 }
218 }
219
220 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
221 Edge GE(*Kind, Offset, *GraphSymbol, Addend);
222 LLVM_DEBUG({
223 dbgs() << " ";
224 printEdge(dbgs(), BlockToFix, GE, x86::getEdgeKindName(*Kind));
225 dbgs() << "\n";
226 });
227
228 BlockToFix.addEdge(std::move(GE));
229 return Error::success();
230 }
231
232 public:
ELFLinkGraphBuilder_x86(StringRef FileName,const object::ELFFile<ELFT> & Obj,std::shared_ptr<orc::SymbolStringPool> SSP,Triple TT,SubtargetFeatures Features)233 ELFLinkGraphBuilder_x86(StringRef FileName, const object::ELFFile<ELFT> &Obj,
234 std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,
235 SubtargetFeatures Features)
236 : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT),
237 std::move(Features), FileName,
238 x86::getEdgeKindName) {}
239 };
240
241 Expected<std::unique_ptr<LinkGraph>>
createLinkGraphFromELFObject_x86(MemoryBufferRef ObjectBuffer,std::shared_ptr<orc::SymbolStringPool> SSP)242 createLinkGraphFromELFObject_x86(MemoryBufferRef ObjectBuffer,
243 std::shared_ptr<orc::SymbolStringPool> SSP) {
244 LLVM_DEBUG({
245 dbgs() << "Building jitlink graph for new input "
246 << ObjectBuffer.getBufferIdentifier() << "...\n";
247 });
248
249 auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
250 if (!ELFObj)
251 return ELFObj.takeError();
252
253 auto Features = (*ELFObj)->getFeatures();
254 if (!Features)
255 return Features.takeError();
256
257 assert((*ELFObj)->getArch() == Triple::x86 &&
258 "Only x86 (little endian) is supported for now");
259
260 auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj);
261
262 return ELFLinkGraphBuilder_x86((*ELFObj)->getFileName(),
263 ELFObjFile.getELFFile(), std::move(SSP),
264 (*ELFObj)->makeTriple(), std::move(*Features))
265 .buildGraph();
266 }
267
link_ELF_x86(std::unique_ptr<LinkGraph> G,std::unique_ptr<JITLinkContext> Ctx)268 void link_ELF_x86(std::unique_ptr<LinkGraph> G,
269 std::unique_ptr<JITLinkContext> Ctx) {
270 PassConfiguration Config;
271 const Triple &TT = G->getTargetTriple();
272 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
273 if (auto MarkLive = Ctx->getMarkLivePass(TT))
274 Config.PrePrunePasses.push_back(std::move(MarkLive));
275 else
276 Config.PrePrunePasses.push_back(markAllSymbolsLive);
277
278 // Add an in-place GOT and PLT build pass.
279 Config.PostPrunePasses.push_back(buildTables_ELF_x86);
280
281 // Add GOT/Stubs optimizer pass.
282 Config.PreFixupPasses.push_back(x86::optimizeGOTAndStubAccesses);
283 }
284 if (auto Err = Ctx->modifyPassConfig(*G, Config))
285 return Ctx->notifyFailed(std::move(Err));
286
287 ELFJITLinker_x86::link(std::move(Ctx), std::move(G), std::move(Config));
288 }
289
290 } // namespace llvm::jitlink
291