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