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 "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