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 static unsigned char *processFDE(unsigned char *P, intptr_t DeltaForText, intptr_t DeltaForEH) {
     25   uint32_t Length = *((uint32_t*)P);
     26   P += 4;
     27   unsigned char *Ret = P + Length;
     28   uint32_t Offset = *((uint32_t*)P);
     29   if (Offset == 0) // is a CIE
     30     return Ret;
     31 
     32   P += 4;
     33   intptr_t FDELocation = *((intptr_t*)P);
     34   intptr_t NewLocation = FDELocation - DeltaForText;
     35   *((intptr_t*)P) = NewLocation;
     36   P += sizeof(intptr_t);
     37 
     38   // Skip the FDE address range
     39   P += sizeof(intptr_t);
     40 
     41   uint8_t Augmentationsize = *P;
     42   P += 1;
     43   if (Augmentationsize != 0) {
     44     intptr_t LSDA = *((intptr_t*)P);
     45     intptr_t NewLSDA = LSDA - DeltaForEH;
     46     *((intptr_t*)P) = NewLSDA;
     47   }
     48 
     49   return Ret;
     50 }
     51 
     52 static intptr_t computeDelta(SectionEntry *A, SectionEntry *B) {
     53   intptr_t ObjDistance = A->ObjAddress  - B->ObjAddress;
     54   intptr_t MemDistance = A->LoadAddress - B->LoadAddress;
     55   return ObjDistance - MemDistance;
     56 }
     57 
     58 StringRef RuntimeDyldMachO::getEHFrameSection() {
     59   SectionEntry *Text = NULL;
     60   SectionEntry *EHFrame = NULL;
     61   SectionEntry *ExceptTab = NULL;
     62   for (int i = 0, e = Sections.size(); i != e; ++i) {
     63     if (Sections[i].Name == "__eh_frame")
     64       EHFrame = &Sections[i];
     65     else if (Sections[i].Name == "__text")
     66       Text = &Sections[i];
     67     else if (Sections[i].Name == "__gcc_except_tab")
     68       ExceptTab = &Sections[i];
     69   }
     70   if (Text == NULL || EHFrame == NULL)
     71     return StringRef();
     72 
     73   intptr_t DeltaForText = computeDelta(Text, EHFrame);
     74   intptr_t DeltaForEH = 0;
     75   if (ExceptTab)
     76     DeltaForEH = computeDelta(ExceptTab, EHFrame);
     77 
     78   unsigned char *P = EHFrame->Address;
     79   unsigned char *End = P + EHFrame->Size;
     80   do  {
     81     P = processFDE(P, DeltaForText, DeltaForEH);
     82   } while(P != End);
     83 
     84   return StringRef((char*)EHFrame->Address, EHFrame->Size);
     85 }
     86 
     87 void RuntimeDyldMachO::resolveRelocation(const RelocationEntry &RE,
     88                                          uint64_t Value) {
     89   const SectionEntry &Section = Sections[RE.SectionID];
     90   return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend,
     91                            RE.IsPCRel, RE.Size);
     92 }
     93 
     94 void RuntimeDyldMachO::resolveRelocation(const SectionEntry &Section,
     95                                          uint64_t Offset,
     96                                          uint64_t Value,
     97                                          uint32_t Type,
     98                                          int64_t Addend,
     99                                          bool isPCRel,
    100                                          unsigned LogSize) {
    101   uint8_t *LocalAddress = Section.Address + Offset;
    102   uint64_t FinalAddress = Section.LoadAddress + Offset;
    103   unsigned MachoType = Type;
    104   unsigned Size = 1 << LogSize;
    105 
    106   DEBUG(dbgs() << "resolveRelocation LocalAddress: "
    107         << format("%p", LocalAddress)
    108         << " FinalAddress: " << format("%p", FinalAddress)
    109         << " Value: " << format("%p", Value)
    110         << " Addend: " << Addend
    111         << " isPCRel: " << isPCRel
    112         << " MachoType: " << MachoType
    113         << " Size: " << Size
    114         << "\n");
    115 
    116   // This just dispatches to the proper target specific routine.
    117   switch (Arch) {
    118   default: llvm_unreachable("Unsupported CPU type!");
    119   case Triple::x86_64:
    120     resolveX86_64Relocation(LocalAddress,
    121                             FinalAddress,
    122                             (uintptr_t)Value,
    123                             isPCRel,
    124                             MachoType,
    125                             Size,
    126                             Addend);
    127     break;
    128   case Triple::x86:
    129     resolveI386Relocation(LocalAddress,
    130                           FinalAddress,
    131                           (uintptr_t)Value,
    132                           isPCRel,
    133                           MachoType,
    134                           Size,
    135                           Addend);
    136     break;
    137   case Triple::arm:    // Fall through.
    138   case Triple::thumb:
    139     resolveARMRelocation(LocalAddress,
    140                          FinalAddress,
    141                          (uintptr_t)Value,
    142                          isPCRel,
    143                          MachoType,
    144                          Size,
    145                          Addend);
    146     break;
    147   }
    148 }
    149 
    150 bool RuntimeDyldMachO::resolveI386Relocation(uint8_t *LocalAddress,
    151                                              uint64_t FinalAddress,
    152                                              uint64_t Value,
    153                                              bool isPCRel,
    154                                              unsigned Type,
    155                                              unsigned Size,
    156                                              int64_t Addend) {
    157   if (isPCRel)
    158     Value -= FinalAddress + 4; // see resolveX86_64Relocation
    159 
    160   switch (Type) {
    161   default:
    162     llvm_unreachable("Invalid relocation type!");
    163   case macho::RIT_Vanilla: {
    164     uint8_t *p = LocalAddress;
    165     uint64_t ValueToWrite = Value + Addend;
    166     for (unsigned i = 0; i < Size; ++i) {
    167       *p++ = (uint8_t)(ValueToWrite & 0xff);
    168       ValueToWrite >>= 8;
    169     }
    170     return false;
    171   }
    172   case macho::RIT_Difference:
    173   case macho::RIT_Generic_LocalDifference:
    174   case macho::RIT_Generic_PreboundLazyPointer:
    175     return Error("Relocation type not implemented yet!");
    176   }
    177 }
    178 
    179 bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress,
    180                                                uint64_t FinalAddress,
    181                                                uint64_t Value,
    182                                                bool isPCRel,
    183                                                unsigned Type,
    184                                                unsigned Size,
    185                                                int64_t Addend) {
    186   // If the relocation is PC-relative, the value to be encoded is the
    187   // pointer difference.
    188   if (isPCRel)
    189     // FIXME: It seems this value needs to be adjusted by 4 for an effective PC
    190     // address. Is that expected? Only for branches, perhaps?
    191     Value -= FinalAddress + 4;
    192 
    193   switch(Type) {
    194   default:
    195     llvm_unreachable("Invalid relocation type!");
    196   case macho::RIT_X86_64_Signed1:
    197   case macho::RIT_X86_64_Signed2:
    198   case macho::RIT_X86_64_Signed4:
    199   case macho::RIT_X86_64_Signed:
    200   case macho::RIT_X86_64_Unsigned:
    201   case macho::RIT_X86_64_Branch: {
    202     Value += Addend;
    203     // Mask in the target value a byte at a time (we don't have an alignment
    204     // guarantee for the target address, so this is safest).
    205     uint8_t *p = (uint8_t*)LocalAddress;
    206     for (unsigned i = 0; i < Size; ++i) {
    207       *p++ = (uint8_t)Value;
    208       Value >>= 8;
    209     }
    210     return false;
    211   }
    212   case macho::RIT_X86_64_GOTLoad:
    213   case macho::RIT_X86_64_GOT:
    214   case macho::RIT_X86_64_Subtractor:
    215   case macho::RIT_X86_64_TLV:
    216     return Error("Relocation type not implemented yet!");
    217   }
    218 }
    219 
    220 bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress,
    221                                             uint64_t FinalAddress,
    222                                             uint64_t Value,
    223                                             bool isPCRel,
    224                                             unsigned Type,
    225                                             unsigned Size,
    226                                             int64_t Addend) {
    227   // If the relocation is PC-relative, the value to be encoded is the
    228   // pointer difference.
    229   if (isPCRel) {
    230     Value -= FinalAddress;
    231     // ARM PCRel relocations have an effective-PC offset of two instructions
    232     // (four bytes in Thumb mode, 8 bytes in ARM mode).
    233     // FIXME: For now, assume ARM mode.
    234     Value -= 8;
    235   }
    236 
    237   switch(Type) {
    238   default:
    239     llvm_unreachable("Invalid relocation type!");
    240   case macho::RIT_Vanilla: {
    241     // Mask in the target value a byte at a time (we don't have an alignment
    242     // guarantee for the target address, so this is safest).
    243     uint8_t *p = (uint8_t*)LocalAddress;
    244     for (unsigned i = 0; i < Size; ++i) {
    245       *p++ = (uint8_t)Value;
    246       Value >>= 8;
    247     }
    248     break;
    249   }
    250   case macho::RIT_ARM_Branch24Bit: {
    251     // Mask the value into the target address. We know instructions are
    252     // 32-bit aligned, so we can do it all at once.
    253     uint32_t *p = (uint32_t*)LocalAddress;
    254     // The low two bits of the value are not encoded.
    255     Value >>= 2;
    256     // Mask the value to 24 bits.
    257     Value &= 0xffffff;
    258     // FIXME: If the destination is a Thumb function (and the instruction
    259     // is a non-predicated BL instruction), we need to change it to a BLX
    260     // instruction instead.
    261 
    262     // Insert the value into the instruction.
    263     *p = (*p & ~0xffffff) | Value;
    264     break;
    265   }
    266   case macho::RIT_ARM_ThumbBranch22Bit:
    267   case macho::RIT_ARM_ThumbBranch32Bit:
    268   case macho::RIT_ARM_Half:
    269   case macho::RIT_ARM_HalfDifference:
    270   case macho::RIT_Pair:
    271   case macho::RIT_Difference:
    272   case macho::RIT_ARM_LocalDifference:
    273   case macho::RIT_ARM_PreboundLazyPointer:
    274     return Error("Relocation type not implemented yet!");
    275   }
    276   return false;
    277 }
    278 
    279 void RuntimeDyldMachO::processRelocationRef(unsigned SectionID,
    280                                             RelocationRef RelI,
    281                                             ObjectImage &Obj,
    282                                             ObjSectionToIDMap &ObjSectionToID,
    283                                             const SymbolTableMap &Symbols,
    284                                             StubMap &Stubs) {
    285   const ObjectFile *OF = Obj.getObjectFile();
    286   const MachOObjectFile *MachO = static_cast<const MachOObjectFile*>(OF);
    287   macho::RelocationEntry RE = MachO->getRelocation(RelI.getRawDataRefImpl());
    288 
    289   uint32_t RelType = MachO->getAnyRelocationType(RE);
    290   RelocationValueRef Value;
    291   SectionEntry &Section = Sections[SectionID];
    292 
    293   bool isExtern = MachO->getPlainRelocationExternal(RE);
    294   bool IsPCRel = MachO->getAnyRelocationPCRel(RE);
    295   unsigned Size = MachO->getAnyRelocationLength(RE);
    296   uint64_t Offset;
    297   RelI.getOffset(Offset);
    298   uint8_t *LocalAddress = Section.Address + Offset;
    299   unsigned NumBytes = 1 << Size;
    300   uint64_t Addend = 0;
    301   memcpy(&Addend, LocalAddress, NumBytes);
    302 
    303   if (isExtern) {
    304     // Obtain the symbol name which is referenced in the relocation
    305     symbol_iterator Symbol = RelI.getSymbol();
    306     StringRef TargetName;
    307     Symbol->getName(TargetName);
    308     // First search for the symbol in the local symbol table
    309     SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data());
    310     if (lsi != Symbols.end()) {
    311       Value.SectionID = lsi->second.first;
    312       Value.Addend = lsi->second.second + Addend;
    313     } else {
    314       // Search for the symbol in the global symbol table
    315       SymbolTableMap::const_iterator gsi = GlobalSymbolTable.find(TargetName.data());
    316       if (gsi != GlobalSymbolTable.end()) {
    317         Value.SectionID = gsi->second.first;
    318         Value.Addend = gsi->second.second + Addend;
    319       } else {
    320         Value.SymbolName = TargetName.data();
    321         Value.Addend = Addend;
    322       }
    323     }
    324   } else {
    325     SectionRef Sec = MachO->getRelocationSection(RE);
    326     Value.SectionID = findOrEmitSection(Obj, Sec, true, ObjSectionToID);
    327     uint64_t Addr;
    328     Sec.getAddress(Addr);
    329     Value.Addend = Addend - Addr;
    330   }
    331 
    332   if (Arch == Triple::x86_64 && RelType == macho::RIT_X86_64_GOT) {
    333     assert(IsPCRel);
    334     assert(Size == 2);
    335     StubMap::const_iterator i = Stubs.find(Value);
    336     uint8_t *Addr;
    337     if (i != Stubs.end()) {
    338       Addr = Section.Address + i->second;
    339     } else {
    340       Stubs[Value] = Section.StubOffset;
    341       uint8_t *GOTEntry = Section.Address + Section.StubOffset;
    342       RelocationEntry RE(SectionID, Section.StubOffset,
    343                          macho::RIT_X86_64_Unsigned, Value.Addend - 4, false,
    344                          3);
    345       if (Value.SymbolName)
    346         addRelocationForSymbol(RE, Value.SymbolName);
    347       else
    348         addRelocationForSection(RE, Value.SectionID);
    349       Section.StubOffset += 8;
    350       Addr = GOTEntry;
    351     }
    352     resolveRelocation(Section, Offset, (uint64_t)Addr,
    353                       macho::RIT_X86_64_Unsigned, 4, true, 2);
    354   } else if (Arch == Triple::arm &&
    355              (RelType & 0xf) == macho::RIT_ARM_Branch24Bit) {
    356     // This is an ARM branch relocation, need to use a stub function.
    357 
    358     //  Look up for existing stub.
    359     StubMap::const_iterator i = Stubs.find(Value);
    360     if (i != Stubs.end())
    361       resolveRelocation(Section, Offset,
    362                         (uint64_t)Section.Address + i->second,
    363                         RelType, 0, IsPCRel, Size);
    364     else {
    365       // Create a new stub function.
    366       Stubs[Value] = Section.StubOffset;
    367       uint8_t *StubTargetAddr = createStubFunction(Section.Address +
    368                                                    Section.StubOffset);
    369       RelocationEntry RE(SectionID, StubTargetAddr - Section.Address,
    370                          macho::RIT_Vanilla, Value.Addend);
    371       if (Value.SymbolName)
    372         addRelocationForSymbol(RE, Value.SymbolName);
    373       else
    374         addRelocationForSection(RE, Value.SectionID);
    375       resolveRelocation(Section, Offset,
    376                         (uint64_t)Section.Address + Section.StubOffset,
    377                         RelType, 0, IsPCRel, Size);
    378       Section.StubOffset += getMaxStubSize();
    379     }
    380   } else {
    381     RelocationEntry RE(SectionID, Offset, RelType, Value.Addend,
    382                        IsPCRel, Size);
    383     if (Value.SymbolName)
    384       addRelocationForSymbol(RE, Value.SymbolName);
    385     else
    386       addRelocationForSection(RE, Value.SectionID);
    387   }
    388 }
    389 
    390 
    391 bool RuntimeDyldMachO::isCompatibleFormat(
    392         const ObjectBuffer *InputBuffer) const {
    393   if (InputBuffer->getBufferSize() < 4)
    394     return false;
    395   StringRef Magic(InputBuffer->getBufferStart(), 4);
    396   if (Magic == "\xFE\xED\xFA\xCE") return true;
    397   if (Magic == "\xCE\xFA\xED\xFE") return true;
    398   if (Magic == "\xFE\xED\xFA\xCF") return true;
    399   if (Magic == "\xCF\xFA\xED\xFE") return true;
    400   return false;
    401 }
    402 
    403 } // end namespace llvm
    404