1 //===-- RuntimeDyldELF.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 ELF support for 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 "llvm/ADT/IntervalMap.h" 19 #include "RuntimeDyldELF.h" 20 #include "llvm/Object/ObjectFile.h" 21 #include "llvm/Support/ELF.h" 22 #include "llvm/ADT/Triple.h" 23 using namespace llvm; 24 using namespace llvm::object; 25 26 namespace llvm { 27 28 29 void RuntimeDyldELF::resolveX86_64Relocation(uint8_t *LocalAddress, 30 uint64_t FinalAddress, 31 uint64_t Value, 32 uint32_t Type, 33 int64_t Addend) { 34 switch (Type) { 35 default: 36 llvm_unreachable("Relocation type not implemented yet!"); 37 break; 38 case ELF::R_X86_64_64: { 39 uint64_t *Target = (uint64_t*)(LocalAddress); 40 *Target = Value + Addend; 41 break; 42 } 43 case ELF::R_X86_64_32: 44 case ELF::R_X86_64_32S: { 45 Value += Addend; 46 // FIXME: Handle the possibility of this assertion failing 47 assert((Type == ELF::R_X86_64_32 && !(Value & 0xFFFFFFFF00000000ULL)) || 48 (Type == ELF::R_X86_64_32S && 49 (Value & 0xFFFFFFFF00000000ULL) == 0xFFFFFFFF00000000ULL)); 50 uint32_t TruncatedAddr = (Value & 0xFFFFFFFF); 51 uint32_t *Target = reinterpret_cast<uint32_t*>(LocalAddress); 52 *Target = TruncatedAddr; 53 break; 54 } 55 case ELF::R_X86_64_PC32: { 56 uint32_t *Placeholder = reinterpret_cast<uint32_t*>(LocalAddress); 57 int64_t RealOffset = *Placeholder + Value + Addend - FinalAddress; 58 assert(RealOffset <= 214783647 && RealOffset >= -214783648); 59 int32_t TruncOffset = (RealOffset & 0xFFFFFFFF); 60 *Placeholder = TruncOffset; 61 break; 62 } 63 } 64 } 65 66 void RuntimeDyldELF::resolveX86Relocation(uint8_t *LocalAddress, 67 uint32_t FinalAddress, 68 uint32_t Value, 69 uint32_t Type, 70 int32_t Addend) { 71 switch (Type) { 72 case ELF::R_386_32: { 73 uint32_t *Target = (uint32_t*)(LocalAddress); 74 *Target = Value + Addend; 75 break; 76 } 77 case ELF::R_386_PC32: { 78 uint32_t *Placeholder = reinterpret_cast<uint32_t*>(LocalAddress); 79 uint32_t RealOffset = *Placeholder + Value + Addend - FinalAddress; 80 *Placeholder = RealOffset; 81 break; 82 } 83 default: 84 // There are other relocation types, but it appears these are the 85 // only ones currently used by the LLVM ELF object writer 86 llvm_unreachable("Relocation type not implemented yet!"); 87 break; 88 } 89 } 90 91 void RuntimeDyldELF::resolveARMRelocation(uint8_t *LocalAddress, 92 uint32_t FinalAddress, 93 uint32_t Value, 94 uint32_t Type, 95 int32_t Addend) { 96 // TODO: Add Thumb relocations. 97 uint32_t* TargetPtr = (uint32_t*)LocalAddress; 98 Value += Addend; 99 100 DEBUG(dbgs() << "resolveARMRelocation, LocalAddress: " << LocalAddress 101 << " FinalAddress: " << format("%p",FinalAddress) 102 << " Value: " << format("%x",Value) 103 << " Type: " << format("%x",Type) 104 << " Addend: " << format("%x",Addend) 105 << "\n"); 106 107 switch(Type) { 108 default: 109 llvm_unreachable("Not implemented relocation type!"); 110 111 // Just write 32bit value to relocation address 112 case ELF::R_ARM_ABS32 : 113 *TargetPtr = Value; 114 break; 115 116 // Write first 16 bit of 32 bit value to the mov instruction. 117 // Last 4 bit should be shifted. 118 case ELF::R_ARM_MOVW_ABS_NC : 119 Value = Value & 0xFFFF; 120 *TargetPtr |= Value & 0xFFF; 121 *TargetPtr |= ((Value >> 12) & 0xF) << 16; 122 break; 123 124 // Write last 16 bit of 32 bit value to the mov instruction. 125 // Last 4 bit should be shifted. 126 case ELF::R_ARM_MOVT_ABS : 127 Value = (Value >> 16) & 0xFFFF; 128 *TargetPtr |= Value & 0xFFF; 129 *TargetPtr |= ((Value >> 12) & 0xF) << 16; 130 break; 131 132 // Write 24 bit relative value to the branch instruction. 133 case ELF::R_ARM_PC24 : // Fall through. 134 case ELF::R_ARM_CALL : // Fall through. 135 case ELF::R_ARM_JUMP24 : 136 int32_t RelValue = static_cast<int32_t>(Value - FinalAddress - 8); 137 RelValue = (RelValue & 0x03FFFFFC) >> 2; 138 *TargetPtr &= 0xFF000000; 139 *TargetPtr |= RelValue; 140 break; 141 } 142 } 143 144 void RuntimeDyldELF::resolveRelocation(uint8_t *LocalAddress, 145 uint64_t FinalAddress, 146 uint64_t Value, 147 uint32_t Type, 148 int64_t Addend) { 149 switch (Arch) { 150 case Triple::x86_64: 151 resolveX86_64Relocation(LocalAddress, FinalAddress, Value, Type, Addend); 152 break; 153 case Triple::x86: 154 resolveX86Relocation(LocalAddress, (uint32_t)(FinalAddress & 0xffffffffL), 155 (uint32_t)(Value & 0xffffffffL), Type, 156 (uint32_t)(Addend & 0xffffffffL)); 157 break; 158 case Triple::arm: // Fall through. 159 case Triple::thumb: 160 resolveARMRelocation(LocalAddress, (uint32_t)(FinalAddress & 0xffffffffL), 161 (uint32_t)(Value & 0xffffffffL), Type, 162 (uint32_t)(Addend & 0xffffffffL)); 163 break; 164 default: llvm_unreachable("Unsupported CPU type!"); 165 } 166 } 167 168 void RuntimeDyldELF::processRelocationRef(const ObjRelocationInfo &Rel, 169 const ObjectFile &Obj, 170 ObjSectionToIDMap &ObjSectionToID, 171 LocalSymbolMap &Symbols, 172 StubMap &Stubs) { 173 174 uint32_t RelType = (uint32_t)(Rel.Type & 0xffffffffL); 175 intptr_t Addend = (intptr_t)Rel.AdditionalInfo; 176 RelocationValueRef Value; 177 StringRef TargetName; 178 const SymbolRef &Symbol = Rel.Symbol; 179 Symbol.getName(TargetName); 180 DEBUG(dbgs() << "\t\tRelType: " << RelType 181 << " Addend: " << Addend 182 << " TargetName: " << TargetName 183 << "\n"); 184 // First look the symbol in object file symbols. 185 LocalSymbolMap::iterator lsi = Symbols.find(TargetName.data()); 186 if (lsi != Symbols.end()) { 187 Value.SectionID = lsi->second.first; 188 Value.Addend = lsi->second.second; 189 } else { 190 // Second look the symbol in global symbol table. 191 StringMap<SymbolLoc>::iterator gsi = SymbolTable.find(TargetName.data()); 192 if (gsi != SymbolTable.end()) { 193 Value.SectionID = gsi->second.first; 194 Value.Addend = gsi->second.second; 195 } else { 196 SymbolRef::Type SymType; 197 Symbol.getType(SymType); 198 switch (SymType) { 199 case SymbolRef::ST_Debug: { 200 // TODO: Now ELF SymbolRef::ST_Debug = STT_SECTION, it's not obviously 201 // and can be changed by another developers. Maybe best way is add 202 // a new symbol type ST_Section to SymbolRef and use it. 203 section_iterator si = Obj.end_sections(); 204 Symbol.getSection(si); 205 if (si == Obj.end_sections()) 206 llvm_unreachable("Symbol section not found, bad object file format!"); 207 DEBUG(dbgs() << "\t\tThis is section symbol\n"); 208 Value.SectionID = findOrEmitSection((*si), true, ObjSectionToID); 209 Value.Addend = Addend; 210 break; 211 } 212 case SymbolRef::ST_Unknown: { 213 Value.SymbolName = TargetName.data(); 214 Value.Addend = Addend; 215 break; 216 } 217 default: 218 llvm_unreachable("Unresolved symbol type!"); 219 break; 220 } 221 } 222 } 223 DEBUG(dbgs() << "\t\tRel.SectionID: " << Rel.SectionID 224 << " Rel.Offset: " << Rel.Offset 225 << "\n"); 226 if (Arch == Triple::arm && 227 (RelType == ELF::R_ARM_PC24 || 228 RelType == ELF::R_ARM_CALL || 229 RelType == ELF::R_ARM_JUMP24)) { 230 // This is an ARM branch relocation, need to use a stub function. 231 DEBUG(dbgs() << "\t\tThis is an ARM branch relocation."); 232 SectionEntry &Section = Sections[Rel.SectionID]; 233 uint8_t *Target = Section.Address + Rel.Offset; 234 235 // Look up for existing stub. 236 StubMap::const_iterator i = Stubs.find(Value); 237 if (i != Stubs.end()) { 238 resolveRelocation(Target, Section.LoadAddress, (uint64_t)Section.Address + 239 i->second, RelType, 0); 240 DEBUG(dbgs() << " Stub function found\n"); 241 } else { 242 // Create a new stub function. 243 DEBUG(dbgs() << " Create a new stub function\n"); 244 Stubs[Value] = Section.StubOffset; 245 uint8_t *StubTargetAddr = createStubFunction(Section.Address + 246 Section.StubOffset); 247 AddRelocation(Value, Rel.SectionID, 248 StubTargetAddr - Section.Address, ELF::R_ARM_ABS32); 249 resolveRelocation(Target, Section.LoadAddress, (uint64_t)Section.Address + 250 Section.StubOffset, RelType, 0); 251 Section.StubOffset += getMaxStubSize(); 252 } 253 } else 254 AddRelocation(Value, Rel.SectionID, Rel.Offset, RelType); 255 } 256 257 bool RuntimeDyldELF::isCompatibleFormat(const MemoryBuffer *InputBuffer) const { 258 StringRef Magic = InputBuffer->getBuffer().slice(0, ELF::EI_NIDENT); 259 return (memcmp(Magic.data(), ELF::ElfMagic, strlen(ELF::ElfMagic))) == 0; 260 } 261 } // namespace llvm 262