ELF_aarch64.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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. #include "llvm/ExecutionEngine/JITLink/ELF_aarch64.h"
  13. #include "ELFLinkGraphBuilder.h"
  14. #include "JITLinkGeneric.h"
  15. #include "llvm/BinaryFormat/ELF.h"
  16. #include "llvm/ExecutionEngine/JITLink/aarch64.h"
  17. #include "llvm/Object/ELFObjectFile.h"
  18. #include "llvm/Support/MathExtras.h"
  19. #define DEBUG_TYPE "jitlink"
  20. using namespace llvm;
  21. using namespace llvm::jitlink;
  22. namespace llvm {
  23. namespace jitlink {
  24. class ELFJITLinker_aarch64 : public JITLinker<ELFJITLinker_aarch64> {
  25. friend class JITLinker<ELFJITLinker_aarch64>;
  26. public:
  27. ELFJITLinker_aarch64(std::unique_ptr<JITLinkContext> Ctx,
  28. std::unique_ptr<LinkGraph> G,
  29. PassConfiguration PassConfig)
  30. : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
  31. private:
  32. Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
  33. using namespace aarch64;
  34. using namespace llvm::support;
  35. char *BlockWorkingMem = B.getAlreadyMutableContent().data();
  36. char *FixupPtr = BlockWorkingMem + E.getOffset();
  37. auto FixupAddress = B.getAddress() + E.getOffset();
  38. switch (E.getKind()) {
  39. case aarch64::R_AARCH64_CALL26: {
  40. assert((FixupAddress.getValue() & 0x3) == 0 &&
  41. "Call-inst is not 32-bit aligned");
  42. int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
  43. if (static_cast<uint64_t>(Value) & 0x3)
  44. return make_error<JITLinkError>("Call target is not 32-bit aligned");
  45. if (!isInt<28>(Value))
  46. return makeTargetOutOfRangeError(G, B, E);
  47. uint32_t RawInstr = *(little32_t *)FixupPtr;
  48. assert((RawInstr & 0x7fffffff) == 0x14000000 &&
  49. "RawInstr isn't a B or BR immediate instruction");
  50. uint32_t Imm = (static_cast<uint32_t>(Value) & ((1 << 28) - 1)) >> 2;
  51. uint32_t FixedInstr = RawInstr | Imm;
  52. *(little32_t *)FixupPtr = FixedInstr;
  53. break;
  54. }
  55. }
  56. return Error::success();
  57. }
  58. };
  59. template <typename ELFT>
  60. class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> {
  61. private:
  62. static Expected<aarch64::EdgeKind_aarch64>
  63. getRelocationKind(const uint32_t Type) {
  64. using namespace aarch64;
  65. switch (Type) {
  66. case ELF::R_AARCH64_CALL26:
  67. return EdgeKind_aarch64::R_AARCH64_CALL26;
  68. }
  69. return make_error<JITLinkError>("Unsupported aarch64 relocation:" +
  70. formatv("{0:d}", Type));
  71. }
  72. Error addRelocations() override {
  73. LLVM_DEBUG(dbgs() << "Processing relocations:\n");
  74. using Base = ELFLinkGraphBuilder<ELFT>;
  75. using Self = ELFLinkGraphBuilder_aarch64<ELFT>;
  76. for (const auto &RelSect : Base::Sections)
  77. if (Error Err = Base::forEachRelocation(RelSect, this,
  78. &Self::addSingleRelocation))
  79. return Err;
  80. return Error::success();
  81. }
  82. Error addSingleRelocation(const typename ELFT::Rela &Rel,
  83. const typename ELFT::Shdr &FixupSect,
  84. Block &BlockToFix) {
  85. using Base = ELFLinkGraphBuilder<ELFT>;
  86. uint32_t SymbolIndex = Rel.getSymbol(false);
  87. auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);
  88. if (!ObjSymbol)
  89. return ObjSymbol.takeError();
  90. Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);
  91. if (!GraphSymbol)
  92. return make_error<StringError>(
  93. formatv("Could not find symbol at given index, did you add it to "
  94. "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",
  95. SymbolIndex, (*ObjSymbol)->st_shndx,
  96. Base::GraphSymbols.size()),
  97. inconvertibleErrorCode());
  98. uint32_t Type = Rel.getType(false);
  99. Expected<aarch64::EdgeKind_aarch64> Kind = getRelocationKind(Type);
  100. if (!Kind)
  101. return Kind.takeError();
  102. int64_t Addend = Rel.r_addend;
  103. orc::ExecutorAddr FixupAddress =
  104. orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset;
  105. Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
  106. Edge GE(*Kind, Offset, *GraphSymbol, Addend);
  107. LLVM_DEBUG({
  108. dbgs() << " ";
  109. printEdge(dbgs(), BlockToFix, GE, aarch64::getEdgeKindName(*Kind));
  110. dbgs() << "\n";
  111. });
  112. BlockToFix.addEdge(std::move(GE));
  113. return Error::success();
  114. }
  115. public:
  116. ELFLinkGraphBuilder_aarch64(StringRef FileName,
  117. const object::ELFFile<ELFT> &Obj, const Triple T)
  118. : ELFLinkGraphBuilder<ELFT>(Obj, std::move(T), FileName,
  119. aarch64::getEdgeKindName) {}
  120. };
  121. Expected<std::unique_ptr<LinkGraph>>
  122. createLinkGraphFromELFObject_aarch64(MemoryBufferRef ObjectBuffer) {
  123. LLVM_DEBUG({
  124. dbgs() << "Building jitlink graph for new input "
  125. << ObjectBuffer.getBufferIdentifier() << "...\n";
  126. });
  127. auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
  128. if (!ELFObj)
  129. return ELFObj.takeError();
  130. assert((*ELFObj)->getArch() == Triple::aarch64 &&
  131. "Only AArch64 (little endian) is supported for now");
  132. auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
  133. return ELFLinkGraphBuilder_aarch64<object::ELF64LE>((*ELFObj)->getFileName(),
  134. ELFObjFile.getELFFile(),
  135. (*ELFObj)->makeTriple())
  136. .buildGraph();
  137. }
  138. void link_ELF_aarch64(std::unique_ptr<LinkGraph> G,
  139. std::unique_ptr<JITLinkContext> Ctx) {
  140. PassConfiguration Config;
  141. const Triple &TT = G->getTargetTriple();
  142. if (Ctx->shouldAddDefaultTargetPasses(TT)) {
  143. if (auto MarkLive = Ctx->getMarkLivePass(TT))
  144. Config.PrePrunePasses.push_back(std::move(MarkLive));
  145. else
  146. Config.PrePrunePasses.push_back(markAllSymbolsLive);
  147. }
  148. if (auto Err = Ctx->modifyPassConfig(*G, Config))
  149. return Ctx->notifyFailed(std::move(Err));
  150. ELFJITLinker_aarch64::link(std::move(Ctx), std::move(G), std::move(Config));
  151. }
  152. } // namespace jitlink
  153. } // namespace llvm