1//===-- RuntimeDyldCOFF.cpp - Run-time dynamic linker for MC-JIT -*- C++ -*-==//
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// Implementation of COFF support for the MC-JIT runtime dynamic linker.
10//
11//===----------------------------------------------------------------------===//
12
13#include "RuntimeDyldCOFF.h"
14#include "Targets/RuntimeDyldCOFFAArch64.h"
15#include "Targets/RuntimeDyldCOFFI386.h"
16#include "Targets/RuntimeDyldCOFFThumb.h"
17#include "Targets/RuntimeDyldCOFFX86_64.h"
18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/Triple.h"
20#include "llvm/Object/ObjectFile.h"
21#include "llvm/Support/FormatVariadic.h"
22
23using namespace llvm;
24using namespace llvm::object;
25
26#define DEBUG_TYPE "dyld"
27
28namespace {
29
30class LoadedCOFFObjectInfo final
31    : public LoadedObjectInfoHelper<LoadedCOFFObjectInfo,
32                                    RuntimeDyld::LoadedObjectInfo> {
33public:
34  LoadedCOFFObjectInfo(
35      RuntimeDyldImpl &RTDyld,
36      RuntimeDyld::LoadedObjectInfo::ObjSectionToIDMap ObjSecToIDMap)
37      : LoadedObjectInfoHelper(RTDyld, std::move(ObjSecToIDMap)) {}
38
39  OwningBinary<ObjectFile>
40  getObjectForDebug(const ObjectFile &Obj) const override {
41    return OwningBinary<ObjectFile>();
42  }
43};
44}
45
46namespace llvm {
47
48std::unique_ptr<RuntimeDyldCOFF>
49llvm::RuntimeDyldCOFF::create(Triple::ArchType Arch,
50                              RuntimeDyld::MemoryManager &MemMgr,
51                              JITSymbolResolver &Resolver) {
52  switch (Arch) {
53  default: llvm_unreachable("Unsupported target for RuntimeDyldCOFF.");
54  case Triple::x86:
55    return std::make_unique<RuntimeDyldCOFFI386>(MemMgr, Resolver);
56  case Triple::thumb:
57    return std::make_unique<RuntimeDyldCOFFThumb>(MemMgr, Resolver);
58  case Triple::x86_64:
59    return std::make_unique<RuntimeDyldCOFFX86_64>(MemMgr, Resolver);
60  case Triple::aarch64:
61    return std::make_unique<RuntimeDyldCOFFAArch64>(MemMgr, Resolver);
62  }
63}
64
65std::unique_ptr<RuntimeDyld::LoadedObjectInfo>
66RuntimeDyldCOFF::loadObject(const object::ObjectFile &O) {
67  if (auto ObjSectionToIDOrErr = loadObjectImpl(O)) {
68    return std::make_unique<LoadedCOFFObjectInfo>(*this, *ObjSectionToIDOrErr);
69  } else {
70    HasError = true;
71    raw_string_ostream ErrStream(ErrorStr);
72    logAllUnhandledErrors(ObjSectionToIDOrErr.takeError(), ErrStream);
73    return nullptr;
74  }
75}
76
77uint64_t RuntimeDyldCOFF::getSymbolOffset(const SymbolRef &Sym) {
78  // The value in a relocatable COFF object is the offset.
79  return cantFail(Sym.getValue());
80}
81
82uint64_t RuntimeDyldCOFF::getDLLImportOffset(unsigned SectionID, StubMap &Stubs,
83                                             StringRef Name,
84                                             bool SetSectionIDMinus1) {
85  LLVM_DEBUG(dbgs() << "Getting DLLImport entry for " << Name << "... ");
86  assert(Name.startswith(getImportSymbolPrefix()) && "Not a DLLImport symbol?");
87  RelocationValueRef Reloc;
88  Reloc.SymbolName = Name.data();
89  auto I = Stubs.find(Reloc);
90  if (I != Stubs.end()) {
91    LLVM_DEBUG(dbgs() << format("{0:x8}", I->second) << "\n");
92    return I->second;
93  }
94
95  assert(SectionID < Sections.size() && "SectionID out of range");
96  auto &Sec = Sections[SectionID];
97  auto EntryOffset = alignTo(Sec.getStubOffset(), PointerSize);
98  Sec.advanceStubOffset(EntryOffset + PointerSize - Sec.getStubOffset());
99  Stubs[Reloc] = EntryOffset;
100
101  RelocationEntry RE(SectionID, EntryOffset, PointerReloc, 0, false,
102                     Log2_64(PointerSize));
103  // Hack to tell I386/Thumb resolveRelocation that this isn't section relative.
104  if (SetSectionIDMinus1)
105    RE.Sections.SectionA = -1;
106  addRelocationForSymbol(RE, Name.drop_front(getImportSymbolPrefix().size()));
107
108  LLVM_DEBUG({
109    dbgs() << "Creating entry at "
110           << formatv("{0:x16} + {1:x8} ( {2:x16} )", Sec.getLoadAddress(),
111                      EntryOffset, Sec.getLoadAddress() + EntryOffset)
112           << "\n";
113  });
114  return EntryOffset;
115}
116
117bool RuntimeDyldCOFF::isCompatibleFile(const object::ObjectFile &Obj) const {
118  return Obj.isCOFF();
119}
120
121} // namespace llvm
122