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" 19using namespace llvm; 20using namespace llvm::object; 21 22namespace llvm { 23 24void 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 MachoType, 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 77bool 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 105bool 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 146bool 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 205void 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 = 0; 250 // FIXME: The size and type of the relocation determines if we can 251 // encode an Addend in the target location itself, and if so, how many 252 // bytes we should read in order to get it. We don't yet support doing 253 // that, and just assuming it's sizeof(intptr_t) is blatantly wrong. 254 //Value.Addend = *(const intptr_t *)Target; 255 if (Value.Addend) { 256 // The MachO addend is an offset from the current section. We need it 257 // to be an offset from the destination section 258 Value.Addend += Section.ObjAddress - Sections[Value.SectionID].ObjAddress; 259 } 260 } 261 262 if (Arch == Triple::arm && (RelType & 0xf) == macho::RIT_ARM_Branch24Bit) { 263 // This is an ARM branch relocation, need to use a stub function. 264 265 // Look up for existing stub. 266 StubMap::const_iterator i = Stubs.find(Value); 267 if (i != Stubs.end()) 268 resolveRelocation(Target, (uint64_t)Target, 269 (uint64_t)Section.Address + i->second, 270 RelType, 0); 271 else { 272 // Create a new stub function. 273 Stubs[Value] = Section.StubOffset; 274 uint8_t *StubTargetAddr = createStubFunction(Section.Address + 275 Section.StubOffset); 276 RelocationEntry RE(Rel.SectionID, StubTargetAddr - Section.Address, 277 macho::RIT_Vanilla, Value.Addend); 278 if (Value.SymbolName) 279 addRelocationForSymbol(RE, Value.SymbolName); 280 else 281 addRelocationForSection(RE, Value.SectionID); 282 resolveRelocation(Target, (uint64_t)Target, 283 (uint64_t)Section.Address + Section.StubOffset, 284 RelType, 0); 285 Section.StubOffset += getMaxStubSize(); 286 } 287 } else { 288 RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend); 289 if (Value.SymbolName) 290 addRelocationForSymbol(RE, Value.SymbolName); 291 else 292 addRelocationForSection(RE, Value.SectionID); 293 } 294} 295 296 297bool RuntimeDyldMachO::isCompatibleFormat( 298 const MemoryBuffer *InputBuffer) const { 299 StringRef Magic = InputBuffer->getBuffer().slice(0, 4); 300 if (Magic == "\xFE\xED\xFA\xCE") return true; 301 if (Magic == "\xCE\xFA\xED\xFE") return true; 302 if (Magic == "\xFE\xED\xFA\xCF") return true; 303 if (Magic == "\xCF\xFA\xED\xFE") return true; 304 return false; 305} 306 307} // end namespace llvm 308