COFF_x86_64.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. //===----- COFF_x86_64.cpp - JIT linker implementation for COFF/x86_64 ----===//
  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. // COFF/x86_64 jit-link implementation.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "llvm/ExecutionEngine/JITLink/COFF_x86_64.h"
  13. #include "COFFLinkGraphBuilder.h"
  14. #include "JITLinkGeneric.h"
  15. #include "SEHFrameSupport.h"
  16. #include "llvm/BinaryFormat/COFF.h"
  17. #include "llvm/ExecutionEngine/JITLink/x86_64.h"
  18. #include "llvm/Object/COFF.h"
  19. #include "llvm/Support/Endian.h"
  20. #define DEBUG_TYPE "jitlink"
  21. using namespace llvm;
  22. using namespace llvm::jitlink;
  23. namespace {
  24. enum EdgeKind_coff_x86_64 : Edge::Kind {
  25. PCRel32 = x86_64::FirstPlatformRelocation,
  26. Pointer32NB,
  27. Pointer64,
  28. SectionIdx16,
  29. SecRel32,
  30. };
  31. class COFFJITLinker_x86_64 : public JITLinker<COFFJITLinker_x86_64> {
  32. friend class JITLinker<COFFJITLinker_x86_64>;
  33. public:
  34. COFFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
  35. std::unique_ptr<LinkGraph> G,
  36. PassConfiguration PassConfig)
  37. : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
  38. private:
  39. Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
  40. return x86_64::applyFixup(G, B, E, nullptr);
  41. }
  42. };
  43. class COFFLinkGraphBuilder_x86_64 : public COFFLinkGraphBuilder {
  44. private:
  45. Error addRelocations() override {
  46. LLVM_DEBUG(dbgs() << "Processing relocations:\n");
  47. for (const auto &RelSect : sections())
  48. if (Error Err = COFFLinkGraphBuilder::forEachRelocation(
  49. RelSect, this, &COFFLinkGraphBuilder_x86_64::addSingleRelocation))
  50. return Err;
  51. return Error::success();
  52. }
  53. Error addSingleRelocation(const object::RelocationRef &Rel,
  54. const object::SectionRef &FixupSect,
  55. Block &BlockToFix) {
  56. const object::coff_relocation *COFFRel = getObject().getCOFFRelocation(Rel);
  57. auto SymbolIt = Rel.getSymbol();
  58. if (SymbolIt == getObject().symbol_end()) {
  59. return make_error<StringError>(
  60. formatv("Invalid symbol index in relocation entry. "
  61. "index: {0}, section: {1}",
  62. COFFRel->SymbolTableIndex, FixupSect.getIndex()),
  63. inconvertibleErrorCode());
  64. }
  65. object::COFFSymbolRef COFFSymbol = getObject().getCOFFSymbol(*SymbolIt);
  66. COFFSymbolIndex SymIndex = getObject().getSymbolIndex(COFFSymbol);
  67. Symbol *GraphSymbol = getGraphSymbol(SymIndex);
  68. if (!GraphSymbol)
  69. return make_error<StringError>(
  70. formatv("Could not find symbol at given index, did you add it to "
  71. "JITSymbolTable? index: {0}, section: {1}",
  72. SymIndex, FixupSect.getIndex()),
  73. inconvertibleErrorCode());
  74. int64_t Addend = 0;
  75. orc::ExecutorAddr FixupAddress =
  76. orc::ExecutorAddr(FixupSect.getAddress()) + Rel.getOffset();
  77. Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();
  78. Edge::Kind Kind = Edge::Invalid;
  79. const char *FixupPtr = BlockToFix.getContent().data() + Offset;
  80. switch (Rel.getType()) {
  81. case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR32NB: {
  82. Kind = EdgeKind_coff_x86_64::Pointer32NB;
  83. Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
  84. break;
  85. }
  86. case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32: {
  87. Kind = EdgeKind_coff_x86_64::PCRel32;
  88. Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
  89. break;
  90. }
  91. case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_1: {
  92. Kind = EdgeKind_coff_x86_64::PCRel32;
  93. Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
  94. Addend -= 1;
  95. break;
  96. }
  97. case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_2: {
  98. Kind = EdgeKind_coff_x86_64::PCRel32;
  99. Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
  100. Addend -= 2;
  101. break;
  102. }
  103. case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_3: {
  104. Kind = EdgeKind_coff_x86_64::PCRel32;
  105. Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
  106. Addend -= 3;
  107. break;
  108. }
  109. case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_4: {
  110. Kind = EdgeKind_coff_x86_64::PCRel32;
  111. Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
  112. Addend -= 4;
  113. break;
  114. }
  115. case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32_5: {
  116. Kind = EdgeKind_coff_x86_64::PCRel32;
  117. Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
  118. Addend -= 5;
  119. break;
  120. }
  121. case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR64: {
  122. Kind = EdgeKind_coff_x86_64::Pointer64;
  123. Addend = *reinterpret_cast<const support::little64_t *>(FixupPtr);
  124. break;
  125. }
  126. case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECTION: {
  127. Kind = EdgeKind_coff_x86_64::SectionIdx16;
  128. Addend = *reinterpret_cast<const support::little16_t *>(FixupPtr);
  129. uint64_t SectionIdx = 0;
  130. if (COFFSymbol.isAbsolute())
  131. SectionIdx = getObject().getNumberOfSections() + 1;
  132. else
  133. SectionIdx = COFFSymbol.getSectionNumber();
  134. auto *AbsSym = &getGraph().addAbsoluteSymbol(
  135. "secidx", orc::ExecutorAddr(SectionIdx), 2, Linkage::Strong,
  136. Scope::Local, false);
  137. GraphSymbol = AbsSym;
  138. break;
  139. }
  140. case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_SECREL: {
  141. // FIXME: SECREL to external symbol should be handled
  142. if (!GraphSymbol->isDefined())
  143. return Error::success();
  144. Kind = EdgeKind_coff_x86_64::SecRel32;
  145. Addend = *reinterpret_cast<const support::little32_t *>(FixupPtr);
  146. break;
  147. }
  148. default: {
  149. return make_error<JITLinkError>("Unsupported x86_64 relocation:" +
  150. formatv("{0:d}", Rel.getType()));
  151. }
  152. };
  153. Edge GE(Kind, Offset, *GraphSymbol, Addend);
  154. LLVM_DEBUG({
  155. dbgs() << " ";
  156. printEdge(dbgs(), BlockToFix, GE, getCOFFX86RelocationKindName(Kind));
  157. dbgs() << "\n";
  158. });
  159. BlockToFix.addEdge(std::move(GE));
  160. return Error::success();
  161. }
  162. public:
  163. COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile &Obj, const Triple T)
  164. : COFFLinkGraphBuilder(Obj, std::move(T), getCOFFX86RelocationKindName) {}
  165. };
  166. class COFFLinkGraphLowering_x86_64 {
  167. public:
  168. // Lowers COFF x86_64 specific edges to generic x86_64 edges.
  169. Error lowerCOFFRelocationEdges(LinkGraph &G, JITLinkContext &Ctx) {
  170. for (auto *B : G.blocks()) {
  171. for (auto &E : B->edges()) {
  172. switch (E.getKind()) {
  173. case EdgeKind_coff_x86_64::Pointer32NB: {
  174. auto ImageBase = getImageBaseAddress(G, Ctx);
  175. if (!ImageBase)
  176. return ImageBase.takeError();
  177. E.setAddend(E.getAddend() - *ImageBase);
  178. E.setKind(x86_64::Pointer32);
  179. break;
  180. }
  181. case EdgeKind_coff_x86_64::PCRel32: {
  182. E.setKind(x86_64::PCRel32);
  183. break;
  184. }
  185. case EdgeKind_coff_x86_64::Pointer64: {
  186. E.setKind(x86_64::Pointer64);
  187. break;
  188. }
  189. case EdgeKind_coff_x86_64::SectionIdx16: {
  190. E.setKind(x86_64::Pointer16);
  191. break;
  192. }
  193. case EdgeKind_coff_x86_64::SecRel32: {
  194. E.setAddend(E.getAddend() -
  195. getSectionStart(E.getTarget().getBlock().getSection())
  196. .getValue());
  197. E.setKind(x86_64::Pointer32);
  198. break;
  199. }
  200. default:
  201. break;
  202. }
  203. }
  204. }
  205. return Error::success();
  206. }
  207. private:
  208. static StringRef getImageBaseSymbolName() { return "__ImageBase"; }
  209. orc::ExecutorAddr getSectionStart(Section &Sec) {
  210. if (!SectionStartCache.count(&Sec)) {
  211. SectionRange Range(Sec);
  212. SectionStartCache[&Sec] = Range.getStart();
  213. }
  214. return SectionStartCache[&Sec];
  215. }
  216. Expected<JITTargetAddress> getImageBaseAddress(LinkGraph &G,
  217. JITLinkContext &Ctx) {
  218. if (this->ImageBase)
  219. return this->ImageBase;
  220. for (auto *S : G.defined_symbols())
  221. if (S->getName() == getImageBaseSymbolName()) {
  222. this->ImageBase = S->getAddress().getValue();
  223. return this->ImageBase;
  224. }
  225. JITLinkContext::LookupMap Symbols;
  226. Symbols[getImageBaseSymbolName()] = SymbolLookupFlags::RequiredSymbol;
  227. JITTargetAddress ImageBase;
  228. Error Err = Error::success();
  229. Ctx.lookup(Symbols,
  230. createLookupContinuation([&](Expected<AsyncLookupResult> LR) {
  231. ErrorAsOutParameter EAO(&Err);
  232. if (!LR) {
  233. Err = LR.takeError();
  234. return;
  235. }
  236. auto &ImageBaseSymbol = LR->begin()->second;
  237. ImageBase = ImageBaseSymbol.getAddress();
  238. }));
  239. if (Err)
  240. return std::move(Err);
  241. this->ImageBase = ImageBase;
  242. return ImageBase;
  243. }
  244. DenseMap<Section *, orc::ExecutorAddr> SectionStartCache;
  245. JITTargetAddress ImageBase = 0;
  246. };
  247. Error lowerEdges_COFF_x86_64(LinkGraph &G, JITLinkContext *Ctx) {
  248. LLVM_DEBUG(dbgs() << "Lowering COFF x86_64 edges:\n");
  249. COFFLinkGraphLowering_x86_64 GraphLowering;
  250. if (auto Err = GraphLowering.lowerCOFFRelocationEdges(G, *Ctx))
  251. return Err;
  252. return Error::success();
  253. }
  254. } // namespace
  255. namespace llvm {
  256. namespace jitlink {
  257. /// Return the string name of the given COFF x86_64 edge kind.
  258. const char *getCOFFX86RelocationKindName(Edge::Kind R) {
  259. switch (R) {
  260. case PCRel32:
  261. return "PCRel32";
  262. case Pointer32NB:
  263. return "Pointer32NB";
  264. case Pointer64:
  265. return "Pointer64";
  266. case SectionIdx16:
  267. return "SectionIdx16";
  268. case SecRel32:
  269. return "SecRel32";
  270. default:
  271. return x86_64::getEdgeKindName(R);
  272. }
  273. }
  274. Expected<std::unique_ptr<LinkGraph>>
  275. createLinkGraphFromCOFFObject_x86_64(MemoryBufferRef ObjectBuffer) {
  276. LLVM_DEBUG({
  277. dbgs() << "Building jitlink graph for new input "
  278. << ObjectBuffer.getBufferIdentifier() << "...\n";
  279. });
  280. auto COFFObj = object::ObjectFile::createCOFFObjectFile(ObjectBuffer);
  281. if (!COFFObj)
  282. return COFFObj.takeError();
  283. return COFFLinkGraphBuilder_x86_64(**COFFObj, (*COFFObj)->makeTriple())
  284. .buildGraph();
  285. }
  286. void link_COFF_x86_64(std::unique_ptr<LinkGraph> G,
  287. std::unique_ptr<JITLinkContext> Ctx) {
  288. PassConfiguration Config;
  289. const Triple &TT = G->getTargetTriple();
  290. if (Ctx->shouldAddDefaultTargetPasses(TT)) {
  291. // Add a mark-live pass.
  292. if (auto MarkLive = Ctx->getMarkLivePass(TT)) {
  293. Config.PrePrunePasses.push_back(std::move(MarkLive));
  294. Config.PrePrunePasses.push_back(SEHFrameKeepAlivePass(".pdata"));
  295. } else
  296. Config.PrePrunePasses.push_back(markAllSymbolsLive);
  297. // Add COFF edge lowering passes.
  298. JITLinkContext *CtxPtr = Ctx.get();
  299. Config.PreFixupPasses.push_back(
  300. [CtxPtr](LinkGraph &G) { return lowerEdges_COFF_x86_64(G, CtxPtr); });
  301. }
  302. if (auto Err = Ctx->modifyPassConfig(*G, Config))
  303. return Ctx->notifyFailed(std::move(Err));
  304. COFFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
  305. }
  306. } // namespace jitlink
  307. } // namespace llvm