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