LLVM  14.0.0git
ELF_x86_64.cpp
Go to the documentation of this file.
1 //===---- ELF_x86_64.cpp -JIT linker implementation for ELF/x86-64 ----===//
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-64 jit-link implementation.
10 //
11 //===----------------------------------------------------------------------===//
12 
18 #include "llvm/Support/Endian.h"
19 
21 #include "EHFrameSupportImpl.h"
22 #include "ELFLinkGraphBuilder.h"
23 #include "JITLinkGeneric.h"
24 
25 #define DEBUG_TYPE "jitlink"
26 
27 using namespace llvm;
28 using namespace llvm::jitlink;
29 using namespace llvm::jitlink::ELF_x86_64_Edges;
30 
31 namespace {
32 
33 constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_";
34 constexpr StringRef ELFTLSInfoSectionName = "$__TLSINFO";
35 
36 class TLSInfoTableManager_ELF_x86_64
37  : public TableManager<TLSInfoTableManager_ELF_x86_64> {
38 public:
39  static const uint8_t TLSInfoEntryContent[16];
40 
41  static StringRef getSectionName() { return ELFTLSInfoSectionName; }
42 
43  bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
45  LLVM_DEBUG({
46  dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
47  << formatv("{0:x}", B->getFixupAddress(E)) << " ("
48  << formatv("{0:x}", B->getAddress()) << " + "
49  << formatv("{0:x}", E.getOffset()) << ")\n";
50  });
51  E.setKind(x86_64::Delta32);
52  E.setTarget(getEntryForTarget(G, E.getTarget()));
53  return true;
54  }
55  return false;
56  }
57 
58  Symbol &createEntry(LinkGraph &G, Symbol &Target) {
59  // the TLS Info entry's key value will be written by the fixTLVSectionByName
60  // pass, so create mutable content.
61  auto &TLSInfoEntry = G.createMutableContentBlock(
62  getTLSInfoSection(G), G.allocateContent(getTLSInfoEntryContent()),
63  orc::ExecutorAddr(), 8, 0);
64  TLSInfoEntry.addEdge(x86_64::Pointer64, 8, Target, 0);
65  return G.addAnonymousSymbol(TLSInfoEntry, 0, 16, false, false);
66  }
67 
68 private:
69  Section &getTLSInfoSection(LinkGraph &G) {
70  if (!TLSInfoTable)
71  TLSInfoTable = &G.createSection(ELFTLSInfoSectionName, MemProt::Read);
72  return *TLSInfoTable;
73  }
74 
75  ArrayRef<char> getTLSInfoEntryContent() const {
76  return {reinterpret_cast<const char *>(TLSInfoEntryContent),
77  sizeof(TLSInfoEntryContent)};
78  }
79 
80  Section *TLSInfoTable = nullptr;
81 };
82 
83 const uint8_t TLSInfoTableManager_ELF_x86_64::TLSInfoEntryContent[16] = {
84  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*pthread key */
85  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*data address*/
86 };
87 
88 Error buildTables_ELF_x86_64(LinkGraph &G) {
89  LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
90 
93  TLSInfoTableManager_ELF_x86_64 TLSInfo;
94  visitExistingEdges(G, GOT, PLT, TLSInfo);
95  return Error::success();
96 }
97 } // namespace
98 
99 static const char *getELFX86_64RelocName(uint32_t Type) {
100  switch (Type) {
101 #define ELF_RELOC(Name, Number) \
102  case Number: \
103  return #Name;
104 #include "llvm/BinaryFormat/ELFRelocs/x86_64.def"
105 #undef ELF_RELOC
106  }
107  return "Unrecognized ELF/x86-64 relocation type";
108 }
109 
110 namespace llvm {
111 namespace jitlink {
112 
113 // This should become a template as the ELFFile is so a lot of this could become
114 // generic
115 class ELFLinkGraphBuilder_x86_64 : public ELFLinkGraphBuilder<object::ELF64LE> {
116 private:
117  using ELFT = object::ELF64LE;
118 
120  getRelocationKind(const uint32_t Type) {
121  switch (Type) {
122  case ELF::R_X86_64_32S:
124  case ELF::R_X86_64_PC32:
126  case ELF::R_X86_64_PC64:
127  case ELF::R_X86_64_GOTPC64:
129  case ELF::R_X86_64_64:
131  case ELF::R_X86_64_GOTPCREL:
133  case ELF::R_X86_64_GOTPCRELX:
135  case ELF::R_X86_64_REX_GOTPCRELX:
137  case ELF::R_X86_64_GOTPCREL64:
139  case ELF::R_X86_64_GOT64:
141  case ELF::R_X86_64_GOTOFF64:
143  case ELF::R_X86_64_PLT32:
145  case ELF::R_X86_64_TLSGD:
147  }
148  return make_error<JITLinkError>("Unsupported x86-64 relocation type " +
149  formatv("{0:d}: ", Type) +
151  }
152 
153  Error addRelocations() override {
154  LLVM_DEBUG(dbgs() << "Processing relocations:\n");
155 
157  using Self = ELFLinkGraphBuilder_x86_64;
158  for (const auto &RelSect : Base::Sections) {
159  // Validate the section to read relocation entries from.
160  if (RelSect.sh_type == ELF::SHT_REL)
161  return make_error<StringError>(
162  "No SHT_REL in valid x64 ELF object files",
164 
165  if (Error Err = Base::forEachRelocation(RelSect, this,
166  &Self::addSingleRelocation))
167  return Err;
168  }
169 
170  return Error::success();
171  }
172 
173  Error addSingleRelocation(const typename ELFT::Rela &Rel,
174  const typename ELFT::Shdr &FixupSection,
175  Block &BlockToFix) {
177 
178  uint32_t SymbolIndex = Rel.getSymbol(false);
179  auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
180  if (!ObjSymbol)
181  return ObjSymbol.takeError();
182 
183  Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
184  if (!GraphSymbol)
185  return make_error<StringError>(
186  formatv("Could not find symbol at given index, did you add it to "
187  "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
188  SymbolIndex, (*ObjSymbol)->st_shndx,
189  Base::GraphSymbols.size()),
191 
192  // Validate the relocation kind.
193  auto ELFRelocKind = getRelocationKind(Rel.getType(false));
194  if (!ELFRelocKind)
195  return ELFRelocKind.takeError();
196 
197  int64_t Addend = Rel.r_addend;
199  switch (*ELFRelocKind) {
200  case PCRel32:
202  break;
203  case Delta64:
205  break;
206  case Pointer32Signed:
208  break;
209  case Pointer64:
211  break;
212  case PCRel32GOTLoad: {
214  break;
215  }
218  Addend = 0;
219  break;
220  }
221  case PCRel32TLV: {
223  break;
224  }
227  Addend = 0;
228  break;
229  }
230  case PCRel64GOT: {
232  break;
233  }
234  case GOT64: {
236  break;
237  }
238  case GOTOFF64: {
240  break;
241  }
242  case Branch32: {
244  // BranchPCRel32 implicitly handles the '-4' PC adjustment, so we have to
245  // adjust the addend by '+4' to compensate.
246  Addend += 4;
247  break;
248  }
249  }
250 
251  auto FixupAddress = orc::ExecutorAddr(FixupSection.sh_addr) + Rel.r_offset;
252  Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
253  Edge GE(Kind, Offset, *GraphSymbol, Addend);
254  LLVM_DEBUG({
255  dbgs() << " ";
256  printEdge(dbgs(), BlockToFix, GE, x86_64::getEdgeKindName(Kind));
257  dbgs() << "\n";
258  });
259 
260  BlockToFix.addEdge(std::move(GE));
261  return Error::success();
262  }
263 
264 public:
267  : ELFLinkGraphBuilder(Obj, Triple("x86_64-unknown-linux"), FileName,
268  x86_64::getEdgeKindName) {}
269 };
270 
271 class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> {
273 
274 public:
275  ELFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
276  std::unique_ptr<LinkGraph> G,
277  PassConfiguration PassConfig)
278  : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {
279  getPassConfig().PostAllocationPasses.push_back(
280  [this](LinkGraph &G) { return getOrCreateGOTSymbol(G); });
281  }
282 
283 private:
284  Symbol *GOTSymbol = nullptr;
285 
286  Error getOrCreateGOTSymbol(LinkGraph &G) {
287  auto DefineExternalGOTSymbolIfPresent =
289  [&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc {
290  if (Sym.getName() == ELFGOTSymbolName)
291  if (auto *GOTSection = G.findSectionByName(
293  GOTSymbol = &Sym;
294  return {*GOTSection, true};
295  }
296  return {};
297  });
298 
299  // Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an
300  // external.
301  if (auto Err = DefineExternalGOTSymbolIfPresent(G))
302  return Err;
303 
304  // If we succeeded then we're done.
305  if (GOTSymbol)
306  return Error::success();
307 
308  // Otherwise look for a GOT section: If it already has a start symbol we'll
309  // record it, otherwise we'll create our own.
310  // If there's a GOT section but we didn't find an external GOT symbol...
311  if (auto *GOTSection =
312  G.findSectionByName(x86_64::GOTTableManager::getSectionName())) {
313 
314  // Check for an existing defined symbol.
315  for (auto *Sym : GOTSection->symbols())
316  if (Sym->getName() == ELFGOTSymbolName) {
317  GOTSymbol = Sym;
318  return Error::success();
319  }
320 
321  // If there's no defined symbol then create one.
322  SectionRange SR(*GOTSection);
323  if (SR.empty())
324  GOTSymbol =
325  &G.addAbsoluteSymbol(ELFGOTSymbolName, orc::ExecutorAddr(), 0,
327  else
328  GOTSymbol =
329  &G.addDefinedSymbol(*SR.getFirstBlock(), 0, ELFGOTSymbolName, 0,
330  Linkage::Strong, Scope::Local, false, true);
331  }
332 
333  return Error::success();
334  }
335 
336  Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
337  return x86_64::applyFixup(G, B, E, GOTSymbol);
338  }
339 };
340 
343  LLVM_DEBUG({
344  dbgs() << "Building jitlink graph for new input "
345  << ObjectBuffer.getBufferIdentifier() << "...\n";
346  });
347 
348  auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
349  if (!ELFObj)
350  return ELFObj.takeError();
351 
352  auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
353  return ELFLinkGraphBuilder_x86_64((*ELFObj)->getFileName(),
354  ELFObjFile.getELFFile())
355  .buildGraph();
356 }
357 
360  constexpr StringRef StartSymbolPrefix = "__start";
361  constexpr StringRef EndSymbolPrefix = "__end";
362 
363  auto SymName = Sym.getName();
364  if (SymName.startswith(StartSymbolPrefix)) {
365  if (auto *Sec =
366  G.findSectionByName(SymName.drop_front(StartSymbolPrefix.size())))
367  return {*Sec, true};
368  } else if (SymName.startswith(EndSymbolPrefix)) {
369  if (auto *Sec =
370  G.findSectionByName(SymName.drop_front(EndSymbolPrefix.size())))
371  return {*Sec, false};
372  }
373  return {};
374 }
375 
376 void link_ELF_x86_64(std::unique_ptr<LinkGraph> G,
377  std::unique_ptr<JITLinkContext> Ctx) {
378  PassConfiguration Config;
379 
380  if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
381 
382  Config.PrePrunePasses.push_back(EHFrameSplitter(".eh_frame"));
383  Config.PrePrunePasses.push_back(
386  Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame"));
387 
388  // Construct a JITLinker and run the link function.
389  // Add a mark-live pass.
390  if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
391  Config.PrePrunePasses.push_back(std::move(MarkLive));
392  else
393  Config.PrePrunePasses.push_back(markAllSymbolsLive);
394 
395  // Add an in-place GOT/Stubs/TLSInfoEntry build pass.
396  Config.PostPrunePasses.push_back(buildTables_ELF_x86_64);
397 
398  // Resolve any external section start / end symbols.
399  Config.PostAllocationPasses.push_back(
402 
403  // Add GOT/Stubs optimizer pass.
405  }
406 
407  if (auto Err = Ctx->modifyPassConfig(*G, Config))
408  return Ctx->notifyFailed(std::move(Err));
409 
411 }
413  switch (R) {
414  case Branch32:
415  return "Branch32";
416  case Pointer32Signed:
417  return "Pointer32Signed";
418  case Pointer64:
419  return "Pointer64";
420  case PCRel32:
421  return "PCRel32";
422  case PCRel32GOTLoad:
423  return "PCRel32GOTLoad";
425  return "PCRel32GOTLoadRelaxable";
427  return "PCRel32REXGOTLoad";
428  case PCRel64GOT:
429  return "PCRel64GOT";
430  case Delta64:
431  return "Delta64";
432  case GOT64:
433  return "GOT64";
434  case GOTOFF64:
435  return "GOTOFF64";
436  }
437  return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
438 }
439 } // end namespace jitlink
440 } // end namespace llvm
llvm::orc::ExecutorAddr
Represents an address in the executor process.
Definition: ExecutorAddress.h:30
llvm::CSKYCP::PLT
@ PLT
Definition: CSKYConstantPoolValue.h:39
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AllocatorList.h:23
llvm::Target
Target - Wrapper for Target specific information.
Definition: TargetRegistry.h:137
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:331
llvm::object::Elf_Rel_Impl
Definition: ELFTypes.h:34
llvm::Triple
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
llvm::Type
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
Offset
uint64_t Offset
Definition: ELFObjHandler.cpp:80
DefineExternalSectionStartAndEndSymbols.h
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:42
llvm::MemoryBufferRef
Definition: MemoryBufferRef.h:22
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
getELFX86_64RelocName
static const char * getELFX86_64RelocName(uint32_t Type)
Definition: ELF_x86_64.cpp:99
llvm::RISCVFenceField::R
@ R
Definition: RISCVBaseInfo.h:207
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
llvm::object::ELFType
Definition: ELFTypes.h:48
llvm::formatv
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
Definition: FormatVariadic.h:250
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
B
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
llvm::object::ObjectFile::createELFObjectFile
static Expected< std::unique_ptr< ObjectFile > > createELFObjectFile(MemoryBufferRef Object, bool InitContent=true)
Definition: ELFObjectFile.cpp:72
llvm::object::Elf_Shdr_Impl
Definition: ELFTypes.h:30
llvm::lltok::Kind
Kind
Definition: LLToken.h:18
G
const DataFlowGraph & G
Definition: RDFGraph.cpp:202
llvm::object::ELF64LE
ELFType< support::little, true > ELF64LE
Definition: ELFTypes.h:97
llvm::ELF::SHT_REL
@ SHT_REL
Definition: ELF.h:929
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
llvm::move
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1707
ELF_x86_64.h
llvm::AArch64CC::GE
@ GE
Definition: AArch64BaseInfo.h:265
llvm::ArrayRef< char >
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:57
if
if(llvm_vc STREQUAL "") set(fake_version_inc "$
Definition: CMakeLists.txt:14
uint32_t
x86_64.h
ELFObjectFile.h
std
Definition: BitVector.h:838
llvm::inconvertibleErrorCode
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:77
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
EHFrameSupportImpl.h
TableManager.h
llvm::MemoryBufferRef::getBufferIdentifier
StringRef getBufferIdentifier() const
Definition: MemoryBufferRef.h:33
ELFLinkGraphBuilder.h
Endian.h
llvm::object::ELFFile
Definition: ELF.h:94
JITLinkGeneric.h
llvm::sampleprof::Base
@ Base
Definition: Discriminator.h:58