RuntimeDyldMachO.cpp revision 251662
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" 19using namespace llvm; 20using namespace llvm::object; 21 22namespace llvm { 23 24static 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 52static 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 58StringRef 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 87void 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 94void 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 150bool 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 179bool 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 220bool 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 279void 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 SymbolRef Symbol; 306 RelI.getSymbol(Symbol); 307 StringRef TargetName; 308 Symbol.getName(TargetName); 309 // First search for the symbol in the local symbol table 310 SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data()); 311 if (lsi != Symbols.end()) { 312 Value.SectionID = lsi->second.first; 313 Value.Addend = lsi->second.second + Addend; 314 } else { 315 // Search for the symbol in the global symbol table 316 SymbolTableMap::const_iterator gsi = GlobalSymbolTable.find(TargetName.data()); 317 if (gsi != GlobalSymbolTable.end()) { 318 Value.SectionID = gsi->second.first; 319 Value.Addend = gsi->second.second + Addend; 320 } else { 321 Value.SymbolName = TargetName.data(); 322 Value.Addend = Addend; 323 } 324 } 325 } else { 326 SectionRef Sec = MachO->getRelocationSection(RE); 327 Value.SectionID = findOrEmitSection(Obj, Sec, true, ObjSectionToID); 328 uint64_t Addr; 329 Sec.getAddress(Addr); 330 Value.Addend = Addend - Addr; 331 } 332 333 if (Arch == Triple::x86_64 && RelType == macho::RIT_X86_64_GOT) { 334 assert(IsPCRel); 335 assert(Size == 2); 336 StubMap::const_iterator i = Stubs.find(Value); 337 uint8_t *Addr; 338 if (i != Stubs.end()) { 339 Addr = Section.Address + i->second; 340 } else { 341 Stubs[Value] = Section.StubOffset; 342 uint8_t *GOTEntry = Section.Address + Section.StubOffset; 343 RelocationEntry RE(SectionID, Section.StubOffset, 344 macho::RIT_X86_64_Unsigned, Value.Addend - 4, false, 345 3); 346 if (Value.SymbolName) 347 addRelocationForSymbol(RE, Value.SymbolName); 348 else 349 addRelocationForSection(RE, Value.SectionID); 350 Section.StubOffset += 8; 351 Addr = GOTEntry; 352 } 353 resolveRelocation(Section, Offset, (uint64_t)Addr, 354 macho::RIT_X86_64_Unsigned, 4, true, 2); 355 } else if (Arch == Triple::arm && 356 (RelType & 0xf) == macho::RIT_ARM_Branch24Bit) { 357 // This is an ARM branch relocation, need to use a stub function. 358 359 // Look up for existing stub. 360 StubMap::const_iterator i = Stubs.find(Value); 361 if (i != Stubs.end()) 362 resolveRelocation(Section, Offset, 363 (uint64_t)Section.Address + i->second, 364 RelType, 0, IsPCRel, Size); 365 else { 366 // Create a new stub function. 367 Stubs[Value] = Section.StubOffset; 368 uint8_t *StubTargetAddr = createStubFunction(Section.Address + 369 Section.StubOffset); 370 RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, 371 macho::RIT_Vanilla, Value.Addend); 372 if (Value.SymbolName) 373 addRelocationForSymbol(RE, Value.SymbolName); 374 else 375 addRelocationForSection(RE, Value.SectionID); 376 resolveRelocation(Section, Offset, 377 (uint64_t)Section.Address + Section.StubOffset, 378 RelType, 0, IsPCRel, Size); 379 Section.StubOffset += getMaxStubSize(); 380 } 381 } else { 382 RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, 383 IsPCRel, Size); 384 if (Value.SymbolName) 385 addRelocationForSymbol(RE, Value.SymbolName); 386 else 387 addRelocationForSection(RE, Value.SectionID); 388 } 389} 390 391 392bool RuntimeDyldMachO::isCompatibleFormat( 393 const ObjectBuffer *InputBuffer) const { 394 if (InputBuffer->getBufferSize() < 4) 395 return false; 396 StringRef Magic(InputBuffer->getBufferStart(), 4); 397 if (Magic == "\xFE\xED\xFA\xCE") return true; 398 if (Magic == "\xCE\xFA\xED\xFE") return true; 399 if (Magic == "\xFE\xED\xFA\xCF") return true; 400 if (Magic == "\xCF\xFA\xED\xFE") return true; 401 return false; 402} 403 404} // end namespace llvm 405