1//===--- RuntimeDyldCOFFI386.h --- COFF/X86_64 specific code ---*- 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// COFF x86 support for MC-JIT runtime dynamic linker.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFI386_H
14#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFI386_H
15
16#include "../RuntimeDyldCOFF.h"
17#include "llvm/BinaryFormat/COFF.h"
18#include "llvm/Object/COFF.h"
19
20#define DEBUG_TYPE "dyld"
21
22namespace llvm {
23
24class RuntimeDyldCOFFI386 : public RuntimeDyldCOFF {
25public:
26  RuntimeDyldCOFFI386(RuntimeDyld::MemoryManager &MM,
27                      JITSymbolResolver &Resolver)
28      : RuntimeDyldCOFF(MM, Resolver, 4, COFF::IMAGE_REL_I386_DIR32) {}
29
30  unsigned getMaxStubSize() const override {
31    return 8; // 2-byte jmp instruction + 32-bit relative address + 2 byte pad
32  }
33
34  Align getStubAlignment() override { return Align(1); }
35
36  Expected<object::relocation_iterator>
37  processRelocationRef(unsigned SectionID,
38                       object::relocation_iterator RelI,
39                       const object::ObjectFile &Obj,
40                       ObjSectionToIDMap &ObjSectionToID,
41                       StubMap &Stubs) override {
42
43    auto Symbol = RelI->getSymbol();
44    if (Symbol == Obj.symbol_end())
45      report_fatal_error("Unknown symbol in relocation");
46
47    Expected<StringRef> TargetNameOrErr = Symbol->getName();
48    if (!TargetNameOrErr)
49      return TargetNameOrErr.takeError();
50    StringRef TargetName = *TargetNameOrErr;
51
52    auto SectionOrErr = Symbol->getSection();
53    if (!SectionOrErr)
54      return SectionOrErr.takeError();
55    auto Section = *SectionOrErr;
56    bool IsExtern = Section == Obj.section_end();
57
58    uint64_t RelType = RelI->getType();
59    uint64_t Offset = RelI->getOffset();
60
61    unsigned TargetSectionID = -1;
62    uint64_t TargetOffset = -1;
63    if (TargetName.startswith(getImportSymbolPrefix())) {
64      TargetSectionID = SectionID;
65      TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName, true);
66      TargetName = StringRef();
67      IsExtern = false;
68    } else if (!IsExtern) {
69      if (auto TargetSectionIDOrErr = findOrEmitSection(
70              Obj, *Section, Section->isText(), ObjSectionToID))
71        TargetSectionID = *TargetSectionIDOrErr;
72      else
73        return TargetSectionIDOrErr.takeError();
74      if (RelType != COFF::IMAGE_REL_I386_SECTION)
75        TargetOffset = getSymbolOffset(*Symbol);
76    }
77
78    // Determine the Addend used to adjust the relocation value.
79    uint64_t Addend = 0;
80    SectionEntry &AddendSection = Sections[SectionID];
81    uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
82    uint8_t *Displacement = (uint8_t *)ObjTarget;
83
84    switch (RelType) {
85    case COFF::IMAGE_REL_I386_DIR32:
86    case COFF::IMAGE_REL_I386_DIR32NB:
87    case COFF::IMAGE_REL_I386_SECREL:
88    case COFF::IMAGE_REL_I386_REL32: {
89      Addend = readBytesUnaligned(Displacement, 4);
90      break;
91    }
92    default:
93      break;
94    }
95
96#if !defined(NDEBUG)
97    SmallString<32> RelTypeName;
98    RelI->getTypeName(RelTypeName);
99#endif
100    LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
101                      << " RelType: " << RelTypeName << " TargetName: "
102                      << TargetName << " Addend " << Addend << "\n");
103
104    if (IsExtern) {
105      RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
106      addRelocationForSymbol(RE, TargetName);
107    } else {
108
109      switch (RelType) {
110      case COFF::IMAGE_REL_I386_ABSOLUTE:
111        // This relocation is ignored.
112        break;
113      case COFF::IMAGE_REL_I386_DIR32:
114      case COFF::IMAGE_REL_I386_DIR32NB:
115      case COFF::IMAGE_REL_I386_REL32: {
116        RelocationEntry RE =
117            RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
118                            TargetOffset, 0, 0, false, 0);
119        addRelocationForSection(RE, TargetSectionID);
120        break;
121      }
122      case COFF::IMAGE_REL_I386_SECTION: {
123        RelocationEntry RE =
124            RelocationEntry(TargetSectionID, Offset, RelType, 0);
125        addRelocationForSection(RE, TargetSectionID);
126        break;
127      }
128      case COFF::IMAGE_REL_I386_SECREL: {
129        RelocationEntry RE =
130            RelocationEntry(SectionID, Offset, RelType, TargetOffset + Addend);
131        addRelocationForSection(RE, TargetSectionID);
132        break;
133      }
134      default:
135        llvm_unreachable("unsupported relocation type");
136      }
137    }
138
139    return ++RelI;
140  }
141
142  void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
143    const auto Section = Sections[RE.SectionID];
144    uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
145
146    switch (RE.RelType) {
147    case COFF::IMAGE_REL_I386_ABSOLUTE:
148      // This relocation is ignored.
149      break;
150    case COFF::IMAGE_REL_I386_DIR32: {
151      // The target's 32-bit VA.
152      uint64_t Result =
153          RE.Sections.SectionA == static_cast<uint32_t>(-1)
154              ? Value
155              : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(
156                    RE.Addend);
157      assert(Result <= UINT32_MAX && "relocation overflow");
158      LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
159                        << " RelType: IMAGE_REL_I386_DIR32"
160                        << " TargetSection: " << RE.Sections.SectionA
161                        << " Value: " << format("0x%08" PRIx32, Result)
162                        << '\n');
163      writeBytesUnaligned(Result, Target, 4);
164      break;
165    }
166    case COFF::IMAGE_REL_I386_DIR32NB: {
167      // The target's 32-bit RVA.
168      // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase
169      uint64_t Result =
170          Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend) -
171          Sections[0].getLoadAddress();
172      assert(Result <= UINT32_MAX && "relocation overflow");
173      LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
174                        << " RelType: IMAGE_REL_I386_DIR32NB"
175                        << " TargetSection: " << RE.Sections.SectionA
176                        << " Value: " << format("0x%08" PRIx32, Result)
177                        << '\n');
178      writeBytesUnaligned(Result, Target, 4);
179      break;
180    }
181    case COFF::IMAGE_REL_I386_REL32: {
182      // 32-bit relative displacement to the target.
183      uint64_t Result = RE.Sections.SectionA == static_cast<uint32_t>(-1)
184                            ? Value
185                            : Sections[RE.Sections.SectionA].getLoadAddress();
186      Result = Result - Section.getLoadAddress() + RE.Addend - 4 - RE.Offset;
187      assert(static_cast<int64_t>(Result) <= INT32_MAX &&
188             "relocation overflow");
189      assert(static_cast<int64_t>(Result) >= INT32_MIN &&
190             "relocation underflow");
191      LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
192                        << " RelType: IMAGE_REL_I386_REL32"
193                        << " TargetSection: " << RE.Sections.SectionA
194                        << " Value: " << format("0x%08" PRIx32, Result)
195                        << '\n');
196      writeBytesUnaligned(Result, Target, 4);
197      break;
198    }
199    case COFF::IMAGE_REL_I386_SECTION:
200      // 16-bit section index of the section that contains the target.
201      assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX &&
202             "relocation overflow");
203      LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
204                        << " RelType: IMAGE_REL_I386_SECTION Value: "
205                        << RE.SectionID << '\n');
206      writeBytesUnaligned(RE.SectionID, Target, 2);
207      break;
208    case COFF::IMAGE_REL_I386_SECREL:
209      // 32-bit offset of the target from the beginning of its section.
210      assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX &&
211             "relocation overflow");
212      LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
213                        << " RelType: IMAGE_REL_I386_SECREL Value: "
214                        << RE.Addend << '\n');
215      writeBytesUnaligned(RE.Addend, Target, 4);
216      break;
217    default:
218      llvm_unreachable("unsupported relocation type");
219    }
220  }
221
222  void registerEHFrames() override {}
223};
224
225}
226
227#endif
228
229