LLVM  16.0.0git
ELF_i386.cpp
Go to the documentation of this file.
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 
14 #include "ELFLinkGraphBuilder.h"
15 #include "JITLinkGeneric.h"
16 #include "llvm/BinaryFormat/ELF.h"
19 
20 #define DEBUG_TYPE "jitlink"
21 
22 using namespace llvm;
23 using namespace llvm::jitlink;
24 
25 namespace llvm::jitlink {
26 
27 class ELFJITLinker_i386 : public JITLinker<ELFJITLinker_i386> {
29 
30 public:
31  ELFJITLinker_i386(std::unique_ptr<JITLinkContext> Ctx,
32  std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)
33  : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
34 
35 private:
36  Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
37  return i386::applyFixup(G, B, E);
38  }
39 };
40 
41 template <typename ELFT>
43 private:
44  static Expected<i386::EdgeKind_i386> getRelocationKind(const uint32_t Type) {
45  using namespace i386;
46  switch (Type) {
47  case ELF::R_386_NONE:
48  return EdgeKind_i386::None;
49  case ELF::R_386_32:
51  case ELF::R_386_PC32:
53  case ELF::R_386_16:
55  case ELF::R_386_PC16:
57  case ELF::R_386_GOTPC:
59  }
60 
61  return make_error<JITLinkError>("Unsupported i386 relocation:" +
62  formatv("{0:d}", Type));
63  }
64 
65  Error addRelocations() override {
66  LLVM_DEBUG(dbgs() << "Adding relocations\n");
68  using Self = ELFLinkGraphBuilder_i386;
69 
70  for (const auto &RelSect : Base::Sections) {
71  // Validate the section to read relocation entries from.
72  if (RelSect.sh_type == ELF::SHT_RELA)
73  return make_error<StringError>(
74  "No SHT_RELA in valid i386 ELF object files",
76 
77  if (Error Err = Base::forEachRelRelocation(RelSect, this,
78  &Self::addSingleRelocation))
79  return Err;
80  }
81 
82  return Error::success();
83  }
84 
85  Error addSingleRelocation(const typename ELFT::Rel &Rel,
86  const typename ELFT::Shdr &FixupSection,
87  Block &BlockToFix) {
89 
90  uint32_t SymbolIndex = Rel.getSymbol(false);
91  auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
92  if (!ObjSymbol)
93  return ObjSymbol.takeError();
94 
95  Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
96  if (!GraphSymbol)
97  return make_error<StringError>(
98  formatv("Could not find symbol at given index, did you add it to "
99  "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
100  SymbolIndex, (*ObjSymbol)->st_shndx,
101  Base::GraphSymbols.size()),
103 
104  Expected<i386::EdgeKind_i386> Kind = getRelocationKind(Rel.getType(false));
105  if (!Kind)
106  return Kind.takeError();
107 
108  // TODO: To be removed when GOT relative relocations are supported.
110  return Error::success();
111 
112  int64_t Addend = 0;
113 
114  auto FixupAddress = orc::ExecutorAddr(FixupSection.sh_addr) + Rel.r_offset;
115  Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
116  Edge GE(*Kind, Offset, *GraphSymbol, Addend);
117  LLVM_DEBUG({
118  dbgs() << " ";
119  printEdge(dbgs(), BlockToFix, GE, i386::getEdgeKindName(*Kind));
120  dbgs() << "\n";
121  });
122 
123  BlockToFix.addEdge(std::move(GE));
124 
125  return Error::success();
126  }
127 
128 public:
130  const Triple T)
131  : ELFLinkGraphBuilder<ELFT>(Obj, std::move(T), FileName,
132  i386::getEdgeKindName) {}
133 };
134 
137  LLVM_DEBUG({
138  dbgs() << "Building jitlink graph for new input "
139  << ObjectBuffer.getBufferIdentifier() << "...\n";
140  });
141 
142  auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
143  if (!ELFObj)
144  return ELFObj.takeError();
145 
146  assert((*ELFObj)->getArch() == Triple::x86 &&
147  "Only i386 (little endian) is supported for now");
148 
149  auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj);
150  return ELFLinkGraphBuilder_i386<object::ELF32LE>((*ELFObj)->getFileName(),
151  ELFObjFile.getELFFile(),
152  (*ELFObj)->makeTriple())
153  .buildGraph();
154 }
155 
156 void link_ELF_i386(std::unique_ptr<LinkGraph> G,
157  std::unique_ptr<JITLinkContext> Ctx) {
158  PassConfiguration Config;
159  const Triple &TT = G->getTargetTriple();
160  if (Ctx->shouldAddDefaultTargetPasses(TT)) {
161  if (auto MarkLive = Ctx->getMarkLivePass(TT))
162  Config.PrePrunePasses.push_back(std::move(MarkLive));
163  else
164  Config.PrePrunePasses.push_back(markAllSymbolsLive);
165  }
166  if (auto Err = Ctx->modifyPassConfig(*G, Config))
167  return Ctx->notifyFailed(std::move(Err));
168 
170 }
171 
172 } // namespace llvm::jitlink
llvm::orc::ExecutorAddr
Represents an address in the executor process.
Definition: ExecutorAddress.h:31
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
T
llvm::Triple::x86
@ x86
Definition: Triple.h:85
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:329
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
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:41
llvm::MemoryBufferRef
Definition: MemoryBufferRef.h:22
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
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:251
ELF.h
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:71
G
const DataFlowGraph & G
Definition: RDFGraph.cpp:200
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
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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:1861
llvm::AArch64CC::GE
@ GE
Definition: AArch64BaseInfo.h:265
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
uint32_t
ELF_i386.h
ELFObjectFile.h
std
Definition: BitVector.h:851
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:79
llvm::None
constexpr std::nullopt_t None
Definition: None.h:27
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:155
llvm::ELF::SHT_RELA
@ SHT_RELA
Definition: ELF.h:983
llvm::MemoryBufferRef::getBufferIdentifier
StringRef getBufferIdentifier() const
Definition: MemoryBufferRef.h:33
ELFLinkGraphBuilder.h
llvm::object::ELFFile
Definition: ELF.h:95
JITLinkGeneric.h
i386.h
llvm::sampleprof::Base
@ Base
Definition: Discriminator.h:58
Shdr
Elf_Shdr Shdr
Definition: ELFObjHandler.cpp:78