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()), 0, 8,
63  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 
92  x86_64::PLTTableManager PLT(GOT);
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  // Sanity check 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  Section &GraphSection) {
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  // Sanity check 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  Addend = 0;
245  break;
246  }
247  }
248 
249  Block *BlockToFix = *(GraphSection.blocks().begin());
250  JITTargetAddress FixupAddress = FixupSection.sh_addr + Rel.r_offset;
251  Edge::OffsetT Offset = FixupAddress - BlockToFix->getAddress();
252  Edge GE(Kind, Offset, *GraphSymbol, Addend);
253  LLVM_DEBUG({
254  dbgs() << " ";
255  printEdge(dbgs(), *BlockToFix, GE, getELFX86RelocationKindName(Kind));
256  dbgs() << "\n";
257  });
258 
259  BlockToFix->addEdge(std::move(GE));
260  return Error::success();
261  }
262 
263 public:
266  : ELFLinkGraphBuilder(Obj, Triple("x86_64-unknown-linux"), FileName,
267  x86_64::getEdgeKindName) {}
268 };
269 
270 class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> {
272 
273 public:
274  ELFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
275  std::unique_ptr<LinkGraph> G,
276  PassConfiguration PassConfig)
277  : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {
278  getPassConfig().PostAllocationPasses.push_back(
279  [this](LinkGraph &G) { return getOrCreateGOTSymbol(G); });
280  }
281 
282 private:
283  Symbol *GOTSymbol = nullptr;
284 
285  Error getOrCreateGOTSymbol(LinkGraph &G) {
286  auto DefineExternalGOTSymbolIfPresent =
288  [&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc {
289  if (Sym.getName() == ELFGOTSymbolName)
290  if (auto *GOTSection = G.findSectionByName(
292  GOTSymbol = &Sym;
293  return {*GOTSection, true};
294  }
295  return {};
296  });
297 
298  // Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an
299  // external.
300  if (auto Err = DefineExternalGOTSymbolIfPresent(G))
301  return Err;
302 
303  // If we succeeded then we're done.
304  if (GOTSymbol)
305  return Error::success();
306 
307  // Otherwise look for a GOT section: If it already has a start symbol we'll
308  // record it, otherwise we'll create our own.
309  // If there's a GOT section but we didn't find an external GOT symbol...
310  if (auto *GOTSection =
311  G.findSectionByName(x86_64::GOTTableManager::getSectionName())) {
312 
313  // Check for an existing defined symbol.
314  for (auto *Sym : GOTSection->symbols())
315  if (Sym->getName() == ELFGOTSymbolName) {
316  GOTSymbol = Sym;
317  return Error::success();
318  }
319 
320  // If there's no defined symbol then create one.
321  SectionRange SR(*GOTSection);
322  if (SR.empty())
323  GOTSymbol = &G.addAbsoluteSymbol(ELFGOTSymbolName, 0, 0,
325  else
326  GOTSymbol =
327  &G.addDefinedSymbol(*SR.getFirstBlock(), 0, ELFGOTSymbolName, 0,
328  Linkage::Strong, Scope::Local, false, true);
329  }
330 
331  return Error::success();
332  }
333 
334  Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
335  return x86_64::applyFixup(G, B, E, GOTSymbol);
336  }
337 };
338 
341  LLVM_DEBUG({
342  dbgs() << "Building jitlink graph for new input "
343  << ObjectBuffer.getBufferIdentifier() << "...\n";
344  });
345 
346  auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
347  if (!ELFObj)
348  return ELFObj.takeError();
349 
350  auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
351  return ELFLinkGraphBuilder_x86_64((*ELFObj)->getFileName(),
352  ELFObjFile.getELFFile())
353  .buildGraph();
354 }
355 
358  constexpr StringRef StartSymbolPrefix = "__start";
359  constexpr StringRef EndSymbolPrefix = "__end";
360 
361  auto SymName = Sym.getName();
362  if (SymName.startswith(StartSymbolPrefix)) {
363  if (auto *Sec =
364  G.findSectionByName(SymName.drop_front(StartSymbolPrefix.size())))
365  return {*Sec, true};
366  } else if (SymName.startswith(EndSymbolPrefix)) {
367  if (auto *Sec =
368  G.findSectionByName(SymName.drop_front(EndSymbolPrefix.size())))
369  return {*Sec, false};
370  }
371  return {};
372 }
373 
374 void link_ELF_x86_64(std::unique_ptr<LinkGraph> G,
375  std::unique_ptr<JITLinkContext> Ctx) {
376  PassConfiguration Config;
377 
378  if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
379 
380  Config.PrePrunePasses.push_back(EHFrameSplitter(".eh_frame"));
381  Config.PrePrunePasses.push_back(
384  Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame"));
385 
386  // Construct a JITLinker and run the link function.
387  // Add a mark-live pass.
388  if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
389  Config.PrePrunePasses.push_back(std::move(MarkLive));
390  else
391  Config.PrePrunePasses.push_back(markAllSymbolsLive);
392 
393  // Add an in-place GOT/Stubs/TLSInfoEntry build pass.
394  Config.PostPrunePasses.push_back(buildTables_ELF_x86_64);
395 
396  // Resolve any external section start / end symbols.
397  Config.PostAllocationPasses.push_back(
400 
401  // Add GOT/Stubs optimizer pass.
403  }
404 
405  if (auto Err = Ctx->modifyPassConfig(*G, Config))
406  return Ctx->notifyFailed(std::move(Err));
407 
409 }
411  switch (R) {
412  case Branch32:
413  return "Branch32";
414  case Pointer32Signed:
415  return "Pointer32Signed";
416  case Pointer64:
417  return "Pointer64";
418  case PCRel32:
419  return "PCRel32";
420  case PCRel32GOTLoad:
421  return "PCRel32GOTLoad";
423  return "PCRel32GOTLoadRelaxable";
425  return "PCRel32REXGOTLoad";
426  case PCRel64GOT:
427  return "PCRel64GOT";
428  case Delta64:
429  return "Delta64";
430  case GOT64:
431  return "GOT64";
432  case GOTOFF64:
433  return "GOTOFF64";
434  }
435  return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
436 }
437 } // end namespace jitlink
438 } // end namespace llvm
llvm
This file implements support for optimizing divisions by a constant.
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:45
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:81
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:198
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:49
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
uint64_t
llvm::object::ELF64LE
ELFType< support::little, true > ELF64LE
Definition: ELFTypes.h:99
llvm::ELF::SHT_REL
@ SHT_REL
Definition: ELF.h:924
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:1609
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:58
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