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 void RuntimeDyldMachO::resolveRelocation(const SectionEntry &Section, 25 uint64_t Offset, 26 uint64_t Value, 27 uint32_t Type, 28 int64_t Addend) { 29 uint8_t *LocalAddress = Section.Address + Offset; 30 uint64_t FinalAddress = Section.LoadAddress + Offset; 31 bool isPCRel = (Type >> 24) & 1; 32 unsigned MachoType = (Type >> 28) & 0xf; 33 unsigned Size = 1 << ((Type >> 25) & 3); 34 35 DEBUG(dbgs() << "resolveRelocation LocalAddress: " 36 << format("%p", LocalAddress) 37 << " FinalAddress: " << format("%p", FinalAddress) 38 << " Value: " << format("%p", Value) 39 << " Addend: " << Addend 40 << " isPCRel: " << isPCRel 41 << " MachoType: " << MachoType 42 << " Size: " << Size 43 << "\n"); 44 45 // This just dispatches to the proper target specific routine. 46 switch (Arch) { 47 default: llvm_unreachable("Unsupported CPU type!"); 48 case Triple::x86_64: 49 resolveX86_64Relocation(LocalAddress, 50 FinalAddress, 51 (uintptr_t)Value, 52 isPCRel, 53 MachoType, 54 Size, 55 Addend); 56 break; 57 case Triple::x86: 58 resolveI386Relocation(LocalAddress, 59 FinalAddress, 60 (uintptr_t)Value, 61 isPCRel, 62 MachoType, 63 Size, 64 Addend); 65 break; 66 case Triple::arm: // Fall through. 67 case Triple::thumb: 68 resolveARMRelocation(LocalAddress, 69 FinalAddress, 70 (uintptr_t)Value, 71 isPCRel, 72 MachoType, 73 Size, 74 Addend); 75 break; 76 } 77 } 78 79 bool RuntimeDyldMachO::resolveI386Relocation(uint8_t *LocalAddress, 80 uint64_t FinalAddress, 81 uint64_t Value, 82 bool isPCRel, 83 unsigned Type, 84 unsigned Size, 85 int64_t Addend) { 86 if (isPCRel) 87 Value -= FinalAddress + 4; // see resolveX86_64Relocation 88 89 switch (Type) { 90 default: 91 llvm_unreachable("Invalid relocation type!"); 92 case macho::RIT_Vanilla: { 93 uint8_t *p = LocalAddress; 94 uint64_t ValueToWrite = Value + Addend; 95 for (unsigned i = 0; i < Size; ++i) { 96 *p++ = (uint8_t)(ValueToWrite & 0xff); 97 ValueToWrite >>= 8; 98 } 99 return false; 100 } 101 case macho::RIT_Difference: 102 case macho::RIT_Generic_LocalDifference: 103 case macho::RIT_Generic_PreboundLazyPointer: 104 return Error("Relocation type not implemented yet!"); 105 } 106 } 107 108 bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress, 109 uint64_t FinalAddress, 110 uint64_t Value, 111 bool isPCRel, 112 unsigned Type, 113 unsigned Size, 114 int64_t Addend) { 115 // If the relocation is PC-relative, the value to be encoded is the 116 // pointer difference. 117 if (isPCRel) 118 // FIXME: It seems this value needs to be adjusted by 4 for an effective PC 119 // address. Is that expected? Only for branches, perhaps? 120 Value -= FinalAddress + 4; 121 122 switch(Type) { 123 default: 124 llvm_unreachable("Invalid relocation type!"); 125 case macho::RIT_X86_64_Signed1: 126 case macho::RIT_X86_64_Signed2: 127 case macho::RIT_X86_64_Signed4: 128 case macho::RIT_X86_64_Signed: 129 case macho::RIT_X86_64_Unsigned: 130 case macho::RIT_X86_64_Branch: { 131 Value += Addend; 132 // Mask in the target value a byte at a time (we don't have an alignment 133 // guarantee for the target address, so this is safest). 134 uint8_t *p = (uint8_t*)LocalAddress; 135 for (unsigned i = 0; i < Size; ++i) { 136 *p++ = (uint8_t)Value; 137 Value >>= 8; 138 } 139 return false; 140 } 141 case macho::RIT_X86_64_GOTLoad: 142 case macho::RIT_X86_64_GOT: 143 case macho::RIT_X86_64_Subtractor: 144 case macho::RIT_X86_64_TLV: 145 return Error("Relocation type not implemented yet!"); 146 } 147 } 148 149 bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress, 150 uint64_t FinalAddress, 151 uint64_t Value, 152 bool isPCRel, 153 unsigned Type, 154 unsigned Size, 155 int64_t Addend) { 156 // If the relocation is PC-relative, the value to be encoded is the 157 // pointer difference. 158 if (isPCRel) { 159 Value -= FinalAddress; 160 // ARM PCRel relocations have an effective-PC offset of two instructions 161 // (four bytes in Thumb mode, 8 bytes in ARM mode). 162 // FIXME: For now, assume ARM mode. 163 Value -= 8; 164 } 165 166 switch(Type) { 167 default: 168 llvm_unreachable("Invalid relocation type!"); 169 case macho::RIT_Vanilla: { 170 // Mask in the target value a byte at a time (we don't have an alignment 171 // guarantee for the target address, so this is safest). 172 uint8_t *p = (uint8_t*)LocalAddress; 173 for (unsigned i = 0; i < Size; ++i) { 174 *p++ = (uint8_t)Value; 175 Value >>= 8; 176 } 177 break; 178 } 179 case macho::RIT_ARM_Branch24Bit: { 180 // Mask the value into the target address. We know instructions are 181 // 32-bit aligned, so we can do it all at once. 182 uint32_t *p = (uint32_t*)LocalAddress; 183 // The low two bits of the value are not encoded. 184 Value >>= 2; 185 // Mask the value to 24 bits. 186 Value &= 0xffffff; 187 // FIXME: If the destination is a Thumb function (and the instruction 188 // is a non-predicated BL instruction), we need to change it to a BLX 189 // instruction instead. 190 191 // Insert the value into the instruction. 192 *p = (*p & ~0xffffff) | Value; 193 break; 194 } 195 case macho::RIT_ARM_ThumbBranch22Bit: 196 case macho::RIT_ARM_ThumbBranch32Bit: 197 case macho::RIT_ARM_Half: 198 case macho::RIT_ARM_HalfDifference: 199 case macho::RIT_Pair: 200 case macho::RIT_Difference: 201 case macho::RIT_ARM_LocalDifference: 202 case macho::RIT_ARM_PreboundLazyPointer: 203 return Error("Relocation type not implemented yet!"); 204 } 205 return false; 206 } 207 208 void RuntimeDyldMachO::processRelocationRef(const ObjRelocationInfo &Rel, 209 ObjectImage &Obj, 210 ObjSectionToIDMap &ObjSectionToID, 211 const SymbolTableMap &Symbols, 212 StubMap &Stubs) { 213 214 uint32_t RelType = (uint32_t) (Rel.Type & 0xffffffffL); 215 RelocationValueRef Value; 216 SectionEntry &Section = Sections[Rel.SectionID]; 217 218 bool isExtern = (RelType >> 27) & 1; 219 if (isExtern) { 220 // Obtain the symbol name which is referenced in the relocation 221 StringRef TargetName; 222 const SymbolRef &Symbol = Rel.Symbol; 223 Symbol.getName(TargetName); 224 // First search for the symbol in the local symbol table 225 SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data()); 226 if (lsi != Symbols.end()) { 227 Value.SectionID = lsi->second.first; 228 Value.Addend = lsi->second.second; 229 } else { 230 // Search for the symbol in the global symbol table 231 SymbolTableMap::const_iterator gsi = GlobalSymbolTable.find(TargetName.data()); 232 if (gsi != GlobalSymbolTable.end()) { 233 Value.SectionID = gsi->second.first; 234 Value.Addend = gsi->second.second; 235 } else 236 Value.SymbolName = TargetName.data(); 237 } 238 } else { 239 error_code err; 240 uint8_t sectionIndex = static_cast<uint8_t>(RelType & 0xFF); 241 section_iterator si = Obj.begin_sections(), 242 se = Obj.end_sections(); 243 for (uint8_t i = 1; i < sectionIndex; i++) { 244 error_code err; 245 si.increment(err); 246 if (si == se) 247 break; 248 } 249 assert(si != se && "No section containing relocation!"); 250 Value.SectionID = findOrEmitSection(Obj, *si, true, ObjSectionToID); 251 Value.Addend = 0; 252 // FIXME: The size and type of the relocation determines if we can 253 // encode an Addend in the target location itself, and if so, how many 254 // bytes we should read in order to get it. We don't yet support doing 255 // that, and just assuming it's sizeof(intptr_t) is blatantly wrong. 256 //Value.Addend = *(const intptr_t *)Target; 257 if (Value.Addend) { 258 // The MachO addend is an offset from the current section. We need it 259 // to be an offset from the destination section 260 Value.Addend += Section.ObjAddress - Sections[Value.SectionID].ObjAddress; 261 } 262 } 263 264 if (Arch == Triple::arm && (RelType & 0xf) == macho::RIT_ARM_Branch24Bit) { 265 // This is an ARM branch relocation, need to use a stub function. 266 267 // Look up for existing stub. 268 StubMap::const_iterator i = Stubs.find(Value); 269 if (i != Stubs.end()) 270 resolveRelocation(Section, Rel.Offset, 271 (uint64_t)Section.Address + i->second, 272 RelType, 0); 273 else { 274 // Create a new stub function. 275 Stubs[Value] = Section.StubOffset; 276 uint8_t *StubTargetAddr = createStubFunction(Section.Address + 277 Section.StubOffset); 278 RelocationEntry RE(Rel.SectionID, StubTargetAddr - Section.Address, 279 macho::RIT_Vanilla, Value.Addend); 280 if (Value.SymbolName) 281 addRelocationForSymbol(RE, Value.SymbolName); 282 else 283 addRelocationForSection(RE, Value.SectionID); 284 resolveRelocation(Section, Rel.Offset, 285 (uint64_t)Section.Address + Section.StubOffset, 286 RelType, 0); 287 Section.StubOffset += getMaxStubSize(); 288 } 289 } else { 290 RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend); 291 if (Value.SymbolName) 292 addRelocationForSymbol(RE, Value.SymbolName); 293 else 294 addRelocationForSection(RE, Value.SectionID); 295 } 296 } 297 298 299 bool RuntimeDyldMachO::isCompatibleFormat( 300 const ObjectBuffer *InputBuffer) const { 301 if (InputBuffer->getBufferSize() < 4) 302 return false; 303 StringRef Magic(InputBuffer->getBufferStart(), 4); 304 if (Magic == "\xFE\xED\xFA\xCE") return true; 305 if (Magic == "\xCE\xFA\xED\xFE") return true; 306 if (Magic == "\xFE\xED\xFA\xCF") return true; 307 if (Magic == "\xCF\xFA\xED\xFE") return true; 308 return false; 309 } 310 311 } // end namespace llvm 312