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