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