• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 namespace llvm {
19 
20 class RuntimeDyldMachOARM
21     : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> {
22 private:
23   typedef RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> ParentT;
24 
25 public:
26 
27   typedef uint32_t TargetPtrT;
28 
RuntimeDyldMachOARM(RuntimeDyld::MemoryManager & MM,RuntimeDyld::SymbolResolver & Resolver)29   RuntimeDyldMachOARM(RuntimeDyld::MemoryManager &MM,
30                       RuntimeDyld::SymbolResolver &Resolver)
31     : RuntimeDyldMachOCRTPBase(MM, Resolver) {}
32 
getMaxStubSize()33   unsigned getMaxStubSize() override { return 8; }
34 
getStubAlignment()35   unsigned getStubAlignment() override { return 4; }
36 
decodeAddend(const RelocationEntry & RE)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>
processRelocationRef(unsigned SectionID,relocation_iterator RelI,const ObjectFile & BaseObjT,ObjSectionToIDMap & ObjSectionToID,StubMap & Stubs)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 
resolveRelocation(const RelocationEntry & RE,uint64_t Value)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 
finalizeSection(const ObjectFile & Obj,unsigned SectionID,const SectionRef & Section)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 
185 private:
186 
processBranchRelocation(const RelocationEntry & RE,const RelocationValueRef & Value,StubMap & Stubs)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>
processHALFSECTDIFFRelocation(unsigned SectionID,relocation_iterator RelI,const ObjectFile & BaseTObj,ObjSectionToIDMap & ObjSectionToID)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