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