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 #include "RuntimeDyldMachO.h" 15 #include "llvm/ADT/STLExtras.h" 16 #include "llvm/ADT/StringRef.h" 17 using namespace llvm; 18 using namespace llvm::object; 19 20 #define DEBUG_TYPE "dyld" 21 22 namespace llvm { 23 24 static unsigned char *processFDE(unsigned char *P, intptr_t DeltaForText, 25 intptr_t DeltaForEH) { 26 uint32_t Length = *((uint32_t *)P); 27 P += 4; 28 unsigned char *Ret = P + Length; 29 uint32_t Offset = *((uint32_t *)P); 30 if (Offset == 0) // is a CIE 31 return Ret; 32 33 P += 4; 34 intptr_t FDELocation = *((intptr_t *)P); 35 intptr_t NewLocation = FDELocation - DeltaForText; 36 *((intptr_t *)P) = NewLocation; 37 P += sizeof(intptr_t); 38 39 // Skip the FDE address range 40 P += sizeof(intptr_t); 41 42 uint8_t Augmentationsize = *P; 43 P += 1; 44 if (Augmentationsize != 0) { 45 intptr_t LSDA = *((intptr_t *)P); 46 intptr_t NewLSDA = LSDA - DeltaForEH; 47 *((intptr_t *)P) = NewLSDA; 48 } 49 50 return Ret; 51 } 52 53 static intptr_t computeDelta(SectionEntry *A, SectionEntry *B) { 54 intptr_t ObjDistance = A->ObjAddress - B->ObjAddress; 55 intptr_t MemDistance = A->LoadAddress - B->LoadAddress; 56 return ObjDistance - MemDistance; 57 } 58 59 void RuntimeDyldMachO::registerEHFrames() { 60 61 if (!MemMgr) 62 return; 63 for (int i = 0, e = UnregisteredEHFrameSections.size(); i != e; ++i) { 64 EHFrameRelatedSections &SectionInfo = UnregisteredEHFrameSections[i]; 65 if (SectionInfo.EHFrameSID == RTDYLD_INVALID_SECTION_ID || 66 SectionInfo.TextSID == RTDYLD_INVALID_SECTION_ID) 67 continue; 68 SectionEntry *Text = &Sections[SectionInfo.TextSID]; 69 SectionEntry *EHFrame = &Sections[SectionInfo.EHFrameSID]; 70 SectionEntry *ExceptTab = NULL; 71 if (SectionInfo.ExceptTabSID != RTDYLD_INVALID_SECTION_ID) 72 ExceptTab = &Sections[SectionInfo.ExceptTabSID]; 73 74 intptr_t DeltaForText = computeDelta(Text, EHFrame); 75 intptr_t DeltaForEH = 0; 76 if (ExceptTab) 77 DeltaForEH = computeDelta(ExceptTab, EHFrame); 78 79 unsigned char *P = EHFrame->Address; 80 unsigned char *End = P + EHFrame->Size; 81 do { 82 P = processFDE(P, DeltaForText, DeltaForEH); 83 } while (P != End); 84 85 MemMgr->registerEHFrames(EHFrame->Address, EHFrame->LoadAddress, 86 EHFrame->Size); 87 } 88 UnregisteredEHFrameSections.clear(); 89 } 90 91 void RuntimeDyldMachO::finalizeLoad(ObjSectionToIDMap &SectionMap) { 92 unsigned EHFrameSID = RTDYLD_INVALID_SECTION_ID; 93 unsigned TextSID = RTDYLD_INVALID_SECTION_ID; 94 unsigned ExceptTabSID = RTDYLD_INVALID_SECTION_ID; 95 ObjSectionToIDMap::iterator i, e; 96 for (i = SectionMap.begin(), e = SectionMap.end(); i != e; ++i) { 97 const SectionRef &Section = i->first; 98 StringRef Name; 99 Section.getName(Name); 100 if (Name == "__eh_frame") 101 EHFrameSID = i->second; 102 else if (Name == "__text") 103 TextSID = i->second; 104 else if (Name == "__gcc_except_tab") 105 ExceptTabSID = i->second; 106 } 107 UnregisteredEHFrameSections.push_back( 108 EHFrameRelatedSections(EHFrameSID, TextSID, ExceptTabSID)); 109 } 110 111 // The target location for the relocation is described by RE.SectionID and 112 // RE.Offset. RE.SectionID can be used to find the SectionEntry. Each 113 // SectionEntry has three members describing its location. 114 // SectionEntry::Address is the address at which the section has been loaded 115 // into memory in the current (host) process. SectionEntry::LoadAddress is the 116 // address that the section will have in the target process. 117 // SectionEntry::ObjAddress is the address of the bits for this section in the 118 // original emitted object image (also in the current address space). 119 // 120 // Relocations will be applied as if the section were loaded at 121 // SectionEntry::LoadAddress, but they will be applied at an address based 122 // on SectionEntry::Address. SectionEntry::ObjAddress will be used to refer to 123 // Target memory contents if they are required for value calculations. 124 // 125 // The Value parameter here is the load address of the symbol for the 126 // relocation to be applied. For relocations which refer to symbols in the 127 // current object Value will be the LoadAddress of the section in which 128 // the symbol resides (RE.Addend provides additional information about the 129 // symbol location). For external symbols, Value will be the address of the 130 // symbol in the target address space. 131 void RuntimeDyldMachO::resolveRelocation(const RelocationEntry &RE, 132 uint64_t Value) { 133 const SectionEntry &Section = Sections[RE.SectionID]; 134 return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend, 135 RE.IsPCRel, RE.Size); 136 } 137 138 void RuntimeDyldMachO::resolveRelocation(const SectionEntry &Section, 139 uint64_t Offset, uint64_t Value, 140 uint32_t Type, int64_t Addend, 141 bool isPCRel, unsigned LogSize) { 142 uint8_t *LocalAddress = Section.Address + Offset; 143 uint64_t FinalAddress = Section.LoadAddress + Offset; 144 unsigned MachoType = Type; 145 unsigned Size = 1 << LogSize; 146 147 DEBUG(dbgs() << "resolveRelocation LocalAddress: " 148 << format("%p", LocalAddress) 149 << " FinalAddress: " << format("%p", FinalAddress) 150 << " Value: " << format("%p", Value) << " Addend: " << Addend 151 << " isPCRel: " << isPCRel << " MachoType: " << MachoType 152 << " Size: " << Size << "\n"); 153 154 // This just dispatches to the proper target specific routine. 155 switch (Arch) { 156 default: 157 llvm_unreachable("Unsupported CPU type!"); 158 case Triple::x86_64: 159 resolveX86_64Relocation(LocalAddress, FinalAddress, (uintptr_t)Value, 160 isPCRel, MachoType, Size, Addend); 161 break; 162 case Triple::x86: 163 resolveI386Relocation(LocalAddress, FinalAddress, (uintptr_t)Value, isPCRel, 164 MachoType, Size, Addend); 165 break; 166 case Triple::arm: // Fall through. 167 case Triple::thumb: 168 resolveARMRelocation(LocalAddress, FinalAddress, (uintptr_t)Value, isPCRel, 169 MachoType, Size, Addend); 170 break; 171 case Triple::arm64: 172 resolveARM64Relocation(LocalAddress, FinalAddress, (uintptr_t)Value, 173 isPCRel, MachoType, Size, Addend); 174 break; 175 } 176 } 177 178 bool RuntimeDyldMachO::resolveI386Relocation(uint8_t *LocalAddress, 179 uint64_t FinalAddress, 180 uint64_t Value, bool isPCRel, 181 unsigned Type, unsigned Size, 182 int64_t Addend) { 183 if (isPCRel) 184 Value -= FinalAddress + 4; // see resolveX86_64Relocation 185 186 switch (Type) { 187 default: 188 llvm_unreachable("Invalid relocation type!"); 189 case MachO::GENERIC_RELOC_VANILLA: { 190 uint8_t *p = LocalAddress; 191 uint64_t ValueToWrite = Value + Addend; 192 for (unsigned i = 0; i < Size; ++i) { 193 *p++ = (uint8_t)(ValueToWrite & 0xff); 194 ValueToWrite >>= 8; 195 } 196 return false; 197 } 198 case MachO::GENERIC_RELOC_SECTDIFF: 199 case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: 200 case MachO::GENERIC_RELOC_PB_LA_PTR: 201 return Error("Relocation type not implemented yet!"); 202 } 203 } 204 205 bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress, 206 uint64_t FinalAddress, 207 uint64_t Value, bool isPCRel, 208 unsigned Type, unsigned Size, 209 int64_t Addend) { 210 // If the relocation is PC-relative, the value to be encoded is the 211 // pointer difference. 212 if (isPCRel) 213 // FIXME: It seems this value needs to be adjusted by 4 for an effective PC 214 // address. Is that expected? Only for branches, perhaps? 215 Value -= FinalAddress + 4; 216 217 switch (Type) { 218 default: 219 llvm_unreachable("Invalid relocation type!"); 220 case MachO::X86_64_RELOC_SIGNED_1: 221 case MachO::X86_64_RELOC_SIGNED_2: 222 case MachO::X86_64_RELOC_SIGNED_4: 223 case MachO::X86_64_RELOC_SIGNED: 224 case MachO::X86_64_RELOC_UNSIGNED: 225 case MachO::X86_64_RELOC_BRANCH: { 226 Value += Addend; 227 // Mask in the target value a byte at a time (we don't have an alignment 228 // guarantee for the target address, so this is safest). 229 uint8_t *p = (uint8_t *)LocalAddress; 230 for (unsigned i = 0; i < Size; ++i) { 231 *p++ = (uint8_t)Value; 232 Value >>= 8; 233 } 234 return false; 235 } 236 case MachO::X86_64_RELOC_GOT_LOAD: 237 case MachO::X86_64_RELOC_GOT: 238 case MachO::X86_64_RELOC_SUBTRACTOR: 239 case MachO::X86_64_RELOC_TLV: 240 return Error("Relocation type not implemented yet!"); 241 } 242 } 243 244 bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress, 245 uint64_t FinalAddress, 246 uint64_t Value, bool isPCRel, 247 unsigned Type, unsigned Size, 248 int64_t Addend) { 249 // If the relocation is PC-relative, the value to be encoded is the 250 // pointer difference. 251 if (isPCRel) { 252 Value -= FinalAddress; 253 // ARM PCRel relocations have an effective-PC offset of two instructions 254 // (four bytes in Thumb mode, 8 bytes in ARM mode). 255 // FIXME: For now, assume ARM mode. 256 Value -= 8; 257 } 258 259 switch (Type) { 260 default: 261 llvm_unreachable("Invalid relocation type!"); 262 case MachO::ARM_RELOC_VANILLA: { 263 // Mask in the target value a byte at a time (we don't have an alignment 264 // guarantee for the target address, so this is safest). 265 uint8_t *p = (uint8_t *)LocalAddress; 266 for (unsigned i = 0; i < Size; ++i) { 267 *p++ = (uint8_t)Value; 268 Value >>= 8; 269 } 270 break; 271 } 272 case MachO::ARM_RELOC_BR24: { 273 // Mask the value into the target address. We know instructions are 274 // 32-bit aligned, so we can do it all at once. 275 uint32_t *p = (uint32_t *)LocalAddress; 276 // The low two bits of the value are not encoded. 277 Value >>= 2; 278 // Mask the value to 24 bits. 279 Value &= 0xffffff; 280 // FIXME: If the destination is a Thumb function (and the instruction 281 // is a non-predicated BL instruction), we need to change it to a BLX 282 // instruction instead. 283 284 // Insert the value into the instruction. 285 *p = (*p & ~0xffffff) | Value; 286 break; 287 } 288 case MachO::ARM_THUMB_RELOC_BR22: 289 case MachO::ARM_THUMB_32BIT_BRANCH: 290 case MachO::ARM_RELOC_HALF: 291 case MachO::ARM_RELOC_HALF_SECTDIFF: 292 case MachO::ARM_RELOC_PAIR: 293 case MachO::ARM_RELOC_SECTDIFF: 294 case MachO::ARM_RELOC_LOCAL_SECTDIFF: 295 case MachO::ARM_RELOC_PB_LA_PTR: 296 return Error("Relocation type not implemented yet!"); 297 } 298 return false; 299 } 300 301 bool RuntimeDyldMachO::resolveARM64Relocation(uint8_t *LocalAddress, 302 uint64_t FinalAddress, 303 uint64_t Value, bool isPCRel, 304 unsigned Type, unsigned Size, 305 int64_t Addend) { 306 // If the relocation is PC-relative, the value to be encoded is the 307 // pointer difference. 308 if (isPCRel) 309 Value -= FinalAddress; 310 311 switch (Type) { 312 default: 313 llvm_unreachable("Invalid relocation type!"); 314 case MachO::ARM64_RELOC_UNSIGNED: { 315 // Mask in the target value a byte at a time (we don't have an alignment 316 // guarantee for the target address, so this is safest). 317 uint8_t *p = (uint8_t *)LocalAddress; 318 for (unsigned i = 0; i < Size; ++i) { 319 *p++ = (uint8_t)Value; 320 Value >>= 8; 321 } 322 break; 323 } 324 case MachO::ARM64_RELOC_BRANCH26: { 325 // Mask the value into the target address. We know instructions are 326 // 32-bit aligned, so we can do it all at once. 327 uint32_t *p = (uint32_t *)LocalAddress; 328 // The low two bits of the value are not encoded. 329 Value >>= 2; 330 // Mask the value to 26 bits. 331 Value &= 0x3ffffff; 332 // Insert the value into the instruction. 333 *p = (*p & ~0x3ffffff) | Value; 334 break; 335 } 336 case MachO::ARM64_RELOC_SUBTRACTOR: 337 case MachO::ARM64_RELOC_PAGE21: 338 case MachO::ARM64_RELOC_PAGEOFF12: 339 case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: 340 case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: 341 case MachO::ARM64_RELOC_POINTER_TO_GOT: 342 case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21: 343 case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12: 344 case MachO::ARM64_RELOC_ADDEND: 345 return Error("Relocation type not implemented yet!"); 346 } 347 return false; 348 } 349 350 relocation_iterator RuntimeDyldMachO::processRelocationRef( 351 unsigned SectionID, relocation_iterator RelI, ObjectImage &Obj, 352 ObjSectionToIDMap &ObjSectionToID, const SymbolTableMap &Symbols, 353 StubMap &Stubs) { 354 const ObjectFile *OF = Obj.getObjectFile(); 355 const MachOObjectFile *MachO = static_cast<const MachOObjectFile *>(OF); 356 MachO::any_relocation_info RE = 357 MachO->getRelocation(RelI->getRawDataRefImpl()); 358 359 uint32_t RelType = MachO->getAnyRelocationType(RE); 360 361 // FIXME: Properly handle scattered relocations. 362 // For now, optimistically skip these: they can often be ignored, as 363 // the static linker will already have applied the relocation, and it 364 // only needs to be reapplied if symbols move relative to one another. 365 // Note: This will fail horribly where the relocations *do* need to be 366 // applied, but that was already the case. 367 if (MachO->isRelocationScattered(RE)) 368 return ++RelI; 369 370 RelocationValueRef Value; 371 SectionEntry &Section = Sections[SectionID]; 372 373 bool isExtern = MachO->getPlainRelocationExternal(RE); 374 bool IsPCRel = MachO->getAnyRelocationPCRel(RE); 375 unsigned Size = MachO->getAnyRelocationLength(RE); 376 uint64_t Offset; 377 RelI->getOffset(Offset); 378 uint8_t *LocalAddress = Section.Address + Offset; 379 unsigned NumBytes = 1 << Size; 380 uint64_t Addend = 0; 381 memcpy(&Addend, LocalAddress, NumBytes); 382 383 if (isExtern) { 384 // Obtain the symbol name which is referenced in the relocation 385 symbol_iterator Symbol = RelI->getSymbol(); 386 StringRef TargetName; 387 Symbol->getName(TargetName); 388 // First search for the symbol in the local symbol table 389 SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data()); 390 if (lsi != Symbols.end()) { 391 Value.SectionID = lsi->second.first; 392 Value.Addend = lsi->second.second + Addend; 393 } else { 394 // Search for the symbol in the global symbol table 395 SymbolTableMap::const_iterator gsi = 396 GlobalSymbolTable.find(TargetName.data()); 397 if (gsi != GlobalSymbolTable.end()) { 398 Value.SectionID = gsi->second.first; 399 Value.Addend = gsi->second.second + Addend; 400 } else { 401 Value.SymbolName = TargetName.data(); 402 Value.Addend = Addend; 403 } 404 } 405 } else { 406 SectionRef Sec = MachO->getRelocationSection(RE); 407 bool IsCode = false; 408 Sec.isText(IsCode); 409 Value.SectionID = findOrEmitSection(Obj, Sec, IsCode, ObjSectionToID); 410 uint64_t Addr; 411 Sec.getAddress(Addr); 412 Value.Addend = Addend - Addr; 413 if (IsPCRel) 414 Value.Addend += Offset + NumBytes; 415 } 416 417 if (Arch == Triple::x86_64 && (RelType == MachO::X86_64_RELOC_GOT || 418 RelType == MachO::X86_64_RELOC_GOT_LOAD)) { 419 assert(IsPCRel); 420 assert(Size == 2); 421 StubMap::const_iterator i = Stubs.find(Value); 422 uint8_t *Addr; 423 if (i != Stubs.end()) { 424 Addr = Section.Address + i->second; 425 } else { 426 Stubs[Value] = Section.StubOffset; 427 uint8_t *GOTEntry = Section.Address + Section.StubOffset; 428 RelocationEntry RE(SectionID, Section.StubOffset, 429 MachO::X86_64_RELOC_UNSIGNED, 0, false, 3); 430 if (Value.SymbolName) 431 addRelocationForSymbol(RE, Value.SymbolName); 432 else 433 addRelocationForSection(RE, Value.SectionID); 434 Section.StubOffset += 8; 435 Addr = GOTEntry; 436 } 437 resolveRelocation(Section, Offset, (uint64_t)Addr, 438 MachO::X86_64_RELOC_UNSIGNED, Value.Addend, true, 2); 439 } else if (Arch == Triple::arm && (RelType & 0xf) == MachO::ARM_RELOC_BR24) { 440 // This is an ARM branch relocation, need to use a stub function. 441 442 // Look up for existing stub. 443 StubMap::const_iterator i = Stubs.find(Value); 444 if (i != Stubs.end()) 445 resolveRelocation(Section, Offset, (uint64_t)Section.Address + i->second, 446 RelType, 0, IsPCRel, Size); 447 else { 448 // Create a new stub function. 449 Stubs[Value] = Section.StubOffset; 450 uint8_t *StubTargetAddr = 451 createStubFunction(Section.Address + Section.StubOffset); 452 RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, 453 MachO::GENERIC_RELOC_VANILLA, Value.Addend); 454 if (Value.SymbolName) 455 addRelocationForSymbol(RE, Value.SymbolName); 456 else 457 addRelocationForSection(RE, Value.SectionID); 458 resolveRelocation(Section, Offset, 459 (uint64_t)Section.Address + Section.StubOffset, RelType, 460 0, IsPCRel, Size); 461 Section.StubOffset += getMaxStubSize(); 462 } 463 } else { 464 RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, IsPCRel, Size); 465 if (Value.SymbolName) 466 addRelocationForSymbol(RE, Value.SymbolName); 467 else 468 addRelocationForSection(RE, Value.SectionID); 469 } 470 return ++RelI; 471 } 472 473 bool 474 RuntimeDyldMachO::isCompatibleFormat(const ObjectBuffer *InputBuffer) const { 475 if (InputBuffer->getBufferSize() < 4) 476 return false; 477 StringRef Magic(InputBuffer->getBufferStart(), 4); 478 if (Magic == "\xFE\xED\xFA\xCE") 479 return true; 480 if (Magic == "\xCE\xFA\xED\xFE") 481 return true; 482 if (Magic == "\xFE\xED\xFA\xCF") 483 return true; 484 if (Magic == "\xCF\xFA\xED\xFE") 485 return true; 486 return false; 487 } 488 489 bool RuntimeDyldMachO::isCompatibleFile(const object::ObjectFile *Obj) const { 490 return Obj->isMachO(); 491 } 492 493 } // end namespace llvm 494