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