Home | History | Annotate | Download | only in MCTargetDesc
      1 //===-- ARMMachObjectWriter.cpp - ARM Mach Object Writer ------------------===//
      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 "MCTargetDesc/ARMBaseInfo.h"
     11 #include "MCTargetDesc/ARMFixupKinds.h"
     12 #include "llvm/ADT/Twine.h"
     13 #include "llvm/MC/MCAssembler.h"
     14 #include "llvm/MC/MCAsmLayout.h"
     15 #include "llvm/MC/MCMachObjectWriter.h"
     16 #include "llvm/MC/MCContext.h"
     17 #include "llvm/MC/MCExpr.h"
     18 #include "llvm/MC/MCFixup.h"
     19 #include "llvm/MC/MCFixupKindInfo.h"
     20 #include "llvm/MC/MCMachOSymbolFlags.h"
     21 #include "llvm/MC/MCValue.h"
     22 #include "llvm/Object/MachOFormat.h"
     23 #include "llvm/Support/ErrorHandling.h"
     24 using namespace llvm;
     25 using namespace llvm::object;
     26 
     27 namespace {
     28 class ARMMachObjectWriter : public MCMachObjectTargetWriter {
     29   void RecordARMScatteredRelocation(MachObjectWriter *Writer,
     30                                     const MCAssembler &Asm,
     31                                     const MCAsmLayout &Layout,
     32                                     const MCFragment *Fragment,
     33                                     const MCFixup &Fixup,
     34                                     MCValue Target,
     35                                     unsigned Log2Size,
     36                                     uint64_t &FixedValue);
     37   void RecordARMScatteredHalfRelocation(MachObjectWriter *Writer,
     38                                         const MCAssembler &Asm,
     39                                         const MCAsmLayout &Layout,
     40                                         const MCFragment *Fragment,
     41                                         const MCFixup &Fixup, MCValue Target,
     42                                         uint64_t &FixedValue);
     43 
     44 public:
     45   ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType,
     46                       uint32_t CPUSubtype)
     47     : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype,
     48                                /*UseAggressiveSymbolFolding=*/true) {}
     49 
     50   void RecordRelocation(MachObjectWriter *Writer,
     51                         const MCAssembler &Asm, const MCAsmLayout &Layout,
     52                         const MCFragment *Fragment, const MCFixup &Fixup,
     53                         MCValue Target, uint64_t &FixedValue);
     54 };
     55 }
     56 
     57 static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType,
     58                               unsigned &Log2Size) {
     59   RelocType = unsigned(macho::RIT_Vanilla);
     60   Log2Size = ~0U;
     61 
     62   switch (Kind) {
     63   default:
     64     return false;
     65 
     66   case FK_Data_1:
     67     Log2Size = llvm::Log2_32(1);
     68     return true;
     69   case FK_Data_2:
     70     Log2Size = llvm::Log2_32(2);
     71     return true;
     72   case FK_Data_4:
     73     Log2Size = llvm::Log2_32(4);
     74     return true;
     75   case FK_Data_8:
     76     Log2Size = llvm::Log2_32(8);
     77     return true;
     78 
     79     // Handle 24-bit branch kinds.
     80   case ARM::fixup_arm_ldst_pcrel_12:
     81   case ARM::fixup_arm_pcrel_10:
     82   case ARM::fixup_arm_adr_pcrel_12:
     83   case ARM::fixup_arm_condbranch:
     84   case ARM::fixup_arm_uncondbranch:
     85   case ARM::fixup_arm_uncondbl:
     86   case ARM::fixup_arm_condbl:
     87   case ARM::fixup_arm_blx:
     88     RelocType = unsigned(macho::RIT_ARM_Branch24Bit);
     89     // Report as 'long', even though that is not quite accurate.
     90     Log2Size = llvm::Log2_32(4);
     91     return true;
     92 
     93     // Handle Thumb branches.
     94   case ARM::fixup_arm_thumb_br:
     95     RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit);
     96     Log2Size = llvm::Log2_32(2);
     97     return true;
     98 
     99   case ARM::fixup_t2_uncondbranch:
    100   case ARM::fixup_arm_thumb_bl:
    101   case ARM::fixup_arm_thumb_blx:
    102     RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit);
    103     Log2Size = llvm::Log2_32(4);
    104     return true;
    105 
    106   // For movw/movt r_type relocations they always have a pair following them and
    107   // the r_length bits are used differently.  The encoding of the r_length is as
    108   // follows:
    109   //   low bit of r_length:
    110   //      0 - :lower16: for movw instructions
    111   //      1 - :upper16: for movt instructions
    112   //   high bit of r_length:
    113   //      0 - arm instructions
    114   //      1 - thumb instructions
    115   case ARM::fixup_arm_movt_hi16:
    116   case ARM::fixup_arm_movt_hi16_pcrel:
    117     RelocType = unsigned(macho::RIT_ARM_Half);
    118     Log2Size = 1;
    119     return true;
    120   case ARM::fixup_t2_movt_hi16:
    121   case ARM::fixup_t2_movt_hi16_pcrel:
    122     RelocType = unsigned(macho::RIT_ARM_Half);
    123     Log2Size = 3;
    124     return true;
    125 
    126   case ARM::fixup_arm_movw_lo16:
    127   case ARM::fixup_arm_movw_lo16_pcrel:
    128     RelocType = unsigned(macho::RIT_ARM_Half);
    129     Log2Size = 0;
    130     return true;
    131   case ARM::fixup_t2_movw_lo16:
    132   case ARM::fixup_t2_movw_lo16_pcrel:
    133     RelocType = unsigned(macho::RIT_ARM_Half);
    134     Log2Size = 2;
    135     return true;
    136   }
    137 }
    138 
    139 void ARMMachObjectWriter::
    140 RecordARMScatteredHalfRelocation(MachObjectWriter *Writer,
    141                                  const MCAssembler &Asm,
    142                                  const MCAsmLayout &Layout,
    143                                  const MCFragment *Fragment,
    144                                  const MCFixup &Fixup,
    145                                  MCValue Target,
    146                                  uint64_t &FixedValue) {
    147   uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
    148   unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
    149   unsigned Type = macho::RIT_ARM_Half;
    150 
    151   // See <reloc.h>.
    152   const MCSymbol *A = &Target.getSymA()->getSymbol();
    153   MCSymbolData *A_SD = &Asm.getSymbolData(*A);
    154 
    155   if (!A_SD->getFragment())
    156     Asm.getContext().FatalError(Fixup.getLoc(),
    157                        "symbol '" + A->getName() +
    158                        "' can not be undefined in a subtraction expression");
    159 
    160   uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
    161   uint32_t Value2 = 0;
    162   uint64_t SecAddr =
    163     Writer->getSectionAddress(A_SD->getFragment()->getParent());
    164   FixedValue += SecAddr;
    165 
    166   if (const MCSymbolRefExpr *B = Target.getSymB()) {
    167     MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
    168 
    169     if (!B_SD->getFragment())
    170       Asm.getContext().FatalError(Fixup.getLoc(),
    171                          "symbol '" + B->getSymbol().getName() +
    172                          "' can not be undefined in a subtraction expression");
    173 
    174     // Select the appropriate difference relocation type.
    175     Type = macho::RIT_ARM_HalfDifference;
    176     Value2 = Writer->getSymbolAddress(B_SD, Layout);
    177     FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
    178   }
    179 
    180   // Relocations are written out in reverse order, so the PAIR comes first.
    181   // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field:
    182   //
    183   // For these two r_type relocations they always have a pair following them and
    184   // the r_length bits are used differently.  The encoding of the r_length is as
    185   // follows:
    186   //   low bit of r_length:
    187   //      0 - :lower16: for movw instructions
    188   //      1 - :upper16: for movt instructions
    189   //   high bit of r_length:
    190   //      0 - arm instructions
    191   //      1 - thumb instructions
    192   // the other half of the relocated expression is in the following pair
    193   // relocation entry in the the low 16 bits of r_address field.
    194   unsigned ThumbBit = 0;
    195   unsigned MovtBit = 0;
    196   switch ((unsigned)Fixup.getKind()) {
    197   default: break;
    198   case ARM::fixup_arm_movt_hi16:
    199   case ARM::fixup_arm_movt_hi16_pcrel:
    200     MovtBit = 1;
    201     // The thumb bit shouldn't be set in the 'other-half' bit of the
    202     // relocation, but it will be set in FixedValue if the base symbol
    203     // is a thumb function. Clear it out here.
    204     if (A_SD->getFlags() & SF_ThumbFunc)
    205       FixedValue &= 0xfffffffe;
    206     break;
    207   case ARM::fixup_t2_movt_hi16:
    208   case ARM::fixup_t2_movt_hi16_pcrel:
    209     if (A_SD->getFlags() & SF_ThumbFunc)
    210       FixedValue &= 0xfffffffe;
    211     MovtBit = 1;
    212     // Fallthrough
    213   case ARM::fixup_t2_movw_lo16:
    214   case ARM::fixup_t2_movw_lo16_pcrel:
    215     ThumbBit = 1;
    216     break;
    217   }
    218 
    219   if (Type == macho::RIT_ARM_HalfDifference) {
    220     uint32_t OtherHalf = MovtBit
    221       ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16);
    222 
    223     macho::RelocationEntry MRE;
    224     MRE.Word0 = ((OtherHalf       <<  0) |
    225                  (macho::RIT_Pair << 24) |
    226                  (MovtBit         << 28) |
    227                  (ThumbBit        << 29) |
    228                  (IsPCRel         << 30) |
    229                  macho::RF_Scattered);
    230     MRE.Word1 = Value2;
    231     Writer->addRelocation(Fragment->getParent(), MRE);
    232   }
    233 
    234   macho::RelocationEntry MRE;
    235   MRE.Word0 = ((FixupOffset <<  0) |
    236                (Type        << 24) |
    237                (MovtBit     << 28) |
    238                (ThumbBit    << 29) |
    239                (IsPCRel     << 30) |
    240                macho::RF_Scattered);
    241   MRE.Word1 = Value;
    242   Writer->addRelocation(Fragment->getParent(), MRE);
    243 }
    244 
    245 void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer,
    246                                                     const MCAssembler &Asm,
    247                                                     const MCAsmLayout &Layout,
    248                                                     const MCFragment *Fragment,
    249                                                     const MCFixup &Fixup,
    250                                                     MCValue Target,
    251                                                     unsigned Log2Size,
    252                                                     uint64_t &FixedValue) {
    253   uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
    254   unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
    255   unsigned Type = macho::RIT_Vanilla;
    256 
    257   // See <reloc.h>.
    258   const MCSymbol *A = &Target.getSymA()->getSymbol();
    259   MCSymbolData *A_SD = &Asm.getSymbolData(*A);
    260 
    261   if (!A_SD->getFragment())
    262     Asm.getContext().FatalError(Fixup.getLoc(),
    263                        "symbol '" + A->getName() +
    264                        "' can not be undefined in a subtraction expression");
    265 
    266   uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
    267   uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent());
    268   FixedValue += SecAddr;
    269   uint32_t Value2 = 0;
    270 
    271   if (const MCSymbolRefExpr *B = Target.getSymB()) {
    272     MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
    273 
    274     if (!B_SD->getFragment())
    275       Asm.getContext().FatalError(Fixup.getLoc(),
    276                          "symbol '" + B->getSymbol().getName() +
    277                          "' can not be undefined in a subtraction expression");
    278 
    279     // Select the appropriate difference relocation type.
    280     Type = macho::RIT_Difference;
    281     Value2 = Writer->getSymbolAddress(B_SD, Layout);
    282     FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
    283   }
    284 
    285   // Relocations are written out in reverse order, so the PAIR comes first.
    286   if (Type == macho::RIT_Difference ||
    287       Type == macho::RIT_Generic_LocalDifference) {
    288     macho::RelocationEntry MRE;
    289     MRE.Word0 = ((0         <<  0) |
    290                  (macho::RIT_Pair  << 24) |
    291                  (Log2Size  << 28) |
    292                  (IsPCRel   << 30) |
    293                  macho::RF_Scattered);
    294     MRE.Word1 = Value2;
    295     Writer->addRelocation(Fragment->getParent(), MRE);
    296   }
    297 
    298   macho::RelocationEntry MRE;
    299   MRE.Word0 = ((FixupOffset <<  0) |
    300                (Type        << 24) |
    301                (Log2Size    << 28) |
    302                (IsPCRel     << 30) |
    303                macho::RF_Scattered);
    304   MRE.Word1 = Value;
    305   Writer->addRelocation(Fragment->getParent(), MRE);
    306 }
    307 
    308 void ARMMachObjectWriter::RecordRelocation(MachObjectWriter *Writer,
    309                                            const MCAssembler &Asm,
    310                                            const MCAsmLayout &Layout,
    311                                            const MCFragment *Fragment,
    312                                            const MCFixup &Fixup,
    313                                            MCValue Target,
    314                                            uint64_t &FixedValue) {
    315   unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
    316   unsigned Log2Size;
    317   unsigned RelocType = macho::RIT_Vanilla;
    318   if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size))
    319     // If we failed to get fixup kind info, it's because there's no legal
    320     // relocation type for the fixup kind. This happens when it's a fixup that's
    321     // expected to always be resolvable at assembly time and not have any
    322     // relocations needed.
    323     Asm.getContext().FatalError(Fixup.getLoc(),
    324                                 "unsupported relocation on symbol");
    325 
    326   // If this is a difference or a defined symbol plus an offset, then we need a
    327   // scattered relocation entry.  Differences always require scattered
    328   // relocations.
    329   if (Target.getSymB()) {
    330     if (RelocType == macho::RIT_ARM_Half)
    331       return RecordARMScatteredHalfRelocation(Writer, Asm, Layout, Fragment,
    332                                               Fixup, Target, FixedValue);
    333     return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
    334                                         Target, Log2Size, FixedValue);
    335   }
    336 
    337   // Get the symbol data, if any.
    338   MCSymbolData *SD = 0;
    339   if (Target.getSymA())
    340     SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
    341 
    342   // FIXME: For other platforms, we need to use scattered relocations for
    343   // internal relocations with offsets.  If this is an internal relocation with
    344   // an offset, it also needs a scattered relocation entry.
    345   //
    346   // Is this right for ARM?
    347   uint32_t Offset = Target.getConstant();
    348   if (IsPCRel && RelocType == macho::RIT_Vanilla)
    349     Offset += 1 << Log2Size;
    350   if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD))
    351     return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
    352                                         Target, Log2Size, FixedValue);
    353 
    354   // See <reloc.h>.
    355   uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
    356   unsigned Index = 0;
    357   unsigned IsExtern = 0;
    358   unsigned Type = 0;
    359 
    360   if (Target.isAbsolute()) { // constant
    361     // FIXME!
    362     report_fatal_error("FIXME: relocations to absolute targets "
    363                        "not yet implemented");
    364   } else {
    365     // Resolve constant variables.
    366     if (SD->getSymbol().isVariable()) {
    367       int64_t Res;
    368       if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute(
    369             Res, Layout, Writer->getSectionAddressMap())) {
    370         FixedValue = Res;
    371         return;
    372       }
    373     }
    374 
    375     // Check whether we need an external or internal relocation.
    376     if (Writer->doesSymbolRequireExternRelocation(SD)) {
    377       IsExtern = 1;
    378       Index = SD->getIndex();
    379 
    380       // For external relocations, make sure to offset the fixup value to
    381       // compensate for the addend of the symbol address, if it was
    382       // undefined. This occurs with weak definitions, for example.
    383       if (!SD->Symbol->isUndefined())
    384         FixedValue -= Layout.getSymbolOffset(SD);
    385     } else {
    386       // The index is the section ordinal (1-based).
    387       const MCSectionData &SymSD = Asm.getSectionData(
    388         SD->getSymbol().getSection());
    389       Index = SymSD.getOrdinal() + 1;
    390       FixedValue += Writer->getSectionAddress(&SymSD);
    391     }
    392     if (IsPCRel)
    393       FixedValue -= Writer->getSectionAddress(Fragment->getParent());
    394 
    395     // The type is determined by the fixup kind.
    396     Type = RelocType;
    397   }
    398 
    399   // struct relocation_info (8 bytes)
    400   macho::RelocationEntry MRE;
    401   MRE.Word0 = FixupOffset;
    402   MRE.Word1 = ((Index     <<  0) |
    403                (IsPCRel   << 24) |
    404                (Log2Size  << 25) |
    405                (IsExtern  << 27) |
    406                (Type      << 28));
    407 
    408   // Even when it's not a scattered relocation, movw/movt always uses
    409   // a PAIR relocation.
    410   if (Type == macho::RIT_ARM_Half) {
    411     // The other-half value only gets populated for the movt relocation.
    412     uint32_t Value = 0;;
    413     switch ((unsigned)Fixup.getKind()) {
    414     default: break;
    415     case ARM::fixup_arm_movt_hi16:
    416     case ARM::fixup_arm_movt_hi16_pcrel:
    417     case ARM::fixup_t2_movt_hi16:
    418     case ARM::fixup_t2_movt_hi16_pcrel:
    419       Value = FixedValue;
    420       break;
    421     }
    422     macho::RelocationEntry MREPair;
    423     MREPair.Word0 = Value;
    424     MREPair.Word1 = ((0xffffff) |
    425                      (Log2Size << 25) |
    426                      (macho::RIT_Pair << 28));
    427 
    428     Writer->addRelocation(Fragment->getParent(), MREPair);
    429   }
    430 
    431   Writer->addRelocation(Fragment->getParent(), MRE);
    432 }
    433 
    434 MCObjectWriter *llvm::createARMMachObjectWriter(raw_ostream &OS,
    435                                                 bool Is64Bit,
    436                                                 uint32_t CPUType,
    437                                                 uint32_t CPUSubtype) {
    438   return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit,
    439                                                         CPUType,
    440                                                         CPUSubtype),
    441                                 OS, /*IsLittleEndian=*/true);
    442 }
    443