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/Object/MachOFormat.h"
     24 #include "llvm/Support/ErrorHandling.h"
     25 using namespace llvm;
     26 using namespace llvm::object;
     27 
     28 namespace {
     29 class ARMMachObjectWriter : public MCMachObjectTargetWriter {
     30   void RecordARMScatteredRelocation(MachObjectWriter *Writer,
     31                                     const MCAssembler &Asm,
     32                                     const MCAsmLayout &Layout,
     33                                     const MCFragment *Fragment,
     34                                     const MCFixup &Fixup,
     35                                     MCValue Target,
     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);
     61 };
     62 }
     63 
     64 static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType,
     65                               unsigned &Log2Size) {
     66   RelocType = unsigned(macho::RIT_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     // Handle 24-bit branch kinds.
     87   case ARM::fixup_arm_ldst_pcrel_12:
     88   case ARM::fixup_arm_pcrel_10:
     89   case ARM::fixup_arm_adr_pcrel_12:
     90   case ARM::fixup_arm_condbranch:
     91   case ARM::fixup_arm_uncondbranch:
     92   case ARM::fixup_arm_uncondbl:
     93   case ARM::fixup_arm_condbl:
     94   case ARM::fixup_arm_blx:
     95     RelocType = unsigned(macho::RIT_ARM_Branch24Bit);
     96     // Report as 'long', even though that is not quite accurate.
     97     Log2Size = llvm::Log2_32(4);
     98     return true;
     99 
    100     // Handle Thumb branches.
    101   case ARM::fixup_arm_thumb_br:
    102     RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit);
    103     Log2Size = llvm::Log2_32(2);
    104     return true;
    105 
    106   case ARM::fixup_t2_uncondbranch:
    107   case ARM::fixup_arm_thumb_bl:
    108   case ARM::fixup_arm_thumb_blx:
    109     RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit);
    110     Log2Size = llvm::Log2_32(4);
    111     return true;
    112 
    113   // For movw/movt r_type relocations they always have a pair following them and
    114   // the r_length bits are used differently.  The encoding of the r_length is as
    115   // follows:
    116   //   low bit of r_length:
    117   //      0 - :lower16: for movw instructions
    118   //      1 - :upper16: for movt instructions
    119   //   high bit of r_length:
    120   //      0 - arm instructions
    121   //      1 - thumb instructions
    122   case ARM::fixup_arm_movt_hi16:
    123   case ARM::fixup_arm_movt_hi16_pcrel:
    124     RelocType = unsigned(macho::RIT_ARM_Half);
    125     Log2Size = 1;
    126     return true;
    127   case ARM::fixup_t2_movt_hi16:
    128   case ARM::fixup_t2_movt_hi16_pcrel:
    129     RelocType = unsigned(macho::RIT_ARM_Half);
    130     Log2Size = 3;
    131     return true;
    132 
    133   case ARM::fixup_arm_movw_lo16:
    134   case ARM::fixup_arm_movw_lo16_pcrel:
    135     RelocType = unsigned(macho::RIT_ARM_Half);
    136     Log2Size = 0;
    137     return true;
    138   case ARM::fixup_t2_movw_lo16:
    139   case ARM::fixup_t2_movw_lo16_pcrel:
    140     RelocType = unsigned(macho::RIT_ARM_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::RIT_ARM_Half;
    157 
    158   // See <reloc.h>.
    159   const MCSymbol *A = &Target.getSymA()->getSymbol();
    160   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     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::RIT_ARM_HalfDifference;
    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   case ARM::fixup_arm_movt_hi16_pcrel:
    207     MovtBit = 1;
    208     // The thumb bit shouldn't be set in the 'other-half' bit of the
    209     // relocation, but it will be set in FixedValue if the base symbol
    210     // is a thumb function. Clear it out here.
    211     if (A_SD->getFlags() & SF_ThumbFunc)
    212       FixedValue &= 0xfffffffe;
    213     break;
    214   case ARM::fixup_t2_movt_hi16:
    215   case ARM::fixup_t2_movt_hi16_pcrel:
    216     if (A_SD->getFlags() & SF_ThumbFunc)
    217       FixedValue &= 0xfffffffe;
    218     MovtBit = 1;
    219     // Fallthrough
    220   case ARM::fixup_t2_movw_lo16:
    221   case ARM::fixup_t2_movw_lo16_pcrel:
    222     ThumbBit = 1;
    223     break;
    224   }
    225 
    226   if (Type == macho::RIT_ARM_HalfDifference) {
    227     uint32_t OtherHalf = MovtBit
    228       ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16);
    229 
    230     macho::RelocationEntry MRE;
    231     MRE.Word0 = ((OtherHalf       <<  0) |
    232                  (macho::RIT_Pair << 24) |
    233                  (MovtBit         << 28) |
    234                  (ThumbBit        << 29) |
    235                  (IsPCRel         << 30) |
    236                  macho::RF_Scattered);
    237     MRE.Word1 = Value2;
    238     Writer->addRelocation(Fragment->getParent(), MRE);
    239   }
    240 
    241   macho::RelocationEntry MRE;
    242   MRE.Word0 = ((FixupOffset <<  0) |
    243                (Type        << 24) |
    244                (MovtBit     << 28) |
    245                (ThumbBit    << 29) |
    246                (IsPCRel     << 30) |
    247                macho::RF_Scattered);
    248   MRE.Word1 = Value;
    249   Writer->addRelocation(Fragment->getParent(), MRE);
    250 }
    251 
    252 void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer,
    253                                                     const MCAssembler &Asm,
    254                                                     const MCAsmLayout &Layout,
    255                                                     const MCFragment *Fragment,
    256                                                     const MCFixup &Fixup,
    257                                                     MCValue Target,
    258                                                     unsigned Log2Size,
    259                                                     uint64_t &FixedValue) {
    260   uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
    261   unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
    262   unsigned Type = macho::RIT_Vanilla;
    263 
    264   // See <reloc.h>.
    265   const MCSymbol *A = &Target.getSymA()->getSymbol();
    266   MCSymbolData *A_SD = &Asm.getSymbolData(*A);
    267 
    268   if (!A_SD->getFragment())
    269     Asm.getContext().FatalError(Fixup.getLoc(),
    270                        "symbol '" + A->getName() +
    271                        "' can not be undefined in a subtraction expression");
    272 
    273   uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
    274   uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent());
    275   FixedValue += SecAddr;
    276   uint32_t Value2 = 0;
    277 
    278   if (const MCSymbolRefExpr *B = Target.getSymB()) {
    279     MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
    280 
    281     if (!B_SD->getFragment())
    282       Asm.getContext().FatalError(Fixup.getLoc(),
    283                          "symbol '" + B->getSymbol().getName() +
    284                          "' can not be undefined in a subtraction expression");
    285 
    286     // Select the appropriate difference relocation type.
    287     Type = macho::RIT_Difference;
    288     Value2 = Writer->getSymbolAddress(B_SD, Layout);
    289     FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
    290   }
    291 
    292   // Relocations are written out in reverse order, so the PAIR comes first.
    293   if (Type == macho::RIT_Difference ||
    294       Type == macho::RIT_Generic_LocalDifference) {
    295     macho::RelocationEntry MRE;
    296     MRE.Word0 = ((0         <<  0) |
    297                  (macho::RIT_Pair  << 24) |
    298                  (Log2Size  << 28) |
    299                  (IsPCRel   << 30) |
    300                  macho::RF_Scattered);
    301     MRE.Word1 = Value2;
    302     Writer->addRelocation(Fragment->getParent(), MRE);
    303   }
    304 
    305   macho::RelocationEntry MRE;
    306   MRE.Word0 = ((FixupOffset <<  0) |
    307                (Type        << 24) |
    308                (Log2Size    << 28) |
    309                (IsPCRel     << 30) |
    310                macho::RF_Scattered);
    311   MRE.Word1 = Value;
    312   Writer->addRelocation(Fragment->getParent(), MRE);
    313 }
    314 
    315 bool ARMMachObjectWriter::requiresExternRelocation(MachObjectWriter *Writer,
    316                                                    const MCAssembler &Asm,
    317                                                    const MCFragment &Fragment,
    318                                                    unsigned RelocType,
    319                                                    const MCSymbolData *SD,
    320                                                    uint64_t FixedValue) {
    321   // Most cases can be identified purely from the symbol.
    322   if (Writer->doesSymbolRequireExternRelocation(SD))
    323     return true;
    324   int64_t Value = (int64_t)FixedValue;  // The displacement is signed.
    325   int64_t Range;
    326   switch (RelocType) {
    327   default:
    328     return false;
    329   case macho::RIT_ARM_Branch24Bit:
    330     // PC pre-adjustment of 8 for these instructions.
    331     Value -= 8;
    332     // ARM BL/BLX has a 25-bit offset.
    333     Range = 0x1ffffff;
    334     break;
    335   case macho::RIT_ARM_ThumbBranch22Bit:
    336     // PC pre-adjustment of 4 for these instructions.
    337     Value -= 4;
    338     // Thumb BL/BLX has a 24-bit offset.
    339     Range = 0xffffff;
    340   }
    341   // BL/BLX also use external relocations when an internal relocation
    342   // would result in the target being out of range. This gives the linker
    343   // enough information to generate a branch island.
    344   const MCSectionData &SymSD = Asm.getSectionData(
    345     SD->getSymbol().getSection());
    346   Value += Writer->getSectionAddress(&SymSD);
    347   Value -= Writer->getSectionAddress(Fragment.getParent());
    348   // If the resultant value would be out of range for an internal relocation,
    349   // use an external instead.
    350   if (Value > Range || Value < -(Range + 1))
    351     return true;
    352   return false;
    353 }
    354 
    355 void ARMMachObjectWriter::RecordRelocation(MachObjectWriter *Writer,
    356                                            const MCAssembler &Asm,
    357                                            const MCAsmLayout &Layout,
    358                                            const MCFragment *Fragment,
    359                                            const MCFixup &Fixup,
    360                                            MCValue Target,
    361                                            uint64_t &FixedValue) {
    362   unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
    363   unsigned Log2Size;
    364   unsigned RelocType = macho::RIT_Vanilla;
    365   if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size))
    366     // If we failed to get fixup kind info, it's because there's no legal
    367     // relocation type for the fixup kind. This happens when it's a fixup that's
    368     // expected to always be resolvable at assembly time and not have any
    369     // relocations needed.
    370     Asm.getContext().FatalError(Fixup.getLoc(),
    371                                 "unsupported relocation on symbol");
    372 
    373   // If this is a difference or a defined symbol plus an offset, then we need a
    374   // scattered relocation entry.  Differences always require scattered
    375   // relocations.
    376   if (Target.getSymB()) {
    377     if (RelocType == macho::RIT_ARM_Half)
    378       return RecordARMScatteredHalfRelocation(Writer, Asm, Layout, Fragment,
    379                                               Fixup, Target, FixedValue);
    380     return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
    381                                         Target, Log2Size, FixedValue);
    382   }
    383 
    384   // Get the symbol data, if any.
    385   MCSymbolData *SD = 0;
    386   if (Target.getSymA())
    387     SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
    388 
    389   // FIXME: For other platforms, we need to use scattered relocations for
    390   // internal relocations with offsets.  If this is an internal relocation with
    391   // an offset, it also needs a scattered relocation entry.
    392   //
    393   // Is this right for ARM?
    394   uint32_t Offset = Target.getConstant();
    395   if (IsPCRel && RelocType == macho::RIT_Vanilla)
    396     Offset += 1 << Log2Size;
    397   if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD))
    398     return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
    399                                         Target, Log2Size, 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::RelocationEntry MRE;
    449   MRE.Word0 = FixupOffset;
    450   MRE.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::RIT_ARM_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_arm_movw_lo16_pcrel:
    466     case ARM::fixup_t2_movw_lo16:
    467     case ARM::fixup_t2_movw_lo16_pcrel:
    468       Value = (FixedValue >> 16) & 0xffff;
    469       break;
    470     case ARM::fixup_arm_movt_hi16:
    471     case ARM::fixup_arm_movt_hi16_pcrel:
    472     case ARM::fixup_t2_movt_hi16:
    473     case ARM::fixup_t2_movt_hi16_pcrel:
    474       Value = FixedValue & 0xffff;
    475       break;
    476     }
    477     macho::RelocationEntry MREPair;
    478     MREPair.Word0 = Value;
    479     MREPair.Word1 = ((0xffffff) |
    480                      (Log2Size << 25) |
    481                      (macho::RIT_Pair << 28));
    482 
    483     Writer->addRelocation(Fragment->getParent(), MREPair);
    484   }
    485 
    486   Writer->addRelocation(Fragment->getParent(), MRE);
    487 }
    488 
    489 MCObjectWriter *llvm::createARMMachObjectWriter(raw_ostream &OS,
    490                                                 bool Is64Bit,
    491                                                 uint32_t CPUType,
    492                                                 uint32_t CPUSubtype) {
    493   return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit,
    494                                                         CPUType,
    495                                                         CPUSubtype),
    496                                 OS, /*IsLittleEndian=*/true);
    497 }
    498