xref: /llvm-project/llvm/lib/ExecutionEngine/JITLink/ELF_i386.cpp (revision 2ccf7ed277df28651b94bbee9fccefdf22fb074f)
1 //===----- ELF_i386.cpp - JIT linker implementation for ELF/i386 ----===//
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/i386 jit-link implementation.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/ExecutionEngine/JITLink/ELF_i386.h"
14 #include "DefineExternalSectionStartAndEndSymbols.h"
15 #include "ELFLinkGraphBuilder.h"
16 #include "JITLinkGeneric.h"
17 #include "llvm/BinaryFormat/ELF.h"
18 #include "llvm/ExecutionEngine/JITLink/i386.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 
29 Error buildTables_ELF_i386(LinkGraph &G) {
30   LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
31 
32   i386::GOTTableManager GOT;
33   i386::PLTTableManager PLT(GOT);
34   visitExistingEdges(G, GOT, PLT);
35   return Error::success();
36 }
37 } // namespace
38 
39 namespace llvm::jitlink {
40 
41 class ELFJITLinker_i386 : public JITLinker<ELFJITLinker_i386> {
42   friend class JITLinker<ELFJITLinker_i386>;
43 
44 public:
45   ELFJITLinker_i386(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 
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                         i386::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(i386::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 
108   Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
109     return i386::applyFixup(G, B, E, GOTSymbol);
110   }
111 };
112 
113 template <typename ELFT>
114 class ELFLinkGraphBuilder_i386 : public ELFLinkGraphBuilder<ELFT> {
115 private:
116   static Expected<i386::EdgeKind_i386> getRelocationKind(const uint32_t Type) {
117     using namespace i386;
118     switch (Type) {
119     case ELF::R_386_NONE:
120       return EdgeKind_i386::None;
121     case ELF::R_386_32:
122       return EdgeKind_i386::Pointer32;
123     case ELF::R_386_PC32:
124       return EdgeKind_i386::PCRel32;
125     case ELF::R_386_16:
126       return EdgeKind_i386::Pointer16;
127     case ELF::R_386_PC16:
128       return EdgeKind_i386::PCRel16;
129     case ELF::R_386_GOT32:
130       return EdgeKind_i386::RequestGOTAndTransformToDelta32FromGOT;
131     case ELF::R_386_GOTPC:
132       return EdgeKind_i386::Delta32;
133     case ELF::R_386_GOTOFF:
134       return EdgeKind_i386::Delta32FromGOT;
135     case ELF::R_386_PLT32:
136       return EdgeKind_i386::BranchPCRel32;
137     }
138 
139     return make_error<JITLinkError>("Unsupported i386 relocation:" +
140                                     formatv("{0:d}", Type));
141   }
142 
143   Error addRelocations() override {
144     LLVM_DEBUG(dbgs() << "Adding relocations\n");
145     using Base = ELFLinkGraphBuilder<ELFT>;
146     using Self = ELFLinkGraphBuilder_i386;
147 
148     for (const auto &RelSect : Base::Sections) {
149       // Validate the section to read relocation entries from.
150       if (RelSect.sh_type == ELF::SHT_RELA)
151         return make_error<StringError>(
152             "No SHT_RELA in valid i386 ELF object files",
153             inconvertibleErrorCode());
154 
155       if (Error Err = Base::forEachRelRelocation(RelSect, this,
156                                                  &Self::addSingleRelocation))
157         return Err;
158     }
159 
160     return Error::success();
161   }
162 
163   Error addSingleRelocation(const typename ELFT::Rel &Rel,
164                             const typename ELFT::Shdr &FixupSection,
165                             Block &BlockToFix) {
166     using Base = ELFLinkGraphBuilder<ELFT>;
167 
168     uint32_t SymbolIndex = Rel.getSymbol(false);
169     auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
170     if (!ObjSymbol)
171       return ObjSymbol.takeError();
172 
173     Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
174     if (!GraphSymbol)
175       return make_error<StringError>(
176           formatv("Could not find symbol at given index, did you add it to "
177                   "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
178                   SymbolIndex, (*ObjSymbol)->st_shndx,
179                   Base::GraphSymbols.size()),
180           inconvertibleErrorCode());
181 
182     Expected<i386::EdgeKind_i386> Kind = getRelocationKind(Rel.getType(false));
183     if (!Kind)
184       return Kind.takeError();
185 
186     auto FixupAddress = orc::ExecutorAddr(FixupSection.sh_addr) + Rel.r_offset;
187     int64_t Addend = 0;
188 
189     switch (*Kind) {
190     case i386::EdgeKind_i386::None:
191       break;
192     case i386::EdgeKind_i386::Pointer32:
193     case i386::EdgeKind_i386::PCRel32:
194     case i386::EdgeKind_i386::RequestGOTAndTransformToDelta32FromGOT:
195     case i386::EdgeKind_i386::Delta32:
196     case i386::EdgeKind_i386::Delta32FromGOT:
197     case i386::EdgeKind_i386::BranchPCRel32:
198     case i386::EdgeKind_i386::BranchPCRel32ToPtrJumpStub:
199     case i386::EdgeKind_i386::BranchPCRel32ToPtrJumpStubBypassable: {
200       const char *FixupContent = BlockToFix.getContent().data() +
201                                  (FixupAddress - BlockToFix.getAddress());
202       Addend = *(const support::little32_t *)FixupContent;
203       break;
204     }
205     case i386::EdgeKind_i386::Pointer16:
206     case i386::EdgeKind_i386::PCRel16: {
207       const char *FixupContent = BlockToFix.getContent().data() +
208                                  (FixupAddress - BlockToFix.getAddress());
209       Addend = *(const support::little16_t *)FixupContent;
210       break;
211     }
212     }
213 
214     Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
215     Edge GE(*Kind, Offset, *GraphSymbol, Addend);
216     LLVM_DEBUG({
217       dbgs() << "    ";
218       printEdge(dbgs(), BlockToFix, GE, i386::getEdgeKindName(*Kind));
219       dbgs() << "\n";
220     });
221 
222     BlockToFix.addEdge(std::move(GE));
223     return Error::success();
224   }
225 
226 public:
227   ELFLinkGraphBuilder_i386(StringRef FileName, const object::ELFFile<ELFT> &Obj,
228                            std::shared_ptr<orc::SymbolStringPool> SSP,
229                            Triple TT, SubtargetFeatures Features)
230       : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT),
231                                   std::move(Features), FileName,
232                                   i386::getEdgeKindName) {}
233 };
234 
235 Expected<std::unique_ptr<LinkGraph>>
236 createLinkGraphFromELFObject_i386(MemoryBufferRef ObjectBuffer,
237                                   std::shared_ptr<orc::SymbolStringPool> SSP) {
238   LLVM_DEBUG({
239     dbgs() << "Building jitlink graph for new input "
240            << ObjectBuffer.getBufferIdentifier() << "...\n";
241   });
242 
243   auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
244   if (!ELFObj)
245     return ELFObj.takeError();
246 
247   auto Features = (*ELFObj)->getFeatures();
248   if (!Features)
249     return Features.takeError();
250 
251   assert((*ELFObj)->getArch() == Triple::x86 &&
252          "Only i386 (little endian) is supported for now");
253 
254   auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj);
255 
256   return ELFLinkGraphBuilder_i386<object::ELF32LE>(
257              (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP),
258              (*ELFObj)->makeTriple(), std::move(*Features))
259       .buildGraph();
260 }
261 
262 void link_ELF_i386(std::unique_ptr<LinkGraph> G,
263                    std::unique_ptr<JITLinkContext> Ctx) {
264   PassConfiguration Config;
265   const Triple &TT = G->getTargetTriple();
266   if (Ctx->shouldAddDefaultTargetPasses(TT)) {
267     if (auto MarkLive = Ctx->getMarkLivePass(TT))
268       Config.PrePrunePasses.push_back(std::move(MarkLive));
269     else
270       Config.PrePrunePasses.push_back(markAllSymbolsLive);
271 
272     // Add an in-place GOT and PLT build pass.
273     Config.PostPrunePasses.push_back(buildTables_ELF_i386);
274 
275     // Add GOT/Stubs optimizer pass.
276     Config.PreFixupPasses.push_back(i386::optimizeGOTAndStubAccesses);
277   }
278   if (auto Err = Ctx->modifyPassConfig(*G, Config))
279     return Ctx->notifyFailed(std::move(Err));
280 
281   ELFJITLinker_i386::link(std::move(Ctx), std::move(G), std::move(Config));
282 }
283 
284 } // namespace llvm::jitlink
285