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 "RuntimeDyldMachO.h" 16 #include "llvm/ADT/OwningPtr.h" 17 #include "llvm/ADT/STLExtras.h" 18 #include "llvm/ADT/StringRef.h" 19 using namespace llvm; 20 using namespace llvm::object; 21 22 namespace llvm { 23 24 static unsigned char *processFDE(unsigned char *P, intptr_t DeltaForText, intptr_t DeltaForEH) { 25 uint32_t Length = *((uint32_t*)P); 26 P += 4; 27 unsigned char *Ret = P + Length; 28 uint32_t Offset = *((uint32_t*)P); 29 if (Offset == 0) // is a CIE 30 return Ret; 31 32 P += 4; 33 intptr_t FDELocation = *((intptr_t*)P); 34 intptr_t NewLocation = FDELocation - DeltaForText; 35 *((intptr_t*)P) = NewLocation; 36 P += sizeof(intptr_t); 37 38 // Skip the FDE address range 39 P += sizeof(intptr_t); 40 41 uint8_t Augmentationsize = *P; 42 P += 1; 43 if (Augmentationsize != 0) { 44 intptr_t LSDA = *((intptr_t*)P); 45 intptr_t NewLSDA = LSDA - DeltaForEH; 46 *((intptr_t*)P) = NewLSDA; 47 } 48 49 return Ret; 50 } 51 52 static intptr_t computeDelta(SectionEntry *A, SectionEntry *B) { 53 intptr_t ObjDistance = A->ObjAddress - B->ObjAddress; 54 intptr_t MemDistance = A->LoadAddress - B->LoadAddress; 55 return ObjDistance - MemDistance; 56 } 57 58 StringRef RuntimeDyldMachO::getEHFrameSection() { 59 SectionEntry *Text = NULL; 60 SectionEntry *EHFrame = NULL; 61 SectionEntry *ExceptTab = NULL; 62 for (int i = 0, e = Sections.size(); i != e; ++i) { 63 if (Sections[i].Name == "__eh_frame") 64 EHFrame = &Sections[i]; 65 else if (Sections[i].Name == "__text") 66 Text = &Sections[i]; 67 else if (Sections[i].Name == "__gcc_except_tab") 68 ExceptTab = &Sections[i]; 69 } 70 if (Text == NULL || EHFrame == NULL) 71 return StringRef(); 72 73 intptr_t DeltaForText = computeDelta(Text, EHFrame); 74 intptr_t DeltaForEH = 0; 75 if (ExceptTab) 76 DeltaForEH = computeDelta(ExceptTab, EHFrame); 77 78 unsigned char *P = EHFrame->Address; 79 unsigned char *End = P + EHFrame->Size; 80 do { 81 P = processFDE(P, DeltaForText, DeltaForEH); 82 } while(P != End); 83 84 return StringRef((char*)EHFrame->Address, EHFrame->Size); 85 } 86 87 void RuntimeDyldMachO::resolveRelocation(const RelocationEntry &RE, 88 uint64_t Value) { 89 const SectionEntry &Section = Sections[RE.SectionID]; 90 return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend, 91 RE.IsPCRel, RE.Size); 92 } 93 94 void RuntimeDyldMachO::resolveRelocation(const SectionEntry &Section, 95 uint64_t Offset, 96 uint64_t Value, 97 uint32_t Type, 98 int64_t Addend, 99 bool isPCRel, 100 unsigned LogSize) { 101 uint8_t *LocalAddress = Section.Address + Offset; 102 uint64_t FinalAddress = Section.LoadAddress + Offset; 103 unsigned MachoType = Type; 104 unsigned Size = 1 << LogSize; 105 106 DEBUG(dbgs() << "resolveRelocation LocalAddress: " 107 << format("%p", LocalAddress) 108 << " FinalAddress: " << format("%p", FinalAddress) 109 << " Value: " << format("%p", Value) 110 << " Addend: " << Addend 111 << " isPCRel: " << isPCRel 112 << " MachoType: " << MachoType 113 << " Size: " << Size 114 << "\n"); 115 116 // This just dispatches to the proper target specific routine. 117 switch (Arch) { 118 default: llvm_unreachable("Unsupported CPU type!"); 119 case Triple::x86_64: 120 resolveX86_64Relocation(LocalAddress, 121 FinalAddress, 122 (uintptr_t)Value, 123 isPCRel, 124 MachoType, 125 Size, 126 Addend); 127 break; 128 case Triple::x86: 129 resolveI386Relocation(LocalAddress, 130 FinalAddress, 131 (uintptr_t)Value, 132 isPCRel, 133 MachoType, 134 Size, 135 Addend); 136 break; 137 case Triple::arm: // Fall through. 138 case Triple::thumb: 139 resolveARMRelocation(LocalAddress, 140 FinalAddress, 141 (uintptr_t)Value, 142 isPCRel, 143 MachoType, 144 Size, 145 Addend); 146 break; 147 } 148 } 149 150 bool RuntimeDyldMachO::resolveI386Relocation(uint8_t *LocalAddress, 151 uint64_t FinalAddress, 152 uint64_t Value, 153 bool isPCRel, 154 unsigned Type, 155 unsigned Size, 156 int64_t Addend) { 157 if (isPCRel) 158 Value -= FinalAddress + 4; // see resolveX86_64Relocation 159 160 switch (Type) { 161 default: 162 llvm_unreachable("Invalid relocation type!"); 163 case macho::RIT_Vanilla: { 164 uint8_t *p = LocalAddress; 165 uint64_t ValueToWrite = Value + Addend; 166 for (unsigned i = 0; i < Size; ++i) { 167 *p++ = (uint8_t)(ValueToWrite & 0xff); 168 ValueToWrite >>= 8; 169 } 170 return false; 171 } 172 case macho::RIT_Difference: 173 case macho::RIT_Generic_LocalDifference: 174 case macho::RIT_Generic_PreboundLazyPointer: 175 return Error("Relocation type not implemented yet!"); 176 } 177 } 178 179 bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress, 180 uint64_t FinalAddress, 181 uint64_t Value, 182 bool isPCRel, 183 unsigned Type, 184 unsigned Size, 185 int64_t Addend) { 186 // If the relocation is PC-relative, the value to be encoded is the 187 // pointer difference. 188 if (isPCRel) 189 // FIXME: It seems this value needs to be adjusted by 4 for an effective PC 190 // address. Is that expected? Only for branches, perhaps? 191 Value -= FinalAddress + 4; 192 193 switch(Type) { 194 default: 195 llvm_unreachable("Invalid relocation type!"); 196 case macho::RIT_X86_64_Signed1: 197 case macho::RIT_X86_64_Signed2: 198 case macho::RIT_X86_64_Signed4: 199 case macho::RIT_X86_64_Signed: 200 case macho::RIT_X86_64_Unsigned: 201 case macho::RIT_X86_64_Branch: { 202 Value += Addend; 203 // Mask in the target value a byte at a time (we don't have an alignment 204 // guarantee for the target address, so this is safest). 205 uint8_t *p = (uint8_t*)LocalAddress; 206 for (unsigned i = 0; i < Size; ++i) { 207 *p++ = (uint8_t)Value; 208 Value >>= 8; 209 } 210 return false; 211 } 212 case macho::RIT_X86_64_GOTLoad: 213 case macho::RIT_X86_64_GOT: 214 case macho::RIT_X86_64_Subtractor: 215 case macho::RIT_X86_64_TLV: 216 return Error("Relocation type not implemented yet!"); 217 } 218 } 219 220 bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress, 221 uint64_t FinalAddress, 222 uint64_t Value, 223 bool isPCRel, 224 unsigned Type, 225 unsigned Size, 226 int64_t Addend) { 227 // If the relocation is PC-relative, the value to be encoded is the 228 // pointer difference. 229 if (isPCRel) { 230 Value -= FinalAddress; 231 // ARM PCRel relocations have an effective-PC offset of two instructions 232 // (four bytes in Thumb mode, 8 bytes in ARM mode). 233 // FIXME: For now, assume ARM mode. 234 Value -= 8; 235 } 236 237 switch(Type) { 238 default: 239 llvm_unreachable("Invalid relocation type!"); 240 case macho::RIT_Vanilla: { 241 // Mask in the target value a byte at a time (we don't have an alignment 242 // guarantee for the target address, so this is safest). 243 uint8_t *p = (uint8_t*)LocalAddress; 244 for (unsigned i = 0; i < Size; ++i) { 245 *p++ = (uint8_t)Value; 246 Value >>= 8; 247 } 248 break; 249 } 250 case macho::RIT_ARM_Branch24Bit: { 251 // Mask the value into the target address. We know instructions are 252 // 32-bit aligned, so we can do it all at once. 253 uint32_t *p = (uint32_t*)LocalAddress; 254 // The low two bits of the value are not encoded. 255 Value >>= 2; 256 // Mask the value to 24 bits. 257 Value &= 0xffffff; 258 // FIXME: If the destination is a Thumb function (and the instruction 259 // is a non-predicated BL instruction), we need to change it to a BLX 260 // instruction instead. 261 262 // Insert the value into the instruction. 263 *p = (*p & ~0xffffff) | Value; 264 break; 265 } 266 case macho::RIT_ARM_ThumbBranch22Bit: 267 case macho::RIT_ARM_ThumbBranch32Bit: 268 case macho::RIT_ARM_Half: 269 case macho::RIT_ARM_HalfDifference: 270 case macho::RIT_Pair: 271 case macho::RIT_Difference: 272 case macho::RIT_ARM_LocalDifference: 273 case macho::RIT_ARM_PreboundLazyPointer: 274 return Error("Relocation type not implemented yet!"); 275 } 276 return false; 277 } 278 279 void RuntimeDyldMachO::processRelocationRef(unsigned SectionID, 280 RelocationRef RelI, 281 ObjectImage &Obj, 282 ObjSectionToIDMap &ObjSectionToID, 283 const SymbolTableMap &Symbols, 284 StubMap &Stubs) { 285 const ObjectFile *OF = Obj.getObjectFile(); 286 const MachOObjectFile *MachO = static_cast<const MachOObjectFile*>(OF); 287 macho::RelocationEntry RE = MachO->getRelocation(RelI.getRawDataRefImpl()); 288 289 uint32_t RelType = MachO->getAnyRelocationType(RE); 290 RelocationValueRef Value; 291 SectionEntry &Section = Sections[SectionID]; 292 293 bool isExtern = MachO->getPlainRelocationExternal(RE); 294 bool IsPCRel = MachO->getAnyRelocationPCRel(RE); 295 unsigned Size = MachO->getAnyRelocationLength(RE); 296 uint64_t Offset; 297 RelI.getOffset(Offset); 298 uint8_t *LocalAddress = Section.Address + Offset; 299 unsigned NumBytes = 1 << Size; 300 uint64_t Addend = 0; 301 memcpy(&Addend, LocalAddress, NumBytes); 302 303 if (isExtern) { 304 // Obtain the symbol name which is referenced in the relocation 305 symbol_iterator Symbol = RelI.getSymbol(); 306 StringRef TargetName; 307 Symbol->getName(TargetName); 308 // First search for the symbol in the local symbol table 309 SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data()); 310 if (lsi != Symbols.end()) { 311 Value.SectionID = lsi->second.first; 312 Value.Addend = lsi->second.second + Addend; 313 } else { 314 // Search for the symbol in the global symbol table 315 SymbolTableMap::const_iterator gsi = GlobalSymbolTable.find(TargetName.data()); 316 if (gsi != GlobalSymbolTable.end()) { 317 Value.SectionID = gsi->second.first; 318 Value.Addend = gsi->second.second + Addend; 319 } else { 320 Value.SymbolName = TargetName.data(); 321 Value.Addend = Addend; 322 } 323 } 324 } else { 325 SectionRef Sec = MachO->getRelocationSection(RE); 326 Value.SectionID = findOrEmitSection(Obj, Sec, true, ObjSectionToID); 327 uint64_t Addr; 328 Sec.getAddress(Addr); 329 Value.Addend = Addend - Addr; 330 } 331 332 if (Arch == Triple::x86_64 && RelType == macho::RIT_X86_64_GOT) { 333 assert(IsPCRel); 334 assert(Size == 2); 335 StubMap::const_iterator i = Stubs.find(Value); 336 uint8_t *Addr; 337 if (i != Stubs.end()) { 338 Addr = Section.Address + i->second; 339 } else { 340 Stubs[Value] = Section.StubOffset; 341 uint8_t *GOTEntry = Section.Address + Section.StubOffset; 342 RelocationEntry RE(SectionID, Section.StubOffset, 343 macho::RIT_X86_64_Unsigned, Value.Addend - 4, false, 344 3); 345 if (Value.SymbolName) 346 addRelocationForSymbol(RE, Value.SymbolName); 347 else 348 addRelocationForSection(RE, Value.SectionID); 349 Section.StubOffset += 8; 350 Addr = GOTEntry; 351 } 352 resolveRelocation(Section, Offset, (uint64_t)Addr, 353 macho::RIT_X86_64_Unsigned, 4, true, 2); 354 } else if (Arch == Triple::arm && 355 (RelType & 0xf) == macho::RIT_ARM_Branch24Bit) { 356 // This is an ARM branch relocation, need to use a stub function. 357 358 // Look up for existing stub. 359 StubMap::const_iterator i = Stubs.find(Value); 360 if (i != Stubs.end()) 361 resolveRelocation(Section, Offset, 362 (uint64_t)Section.Address + i->second, 363 RelType, 0, IsPCRel, Size); 364 else { 365 // Create a new stub function. 366 Stubs[Value] = Section.StubOffset; 367 uint8_t *StubTargetAddr = createStubFunction(Section.Address + 368 Section.StubOffset); 369 RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, 370 macho::RIT_Vanilla, Value.Addend); 371 if (Value.SymbolName) 372 addRelocationForSymbol(RE, Value.SymbolName); 373 else 374 addRelocationForSection(RE, Value.SectionID); 375 resolveRelocation(Section, Offset, 376 (uint64_t)Section.Address + Section.StubOffset, 377 RelType, 0, IsPCRel, Size); 378 Section.StubOffset += getMaxStubSize(); 379 } 380 } else { 381 RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, 382 IsPCRel, Size); 383 if (Value.SymbolName) 384 addRelocationForSymbol(RE, Value.SymbolName); 385 else 386 addRelocationForSection(RE, Value.SectionID); 387 } 388 } 389 390 391 bool RuntimeDyldMachO::isCompatibleFormat( 392 const ObjectBuffer *InputBuffer) const { 393 if (InputBuffer->getBufferSize() < 4) 394 return false; 395 StringRef Magic(InputBuffer->getBufferStart(), 4); 396 if (Magic == "\xFE\xED\xFA\xCE") return true; 397 if (Magic == "\xCE\xFA\xED\xFE") return true; 398 if (Magic == "\xFE\xED\xFA\xCF") return true; 399 if (Magic == "\xCF\xFA\xED\xFE") return true; 400 return false; 401 } 402 403 } // end namespace llvm 404