RuntimeDyldCOFFThumb.h revision 327952
1303231Sdim//===--- RuntimeDyldCOFFThumb.h --- COFF/Thumb specific code ---*- C++ --*-===//
2303231Sdim//
3303231Sdim//                     The LLVM Compiler Infrastructure
4303231Sdim//
5303231Sdim// This file is distributed under the University of Illinois Open Source
6303231Sdim// License. See LICENSE.TXT for details.
7303231Sdim//
8303231Sdim//===----------------------------------------------------------------------===//
9303231Sdim//
10303231Sdim// COFF thumb support for MC-JIT runtime dynamic linker.
11303231Sdim//
12303231Sdim//===----------------------------------------------------------------------===//
13303231Sdim
14303231Sdim#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H
15303231Sdim#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H
16303231Sdim
17321369Sdim#include "../RuntimeDyldCOFF.h"
18321369Sdim#include "llvm/BinaryFormat/COFF.h"
19303231Sdim#include "llvm/Object/COFF.h"
20303231Sdim
21303231Sdim#define DEBUG_TYPE "dyld"
22303231Sdim
23303231Sdimnamespace llvm {
24303231Sdim
25314564Sdimstatic bool isThumbFunc(symbol_iterator Symbol, const ObjectFile &Obj,
26314564Sdim                        section_iterator Section) {
27314564Sdim  Expected<SymbolRef::Type> SymTypeOrErr = Symbol->getType();
28314564Sdim  if (!SymTypeOrErr) {
29314564Sdim    std::string Buf;
30314564Sdim    raw_string_ostream OS(Buf);
31314564Sdim    logAllUnhandledErrors(SymTypeOrErr.takeError(), OS, "");
32314564Sdim    OS.flush();
33314564Sdim    report_fatal_error(Buf);
34314564Sdim  }
35314564Sdim
36314564Sdim  if (*SymTypeOrErr != SymbolRef::ST_Function)
37314564Sdim    return false;
38314564Sdim
39314564Sdim  // We check the IMAGE_SCN_MEM_16BIT flag in the section of the symbol to tell
40314564Sdim  // if it's thumb or not
41314564Sdim  return cast<COFFObjectFile>(Obj).getCOFFSection(*Section)->Characteristics &
42314564Sdim         COFF::IMAGE_SCN_MEM_16BIT;
43314564Sdim}
44314564Sdim
45303231Sdimclass RuntimeDyldCOFFThumb : public RuntimeDyldCOFF {
46303231Sdimpublic:
47303231Sdim  RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM,
48314564Sdim                       JITSymbolResolver &Resolver)
49303231Sdim      : RuntimeDyldCOFF(MM, Resolver) {}
50303231Sdim
51303231Sdim  unsigned getMaxStubSize() override {
52303231Sdim    return 16; // 8-byte load instructions, 4-byte jump, 4-byte padding
53303231Sdim  }
54303231Sdim
55303231Sdim  unsigned getStubAlignment() override { return 1; }
56303231Sdim
57303231Sdim  Expected<relocation_iterator>
58303231Sdim  processRelocationRef(unsigned SectionID,
59303231Sdim                       relocation_iterator RelI,
60303231Sdim                       const ObjectFile &Obj,
61303231Sdim                       ObjSectionToIDMap &ObjSectionToID,
62303231Sdim                       StubMap &Stubs) override {
63303231Sdim    auto Symbol = RelI->getSymbol();
64303231Sdim    if (Symbol == Obj.symbol_end())
65303231Sdim      report_fatal_error("Unknown symbol in relocation");
66303231Sdim
67303231Sdim    Expected<StringRef> TargetNameOrErr = Symbol->getName();
68303231Sdim    if (!TargetNameOrErr)
69303231Sdim      return TargetNameOrErr.takeError();
70303231Sdim    StringRef TargetName = *TargetNameOrErr;
71303231Sdim
72303231Sdim    auto SectionOrErr = Symbol->getSection();
73303231Sdim    if (!SectionOrErr)
74303231Sdim      return SectionOrErr.takeError();
75303231Sdim    auto Section = *SectionOrErr;
76303231Sdim
77303231Sdim    uint64_t RelType = RelI->getType();
78303231Sdim    uint64_t Offset = RelI->getOffset();
79303231Sdim
80303231Sdim    // Determine the Addend used to adjust the relocation value.
81303231Sdim    uint64_t Addend = 0;
82303231Sdim    SectionEntry &AddendSection = Sections[SectionID];
83303231Sdim    uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset;
84303231Sdim    uint8_t *Displacement = (uint8_t *)ObjTarget;
85303231Sdim
86303231Sdim    switch (RelType) {
87303231Sdim    case COFF::IMAGE_REL_ARM_ADDR32:
88303231Sdim    case COFF::IMAGE_REL_ARM_ADDR32NB:
89303231Sdim    case COFF::IMAGE_REL_ARM_SECREL:
90303231Sdim      Addend = readBytesUnaligned(Displacement, 4);
91303231Sdim      break;
92303231Sdim    default:
93303231Sdim      break;
94303231Sdim    }
95303231Sdim
96303231Sdim#if !defined(NDEBUG)
97303231Sdim    SmallString<32> RelTypeName;
98303231Sdim    RelI->getTypeName(RelTypeName);
99303231Sdim#endif
100303231Sdim    DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
101303231Sdim                 << " RelType: " << RelTypeName << " TargetName: " << TargetName
102303231Sdim                 << " Addend " << Addend << "\n");
103303231Sdim
104303231Sdim    unsigned TargetSectionID = -1;
105303231Sdim    if (Section == Obj.section_end()) {
106303231Sdim      RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0);
107303231Sdim      addRelocationForSymbol(RE, TargetName);
108303231Sdim    } else {
109303231Sdim      if (auto TargetSectionIDOrErr =
110303231Sdim          findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID))
111303231Sdim        TargetSectionID = *TargetSectionIDOrErr;
112303231Sdim      else
113303231Sdim        return TargetSectionIDOrErr.takeError();
114303231Sdim
115314564Sdim      // We need to find out if the relocation is relative to a thumb function
116314564Sdim      // so that we include the ISA selection bit when resolve the relocation
117314564Sdim      bool IsTargetThumbFunc = isThumbFunc(Symbol, Obj, Section);
118314564Sdim
119303231Sdim      switch (RelType) {
120303231Sdim      default: llvm_unreachable("unsupported relocation type");
121303231Sdim      case COFF::IMAGE_REL_ARM_ABSOLUTE:
122303231Sdim        // This relocation is ignored.
123303231Sdim        break;
124314564Sdim      case COFF::IMAGE_REL_ARM_ADDR32: {
125314564Sdim        RelocationEntry RE = RelocationEntry(
126314564Sdim            SectionID, Offset, RelType, Addend, TargetSectionID,
127314564Sdim            getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc);
128314564Sdim        addRelocationForSection(RE, TargetSectionID);
129314564Sdim        break;
130314564Sdim      }
131303231Sdim      case COFF::IMAGE_REL_ARM_ADDR32NB: {
132303231Sdim        RelocationEntry RE =
133303231Sdim            RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID,
134303231Sdim                            getSymbolOffset(*Symbol), 0, 0, false, 0);
135303231Sdim        addRelocationForSection(RE, TargetSectionID);
136303231Sdim        break;
137303231Sdim      }
138303231Sdim      case COFF::IMAGE_REL_ARM_SECTION: {
139303231Sdim        RelocationEntry RE =
140303231Sdim            RelocationEntry(TargetSectionID, Offset, RelType, 0);
141303231Sdim        addRelocationForSection(RE, TargetSectionID);
142303231Sdim        break;
143303231Sdim      }
144303231Sdim      case COFF::IMAGE_REL_ARM_SECREL: {
145303231Sdim        RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType,
146303231Sdim                                             getSymbolOffset(*Symbol) + Addend);
147303231Sdim        addRelocationForSection(RE, TargetSectionID);
148303231Sdim        break;
149303231Sdim      }
150303231Sdim      case COFF::IMAGE_REL_ARM_MOV32T: {
151314564Sdim        RelocationEntry RE = RelocationEntry(
152314564Sdim            SectionID, Offset, RelType, Addend, TargetSectionID,
153314564Sdim            getSymbolOffset(*Symbol), 0, 0, false, 0, IsTargetThumbFunc);
154303231Sdim        addRelocationForSection(RE, TargetSectionID);
155303231Sdim        break;
156303231Sdim      }
157303231Sdim      case COFF::IMAGE_REL_ARM_BRANCH20T:
158303231Sdim      case COFF::IMAGE_REL_ARM_BRANCH24T:
159303231Sdim      case COFF::IMAGE_REL_ARM_BLX23T: {
160303231Sdim        RelocationEntry RE =
161303231Sdim            RelocationEntry(SectionID, Offset, RelType,
162303231Sdim                            getSymbolOffset(*Symbol) + Addend, true, 0);
163303231Sdim        addRelocationForSection(RE, TargetSectionID);
164303231Sdim        break;
165303231Sdim      }
166303231Sdim      }
167303231Sdim    }
168303231Sdim
169303231Sdim    return ++RelI;
170303231Sdim  }
171303231Sdim
172303231Sdim  void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
173303231Sdim    const auto Section = Sections[RE.SectionID];
174303231Sdim    uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
175314564Sdim    int ISASelectionBit = RE.IsTargetThumbFunc ? 1 : 0;
176303231Sdim
177303231Sdim    switch (RE.RelType) {
178303231Sdim    default: llvm_unreachable("unsupported relocation type");
179303231Sdim    case COFF::IMAGE_REL_ARM_ABSOLUTE:
180303231Sdim      // This relocation is ignored.
181303231Sdim      break;
182303231Sdim    case COFF::IMAGE_REL_ARM_ADDR32: {
183303231Sdim      // The target's 32-bit VA.
184303231Sdim      uint64_t Result =
185303231Sdim          RE.Sections.SectionA == static_cast<uint32_t>(-1)
186303231Sdim              ? Value
187303231Sdim              : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
188314564Sdim      Result |= ISASelectionBit;
189327952Sdim      assert(Result <= UINT32_MAX && "relocation overflow");
190303231Sdim      DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
191303231Sdim                   << " RelType: IMAGE_REL_ARM_ADDR32"
192303231Sdim                   << " TargetSection: " << RE.Sections.SectionA
193303231Sdim                   << " Value: " << format("0x%08" PRIx32, Result) << '\n');
194303231Sdim      writeBytesUnaligned(Result, Target, 4);
195303231Sdim      break;
196303231Sdim    }
197303231Sdim    case COFF::IMAGE_REL_ARM_ADDR32NB: {
198303231Sdim      // The target's 32-bit RVA.
199303231Sdim      // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase
200303231Sdim      uint64_t Result = Sections[RE.Sections.SectionA].getLoadAddress() -
201303231Sdim                        Sections[0].getLoadAddress() + RE.Addend;
202327952Sdim      assert(Result <= UINT32_MAX && "relocation overflow");
203303231Sdim      DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
204303231Sdim                   << " RelType: IMAGE_REL_ARM_ADDR32NB"
205303231Sdim                   << " TargetSection: " << RE.Sections.SectionA
206303231Sdim                   << " Value: " << format("0x%08" PRIx32, Result) << '\n');
207314564Sdim      Result |= ISASelectionBit;
208303231Sdim      writeBytesUnaligned(Result, Target, 4);
209303231Sdim      break;
210303231Sdim    }
211303231Sdim    case COFF::IMAGE_REL_ARM_SECTION:
212303231Sdim      // 16-bit section index of the section that contains the target.
213327952Sdim      assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX &&
214303231Sdim             "relocation overflow");
215303231Sdim      DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
216303231Sdim                   << " RelType: IMAGE_REL_ARM_SECTION Value: " << RE.SectionID
217303231Sdim                   << '\n');
218303231Sdim      writeBytesUnaligned(RE.SectionID, Target, 2);
219303231Sdim      break;
220303231Sdim    case COFF::IMAGE_REL_ARM_SECREL:
221303231Sdim      // 32-bit offset of the target from the beginning of its section.
222327952Sdim      assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX &&
223303231Sdim             "relocation overflow");
224303231Sdim      DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
225303231Sdim                   << " RelType: IMAGE_REL_ARM_SECREL Value: " << RE.Addend
226303231Sdim                   << '\n');
227303231Sdim      writeBytesUnaligned(RE.Addend, Target, 2);
228303231Sdim      break;
229303231Sdim    case COFF::IMAGE_REL_ARM_MOV32T: {
230303231Sdim      // 32-bit VA of the target applied to a contiguous MOVW+MOVT pair.
231303231Sdim      uint64_t Result =
232303231Sdim          Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend);
233327952Sdim      assert(Result <= UINT32_MAX && "relocation overflow");
234303231Sdim      DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
235303231Sdim                   << " RelType: IMAGE_REL_ARM_MOV32T"
236303231Sdim                   << " TargetSection: " << RE.Sections.SectionA
237303231Sdim                   << " Value: " << format("0x%08" PRIx32, Result) << '\n');
238303231Sdim
239303231Sdim      // MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8|
240303231Sdim      //            imm32 = zext imm4:i:imm3:imm8
241303231Sdim      // MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8|
242303231Sdim      //            imm16 =      imm4:i:imm3:imm8
243303231Sdim
244303231Sdim      auto EncodeImmediate = [](uint8_t *Bytes, uint16_t Immediate)  {
245303231Sdim        Bytes[0] |= ((Immediate & 0xf000) >> 12);
246303231Sdim        Bytes[1] |= ((Immediate & 0x0800) >> 11);
247303231Sdim        Bytes[2] |= ((Immediate & 0x00ff) >>  0);
248314564Sdim        Bytes[3] |= (((Immediate & 0x0700) >>  8) << 4);
249303231Sdim      };
250303231Sdim
251314564Sdim      EncodeImmediate(&Target[0],
252314564Sdim                      (static_cast<uint32_t>(Result) >> 00) | ISASelectionBit);
253303231Sdim      EncodeImmediate(&Target[4], static_cast<uint32_t>(Result) >> 16);
254303231Sdim
255303231Sdim      break;
256303231Sdim    }
257303231Sdim    case COFF::IMAGE_REL_ARM_BRANCH20T: {
258303231Sdim      // The most significant 20-bits of the signed 21-bit relative displacement
259303231Sdim      uint64_t Value =
260303231Sdim          RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
261327952Sdim      assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
262303231Sdim             "relocation overflow");
263327952Sdim      assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
264303231Sdim             "relocation underflow");
265303231Sdim      DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
266303231Sdim                   << " RelType: IMAGE_REL_ARM_BRANCH20T"
267303231Sdim                   << " Value: " << static_cast<int32_t>(Value) << '\n');
268303231Sdim      static_cast<void>(Value);
269303231Sdim      llvm_unreachable("unimplemented relocation");
270303231Sdim      break;
271303231Sdim    }
272303231Sdim    case COFF::IMAGE_REL_ARM_BRANCH24T: {
273303231Sdim      // The most significant 24-bits of the signed 25-bit relative displacement
274303231Sdim      uint64_t Value =
275303231Sdim          RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
276327952Sdim      assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
277303231Sdim             "relocation overflow");
278327952Sdim      assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
279303231Sdim             "relocation underflow");
280303231Sdim      DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
281303231Sdim                   << " RelType: IMAGE_REL_ARM_BRANCH24T"
282303231Sdim                   << " Value: " << static_cast<int32_t>(Value) << '\n');
283303231Sdim      static_cast<void>(Value);
284303231Sdim      llvm_unreachable("unimplemented relocation");
285303231Sdim      break;
286303231Sdim    }
287303231Sdim    case COFF::IMAGE_REL_ARM_BLX23T: {
288303231Sdim      // The most significant 24-bits of the signed 25-bit relative displacement
289303231Sdim      uint64_t Value =
290303231Sdim          RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4;
291327952Sdim      assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX &&
292303231Sdim             "relocation overflow");
293327952Sdim      assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN &&
294303231Sdim             "relocation underflow");
295303231Sdim      DEBUG(dbgs() << "\t\tOffset: " << RE.Offset
296303231Sdim                   << " RelType: IMAGE_REL_ARM_BLX23T"
297303231Sdim                   << " Value: " << static_cast<int32_t>(Value) << '\n');
298303231Sdim      static_cast<void>(Value);
299303231Sdim      llvm_unreachable("unimplemented relocation");
300303231Sdim      break;
301303231Sdim    }
302303231Sdim    }
303303231Sdim  }
304303231Sdim
305303231Sdim  void registerEHFrames() override {}
306303231Sdim};
307303231Sdim
308303231Sdim}
309303231Sdim
310303231Sdim#endif
311