1 //===-- RuntimeDyldMachO.cpp - Run-time dynamic linker for MC-JIT -*- 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 // Implementation of the MC-JIT runtime dynamic linker. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #define DEBUG_TYPE "dyld" 15 #include "llvm/ADT/OwningPtr.h" 16 #include "llvm/ADT/StringRef.h" 17 #include "llvm/ADT/STLExtras.h" 18 #include "RuntimeDyldMachO.h" 19 using namespace llvm; 20 using namespace llvm::object; 21 22 namespace llvm { 23 24 void RuntimeDyldMachO::resolveRelocation(uint8_t *LocalAddress, 25 uint64_t FinalAddress, 26 uint64_t Value, 27 uint32_t Type, 28 int64_t Addend) { 29 bool isPCRel = (Type >> 24) & 1; 30 unsigned MachoType = (Type >> 28) & 0xf; 31 unsigned Size = 1 << ((Type >> 25) & 3); 32 33 DEBUG(dbgs() << "resolveRelocation LocalAddress: " 34 << format("%p", LocalAddress) 35 << " FinalAddress: " << format("%p", FinalAddress) 36 << " Value: " << format("%p", Value) 37 << " Addend: " << Addend 38 << " isPCRel: " << isPCRel 39 << " MachoType: " << MachoType 40 << " Size: " << Size 41 << "\n"); 42 43 // This just dispatches to the proper target specific routine. 44 switch (Arch) { 45 default: llvm_unreachable("Unsupported CPU type!"); 46 case Triple::x86_64: 47 resolveX86_64Relocation(LocalAddress, 48 FinalAddress, 49 (uintptr_t)Value, 50 isPCRel, 51 MachoType, 52 Size, 53 Addend); 54 break; 55 case Triple::x86: 56 resolveI386Relocation(LocalAddress, 57 FinalAddress, 58 (uintptr_t)Value, 59 isPCRel, 60 Type, 61 Size, 62 Addend); 63 break; 64 case Triple::arm: // Fall through. 65 case Triple::thumb: 66 resolveARMRelocation(LocalAddress, 67 FinalAddress, 68 (uintptr_t)Value, 69 isPCRel, 70 MachoType, 71 Size, 72 Addend); 73 break; 74 } 75 } 76 77 bool RuntimeDyldMachO::resolveI386Relocation(uint8_t *LocalAddress, 78 uint64_t FinalAddress, 79 uint64_t Value, 80 bool isPCRel, 81 unsigned Type, 82 unsigned Size, 83 int64_t Addend) { 84 if (isPCRel) 85 Value -= FinalAddress + 4; // see resolveX86_64Relocation 86 87 switch (Type) { 88 default: 89 llvm_unreachable("Invalid relocation type!"); 90 case macho::RIT_Vanilla: { 91 uint8_t *p = LocalAddress; 92 uint64_t ValueToWrite = Value + Addend; 93 for (unsigned i = 0; i < Size; ++i) { 94 *p++ = (uint8_t)(ValueToWrite & 0xff); 95 ValueToWrite >>= 8; 96 } 97 } 98 case macho::RIT_Difference: 99 case macho::RIT_Generic_LocalDifference: 100 case macho::RIT_Generic_PreboundLazyPointer: 101 return Error("Relocation type not implemented yet!"); 102 } 103 } 104 105 bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress, 106 uint64_t FinalAddress, 107 uint64_t Value, 108 bool isPCRel, 109 unsigned Type, 110 unsigned Size, 111 int64_t Addend) { 112 // If the relocation is PC-relative, the value to be encoded is the 113 // pointer difference. 114 if (isPCRel) 115 // FIXME: It seems this value needs to be adjusted by 4 for an effective PC 116 // address. Is that expected? Only for branches, perhaps? 117 Value -= FinalAddress + 4; 118 119 switch(Type) { 120 default: 121 llvm_unreachable("Invalid relocation type!"); 122 case macho::RIT_X86_64_Signed1: 123 case macho::RIT_X86_64_Signed2: 124 case macho::RIT_X86_64_Signed4: 125 case macho::RIT_X86_64_Signed: 126 case macho::RIT_X86_64_Unsigned: 127 case macho::RIT_X86_64_Branch: { 128 Value += Addend; 129 // Mask in the target value a byte at a time (we don't have an alignment 130 // guarantee for the target address, so this is safest). 131 uint8_t *p = (uint8_t*)LocalAddress; 132 for (unsigned i = 0; i < Size; ++i) { 133 *p++ = (uint8_t)Value; 134 Value >>= 8; 135 } 136 return false; 137 } 138 case macho::RIT_X86_64_GOTLoad: 139 case macho::RIT_X86_64_GOT: 140 case macho::RIT_X86_64_Subtractor: 141 case macho::RIT_X86_64_TLV: 142 return Error("Relocation type not implemented yet!"); 143 } 144 } 145 146 bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress, 147 uint64_t FinalAddress, 148 uint64_t Value, 149 bool isPCRel, 150 unsigned Type, 151 unsigned Size, 152 int64_t Addend) { 153 // If the relocation is PC-relative, the value to be encoded is the 154 // pointer difference. 155 if (isPCRel) { 156 Value -= FinalAddress; 157 // ARM PCRel relocations have an effective-PC offset of two instructions 158 // (four bytes in Thumb mode, 8 bytes in ARM mode). 159 // FIXME: For now, assume ARM mode. 160 Value -= 8; 161 } 162 163 switch(Type) { 164 default: 165 llvm_unreachable("Invalid relocation type!"); 166 case macho::RIT_Vanilla: { 167 // Mask in the target value a byte at a time (we don't have an alignment 168 // guarantee for the target address, so this is safest). 169 uint8_t *p = (uint8_t*)LocalAddress; 170 for (unsigned i = 0; i < Size; ++i) { 171 *p++ = (uint8_t)Value; 172 Value >>= 8; 173 } 174 break; 175 } 176 case macho::RIT_ARM_Branch24Bit: { 177 // Mask the value into the target address. We know instructions are 178 // 32-bit aligned, so we can do it all at once. 179 uint32_t *p = (uint32_t*)LocalAddress; 180 // The low two bits of the value are not encoded. 181 Value >>= 2; 182 // Mask the value to 24 bits. 183 Value &= 0xffffff; 184 // FIXME: If the destination is a Thumb function (and the instruction 185 // is a non-predicated BL instruction), we need to change it to a BLX 186 // instruction instead. 187 188 // Insert the value into the instruction. 189 *p = (*p & ~0xffffff) | Value; 190 break; 191 } 192 case macho::RIT_ARM_ThumbBranch22Bit: 193 case macho::RIT_ARM_ThumbBranch32Bit: 194 case macho::RIT_ARM_Half: 195 case macho::RIT_ARM_HalfDifference: 196 case macho::RIT_Pair: 197 case macho::RIT_Difference: 198 case macho::RIT_ARM_LocalDifference: 199 case macho::RIT_ARM_PreboundLazyPointer: 200 return Error("Relocation type not implemented yet!"); 201 } 202 return false; 203 } 204 205 void RuntimeDyldMachO::processRelocationRef(const ObjRelocationInfo &Rel, 206 ObjectImage &Obj, 207 ObjSectionToIDMap &ObjSectionToID, 208 const SymbolTableMap &Symbols, 209 StubMap &Stubs) { 210 211 uint32_t RelType = (uint32_t) (Rel.Type & 0xffffffffL); 212 RelocationValueRef Value; 213 SectionEntry &Section = Sections[Rel.SectionID]; 214 uint8_t *Target = Section.Address + Rel.Offset; 215 216 bool isExtern = (RelType >> 27) & 1; 217 if (isExtern) { 218 // Obtain the symbol name which is referenced in the relocation 219 StringRef TargetName; 220 const SymbolRef &Symbol = Rel.Symbol; 221 Symbol.getName(TargetName); 222 // First search for the symbol in the local symbol table 223 SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data()); 224 if (lsi != Symbols.end()) { 225 Value.SectionID = lsi->second.first; 226 Value.Addend = lsi->second.second; 227 } else { 228 // Search for the symbol in the global symbol table 229 SymbolTableMap::const_iterator gsi = GlobalSymbolTable.find(TargetName.data()); 230 if (gsi != GlobalSymbolTable.end()) { 231 Value.SectionID = gsi->second.first; 232 Value.Addend = gsi->second.second; 233 } else 234 Value.SymbolName = TargetName.data(); 235 } 236 } else { 237 error_code err; 238 uint8_t sectionIndex = static_cast<uint8_t>(RelType & 0xFF); 239 section_iterator si = Obj.begin_sections(), 240 se = Obj.end_sections(); 241 for (uint8_t i = 1; i < sectionIndex; i++) { 242 error_code err; 243 si.increment(err); 244 if (si == se) 245 break; 246 } 247 assert(si != se && "No section containing relocation!"); 248 Value.SectionID = findOrEmitSection(Obj, *si, true, ObjSectionToID); 249 Value.Addend = *(const intptr_t *)Target; 250 if (Value.Addend) { 251 // The MachO addend is an offset from the current section. We need it 252 // to be an offset from the destination section 253 Value.Addend += Section.ObjAddress - Sections[Value.SectionID].ObjAddress; 254 } 255 } 256 257 if (Arch == Triple::arm && RelType == macho::RIT_ARM_Branch24Bit) { 258 // This is an ARM branch relocation, need to use a stub function. 259 260 // Look up for existing stub. 261 StubMap::const_iterator i = Stubs.find(Value); 262 if (i != Stubs.end()) 263 resolveRelocation(Target, (uint64_t)Target, 264 (uint64_t)Section.Address + i->second, 265 RelType, 0); 266 else { 267 // Create a new stub function. 268 Stubs[Value] = Section.StubOffset; 269 uint8_t *StubTargetAddr = createStubFunction(Section.Address + 270 Section.StubOffset); 271 RelocationEntry RE(Rel.SectionID, StubTargetAddr - Section.Address, 272 macho::RIT_Vanilla, Value.Addend); 273 if (Value.SymbolName) 274 addRelocationForSymbol(RE, Value.SymbolName); 275 else 276 addRelocationForSection(RE, Value.SectionID); 277 resolveRelocation(Target, (uint64_t)Target, 278 (uint64_t)Section.Address + Section.StubOffset, 279 RelType, 0); 280 Section.StubOffset += getMaxStubSize(); 281 } 282 } else { 283 RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend); 284 if (Value.SymbolName) 285 addRelocationForSymbol(RE, Value.SymbolName); 286 else 287 addRelocationForSection(RE, Value.SectionID); 288 } 289 } 290 291 292 bool RuntimeDyldMachO::isCompatibleFormat( 293 const MemoryBuffer *InputBuffer) const { 294 StringRef Magic = InputBuffer->getBuffer().slice(0, 4); 295 if (Magic == "\xFE\xED\xFA\xCE") return true; 296 if (Magic == "\xCE\xFA\xED\xFE") return true; 297 if (Magic == "\xFE\xED\xFA\xCF") return true; 298 if (Magic == "\xCF\xFA\xED\xFE") return true; 299 return false; 300 } 301 302 } // end namespace llvm 303