Home | History | Annotate | Download | only in RuntimeDyld
      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"
     19 using namespace llvm;
     20 using namespace llvm::object;
     21 
     22 namespace llvm {
     23 
     24 void 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                           Type,
     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 
     77 bool 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 
    105 bool 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 
    146 bool 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 
    205 void 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 = *(const intptr_t *)Target;
    250     if (Value.Addend) {
    251       // The MachO addend is an offset from the current section.  We need it
    252       // to be an offset from the destination section
    253       Value.Addend += Section.ObjAddress - Sections[Value.SectionID].ObjAddress;
    254     }
    255   }
    256 
    257   if (Arch == Triple::arm && RelType == macho::RIT_ARM_Branch24Bit) {
    258     // This is an ARM branch relocation, need to use a stub function.
    259 
    260     //  Look up for existing stub.
    261     StubMap::const_iterator i = Stubs.find(Value);
    262     if (i != Stubs.end())
    263       resolveRelocation(Target, (uint64_t)Target,
    264                         (uint64_t)Section.Address + i->second,
    265                         RelType, 0);
    266     else {
    267       // Create a new stub function.
    268       Stubs[Value] = Section.StubOffset;
    269       uint8_t *StubTargetAddr = createStubFunction(Section.Address +
    270                                                    Section.StubOffset);
    271       RelocationEntry RE(Rel.SectionID, StubTargetAddr - Section.Address,
    272                          macho::RIT_Vanilla, Value.Addend);
    273       if (Value.SymbolName)
    274         addRelocationForSymbol(RE, Value.SymbolName);
    275       else
    276         addRelocationForSection(RE, Value.SectionID);
    277       resolveRelocation(Target, (uint64_t)Target,
    278                         (uint64_t)Section.Address + Section.StubOffset,
    279                         RelType, 0);
    280       Section.StubOffset += getMaxStubSize();
    281     }
    282   } else {
    283     RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend);
    284     if (Value.SymbolName)
    285       addRelocationForSymbol(RE, Value.SymbolName);
    286     else
    287       addRelocationForSection(RE, Value.SectionID);
    288   }
    289 }
    290 
    291 
    292 bool RuntimeDyldMachO::isCompatibleFormat(
    293         const MemoryBuffer *InputBuffer) const {
    294   StringRef Magic = InputBuffer->getBuffer().slice(0, 4);
    295   if (Magic == "\xFE\xED\xFA\xCE") return true;
    296   if (Magic == "\xCE\xFA\xED\xFE") return true;
    297   if (Magic == "\xFE\xED\xFA\xCF") return true;
    298   if (Magic == "\xCF\xFA\xED\xFE") return true;
    299   return false;
    300 }
    301 
    302 } // end namespace llvm
    303