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  JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
45  switch (E.getKind()) {
47  assert((FixupAddress & 0x3) == 0 && "Call-inst is not 32-bit aligned");
48  int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
49 
50  if (static_cast<uint64_t>(Value) & 0x3)
51  return make_error<JITLinkError>("Call target is not 32-bit aligned");
52 
53  if (!fitsRangeSignedInt<27>(Value))
54  return makeTargetOutOfRangeError(G, B, E);
55 
56  uint32_t RawInstr = *(little32_t *)FixupPtr;
57  assert((RawInstr & 0x7fffffff) == 0x14000000 &&
58  "RawInstr isn't a B or BR immediate instruction");
59  uint32_t Imm = (static_cast<uint32_t>(Value) & ((1 << 28) - 1)) >> 2;
60  uint32_t FixedInstr = RawInstr | Imm;
61  *(little32_t *)FixupPtr = FixedInstr;
62  break;
63  }
64  }
65  return Error::success();
66  }
67 
68  template <uint8_t Bits> static bool fitsRangeSignedInt(int64_t Value) {
69  return Value >= -(1ll << Bits) && Value < (1ll << Bits);
70  }
71 };
72 
73 template <typename ELFT>
75 private:
77  getRelocationKind(const uint32_t Type) {
78  using namespace aarch64;
79  switch (Type) {
82  }
83 
84  return make_error<JITLinkError>("Unsupported aarch64 relocation:" +
85  formatv("{0:d}", Type));
86  }
87 
88  Error addRelocations() override {
89  LLVM_DEBUG(dbgs() << "Processing relocations:\n");
90 
93  for (const auto &RelSect : Base::Sections)
94  if (Error Err = Base::forEachRelocation(RelSect, this,
95  &Self::addSingleRelocation))
96  return Err;
97 
98  return Error::success();
99  }
100 
101  Error addSingleRelocation(const typename ELFT::Rela &Rel,
102  const typename ELFT::Shdr &FixupSect,
103  Section &GraphSection) {
105 
106  uint32_t SymbolIndex = Rel.getSymbol(false);
107  auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
108  if (!ObjSymbol)
109  return ObjSymbol.takeError();
110 
111  Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
112  if (!GraphSymbol)
113  return make_error<StringError>(
114  formatv("Could not find symbol at given index, did you add it to "
115  "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
116  SymbolIndex, (*ObjSymbol)->st_shndx,
117  Base::GraphSymbols.size()),
119 
120  uint32_t Type = Rel.getType(false);
121  Expected<aarch64::EdgeKind_aarch64> Kind = getRelocationKind(Type);
122  if (!Kind)
123  return Kind.takeError();
124 
125  int64_t Addend = Rel.r_addend;
126  Block *BlockToFix = *(GraphSection.blocks().begin());
127  JITTargetAddress FixupAddress = FixupSect.sh_addr + Rel.r_offset;
128  Edge::OffsetT Offset = FixupAddress - BlockToFix->getAddress();
129  Edge GE(*Kind, Offset, *GraphSymbol, Addend);
130  LLVM_DEBUG({
131  dbgs() << " ";
132  printEdge(dbgs(), *BlockToFix, GE, aarch64::getEdgeKindName(*Kind));
133  dbgs() << "\n";
134  });
135 
136  BlockToFix->addEdge(std::move(GE));
137  return Error::success();
138  }
139 
140 public:
142  const object::ELFFile<ELFT> &Obj, const Triple T)
143  : ELFLinkGraphBuilder<ELFT>(Obj, std::move(T), FileName,
144  aarch64::getEdgeKindName) {}
145 };
146 
149  LLVM_DEBUG({
150  dbgs() << "Building jitlink graph for new input "
151  << ObjectBuffer.getBufferIdentifier() << "...\n";
152  });
153 
154  auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
155  if (!ELFObj)
156  return ELFObj.takeError();
157 
158  assert((*ELFObj)->getArch() == Triple::aarch64 &&
159  "Only AArch64 (little endian) is supported for now");
160 
161  auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
162  return ELFLinkGraphBuilder_aarch64<object::ELF64LE>((*ELFObj)->getFileName(),
163  ELFObjFile.getELFFile(),
164  (*ELFObj)->makeTriple())
165  .buildGraph();
166 }
167 
168 void link_ELF_aarch64(std::unique_ptr<LinkGraph> G,
169  std::unique_ptr<JITLinkContext> Ctx) {
170  PassConfiguration Config;
171  const Triple &TT = G->getTargetTriple();
172  if (Ctx->shouldAddDefaultTargetPasses(TT)) {
173  if (auto MarkLive = Ctx->getMarkLivePass(TT))
174  Config.PrePrunePasses.push_back(std::move(MarkLive));
175  else
176  Config.PrePrunePasses.push_back(markAllSymbolsLive);
177  }
178  if (auto Err = Ctx->modifyPassConfig(*G, Config))
179  return Ctx->notifyFailed(std::move(Err));
180 
182 }
183 
184 } // namespace jitlink
185 } // namespace llvm
llvm
This file implements support for optimizing divisions by a constant.
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:331
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
llvm::tgtok::Bits
@ Bits
Definition: TGLexer.h:50
aarch64.h
Offset
uint64_t Offset
Definition: ELFObjHandler.cpp:81
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:250
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:1609
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:58
uint32_t
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
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:52
JITLinkGeneric.h
llvm::sampleprof::Base
@ Base
Definition: Discriminator.h:58
Shdr
Elf_Shdr Shdr
Definition: ELFObjHandler.cpp:79