LLVM  11.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 
14 #include "JITLinkGeneric.h"
17 
18 #define DEBUG_TYPE "jitlink"
19 
20 using namespace llvm;
21 using namespace llvm::jitlink;
22 
23 static const char *CommonSectionName = "__common";
24 
25 namespace llvm {
26 namespace jitlink {
27 
28 // This should become a template as the ELFFile is so a lot of this could become
29 // generic
31 
32 private:
33  Section *CommonSection = nullptr;
34  // TODO hack to get this working
35  // Find a better way
37  // For now we just assume
38  std::map<int32_t, Symbol *> JITSymbolTable;
39 
40  Section &getCommonSection() {
41  if (!CommonSection) {
42  auto Prot = static_cast<sys::Memory::ProtectionFlags>(
44  CommonSection = &G->createSection(CommonSectionName, Prot);
45  }
46  return *CommonSection;
47  }
48 
50  getRelocationKind(const uint32_t Type) {
51  switch (Type) {
52  case ELF::R_X86_64_PC32:
54  }
55  return make_error<JITLinkError>("Unsupported x86-64 relocation:" +
56  formatv("{0:d}", Type));
57  }
58 
59  std::unique_ptr<LinkGraph> G;
60  // This could be a template
63  SymbolTable SymTab;
64 
65  bool isRelocatable() { return Obj.getHeader()->e_type == llvm::ELF::ET_REL; }
66 
68  getEndianness(const object::ELFFile<object::ELF64LE> &Obj) {
69  return Obj.isLE() ? support::little : support::big;
70  }
71 
72  // This could also just become part of a template
74  return Obj.getHeader()->getFileClass() == ELF::ELFCLASS64 ? 8 : 4;
75  }
76 
77  // We don't technically need this right now
78  // But for now going to keep it as it helps me to debug things
79 
80  Error createNormalizedSymbols() {
81  LLVM_DEBUG(dbgs() << "Creating normalized symbols...\n");
82 
83  for (auto SecRef : sections) {
84  if (SecRef.sh_type != ELF::SHT_SYMTAB &&
85  SecRef.sh_type != ELF::SHT_DYNSYM)
86  continue;
87 
88  auto Symbols = Obj.symbols(&SecRef);
89  // TODO: Currently I use this function to test things
90  // I also want to leave it to see if its common between MACH and elf
91  // so for now I just want to continue even if there is an error
92  if (errorToBool(Symbols.takeError()))
93  continue;
94 
95  auto StrTabSec = Obj.getSection(SecRef.sh_link);
96  if (!StrTabSec)
97  return StrTabSec.takeError();
98  auto StringTable = Obj.getStringTable(*StrTabSec);
99  if (!StringTable)
100  return StringTable.takeError();
101 
102  for (auto SymRef : *Symbols) {
104  uint64_t Size = 0;
105 
106  // FIXME: Read size.
107  (void)Size;
108 
109  if (auto NameOrErr = SymRef.getName(*StringTable))
110  Name = *NameOrErr;
111  else
112  return NameOrErr.takeError();
113 
114  LLVM_DEBUG({
115  dbgs() << " ";
116  if (!Name)
117  dbgs() << "<anonymous symbol>";
118  else
119  dbgs() << *Name;
120  dbgs() << ": value = " << formatv("{0:x16}", SymRef.getValue())
121  << ", type = " << formatv("{0:x2}", SymRef.getType())
122  << ", binding = " << SymRef.getBinding()
123  << ", size =" << Size;
124  dbgs() << "\n";
125  });
126  }
127  }
128  return Error::success();
129  }
130 
131  Error createNormalizedSections() {
132  LLVM_DEBUG(dbgs() << "Creating normalized sections...\n");
133  for (auto &SecRef : sections) {
134  auto Name = Obj.getSectionName(&SecRef);
135  if (!Name)
136  return Name.takeError();
138  if (SecRef.sh_flags & ELF::SHF_EXECINSTR) {
141  } else {
144  }
145  uint64_t Address = SecRef.sh_addr;
146  uint64_t Size = SecRef.sh_size;
147  uint64_t Flags = SecRef.sh_flags;
148  uint64_t Alignment = SecRef.sh_addralign;
149  const char *Data = nullptr;
150  // TODO: figure out what it is that has 0 size no name and address
151  // 0000-0000
152  if (Size == 0)
153  continue;
154 
155  // FIXME: Use flags.
156  (void)Flags;
157 
158  LLVM_DEBUG({
159  dbgs() << " " << *Name << ": " << formatv("{0:x16}", Address) << " -- "
160  << formatv("{0:x16}", Address + Size) << ", align: " << Alignment
161  << " Flags:" << Flags << "\n";
162  });
163 
164  if (SecRef.sh_type != ELF::SHT_NOBITS) {
165  // .sections() already checks that the data is not beyond the end of
166  // file
167  auto contents = Obj.getSectionContentsAsArray<char>(&SecRef);
168  if (!contents)
169  return contents.takeError();
170 
171  Data = contents->data();
172  // TODO protection flags.
173  // for now everything is
174  auto &section = G->createSection(*Name, Prot);
175  // Do this here because we have it, but move it into graphify later
176  G->createContentBlock(section, StringRef(Data, Size), Address,
177  Alignment, 0);
178  if (SecRef.sh_type == ELF::SHT_SYMTAB)
179  // TODO: Dynamic?
180  SymTab = SecRef;
181  }
182  }
183 
184  return Error::success();
185  }
186 
187  Error addRelocations() {
188  LLVM_DEBUG(dbgs() << "Adding relocations\n");
189  // TODO a partern is forming of iterate some sections but only give me
190  // ones I am interested, i should abstract that concept some where
191  for (auto &SecRef : sections) {
192  if (SecRef.sh_type != ELF::SHT_RELA && SecRef.sh_type != ELF::SHT_REL)
193  continue;
194  // TODO can the elf obj file do this for me?
195  if (SecRef.sh_type == ELF::SHT_REL)
196  return make_error<llvm::StringError>("Shouldn't have REL in x64",
198 
199  auto RelSectName = Obj.getSectionName(&SecRef);
200  if (!RelSectName)
201  return RelSectName.takeError();
202  // Deal with .eh_frame later
203  if (*RelSectName == StringRef(".rela.eh_frame"))
204  continue;
205 
206  auto UpdateSection = Obj.getSection(SecRef.sh_info);
207  if (!UpdateSection)
208  return UpdateSection.takeError();
209 
210  auto UpdateSectionName = Obj.getSectionName(*UpdateSection);
211  if (!UpdateSectionName)
212  return UpdateSectionName.takeError();
213 
214  auto JITSection = G->findSectionByName(*UpdateSectionName);
215  if (!JITSection)
216  return make_error<llvm::StringError>(
217  "Refencing a a section that wasn't added to graph" +
218  *UpdateSectionName,
220 
221  auto Relocations = Obj.relas(&SecRef);
222  if (!Relocations)
223  return Relocations.takeError();
224 
225  for (const auto &Rela : *Relocations) {
226  auto Type = Rela.getType(false);
227 
228  LLVM_DEBUG({
229  dbgs() << "Relocation Type: " << Type << "\n"
230  << "Name: " << Obj.getRelocationTypeName(Type) << "\n";
231  });
232 
233  auto Symbol = Obj.getRelocationSymbol(&Rela, &SymTab);
234  if (!Symbol)
235  return Symbol.takeError();
236 
237  auto BlockToFix = *(JITSection->blocks().begin());
238  auto TargetSymbol = JITSymbolTable[(*Symbol)->st_shndx];
239  uint64_t Addend = Rela.r_addend;
240  JITTargetAddress FixupAddress =
241  (*UpdateSection)->sh_addr + Rela.r_offset;
242 
243  LLVM_DEBUG({
244  dbgs() << "Processing relocation at "
245  << format("0x%016" PRIx64, FixupAddress) << "\n";
246  });
247  auto Kind = getRelocationKind(Type);
248  if (!Kind)
249  return Kind.takeError();
250 
251  LLVM_DEBUG({
252  Edge GE(*Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
253  Addend);
254  // TODO a mapping of KIND => type then call getRelocationTypeName4
255  printEdge(dbgs(), *BlockToFix, GE, StringRef(""));
256  dbgs() << "\n";
257  });
258  BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(),
259  *TargetSymbol, Addend);
260  }
261  }
262  return Error::success();
263  }
264 
265  Error graphifyRegularSymbols() {
266 
267  // TODO: ELF supports beyond SHN_LORESERVE,
268  // need to perf test how a vector vs map handles those cases
269 
270  std::vector<std::vector<object::ELFFile<object::ELF64LE>::Elf_Shdr_Range *>>
271  SecIndexToSymbols;
272 
273  LLVM_DEBUG(dbgs() << "Creating graph symbols...\n");
274 
275  for (auto SecRef : sections) {
276 
277  if (SecRef.sh_type != ELF::SHT_SYMTAB &&
278  SecRef.sh_type != ELF::SHT_DYNSYM)
279  continue;
280  auto Symbols = Obj.symbols(&SecRef);
281  if (!Symbols)
282  return Symbols.takeError();
283 
284  auto StrTabSec = Obj.getSection(SecRef.sh_link);
285  if (!StrTabSec)
286  return StrTabSec.takeError();
287  auto StringTable = Obj.getStringTable(*StrTabSec);
288  if (!StringTable)
289  return StringTable.takeError();
290  auto Name = Obj.getSectionName(&SecRef);
291  if (!Name)
292  return Name.takeError();
293  auto Section = G->findSectionByName(*Name);
294  if (!Section)
295  return make_error<llvm::StringError>("Could not find a section",
297  // we only have one for now
298  auto blocks = Section->blocks();
299  if (blocks.empty())
300  return make_error<llvm::StringError>("Section has no block",
302 
303  for (auto SymRef : *Symbols) {
304  auto Type = SymRef.getType();
305  if (Type == ELF::STT_NOTYPE || Type == ELF::STT_FILE)
306  continue;
307  // these should do it for now
308  // if(Type != ELF::STT_NOTYPE &&
309  // Type != ELF::STT_OBJECT &&
310  // Type != ELF::STT_FUNC &&
311  // Type != ELF::STT_SECTION &&
312  // Type != ELF::STT_COMMON) {
313  // continue;
314  // }
315  std::pair<Linkage, Scope> bindings;
316  auto Name = SymRef.getName(*StringTable);
317  // I am not sure on If this is going to hold as an invariant. Revisit.
318  if (!Name)
319  return Name.takeError();
320  // TODO: weak and hidden
321  if (SymRef.isExternal())
322  bindings = {Linkage::Strong, Scope::Default};
323  else
324  bindings = {Linkage::Strong, Scope::Local};
325 
326  if (SymRef.isDefined() &&
327  (Type == ELF::STT_FUNC || Type == ELF::STT_OBJECT)) {
328 
329  auto DefinedSection = Obj.getSection(SymRef.st_shndx);
330  if (!DefinedSection)
331  return DefinedSection.takeError();
332  auto sectName = Obj.getSectionName(*DefinedSection);
333  if (!sectName)
334  return Name.takeError();
335 
336  auto JitSection = G->findSectionByName(*sectName);
337  if (!JitSection)
338  return make_error<llvm::StringError>(
339  "Could not find a section", llvm::inconvertibleErrorCode());
340  auto bs = JitSection->blocks();
341  if (bs.empty())
342  return make_error<llvm::StringError>(
343  "Section has no block", llvm::inconvertibleErrorCode());
344 
345  auto B = *bs.begin();
346  LLVM_DEBUG({ dbgs() << " " << *Name << ": "; });
347 
348  auto &S = G->addDefinedSymbol(
349  *B, SymRef.getValue(), *Name, SymRef.st_size, bindings.first,
350  bindings.second, SymRef.getType() == ELF::STT_FUNC, false);
351  JITSymbolTable[SymRef.st_shndx] = &S;
352  }
353  //TODO: The following has to be implmented.
354  // leaving commented out to save time for future patchs
355  /*
356  G->addAbsoluteSymbol(*Name, SymRef.getValue(), SymRef.st_size,
357  Linkage::Strong, Scope::Default, false);
358 
359  if(SymRef.isCommon()) {
360  G->addCommonSymbol(*Name, Scope::Default, getCommonSection(), 0, 0,
361  SymRef.getValue(), false);
362  }
363 
364 
365  //G->addExternalSymbol(*Name, SymRef.st_size, Linkage::Strong);
366  */
367  }
368  }
369  return Error::success();
370  }
371 
372 public:
375  : G(std::make_unique<LinkGraph>(filename, getPointerSize(Obj),
376  getEndianness(Obj))),
377  Obj(Obj) {}
378 
380  // Sanity check: we only operate on relocatable objects.
381  if (!isRelocatable())
382  return make_error<JITLinkError>("Object is not a relocatable ELF");
383 
384  auto Secs = Obj.sections();
385 
386  if (!Secs) {
387  return Secs.takeError();
388  }
389  sections = *Secs;
390 
391  if (auto Err = createNormalizedSections())
392  return std::move(Err);
393 
394  if (auto Err = createNormalizedSymbols())
395  return std::move(Err);
396 
397  if (auto Err = graphifyRegularSymbols())
398  return std::move(Err);
399 
400  if (auto Err = addRelocations())
401  return std::move(Err);
402 
403  return std::move(G);
404  }
405 };
406 
407 class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> {
409 
410 public:
411  ELFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
412  PassConfiguration PassConfig)
413  : JITLinker(std::move(Ctx), std::move(PassConfig)) {}
414 
415 private:
416  StringRef getEdgeKindName(Edge::Kind R) const override { return StringRef(); }
417 
419  buildGraph(MemoryBufferRef ObjBuffer) override {
420  auto ELFObj = object::ObjectFile::createELFObjectFile(ObjBuffer);
421  if (!ELFObj)
422  return ELFObj.takeError();
423 
424  auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
425  std::string fileName(ELFObj->get()->getFileName());
426  return ELFLinkGraphBuilder_x86_64(std::move(fileName),
427  *ELFObjFile.getELFFile())
428  .buildGraph();
429  }
430 
431  Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const {
432  using namespace ELF_x86_64_Edges;
433  char *FixupPtr = BlockWorkingMem + E.getOffset();
434  JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
435  switch (E.getKind()) {
436 
438  int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
439  // verify
440  *(support::little32_t *)FixupPtr = Value;
441  break;
442  }
443  return Error::success();
444  }
445 };
446 
447 void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
448  PassConfiguration Config;
449  Triple TT("x86_64-linux");
450  // Construct a JITLinker and run the link function.
451  // Add a mark-live pass.
452  if (auto MarkLive = Ctx->getMarkLivePass(TT))
453  Config.PrePrunePasses.push_back(std::move(MarkLive));
454  else
455  Config.PrePrunePasses.push_back(markAllSymbolsLive);
456 
457  if (auto Err = Ctx->modifyPassConfig(TT, Config))
458  return Ctx->notifyFailed(std::move(Err));
459 
460  ELFJITLinker_x86_64::link(std::move(Ctx), std::move(Config));
461 }
462 } // end namespace jitlink
463 } // end namespace llvm
This class represents lattice values for constants.
Definition: AllocatorList.h:23
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
Expected< StringRef > getStringTable(const Elf_Shdr *Section, WarningHandler WarnHandler=&defaultWarningHandler) const
Definition: ELF.h:637
StringRef getRelocationTypeName(uint32_t Type) const
Definition: ELF.h:464
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:124
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
Expected< const Elf_Shdr * > getSection(const Elf_Sym *Sym, const Elf_Shdr *SymTab, ArrayRef< Elf_Word > ShndxTable) const
Definition: ELF.h:365
Definition: BitVector.h:959
Expected< Elf_Shdr_Range > sections() const
Definition: ELF.h:551
Tagged union holding either a T or a Error.
Definition: APFloat.h:42
bool isLE() const
Definition: ELF.h:164
static uint64_t getPointerSize(const Value *V, const DataLayout &DL, const TargetLibraryInfo &TLI, const Function *F)
uint64_t JITTargetAddress
Represents an address in the target process&#39;s address space.
Definition: JITSymbol.h:42
Expected< ArrayRef< T > > getSectionContentsAsArray(const Elf_Shdr *Sec) const
Definition: ELF.h:404
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:46
bool errorToBool(Error Err)
Helper for converting an Error to a bool.
Definition: Error.h:1029
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Expected< Elf_Rela_Range > relas(const Elf_Shdr *Sec) const
Definition: ELF.h:187
static Expected< std::unique_ptr< ObjectFile > > createELFObjectFile(MemoryBufferRef Object)
Expected< StringRef > getSectionName(const Elf_Shdr *Section, WarningHandler WarnHandler=&defaultWarningHandler) const
Definition: ELF.h:724
static const char * CommonSectionName
Definition: ELF_x86_64.cpp:23
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:45
static ErrorSuccess success()
Create a success value.
Definition: Error.h:332
const DataFlowGraph & G
Definition: RDFGraph.cpp:202
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
Expected< const Elf_Sym * > getRelocationSymbol(const Elf_Rel *Rel, const Elf_Shdr *SymTab) const
Get the symbol for a given relocation.
Definition: ELF.h:506
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
Definition: Path.cpp:577
Expected< Elf_Sym_Range > symbols(const Elf_Shdr *Sec) const
Definition: ELF.h:181
uint32_t Size
Definition: Profile.cpp:46
LLVM Value Representation.
Definition: Value.h:74
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:57
typename ELFT::ShdrRange Elf_Shdr_Range
Definition: ELF.h:106
const Elf_Ehdr * getHeader() const
Definition: ELF.h:130
#define LLVM_DEBUG(X)
Definition: Debug.h:122
typename ELFT::Shdr Elf_Shdr
Definition: ELF.h:88
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:77