LLVM  14.0.0git
ELF_aarch64.cpp
Go to the documentation of this file.
1 //===----- ELF_aarch64.cpp - JIT linker implementation for ELF/aarch64 ----===//
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/aarch64 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 {
26 namespace jitlink {
27 
28 class ELFJITLinker_aarch64 : public JITLinker<ELFJITLinker_aarch64> {
30 
31 public:
32  ELFJITLinker_aarch64(std::unique_ptr<JITLinkContext> Ctx,
33  std::unique_ptr<LinkGraph> G,
34  PassConfiguration PassConfig)
35  : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
36 
37 private:
38  Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
39  using namespace aarch64;
40  using namespace llvm::support;
41 
42  char *BlockWorkingMem = B.getAlreadyMutableContent().data();
43  char *FixupPtr = BlockWorkingMem + E.getOffset();
44  auto FixupAddress = B.getAddress() + E.getOffset();
45  switch (E.getKind()) {
47  assert((FixupAddress.getValue() & 0x3) == 0 &&
48  "Call-inst is not 32-bit aligned");
49  int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
50 
51  if (static_cast<uint64_t>(Value) & 0x3)
52  return make_error<JITLinkError>("Call target is not 32-bit aligned");
53 
54  if (!fitsRangeSignedInt<27>(Value))
55  return makeTargetOutOfRangeError(G, B, E);
56 
57  uint32_t RawInstr = *(little32_t *)FixupPtr;
58  assert((RawInstr & 0x7fffffff) == 0x14000000 &&
59  "RawInstr isn't a B or BR immediate instruction");
60  uint32_t Imm = (static_cast<uint32_t>(Value) & ((1 << 28) - 1)) >> 2;
61  uint32_t FixedInstr = RawInstr | Imm;
62  *(little32_t *)FixupPtr = FixedInstr;
63  break;
64  }
65  }
66  return Error::success();
67  }
68 
69  template <uint8_t Bits> static bool fitsRangeSignedInt(int64_t Value) {
70  return Value >= -(1ll << Bits) && Value < (1ll << Bits);
71  }
72 };
73 
74 template <typename ELFT>
76 private:
78  getRelocationKind(const uint32_t Type) {
79  using namespace aarch64;
80  switch (Type) {
83  }
84 
85  return make_error<JITLinkError>("Unsupported aarch64 relocation:" +
86  formatv("{0:d}", Type));
87  }
88 
89  Error addRelocations() override {
90  LLVM_DEBUG(dbgs() << "Processing relocations:\n");
91 
94  for (const auto &RelSect : Base::Sections)
95  if (Error Err = Base::forEachRelocation(RelSect, this,
96  &Self::addSingleRelocation))
97  return Err;
98 
99  return Error::success();
100  }
101 
102  Error addSingleRelocation(const typename ELFT::Rela &Rel,
103  const typename ELFT::Shdr &FixupSect,
104  Block &BlockToFix) {
106 
107  uint32_t SymbolIndex = Rel.getSymbol(false);
108  auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
109  if (!ObjSymbol)
110  return ObjSymbol.takeError();
111 
112  Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
113  if (!GraphSymbol)
114  return make_error<StringError>(
115  formatv("Could not find symbol at given index, did you add it to "
116  "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
117  SymbolIndex, (*ObjSymbol)->st_shndx,
118  Base::GraphSymbols.size()),
120 
121  uint32_t Type = Rel.getType(false);
122  Expected<aarch64::EdgeKind_aarch64> Kind = getRelocationKind(Type);
123  if (!Kind)
124  return Kind.takeError();
125 
126  int64_t Addend = Rel.r_addend;
127  orc::ExecutorAddr FixupAddress =
128  orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
129  Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
130  Edge GE(*Kind, Offset, *GraphSymbol, Addend);
131  LLVM_DEBUG({
132  dbgs() << " ";
133  printEdge(dbgs(), BlockToFix, GE, aarch64::getEdgeKindName(*Kind));
134  dbgs() << "\n";
135  });
136 
137  BlockToFix.addEdge(std::move(GE));
138  return Error::success();
139  }
140 
141 public:
143  const object::ELFFile<ELFT> &Obj, const Triple T)
144  : ELFLinkGraphBuilder<ELFT>(Obj, std::move(T), FileName,
145  aarch64::getEdgeKindName) {}
146 };
147 
150  LLVM_DEBUG({
151  dbgs() << "Building jitlink graph for new input "
152  << ObjectBuffer.getBufferIdentifier() << "...\n";
153  });
154 
155  auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
156  if (!ELFObj)
157  return ELFObj.takeError();
158 
159  assert((*ELFObj)->getArch() == Triple::aarch64 &&
160  "Only AArch64 (little endian) is supported for now");
161 
162  auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
163  return ELFLinkGraphBuilder_aarch64<object::ELF64LE>((*ELFObj)->getFileName(),
164  ELFObjFile.getELFFile(),
165  (*ELFObj)->makeTriple())
166  .buildGraph();
167 }
168 
169 void link_ELF_aarch64(std::unique_ptr<LinkGraph> G,
170  std::unique_ptr<JITLinkContext> Ctx) {
171  PassConfiguration Config;
172  const Triple &TT = G->getTargetTriple();
173  if (Ctx->shouldAddDefaultTargetPasses(TT)) {
174  if (auto MarkLive = Ctx->getMarkLivePass(TT))
175  Config.PrePrunePasses.push_back(std::move(MarkLive));
176  else
177  Config.PrePrunePasses.push_back(markAllSymbolsLive);
178  }
179  if (auto Err = Ctx->modifyPassConfig(*G, Config))
180  return Ctx->notifyFailed(std::move(Err));
181 
183 }
184 
185 } // namespace jitlink
186 } // namespace llvm
llvm::orc::ExecutorAddr
Represents an address in the executor process.
Definition: ExecutorAddress.h:30
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AllocatorList.h:23
llvm::support::detail::packed_endian_specific_integral
Definition: Endian.h:206
T
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:330
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::tgtok::Bits
@ Bits
Definition: TGLexer.h:50
aarch64.h
Offset
uint64_t Offset
Definition: ELFObjHandler.cpp:80
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
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
x3
In x86 we generate this spiffy xmm0 xmm0 ret in x86 we generate this which could be xmm1 movss xmm1 xmm0 ret In sse4 we could use insertps to make both better Here s another testcase that could use x3
Definition: README-SSE.txt:547
ELF.h
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
B
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
ll
Analysis the ScalarEvolution expression for r is< loop > Outside the this could be evaluated simply however ScalarEvolution currently evaluates it it involves i65 which is very inefficient when expanded into code In formatValue in test CodeGen X86 lsr delayed fold ll
Definition: README.txt:20
llvm::object::ObjectFile::createELFObjectFile
static Expected< std::unique_ptr< ObjectFile > > createELFObjectFile(MemoryBufferRef Object, bool InitContent=true)
Definition: ELFObjectFile.cpp:72
llvm::lltok::Kind
Kind
Definition: LLToken.h:18
G
const DataFlowGraph & G
Definition: RDFGraph.cpp:202
uint64_t
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:1707
ELF_aarch64.h
llvm::AArch64CC::GE
@ GE
Definition: AArch64BaseInfo.h:265
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:57
uint32_t
ELFObjectFile.h
std
Definition: BitVector.h:850
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:156
llvm::support
Definition: Endian.h:25
llvm::TargetStackID::Value
Value
Definition: TargetFrameLowering.h:27
llvm::MemoryBufferRef::getBufferIdentifier
StringRef getBufferIdentifier() const
Definition: MemoryBufferRef.h:33
ELFLinkGraphBuilder.h
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
llvm::object::ELFFile
Definition: ELF.h:94
llvm::Triple::aarch64
@ aarch64
Definition: Triple.h:51
JITLinkGeneric.h
llvm::sampleprof::Base
@ Base
Definition: Discriminator.h:58
Shdr
Elf_Shdr Shdr
Definition: ELFObjHandler.cpp:78