RuntimeDyldCOFFI386.h revision 360660
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) {}
29
30  unsigned getMaxStubSize() const override {
31    return 8; // 2-byte jmp instruction + 32-bit relative address + 2 byte pad
32  }
33
34  unsigned getStubAlignment() override { return 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
57    uint64_t RelType = RelI->getType();
58    uint64_t Offset = RelI->getOffset();
59
60    // Determine the Addend used to adjust the relocation value.
61    uint64_t Addend = 0;
62    SectionEntry &AddendSection = Sections[SectionID];
63    uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
64    uint8_t *Displacement = (uint8_t *)ObjTarget;
65
66    switch (RelType) {
67    case COFF::IMAGE_REL_I386_DIR32:
68    case COFF::IMAGE_REL_I386_DIR32NB:
69    case COFF::IMAGE_REL_I386_SECREL:
70    case COFF::IMAGE_REL_I386_REL32: {
71      Addend = readBytesUnaligned(Displacement, 4);
72      break;
73    }
74    default:
75      break;
76    }
77
78#if !defined(NDEBUG)
79    SmallString<32> RelTypeName;
80    RelI->getTypeName(RelTypeName);
81#endif
82    LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
83                      << " RelType: " << RelTypeName << " TargetName: "
84                      << TargetName << " Addend " << Addend << "\n");
85
86    unsigned TargetSectionID = -1;
87    if (Section == Obj.section_end()) {
88      RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
89      addRelocationForSymbol(RE, TargetName);
90    } else {
91      if (auto TargetSectionIDOrErr =
92          findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID))
93        TargetSectionID = *TargetSectionIDOrErr;
94      else
95        return TargetSectionIDOrErr.takeError();
96
97      switch (RelType) {
98      case COFF::IMAGE_REL_I386_ABSOLUTE:
99        // This relocation is ignored.
100        break;
101      case COFF::IMAGE_REL_I386_DIR32:
102      case COFF::IMAGE_REL_I386_DIR32NB:
103      case COFF::IMAGE_REL_I386_REL32: {
104        RelocationEntry RE =
105            RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
106                            getSymbolOffset(*Symbol), 0, 0, false, 0);
107        addRelocationForSection(RE, TargetSectionID);
108        break;
109      }
110      case COFF::IMAGE_REL_I386_SECTION: {
111        RelocationEntry RE =
112            RelocationEntry(TargetSectionID, Offset, RelType, 0);
113        addRelocationForSection(RE, TargetSectionID);
114        break;
115      }
116      case COFF::IMAGE_REL_I386_SECREL: {
117        RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType,
118                                             getSymbolOffset(*Symbol) + Addend);
119        addRelocationForSection(RE, TargetSectionID);
120        break;
121      }
122      default:
123        llvm_unreachable("unsupported relocation type");
124      }
125
126    }
127
128    return ++RelI;
129  }
130
131  void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
132    const auto Section = Sections[RE.SectionID];
133    uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
134
135    switch (RE.RelType) {
136    case COFF::IMAGE_REL_I386_ABSOLUTE:
137      // This relocation is ignored.
138      break;
139    case COFF::IMAGE_REL_I386_DIR32: {
140      // The target's 32-bit VA.
141      uint64_t Result =
142          RE.Sections.SectionA == static_cast<uint32_t>(-1)
143              ? Value
144              : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(
145                    RE.Addend);
146      assert(Result <= UINT32_MAX && "relocation overflow");
147      LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
148                        << " RelType: IMAGE_REL_I386_DIR32"
149                        << " TargetSection: " << RE.Sections.SectionA
150                        << " Value: " << format("0x%08" PRIx32, Result)
151                        << '\n');
152      writeBytesUnaligned(Result, Target, 4);
153      break;
154    }
155    case COFF::IMAGE_REL_I386_DIR32NB: {
156      // The target's 32-bit RVA.
157      // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase
158      uint64_t Result =
159          Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend) -
160          Sections[0].getLoadAddress();
161      assert(Result <= UINT32_MAX && "relocation overflow");
162      LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
163                        << " RelType: IMAGE_REL_I386_DIR32NB"
164                        << " TargetSection: " << RE.Sections.SectionA
165                        << " Value: " << format("0x%08" PRIx32, Result)
166                        << '\n');
167      writeBytesUnaligned(Result, Target, 4);
168      break;
169    }
170    case COFF::IMAGE_REL_I386_REL32: {
171      // 32-bit relative displacement to the target.
172      uint64_t Result = RE.Sections.SectionA == static_cast<uint32_t>(-1)
173                            ? Value
174                            : Sections[RE.Sections.SectionA].getLoadAddress();
175      Result = Result - Section.getLoadAddress() + RE.Addend - 4 - RE.Offset;
176      assert(static_cast<int64_t>(Result) <= INT32_MAX &&
177             "relocation overflow");
178      assert(static_cast<int64_t>(Result) >= INT32_MIN &&
179             "relocation underflow");
180      LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
181                        << " RelType: IMAGE_REL_I386_REL32"
182                        << " TargetSection: " << RE.Sections.SectionA
183                        << " Value: " << format("0x%08" PRIx32, Result)
184                        << '\n');
185      writeBytesUnaligned(Result, Target, 4);
186      break;
187    }
188    case COFF::IMAGE_REL_I386_SECTION:
189      // 16-bit section index of the section that contains the target.
190      assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX &&
191             "relocation overflow");
192      LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
193                        << " RelType: IMAGE_REL_I386_SECTION Value: "
194                        << RE.SectionID << '\n');
195      writeBytesUnaligned(RE.SectionID, Target, 2);
196      break;
197    case COFF::IMAGE_REL_I386_SECREL:
198      // 32-bit offset of the target from the beginning of its section.
199      assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX &&
200             "relocation overflow");
201      LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
202                        << " RelType: IMAGE_REL_I386_SECREL Value: "
203                        << RE.Addend << '\n');
204      writeBytesUnaligned(RE.Addend, Target, 4);
205      break;
206    default:
207      llvm_unreachable("unsupported relocation type");
208    }
209  }
210
211  void registerEHFrames() override {}
212};
213
214}
215
216#endif
217
218