Home | History | Annotate | Download | only in Targets
      1 //===-- RuntimeDyldELFMips.cpp ---- ELF/Mips specific code. -----*- 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 #include "RuntimeDyldELFMips.h"
     11 #include "llvm/BinaryFormat/ELF.h"
     12 
     13 #define DEBUG_TYPE "dyld"
     14 
     15 void RuntimeDyldELFMips::resolveRelocation(const RelocationEntry &RE,
     16                                            uint64_t Value) {
     17   const SectionEntry &Section = Sections[RE.SectionID];
     18   if (IsMipsO32ABI)
     19     resolveMIPSO32Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend);
     20   else if (IsMipsN32ABI) {
     21     resolveMIPSN32Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend,
     22                              RE.SymOffset, RE.SectionID);
     23   } else if (IsMipsN64ABI)
     24     resolveMIPSN64Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend,
     25                              RE.SymOffset, RE.SectionID);
     26   else
     27     llvm_unreachable("Mips ABI not handled");
     28 }
     29 
     30 uint64_t RuntimeDyldELFMips::evaluateRelocation(const RelocationEntry &RE,
     31                                                 uint64_t Value,
     32                                                 uint64_t Addend) {
     33   if (IsMipsN32ABI) {
     34     const SectionEntry &Section = Sections[RE.SectionID];
     35     Value = evaluateMIPS64Relocation(Section, RE.Offset, Value, RE.RelType,
     36                                      Addend, RE.SymOffset, RE.SectionID);
     37     return Value;
     38   }
     39   llvm_unreachable("Not reachable");
     40 }
     41 
     42 void RuntimeDyldELFMips::applyRelocation(const RelocationEntry &RE,
     43                                          uint64_t Value) {
     44   if (IsMipsN32ABI) {
     45     const SectionEntry &Section = Sections[RE.SectionID];
     46     applyMIPSRelocation(Section.getAddressWithOffset(RE.Offset), Value,
     47                         RE.RelType);
     48     return;
     49   }
     50   llvm_unreachable("Not reachable");
     51 }
     52 
     53 int64_t
     54 RuntimeDyldELFMips::evaluateMIPS32Relocation(const SectionEntry &Section,
     55                                              uint64_t Offset, uint64_t Value,
     56                                              uint32_t Type) {
     57 
     58   LLVM_DEBUG(dbgs() << "evaluateMIPS32Relocation, LocalAddress: 0x"
     59                     << format("%llx", Section.getAddressWithOffset(Offset))
     60                     << " FinalAddress: 0x"
     61                     << format("%llx", Section.getLoadAddressWithOffset(Offset))
     62                     << " Value: 0x" << format("%llx", Value) << " Type: 0x"
     63                     << format("%x", Type) << "\n");
     64 
     65   switch (Type) {
     66   default:
     67     llvm_unreachable("Unknown relocation type!");
     68     return Value;
     69   case ELF::R_MIPS_32:
     70     return Value;
     71   case ELF::R_MIPS_26:
     72     return Value >> 2;
     73   case ELF::R_MIPS_HI16:
     74     // Get the higher 16-bits. Also add 1 if bit 15 is 1.
     75     return (Value + 0x8000) >> 16;
     76   case ELF::R_MIPS_LO16:
     77     return Value;
     78   case ELF::R_MIPS_PC32: {
     79     uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
     80     return Value - FinalAddress;
     81   }
     82   case ELF::R_MIPS_PC16: {
     83     uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
     84     return (Value - FinalAddress) >> 2;
     85   }
     86   case ELF::R_MIPS_PC19_S2: {
     87     uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
     88     return (Value - (FinalAddress & ~0x3)) >> 2;
     89   }
     90   case ELF::R_MIPS_PC21_S2: {
     91     uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
     92     return (Value - FinalAddress) >> 2;
     93   }
     94   case ELF::R_MIPS_PC26_S2: {
     95     uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
     96     return (Value - FinalAddress) >> 2;
     97   }
     98   case ELF::R_MIPS_PCHI16: {
     99     uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
    100     return (Value - FinalAddress + 0x8000) >> 16;
    101   }
    102   case ELF::R_MIPS_PCLO16: {
    103     uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
    104     return Value - FinalAddress;
    105   }
    106   }
    107 }
    108 
    109 int64_t RuntimeDyldELFMips::evaluateMIPS64Relocation(
    110     const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type,
    111     int64_t Addend, uint64_t SymOffset, SID SectionID) {
    112 
    113   LLVM_DEBUG(dbgs() << "evaluateMIPS64Relocation, LocalAddress: 0x"
    114                     << format("%llx", Section.getAddressWithOffset(Offset))
    115                     << " FinalAddress: 0x"
    116                     << format("%llx", Section.getLoadAddressWithOffset(Offset))
    117                     << " Value: 0x" << format("%llx", Value) << " Type: 0x"
    118                     << format("%x", Type) << " Addend: 0x"
    119                     << format("%llx", Addend)
    120                     << " Offset: " << format("%llx" PRIx64, Offset)
    121                     << " SID: " << format("%d", SectionID)
    122                     << " SymOffset: " << format("%x", SymOffset) << "\n");
    123 
    124   switch (Type) {
    125   default:
    126     llvm_unreachable("Not implemented relocation type!");
    127     break;
    128   case ELF::R_MIPS_JALR:
    129   case ELF::R_MIPS_NONE:
    130     break;
    131   case ELF::R_MIPS_32:
    132   case ELF::R_MIPS_64:
    133     return Value + Addend;
    134   case ELF::R_MIPS_26:
    135     return ((Value + Addend) >> 2) & 0x3ffffff;
    136   case ELF::R_MIPS_GPREL16: {
    137     uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]);
    138     return Value + Addend - (GOTAddr + 0x7ff0);
    139   }
    140   case ELF::R_MIPS_SUB:
    141     return Value - Addend;
    142   case ELF::R_MIPS_HI16:
    143     // Get the higher 16-bits. Also add 1 if bit 15 is 1.
    144     return ((Value + Addend + 0x8000) >> 16) & 0xffff;
    145   case ELF::R_MIPS_LO16:
    146     return (Value + Addend) & 0xffff;
    147   case ELF::R_MIPS_HIGHER:
    148     return ((Value + Addend + 0x80008000) >> 32) & 0xffff;
    149   case ELF::R_MIPS_HIGHEST:
    150     return ((Value + Addend + 0x800080008000) >> 48) & 0xffff;
    151   case ELF::R_MIPS_CALL16:
    152   case ELF::R_MIPS_GOT_DISP:
    153   case ELF::R_MIPS_GOT_PAGE: {
    154     uint8_t *LocalGOTAddr =
    155         getSectionAddress(SectionToGOTMap[SectionID]) + SymOffset;
    156     uint64_t GOTEntry = readBytesUnaligned(LocalGOTAddr, getGOTEntrySize());
    157 
    158     Value += Addend;
    159     if (Type == ELF::R_MIPS_GOT_PAGE)
    160       Value = (Value + 0x8000) & ~0xffff;
    161 
    162     if (GOTEntry)
    163       assert(GOTEntry == Value &&
    164                    "GOT entry has two different addresses.");
    165     else
    166       writeBytesUnaligned(Value, LocalGOTAddr, getGOTEntrySize());
    167 
    168     return (SymOffset - 0x7ff0) & 0xffff;
    169   }
    170   case ELF::R_MIPS_GOT_OFST: {
    171     int64_t page = (Value + Addend + 0x8000) & ~0xffff;
    172     return (Value + Addend - page) & 0xffff;
    173   }
    174   case ELF::R_MIPS_GPREL32: {
    175     uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]);
    176     return Value + Addend - (GOTAddr + 0x7ff0);
    177   }
    178   case ELF::R_MIPS_PC16: {
    179     uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
    180     return ((Value + Addend - FinalAddress) >> 2) & 0xffff;
    181   }
    182   case ELF::R_MIPS_PC32: {
    183     uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
    184     return Value + Addend - FinalAddress;
    185   }
    186   case ELF::R_MIPS_PC18_S3: {
    187     uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
    188     return ((Value + Addend - (FinalAddress & ~0x7)) >> 3) & 0x3ffff;
    189   }
    190   case ELF::R_MIPS_PC19_S2: {
    191     uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
    192     return ((Value + Addend - (FinalAddress & ~0x3)) >> 2) & 0x7ffff;
    193   }
    194   case ELF::R_MIPS_PC21_S2: {
    195     uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
    196     return ((Value + Addend - FinalAddress) >> 2) & 0x1fffff;
    197   }
    198   case ELF::R_MIPS_PC26_S2: {
    199     uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
    200     return ((Value + Addend - FinalAddress) >> 2) & 0x3ffffff;
    201   }
    202   case ELF::R_MIPS_PCHI16: {
    203     uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
    204     return ((Value + Addend - FinalAddress + 0x8000) >> 16) & 0xffff;
    205   }
    206   case ELF::R_MIPS_PCLO16: {
    207     uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset);
    208     return (Value + Addend - FinalAddress) & 0xffff;
    209   }
    210   }
    211   return 0;
    212 }
    213 
    214 void RuntimeDyldELFMips::applyMIPSRelocation(uint8_t *TargetPtr, int64_t Value,
    215                                              uint32_t Type) {
    216   uint32_t Insn = readBytesUnaligned(TargetPtr, 4);
    217 
    218   switch (Type) {
    219   default:
    220     llvm_unreachable("Unknown relocation type!");
    221     break;
    222   case ELF::R_MIPS_GPREL16:
    223   case ELF::R_MIPS_HI16:
    224   case ELF::R_MIPS_LO16:
    225   case ELF::R_MIPS_HIGHER:
    226   case ELF::R_MIPS_HIGHEST:
    227   case ELF::R_MIPS_PC16:
    228   case ELF::R_MIPS_PCHI16:
    229   case ELF::R_MIPS_PCLO16:
    230   case ELF::R_MIPS_CALL16:
    231   case ELF::R_MIPS_GOT_DISP:
    232   case ELF::R_MIPS_GOT_PAGE:
    233   case ELF::R_MIPS_GOT_OFST:
    234     Insn = (Insn & 0xffff0000) | (Value & 0x0000ffff);
    235     writeBytesUnaligned(Insn, TargetPtr, 4);
    236     break;
    237   case ELF::R_MIPS_PC18_S3:
    238     Insn = (Insn & 0xfffc0000) | (Value & 0x0003ffff);
    239     writeBytesUnaligned(Insn, TargetPtr, 4);
    240     break;
    241   case ELF::R_MIPS_PC19_S2:
    242     Insn = (Insn & 0xfff80000) | (Value & 0x0007ffff);
    243     writeBytesUnaligned(Insn, TargetPtr, 4);
    244     break;
    245   case ELF::R_MIPS_PC21_S2:
    246     Insn = (Insn & 0xffe00000) | (Value & 0x001fffff);
    247     writeBytesUnaligned(Insn, TargetPtr, 4);
    248     break;
    249   case ELF::R_MIPS_26:
    250   case ELF::R_MIPS_PC26_S2:
    251     Insn = (Insn & 0xfc000000) | (Value & 0x03ffffff);
    252     writeBytesUnaligned(Insn, TargetPtr, 4);
    253     break;
    254   case ELF::R_MIPS_32:
    255   case ELF::R_MIPS_GPREL32:
    256   case ELF::R_MIPS_PC32:
    257     writeBytesUnaligned(Value & 0xffffffff, TargetPtr, 4);
    258     break;
    259   case ELF::R_MIPS_64:
    260   case ELF::R_MIPS_SUB:
    261     writeBytesUnaligned(Value, TargetPtr, 8);
    262     break;
    263   }
    264 }
    265 
    266 void RuntimeDyldELFMips::resolveMIPSN32Relocation(
    267     const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type,
    268     int64_t Addend, uint64_t SymOffset, SID SectionID) {
    269   int64_t CalculatedValue = evaluateMIPS64Relocation(
    270       Section, Offset, Value, Type, Addend, SymOffset, SectionID);
    271   applyMIPSRelocation(Section.getAddressWithOffset(Offset), CalculatedValue,
    272                       Type);
    273 }
    274 
    275 void RuntimeDyldELFMips::resolveMIPSN64Relocation(
    276     const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type,
    277     int64_t Addend, uint64_t SymOffset, SID SectionID) {
    278   uint32_t r_type = Type & 0xff;
    279   uint32_t r_type2 = (Type >> 8) & 0xff;
    280   uint32_t r_type3 = (Type >> 16) & 0xff;
    281 
    282   // RelType is used to keep information for which relocation type we are
    283   // applying relocation.
    284   uint32_t RelType = r_type;
    285   int64_t CalculatedValue = evaluateMIPS64Relocation(Section, Offset, Value,
    286                                                      RelType, Addend,
    287                                                      SymOffset, SectionID);
    288   if (r_type2 != ELF::R_MIPS_NONE) {
    289     RelType = r_type2;
    290     CalculatedValue = evaluateMIPS64Relocation(Section, Offset, 0, RelType,
    291                                                CalculatedValue, SymOffset,
    292                                                SectionID);
    293   }
    294   if (r_type3 != ELF::R_MIPS_NONE) {
    295     RelType = r_type3;
    296     CalculatedValue = evaluateMIPS64Relocation(Section, Offset, 0, RelType,
    297                                                CalculatedValue, SymOffset,
    298                                                SectionID);
    299   }
    300   applyMIPSRelocation(Section.getAddressWithOffset(Offset), CalculatedValue,
    301                       RelType);
    302 }
    303 
    304 void RuntimeDyldELFMips::resolveMIPSO32Relocation(const SectionEntry &Section,
    305                                                   uint64_t Offset,
    306                                                   uint32_t Value, uint32_t Type,
    307                                                   int32_t Addend) {
    308   uint8_t *TargetPtr = Section.getAddressWithOffset(Offset);
    309   Value += Addend;
    310 
    311   LLVM_DEBUG(dbgs() << "resolveMIPSO32Relocation, LocalAddress: "
    312                     << Section.getAddressWithOffset(Offset) << " FinalAddress: "
    313                     << format("%p", Section.getLoadAddressWithOffset(Offset))
    314                     << " Value: " << format("%x", Value) << " Type: "
    315                     << format("%x", Type) << " Addend: " << format("%x", Addend)
    316                     << " SymOffset: " << format("%x", Offset) << "\n");
    317 
    318   Value = evaluateMIPS32Relocation(Section, Offset, Value, Type);
    319 
    320   applyMIPSRelocation(TargetPtr, Value, Type);
    321 }
    322