1//===----- RuntimeDyldMachOARM.h ---- MachO/ARM specific code. ----*- C++ -*-=//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H
11#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H
12
13#include "../RuntimeDyldMachO.h"
14#include <string>
15
16#define DEBUG_TYPE "dyld"
17
18namespace llvm {
19
20class RuntimeDyldMachOARM
21    : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> {
22private:
23  typedef RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> ParentT;
24
25public:
26
27  typedef uint32_t TargetPtrT;
28
29  RuntimeDyldMachOARM(RuntimeDyld::MemoryManager &MM,
30                      RuntimeDyld::SymbolResolver &Resolver)
31    : RuntimeDyldMachOCRTPBase(MM, Resolver) {}
32
33  unsigned getMaxStubSize() override { return 8; }
34
35  unsigned getStubAlignment() override { return 4; }
36
37  int64_t decodeAddend(const RelocationEntry &RE) const {
38    const SectionEntry &Section = Sections[RE.SectionID];
39    uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
40
41    switch (RE.RelType) {
42      default:
43        return memcpyAddend(RE);
44      case MachO::ARM_RELOC_BR24: {
45        uint32_t Temp = readBytesUnaligned(LocalAddress, 4);
46        Temp &= 0x00ffffff; // Mask out the opcode.
47        // Now we've got the shifted immediate, shift by 2, sign extend and ret.
48        return SignExtend32<26>(Temp << 2);
49      }
50    }
51  }
52
53  Expected<relocation_iterator>
54  processRelocationRef(unsigned SectionID, relocation_iterator RelI,
55                       const ObjectFile &BaseObjT,
56                       ObjSectionToIDMap &ObjSectionToID,
57                       StubMap &Stubs) override {
58    const MachOObjectFile &Obj =
59        static_cast<const MachOObjectFile &>(BaseObjT);
60    MachO::any_relocation_info RelInfo =
61        Obj.getRelocation(RelI->getRawDataRefImpl());
62    uint32_t RelType = Obj.getAnyRelocationType(RelInfo);
63
64    if (Obj.isRelocationScattered(RelInfo)) {
65      if (RelType == MachO::ARM_RELOC_HALF_SECTDIFF)
66        return processHALFSECTDIFFRelocation(SectionID, RelI, Obj,
67                                             ObjSectionToID);
68      else if (RelType == MachO::GENERIC_RELOC_VANILLA)
69        return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID);
70      else
71        return ++RelI;
72    }
73
74    // Sanity check relocation type.
75    switch (RelType) {
76    UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PAIR);
77    UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_SECTDIFF);
78    UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_LOCAL_SECTDIFF);
79    UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PB_LA_PTR);
80    UNIMPLEMENTED_RELOC(MachO::ARM_THUMB_RELOC_BR22);
81    UNIMPLEMENTED_RELOC(MachO::ARM_THUMB_32BIT_BRANCH);
82    UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_HALF);
83    default:
84      if (RelType > MachO::ARM_RELOC_HALF_SECTDIFF)
85        return make_error<RuntimeDyldError>(("MachO ARM relocation type " +
86                                             Twine(RelType) +
87                                             " is out of range").str());
88      break;
89    }
90
91    RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));
92    RE.Addend = decodeAddend(RE);
93    RelocationValueRef Value;
94    if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID))
95      Value = *ValueOrErr;
96    else
97      return ValueOrErr.takeError();
98
99    if (RE.IsPCRel)
100      makeValueAddendPCRel(Value, RelI, 8);
101
102    if ((RE.RelType & 0xf) == MachO::ARM_RELOC_BR24)
103      processBranchRelocation(RE, Value, Stubs);
104    else {
105      RE.Addend = Value.Offset;
106      if (Value.SymbolName)
107        addRelocationForSymbol(RE, Value.SymbolName);
108      else
109        addRelocationForSection(RE, Value.SectionID);
110    }
111
112    return ++RelI;
113  }
114
115  void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
116    DEBUG(dumpRelocationToResolve(RE, Value));
117    const SectionEntry &Section = Sections[RE.SectionID];
118    uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
119
120    // If the relocation is PC-relative, the value to be encoded is the
121    // pointer difference.
122    if (RE.IsPCRel) {
123      uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
124      Value -= FinalAddress;
125      // ARM PCRel relocations have an effective-PC offset of two instructions
126      // (four bytes in Thumb mode, 8 bytes in ARM mode).
127      // FIXME: For now, assume ARM mode.
128      Value -= 8;
129    }
130
131    switch (RE.RelType) {
132    case MachO::ARM_RELOC_VANILLA:
133      writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size);
134      break;
135    case MachO::ARM_RELOC_BR24: {
136      // Mask the value into the target address. We know instructions are
137      // 32-bit aligned, so we can do it all at once.
138      Value += RE.Addend;
139      // The low two bits of the value are not encoded.
140      Value >>= 2;
141      // Mask the value to 24 bits.
142      uint64_t FinalValue = Value & 0xffffff;
143      // FIXME: If the destination is a Thumb function (and the instruction
144      // is a non-predicated BL instruction), we need to change it to a BLX
145      // instruction instead.
146
147      // Insert the value into the instruction.
148      uint32_t Temp = readBytesUnaligned(LocalAddress, 4);
149      writeBytesUnaligned((Temp & ~0xffffff) | FinalValue, LocalAddress, 4);
150
151      break;
152    }
153    case MachO::ARM_RELOC_HALF_SECTDIFF: {
154      uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress();
155      uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress();
156      assert((Value == SectionABase || Value == SectionBBase) &&
157             "Unexpected HALFSECTDIFF relocation value.");
158      Value = SectionABase - SectionBBase + RE.Addend;
159      if (RE.Size & 0x1) // :upper16:
160        Value = (Value >> 16);
161      Value &= 0xffff;
162
163      uint32_t Insn = readBytesUnaligned(LocalAddress, 4);
164      Insn = (Insn & 0xfff0f000) | ((Value & 0xf000) << 4) | (Value & 0x0fff);
165      writeBytesUnaligned(Insn, LocalAddress, 4);
166      break;
167    }
168
169    default:
170      llvm_unreachable("Invalid relocation type");
171    }
172  }
173
174  Error finalizeSection(const ObjectFile &Obj, unsigned SectionID,
175                       const SectionRef &Section) {
176    StringRef Name;
177    Section.getName(Name);
178
179    if (Name == "__nl_symbol_ptr")
180      return populateIndirectSymbolPointersSection(cast<MachOObjectFile>(Obj),
181                                                   Section, SectionID);
182    return Error::success();
183  }
184
185private:
186
187  void processBranchRelocation(const RelocationEntry &RE,
188                               const RelocationValueRef &Value,
189                               StubMap &Stubs) {
190    // This is an ARM branch relocation, need to use a stub function.
191    // Look up for existing stub.
192    SectionEntry &Section = Sections[RE.SectionID];
193    RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value);
194    uint8_t *Addr;
195    if (i != Stubs.end()) {
196      Addr = Section.getAddressWithOffset(i->second);
197    } else {
198      // Create a new stub function.
199      Stubs[Value] = Section.getStubOffset();
200      uint8_t *StubTargetAddr = createStubFunction(
201          Section.getAddressWithOffset(Section.getStubOffset()));
202      RelocationEntry StubRE(
203          RE.SectionID, StubTargetAddr - Section.getAddress(),
204          MachO::GENERIC_RELOC_VANILLA, Value.Offset, false, 2);
205      if (Value.SymbolName)
206        addRelocationForSymbol(StubRE, Value.SymbolName);
207      else
208        addRelocationForSection(StubRE, Value.SectionID);
209      Addr = Section.getAddressWithOffset(Section.getStubOffset());
210      Section.advanceStubOffset(getMaxStubSize());
211    }
212    RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, 0,
213                             RE.IsPCRel, RE.Size);
214    resolveRelocation(TargetRE, (uint64_t)Addr);
215  }
216
217  Expected<relocation_iterator>
218  processHALFSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI,
219                                const ObjectFile &BaseTObj,
220                                ObjSectionToIDMap &ObjSectionToID) {
221    const MachOObjectFile &MachO =
222        static_cast<const MachOObjectFile&>(BaseTObj);
223    MachO::any_relocation_info RE =
224        MachO.getRelocation(RelI->getRawDataRefImpl());
225
226
227    // For a half-diff relocation the length bits actually record whether this
228    // is a movw/movt, and whether this is arm or thumb.
229    // Bit 0 indicates movw (b0 == 0) or movt (b0 == 1).
230    // Bit 1 indicates arm (b1 == 0) or thumb (b1 == 1).
231    unsigned HalfDiffKindBits = MachO.getAnyRelocationLength(RE);
232    if (HalfDiffKindBits & 0x2)
233      llvm_unreachable("Thumb not yet supported.");
234
235    SectionEntry &Section = Sections[SectionID];
236    uint32_t RelocType = MachO.getAnyRelocationType(RE);
237    bool IsPCRel = MachO.getAnyRelocationPCRel(RE);
238    uint64_t Offset = RelI->getOffset();
239    uint8_t *LocalAddress = Section.getAddressWithOffset(Offset);
240    int64_t Immediate = readBytesUnaligned(LocalAddress, 4); // Copy the whole instruction out.
241    Immediate = ((Immediate >> 4) & 0xf000) | (Immediate & 0xfff);
242
243    ++RelI;
244    MachO::any_relocation_info RE2 =
245      MachO.getRelocation(RelI->getRawDataRefImpl());
246    uint32_t AddrA = MachO.getScatteredRelocationValue(RE);
247    section_iterator SAI = getSectionByAddress(MachO, AddrA);
248    assert(SAI != MachO.section_end() && "Can't find section for address A");
249    uint64_t SectionABase = SAI->getAddress();
250    uint64_t SectionAOffset = AddrA - SectionABase;
251    SectionRef SectionA = *SAI;
252    bool IsCode = SectionA.isText();
253    uint32_t SectionAID = ~0U;
254    if (auto SectionAIDOrErr =
255          findOrEmitSection(MachO, SectionA, IsCode, ObjSectionToID))
256      SectionAID = *SectionAIDOrErr;
257    else
258      return SectionAIDOrErr.takeError();
259
260    uint32_t AddrB = MachO.getScatteredRelocationValue(RE2);
261    section_iterator SBI = getSectionByAddress(MachO, AddrB);
262    assert(SBI != MachO.section_end() && "Can't find section for address B");
263    uint64_t SectionBBase = SBI->getAddress();
264    uint64_t SectionBOffset = AddrB - SectionBBase;
265    SectionRef SectionB = *SBI;
266    uint32_t SectionBID = ~0U;
267    if (auto SectionBIDOrErr =
268          findOrEmitSection(MachO, SectionB, IsCode, ObjSectionToID))
269      SectionBID = *SectionBIDOrErr;
270    else
271      return SectionBIDOrErr.takeError();
272
273    uint32_t OtherHalf = MachO.getAnyRelocationAddress(RE2) & 0xffff;
274    unsigned Shift = (HalfDiffKindBits & 0x1) ? 16 : 0;
275    uint32_t FullImmVal = (Immediate << Shift) | (OtherHalf << (16 - Shift));
276    int64_t Addend = FullImmVal - (AddrA - AddrB);
277
278    // addend = Encoded - Expected
279    //        = Encoded - (AddrA - AddrB)
280
281    DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA << ", AddrB: " << AddrB
282                 << ", Addend: " << Addend << ", SectionA ID: " << SectionAID
283                 << ", SectionAOffset: " << SectionAOffset
284                 << ", SectionB ID: " << SectionBID
285                 << ", SectionBOffset: " << SectionBOffset << "\n");
286    RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID,
287                      SectionAOffset, SectionBID, SectionBOffset, IsPCRel,
288                      HalfDiffKindBits);
289
290    addRelocationForSection(R, SectionAID);
291    addRelocationForSection(R, SectionBID);
292
293    return ++RelI;
294  }
295
296};
297}
298
299#undef DEBUG_TYPE
300
301#endif
302