1283625Sdim//===-- RuntimeDyldCOFFX86_64.h --- COFF/X86_64 specific code ---*- C++ -*-===//
2283625Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6283625Sdim//
7283625Sdim//===----------------------------------------------------------------------===//
8283625Sdim//
9283625Sdim// COFF x86_x64 support for MC-JIT runtime dynamic linker.
10283625Sdim//
11283625Sdim//===----------------------------------------------------------------------===//
12283625Sdim
13283625Sdim#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFF86_64_H
14283625Sdim#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFF86_64_H
15283625Sdim
16321369Sdim#include "../RuntimeDyldCOFF.h"
17321369Sdim#include "llvm/BinaryFormat/COFF.h"
18283625Sdim#include "llvm/Object/COFF.h"
19283625Sdim
20283625Sdim#define DEBUG_TYPE "dyld"
21283625Sdim
22283625Sdimnamespace llvm {
23283625Sdim
24283625Sdimclass RuntimeDyldCOFFX86_64 : public RuntimeDyldCOFF {
25283625Sdim
26283625Sdimprivate:
27283625Sdim  // When a module is loaded we save the SectionID of the unwind
28283625Sdim  // sections in a table until we receive a request to register all
29283625Sdim  // unregisteredEH frame sections with the memory manager.
30283625Sdim  SmallVector<SID, 2> UnregisteredEHFrameSections;
31283625Sdim  SmallVector<SID, 2> RegisteredEHFrameSections;
32341825Sdim  uint64_t ImageBase;
33283625Sdim
34341825Sdim  // Fake an __ImageBase pointer by returning the section with the lowest adress
35341825Sdim  uint64_t getImageBase() {
36341825Sdim    if (!ImageBase) {
37341825Sdim      ImageBase = std::numeric_limits<uint64_t>::max();
38341825Sdim      for (const SectionEntry &Section : Sections)
39344779Sdim        // The Sections list may contain sections that weren't loaded for
40344779Sdim        // whatever reason: they may be debug sections, and ProcessAllSections
41344779Sdim        // is false, or they may be sections that contain 0 bytes. If the
42344779Sdim        // section isn't loaded, the load address will be 0, and it should not
43344779Sdim        // be included in the ImageBase calculation.
44344779Sdim        if (Section.getLoadAddress() != 0)
45344779Sdim          ImageBase = std::min(ImageBase, Section.getLoadAddress());
46341825Sdim    }
47341825Sdim    return ImageBase;
48341825Sdim  }
49341825Sdim
50341825Sdim  void write32BitOffset(uint8_t *Target, int64_t Addend, uint64_t Delta) {
51341825Sdim    uint64_t Result = Addend + Delta;
52341825Sdim    assert(Result <= UINT32_MAX && "Relocation overflow");
53341825Sdim    writeBytesUnaligned(Result, Target, 4);
54341825Sdim  }
55341825Sdim
56283625Sdimpublic:
57283625Sdim  RuntimeDyldCOFFX86_64(RuntimeDyld::MemoryManager &MM,
58314564Sdim                        JITSymbolResolver &Resolver)
59341825Sdim    : RuntimeDyldCOFF(MM, Resolver), ImageBase(0) {}
60283625Sdim
61341825Sdim  unsigned getStubAlignment() override { return 1; }
62283625Sdim
63341825Sdim  // 2-byte jmp instruction + 32-bit relative address + 64-bit absolute jump
64353358Sdim  unsigned getMaxStubSize() const override { return 14; }
65341825Sdim
66283625Sdim  // The target location for the relocation is described by RE.SectionID and
67283625Sdim  // RE.Offset.  RE.SectionID can be used to find the SectionEntry.  Each
68283625Sdim  // SectionEntry has three members describing its location.
69283625Sdim  // SectionEntry::Address is the address at which the section has been loaded
70283625Sdim  // into memory in the current (host) process.  SectionEntry::LoadAddress is
71283625Sdim  // the address that the section will have in the target process.
72283625Sdim  // SectionEntry::ObjAddress is the address of the bits for this section in the
73283625Sdim  // original emitted object image (also in the current address space).
74283625Sdim  //
75283625Sdim  // Relocations will be applied as if the section were loaded at
76283625Sdim  // SectionEntry::LoadAddress, but they will be applied at an address based
77283625Sdim  // on SectionEntry::Address.  SectionEntry::ObjAddress will be used to refer
78283625Sdim  // to Target memory contents if they are required for value calculations.
79283625Sdim  //
80283625Sdim  // The Value parameter here is the load address of the symbol for the
81283625Sdim  // relocation to be applied.  For relocations which refer to symbols in the
82283625Sdim  // current object Value will be the LoadAddress of the section in which
83283625Sdim  // the symbol resides (RE.Addend provides additional information about the
84283625Sdim  // symbol location).  For external symbols, Value will be the address of the
85283625Sdim  // symbol in the target address space.
86283625Sdim  void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
87283625Sdim    const SectionEntry &Section = Sections[RE.SectionID];
88296417Sdim    uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
89283625Sdim
90283625Sdim    switch (RE.RelType) {
91283625Sdim
92283625Sdim    case COFF::IMAGE_REL_AMD64_REL32:
93283625Sdim    case COFF::IMAGE_REL_AMD64_REL32_1:
94283625Sdim    case COFF::IMAGE_REL_AMD64_REL32_2:
95283625Sdim    case COFF::IMAGE_REL_AMD64_REL32_3:
96283625Sdim    case COFF::IMAGE_REL_AMD64_REL32_4:
97283625Sdim    case COFF::IMAGE_REL_AMD64_REL32_5: {
98296417Sdim      uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
99283625Sdim      // Delta is the distance from the start of the reloc to the end of the
100283625Sdim      // instruction with the reloc.
101283625Sdim      uint64_t Delta = 4 + (RE.RelType - COFF::IMAGE_REL_AMD64_REL32);
102283625Sdim      Value -= FinalAddress + Delta;
103283625Sdim      uint64_t Result = Value + RE.Addend;
104283625Sdim      assert(((int64_t)Result <= INT32_MAX) && "Relocation overflow");
105283625Sdim      assert(((int64_t)Result >= INT32_MIN) && "Relocation underflow");
106296417Sdim      writeBytesUnaligned(Result, Target, 4);
107283625Sdim      break;
108283625Sdim    }
109283625Sdim
110283625Sdim    case COFF::IMAGE_REL_AMD64_ADDR32NB: {
111341825Sdim      // ADDR32NB requires an offset less than 2GB from 'ImageBase'.
112341825Sdim      // The MemoryManager can make sure this is always true by forcing the
113341825Sdim      // memory layout to be: CodeSection < ReadOnlySection < ReadWriteSection.
114341825Sdim      const uint64_t ImageBase = getImageBase();
115341825Sdim      if (Value < ImageBase || ((Value - ImageBase) > UINT32_MAX)) {
116341825Sdim        llvm::errs() << "IMAGE_REL_AMD64_ADDR32NB relocation requires an"
117341825Sdim                     << "ordered section layout.\n";
118341825Sdim        write32BitOffset(Target, 0, 0);
119341825Sdim      } else {
120341825Sdim        write32BitOffset(Target, RE.Addend, Value - ImageBase);
121341825Sdim      }
122283625Sdim      break;
123283625Sdim    }
124283625Sdim
125283625Sdim    case COFF::IMAGE_REL_AMD64_ADDR64: {
126296417Sdim      writeBytesUnaligned(Value + RE.Addend, Target, 8);
127283625Sdim      break;
128283625Sdim    }
129283625Sdim
130344779Sdim    case COFF::IMAGE_REL_AMD64_SECREL: {
131344779Sdim      assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && "Relocation overflow");
132344779Sdim      assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && "Relocation underflow");
133344779Sdim      writeBytesUnaligned(RE.Addend, Target, 4);
134344779Sdim      break;
135344779Sdim    }
136344779Sdim
137283625Sdim    default:
138283625Sdim      llvm_unreachable("Relocation type not implemented yet!");
139283625Sdim      break;
140283625Sdim    }
141283625Sdim  }
142283625Sdim
143341825Sdim  std::tuple<uint64_t, uint64_t, uint64_t>
144341825Sdim  generateRelocationStub(unsigned SectionID, StringRef TargetName,
145341825Sdim                         uint64_t Offset, uint64_t RelType, uint64_t Addend,
146341825Sdim                         StubMap &Stubs) {
147341825Sdim    uintptr_t StubOffset;
148341825Sdim    SectionEntry &Section = Sections[SectionID];
149341825Sdim
150341825Sdim    RelocationValueRef OriginalRelValueRef;
151341825Sdim    OriginalRelValueRef.SectionID = SectionID;
152341825Sdim    OriginalRelValueRef.Offset = Offset;
153341825Sdim    OriginalRelValueRef.Addend = Addend;
154341825Sdim    OriginalRelValueRef.SymbolName = TargetName.data();
155341825Sdim
156341825Sdim    auto Stub = Stubs.find(OriginalRelValueRef);
157341825Sdim    if (Stub == Stubs.end()) {
158341825Sdim      LLVM_DEBUG(dbgs() << " Create a new stub function for "
159341825Sdim                        << TargetName.data() << "\n");
160341825Sdim
161341825Sdim      StubOffset = Section.getStubOffset();
162341825Sdim      Stubs[OriginalRelValueRef] = StubOffset;
163341825Sdim      createStubFunction(Section.getAddressWithOffset(StubOffset));
164341825Sdim      Section.advanceStubOffset(getMaxStubSize());
165341825Sdim    } else {
166341825Sdim      LLVM_DEBUG(dbgs() << " Stub function found for " << TargetName.data()
167341825Sdim                        << "\n");
168341825Sdim      StubOffset = Stub->second;
169341825Sdim    }
170341825Sdim
171341825Sdim    // FIXME: If RelType == COFF::IMAGE_REL_AMD64_ADDR32NB we should be able
172341825Sdim    // to ignore the __ImageBase requirement and just forward to the stub
173341825Sdim    // directly as an offset of this section:
174341825Sdim    // write32BitOffset(Section.getAddressWithOffset(Offset), 0, StubOffset);
175341825Sdim    // .xdata exception handler's aren't having this though.
176341825Sdim
177341825Sdim    // Resolve original relocation to stub function.
178341825Sdim    const RelocationEntry RE(SectionID, Offset, RelType, Addend);
179341825Sdim    resolveRelocation(RE, Section.getLoadAddressWithOffset(StubOffset));
180341825Sdim
181341825Sdim    // adjust relocation info so resolution writes to the stub function
182341825Sdim    Addend = 0;
183341825Sdim    Offset = StubOffset + 6;
184341825Sdim    RelType = COFF::IMAGE_REL_AMD64_ADDR64;
185341825Sdim
186341825Sdim    return std::make_tuple(Offset, RelType, Addend);
187341825Sdim  }
188341825Sdim
189353358Sdim  Expected<object::relocation_iterator>
190309124Sdim  processRelocationRef(unsigned SectionID,
191353358Sdim                       object::relocation_iterator RelI,
192353358Sdim                       const object::ObjectFile &Obj,
193309124Sdim                       ObjSectionToIDMap &ObjSectionToID,
194309124Sdim                       StubMap &Stubs) override {
195283625Sdim    // If possible, find the symbol referred to in the relocation,
196283625Sdim    // and the section that contains it.
197353358Sdim    object::symbol_iterator Symbol = RelI->getSymbol();
198283625Sdim    if (Symbol == Obj.symbol_end())
199283625Sdim      report_fatal_error("Unknown symbol in relocation");
200309124Sdim    auto SectionOrError = Symbol->getSection();
201309124Sdim    if (!SectionOrError)
202309124Sdim      return SectionOrError.takeError();
203353358Sdim    object::section_iterator SecI = *SectionOrError;
204283625Sdim    // If there is no section, this must be an external reference.
205283625Sdim    const bool IsExtern = SecI == Obj.section_end();
206283625Sdim
207283625Sdim    // Determine the Addend used to adjust the relocation value.
208285181Sdim    uint64_t RelType = RelI->getType();
209285181Sdim    uint64_t Offset = RelI->getOffset();
210283625Sdim    uint64_t Addend = 0;
211283625Sdim    SectionEntry &Section = Sections[SectionID];
212296417Sdim    uintptr_t ObjTarget = Section.getObjAddress() + Offset;
213283625Sdim
214341825Sdim    Expected<StringRef> TargetNameOrErr = Symbol->getName();
215341825Sdim    if (!TargetNameOrErr)
216341825Sdim      return TargetNameOrErr.takeError();
217341825Sdim    StringRef TargetName = *TargetNameOrErr;
218341825Sdim
219283625Sdim    switch (RelType) {
220283625Sdim
221283625Sdim    case COFF::IMAGE_REL_AMD64_REL32:
222283625Sdim    case COFF::IMAGE_REL_AMD64_REL32_1:
223283625Sdim    case COFF::IMAGE_REL_AMD64_REL32_2:
224283625Sdim    case COFF::IMAGE_REL_AMD64_REL32_3:
225283625Sdim    case COFF::IMAGE_REL_AMD64_REL32_4:
226283625Sdim    case COFF::IMAGE_REL_AMD64_REL32_5:
227283625Sdim    case COFF::IMAGE_REL_AMD64_ADDR32NB: {
228296417Sdim      uint8_t *Displacement = (uint8_t *)ObjTarget;
229296417Sdim      Addend = readBytesUnaligned(Displacement, 4);
230341825Sdim
231341825Sdim      if (IsExtern)
232341825Sdim        std::tie(Offset, RelType, Addend) = generateRelocationStub(
233341825Sdim          SectionID, TargetName, Offset, RelType, Addend, Stubs);
234341825Sdim
235283625Sdim      break;
236283625Sdim    }
237283625Sdim
238283625Sdim    case COFF::IMAGE_REL_AMD64_ADDR64: {
239296417Sdim      uint8_t *Displacement = (uint8_t *)ObjTarget;
240296417Sdim      Addend = readBytesUnaligned(Displacement, 8);
241283625Sdim      break;
242283625Sdim    }
243283625Sdim
244283625Sdim    default:
245283625Sdim      break;
246283625Sdim    }
247283625Sdim
248341825Sdim    LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
249341825Sdim                      << " RelType: " << RelType << " TargetName: "
250341825Sdim                      << TargetName << " Addend " << Addend << "\n");
251283625Sdim
252283625Sdim    if (IsExtern) {
253283625Sdim      RelocationEntry RE(SectionID, Offset, RelType, Addend);
254283625Sdim      addRelocationForSymbol(RE, TargetName);
255283625Sdim    } else {
256283625Sdim      bool IsCode = SecI->isText();
257309124Sdim      unsigned TargetSectionID;
258309124Sdim      if (auto TargetSectionIDOrErr =
259309124Sdim          findOrEmitSection(Obj, *SecI, IsCode, ObjSectionToID))
260309124Sdim        TargetSectionID = *TargetSectionIDOrErr;
261309124Sdim      else
262309124Sdim        return TargetSectionIDOrErr.takeError();
263283625Sdim      uint64_t TargetOffset = getSymbolOffset(*Symbol);
264283625Sdim      RelocationEntry RE(SectionID, Offset, RelType, TargetOffset + Addend);
265283625Sdim      addRelocationForSection(RE, TargetSectionID);
266283625Sdim    }
267283625Sdim
268283625Sdim    return ++RelI;
269283625Sdim  }
270283625Sdim
271283625Sdim  void registerEHFrames() override {
272283625Sdim    for (auto const &EHFrameSID : UnregisteredEHFrameSections) {
273296417Sdim      uint8_t *EHFrameAddr = Sections[EHFrameSID].getAddress();
274296417Sdim      uint64_t EHFrameLoadAddr = Sections[EHFrameSID].getLoadAddress();
275296417Sdim      size_t EHFrameSize = Sections[EHFrameSID].getSize();
276283625Sdim      MemMgr.registerEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize);
277283625Sdim      RegisteredEHFrameSections.push_back(EHFrameSID);
278283625Sdim    }
279283625Sdim    UnregisteredEHFrameSections.clear();
280283625Sdim  }
281341825Sdim
282353358Sdim  Error finalizeLoad(const object::ObjectFile &Obj,
283309124Sdim                     ObjSectionToIDMap &SectionMap) override {
284283625Sdim    // Look for and record the EH frame section IDs.
285283625Sdim    for (const auto &SectionPair : SectionMap) {
286353358Sdim      const object::SectionRef &Section = SectionPair.first;
287360784Sdim      Expected<StringRef> NameOrErr = Section.getName();
288360784Sdim      if (!NameOrErr)
289360784Sdim        return NameOrErr.takeError();
290341825Sdim
291341825Sdim      // Note unwind info is stored in .pdata but often points to .xdata
292341825Sdim      // with an IMAGE_REL_AMD64_ADDR32NB relocation. Using a memory manager
293341825Sdim      // that keeps sections ordered in relation to __ImageBase is necessary.
294360784Sdim      if ((*NameOrErr) == ".pdata")
295283625Sdim        UnregisteredEHFrameSections.push_back(SectionPair.second);
296283625Sdim    }
297309124Sdim    return Error::success();
298283625Sdim  }
299283625Sdim};
300283625Sdim
301283625Sdim} // end namespace llvm
302283625Sdim
303283625Sdim#undef DEBUG_TYPE
304283625Sdim
305283625Sdim#endif
306