LLVM  15.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"
20 
21 #define DEBUG_TYPE "jitlink"
22 
23 using namespace llvm;
24 using namespace llvm::jitlink;
25 
26 namespace llvm {
27 namespace jitlink {
28 
29 class ELFJITLinker_aarch64 : public JITLinker<ELFJITLinker_aarch64> {
31 
32 public:
33  ELFJITLinker_aarch64(std::unique_ptr<JITLinkContext> Ctx,
34  std::unique_ptr<LinkGraph> G,
35  PassConfiguration PassConfig)
36  : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
37 
38 private:
39  Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
40  using namespace aarch64;
41  using namespace llvm::support;
42 
43  char *BlockWorkingMem = B.getAlreadyMutableContent().data();
44  char *FixupPtr = BlockWorkingMem + E.getOffset();
45  auto FixupAddress = B.getAddress() + E.getOffset();
46  switch (E.getKind()) {
48  assert((FixupAddress.getValue() & 0x3) == 0 &&
49  "Call-inst is not 32-bit aligned");
50  int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
51 
52  if (static_cast<uint64_t>(Value) & 0x3)
53  return make_error<JITLinkError>("Call target is not 32-bit aligned");
54 
55  if (!isInt<28>(Value))
56  return makeTargetOutOfRangeError(G, B, E);
57 
58  uint32_t RawInstr = *(little32_t *)FixupPtr;
59  assert((RawInstr & 0x7fffffff) == 0x14000000 &&
60  "RawInstr isn't a B or BR immediate instruction");
61  uint32_t Imm = (static_cast<uint32_t>(Value) & ((1 << 28) - 1)) >> 2;
62  uint32_t FixedInstr = RawInstr | Imm;
63  *(little32_t *)FixupPtr = FixedInstr;
64  break;
65  }
66  }
67  return Error::success();
68  }
69 };
70 
71 template <typename ELFT>
73 private:
75  getRelocationKind(const uint32_t Type) {
76  using namespace aarch64;
77  switch (Type) {
80  }
81 
82  return make_error<JITLinkError>("Unsupported aarch64 relocation:" +
83  formatv("{0:d}", Type));
84  }
85 
86  Error addRelocations() override {
87  LLVM_DEBUG(dbgs() << "Processing relocations:\n");
88 
91  for (const auto &RelSect : Base::Sections)
92  if (Error Err = Base::forEachRelocation(RelSect, this,
93  &Self::addSingleRelocation))
94  return Err;
95 
96  return Error::success();
97  }
98 
99  Error addSingleRelocation(const typename ELFT::Rela &Rel,
100  const typename ELFT::Shdr &FixupSect,
101  Block &BlockToFix) {
103 
104  uint32_t SymbolIndex = Rel.getSymbol(false);
105  auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
106  if (!ObjSymbol)
107  return ObjSymbol.takeError();
108 
109  Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
110  if (!GraphSymbol)
111  return make_error<StringError>(
112  formatv("Could not find symbol at given index, did you add it to "
113  "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
114  SymbolIndex, (*ObjSymbol)->st_shndx,
115  Base::GraphSymbols.size()),
117 
118  uint32_t Type = Rel.getType(false);
119  Expected<aarch64::EdgeKind_aarch64> Kind = getRelocationKind(Type);
120  if (!Kind)
121  return Kind.takeError();
122 
123  int64_t Addend = Rel.r_addend;
124  orc::ExecutorAddr FixupAddress =
125  orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
126  Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
127  Edge GE(*Kind, Offset, *GraphSymbol, Addend);
128  LLVM_DEBUG({
129  dbgs() << " ";
130  printEdge(dbgs(), BlockToFix, GE, aarch64::getEdgeKindName(*Kind));
131  dbgs() << "\n";
132  });
133 
134  BlockToFix.addEdge(std::move(GE));
135  return Error::success();
136  }
137 
138 public:
140  const object::ELFFile<ELFT> &Obj, const Triple T)
141  : ELFLinkGraphBuilder<ELFT>(Obj, std::move(T), FileName,
142  aarch64::getEdgeKindName) {}
143 };
144 
147  LLVM_DEBUG({
148  dbgs() << "Building jitlink graph for new input "
149  << ObjectBuffer.getBufferIdentifier() << "...\n";
150  });
151 
152  auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
153  if (!ELFObj)
154  return ELFObj.takeError();
155 
156  assert((*ELFObj)->getArch() == Triple::aarch64 &&
157  "Only AArch64 (little endian) is supported for now");
158 
159  auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
160  return ELFLinkGraphBuilder_aarch64<object::ELF64LE>((*ELFObj)->getFileName(),
161  ELFObjFile.getELFFile(),
162  (*ELFObj)->makeTriple())
163  .buildGraph();
164 }
165 
166 void link_ELF_aarch64(std::unique_ptr<LinkGraph> G,
167  std::unique_ptr<JITLinkContext> Ctx) {
168  PassConfiguration Config;
169  const Triple &TT = G->getTargetTriple();
170  if (Ctx->shouldAddDefaultTargetPasses(TT)) {
171  if (auto MarkLive = Ctx->getMarkLivePass(TT))
172  Config.PrePrunePasses.push_back(std::move(MarkLive));
173  else
174  Config.PrePrunePasses.push_back(markAllSymbolsLive);
175  }
176  if (auto Err = Ctx->modifyPassConfig(*G, Config))
177  return Ctx->notifyFailed(std::move(Err));
178 
180 }
181 
182 } // namespace jitlink
183 } // namespace llvm
llvm::orc::ExecutorAddr
Represents an address in the executor process.
Definition: ExecutorAddress.h:30
MathExtras.h
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
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: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
aarch64.h
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
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")
llvm::object::ObjectFile::createELFObjectFile
static Expected< std::unique_ptr< ObjectFile > > createELFObjectFile(MemoryBufferRef Object, bool InitContent=true)
Definition: ELFObjectFile.cpp:70
llvm::lltok::Kind
Kind
Definition: LLToken.h:18
G
const DataFlowGraph & G
Definition: RDFGraph.cpp:200
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:1665
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: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:77
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:155
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:77