xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/ELF_x86.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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