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