LLVM API Documentation

ARMMachObjectWriter.cpp
Go to the documentation of this file.
00001 //===-- ARMMachObjectWriter.cpp - ARM Mach Object Writer ------------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 #include "MCTargetDesc/ARMMCTargetDesc.h"
00011 #include "MCTargetDesc/ARMBaseInfo.h"
00012 #include "MCTargetDesc/ARMFixupKinds.h"
00013 #include "llvm/ADT/Twine.h"
00014 #include "llvm/MC/MCAsmLayout.h"
00015 #include "llvm/MC/MCAssembler.h"
00016 #include "llvm/MC/MCContext.h"
00017 #include "llvm/MC/MCExpr.h"
00018 #include "llvm/MC/MCFixup.h"
00019 #include "llvm/MC/MCFixupKindInfo.h"
00020 #include "llvm/MC/MCMachOSymbolFlags.h"
00021 #include "llvm/MC/MCMachObjectWriter.h"
00022 #include "llvm/MC/MCValue.h"
00023 #include "llvm/Support/ErrorHandling.h"
00024 #include "llvm/Support/MachO.h"
00025 using namespace llvm;
00026 
00027 namespace {
00028 class ARMMachObjectWriter : public MCMachObjectTargetWriter {
00029   void RecordARMScatteredRelocation(MachObjectWriter *Writer,
00030                                     const MCAssembler &Asm,
00031                                     const MCAsmLayout &Layout,
00032                                     const MCFragment *Fragment,
00033                                     const MCFixup &Fixup,
00034                                     MCValue Target,
00035                                     unsigned Type,
00036                                     unsigned Log2Size,
00037                                     uint64_t &FixedValue);
00038   void RecordARMScatteredHalfRelocation(MachObjectWriter *Writer,
00039                                         const MCAssembler &Asm,
00040                                         const MCAsmLayout &Layout,
00041                                         const MCFragment *Fragment,
00042                                         const MCFixup &Fixup, MCValue Target,
00043                                         uint64_t &FixedValue);
00044 
00045   bool requiresExternRelocation(MachObjectWriter *Writer,
00046                                 const MCAssembler &Asm,
00047                                 const MCFragment &Fragment,
00048                                 unsigned RelocType, const MCSymbolData *SD,
00049                                 uint64_t FixedValue);
00050 
00051 public:
00052   ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType,
00053                       uint32_t CPUSubtype)
00054     : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype,
00055                                /*UseAggressiveSymbolFolding=*/true) {}
00056 
00057   void RecordRelocation(MachObjectWriter *Writer,
00058                         const MCAssembler &Asm, const MCAsmLayout &Layout,
00059                         const MCFragment *Fragment, const MCFixup &Fixup,
00060                         MCValue Target, uint64_t &FixedValue) override;
00061 };
00062 }
00063 
00064 static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType,
00065                               unsigned &Log2Size) {
00066   RelocType = unsigned(MachO::ARM_RELOC_VANILLA);
00067   Log2Size = ~0U;
00068 
00069   switch (Kind) {
00070   default:
00071     return false;
00072 
00073   case FK_Data_1:
00074     Log2Size = llvm::Log2_32(1);
00075     return true;
00076   case FK_Data_2:
00077     Log2Size = llvm::Log2_32(2);
00078     return true;
00079   case FK_Data_4:
00080     Log2Size = llvm::Log2_32(4);
00081     return true;
00082   case FK_Data_8:
00083     Log2Size = llvm::Log2_32(8);
00084     return true;
00085 
00086     // These fixups are expected to always be resolvable at assembly time and
00087     // have no relocations supported.
00088   case ARM::fixup_arm_ldst_pcrel_12:
00089   case ARM::fixup_arm_pcrel_10:
00090   case ARM::fixup_arm_adr_pcrel_12:
00091     return false;
00092 
00093     // Handle 24-bit branch kinds.
00094   case ARM::fixup_arm_condbranch:
00095   case ARM::fixup_arm_uncondbranch:
00096   case ARM::fixup_arm_uncondbl:
00097   case ARM::fixup_arm_condbl:
00098   case ARM::fixup_arm_blx:
00099     RelocType = unsigned(MachO::ARM_RELOC_BR24);
00100     // Report as 'long', even though that is not quite accurate.
00101     Log2Size = llvm::Log2_32(4);
00102     return true;
00103 
00104     // Handle Thumb branches.
00105   case ARM::fixup_arm_thumb_br:
00106     RelocType = unsigned(MachO::ARM_THUMB_RELOC_BR22);
00107     Log2Size = llvm::Log2_32(2);
00108     return true;
00109 
00110   case ARM::fixup_t2_uncondbranch:
00111   case ARM::fixup_arm_thumb_bl:
00112   case ARM::fixup_arm_thumb_blx:
00113     RelocType = unsigned(MachO::ARM_THUMB_RELOC_BR22);
00114     Log2Size = llvm::Log2_32(4);
00115     return true;
00116 
00117   // For movw/movt r_type relocations they always have a pair following them and
00118   // the r_length bits are used differently.  The encoding of the r_length is as
00119   // follows:
00120   //   low bit of r_length:
00121   //      0 - :lower16: for movw instructions
00122   //      1 - :upper16: for movt instructions
00123   //   high bit of r_length:
00124   //      0 - arm instructions
00125   //      1 - thumb instructions
00126   case ARM::fixup_arm_movt_hi16:
00127     RelocType = unsigned(MachO::ARM_RELOC_HALF);
00128     Log2Size = 1;
00129     return true;
00130   case ARM::fixup_t2_movt_hi16:
00131     RelocType = unsigned(MachO::ARM_RELOC_HALF);
00132     Log2Size = 3;
00133     return true;
00134 
00135   case ARM::fixup_arm_movw_lo16:
00136     RelocType = unsigned(MachO::ARM_RELOC_HALF);
00137     Log2Size = 0;
00138     return true;
00139   case ARM::fixup_t2_movw_lo16:
00140     RelocType = unsigned(MachO::ARM_RELOC_HALF);
00141     Log2Size = 2;
00142     return true;
00143   }
00144 }
00145 
00146 void ARMMachObjectWriter::
00147 RecordARMScatteredHalfRelocation(MachObjectWriter *Writer,
00148                                  const MCAssembler &Asm,
00149                                  const MCAsmLayout &Layout,
00150                                  const MCFragment *Fragment,
00151                                  const MCFixup &Fixup,
00152                                  MCValue Target,
00153                                  uint64_t &FixedValue) {
00154   uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
00155   unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
00156   unsigned Type = MachO::ARM_RELOC_HALF;
00157 
00158   // See <reloc.h>.
00159   const MCSymbol *A = &Target.getSymA()->getSymbol();
00160   const MCSymbolData *A_SD = &Asm.getSymbolData(*A);
00161 
00162   if (!A_SD->getFragment())
00163     Asm.getContext().FatalError(Fixup.getLoc(),
00164                        "symbol '" + A->getName() +
00165                        "' can not be undefined in a subtraction expression");
00166 
00167   uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
00168   uint32_t Value2 = 0;
00169   uint64_t SecAddr =
00170     Writer->getSectionAddress(A_SD->getFragment()->getParent());
00171   FixedValue += SecAddr;
00172 
00173   if (const MCSymbolRefExpr *B = Target.getSymB()) {
00174     const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
00175 
00176     if (!B_SD->getFragment())
00177       Asm.getContext().FatalError(Fixup.getLoc(),
00178                          "symbol '" + B->getSymbol().getName() +
00179                          "' can not be undefined in a subtraction expression");
00180 
00181     // Select the appropriate difference relocation type.
00182     Type = MachO::ARM_RELOC_HALF_SECTDIFF;
00183     Value2 = Writer->getSymbolAddress(B_SD, Layout);
00184     FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
00185   }
00186 
00187   // Relocations are written out in reverse order, so the PAIR comes first.
00188   // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field:
00189   //
00190   // For these two r_type relocations they always have a pair following them and
00191   // the r_length bits are used differently.  The encoding of the r_length is as
00192   // follows:
00193   //   low bit of r_length:
00194   //      0 - :lower16: for movw instructions
00195   //      1 - :upper16: for movt instructions
00196   //   high bit of r_length:
00197   //      0 - arm instructions
00198   //      1 - thumb instructions
00199   // the other half of the relocated expression is in the following pair
00200   // relocation entry in the low 16 bits of r_address field.
00201   unsigned ThumbBit = 0;
00202   unsigned MovtBit = 0;
00203   switch ((unsigned)Fixup.getKind()) {
00204   default: break;
00205   case ARM::fixup_arm_movt_hi16:
00206     MovtBit = 1;
00207     // The thumb bit shouldn't be set in the 'other-half' bit of the
00208     // relocation, but it will be set in FixedValue if the base symbol
00209     // is a thumb function. Clear it out here.
00210     if (Asm.isThumbFunc(A))
00211       FixedValue &= 0xfffffffe;
00212     break;
00213   case ARM::fixup_t2_movt_hi16:
00214     if (Asm.isThumbFunc(A))
00215       FixedValue &= 0xfffffffe;
00216     MovtBit = 1;
00217     // Fallthrough
00218   case ARM::fixup_t2_movw_lo16:
00219     ThumbBit = 1;
00220     break;
00221   }
00222 
00223   if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
00224     uint32_t OtherHalf = MovtBit
00225       ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16);
00226 
00227     MachO::any_relocation_info MRE;
00228     MRE.r_word0 = ((OtherHalf             <<  0) |
00229                    (MachO::ARM_RELOC_PAIR << 24) |
00230                    (MovtBit               << 28) |
00231                    (ThumbBit              << 29) |
00232                    (IsPCRel               << 30) |
00233                    MachO::R_SCATTERED);
00234     MRE.r_word1 = Value2;
00235     Writer->addRelocation(Fragment->getParent(), MRE);
00236   }
00237 
00238   MachO::any_relocation_info MRE;
00239   MRE.r_word0 = ((FixupOffset <<  0) |
00240                  (Type        << 24) |
00241                  (MovtBit     << 28) |
00242                  (ThumbBit    << 29) |
00243                  (IsPCRel     << 30) |
00244                  MachO::R_SCATTERED);
00245   MRE.r_word1 = Value;
00246   Writer->addRelocation(Fragment->getParent(), MRE);
00247 }
00248 
00249 void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer,
00250                                                     const MCAssembler &Asm,
00251                                                     const MCAsmLayout &Layout,
00252                                                     const MCFragment *Fragment,
00253                                                     const MCFixup &Fixup,
00254                                                     MCValue Target,
00255                                                     unsigned Type,
00256                                                     unsigned Log2Size,
00257                                                     uint64_t &FixedValue) {
00258   uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
00259   unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
00260 
00261   // See <reloc.h>.
00262   const MCSymbol *A = &Target.getSymA()->getSymbol();
00263   const MCSymbolData *A_SD = &Asm.getSymbolData(*A);
00264 
00265   if (!A_SD->getFragment())
00266     Asm.getContext().FatalError(Fixup.getLoc(),
00267                        "symbol '" + A->getName() +
00268                        "' can not be undefined in a subtraction expression");
00269 
00270   uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
00271   uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent());
00272   FixedValue += SecAddr;
00273   uint32_t Value2 = 0;
00274 
00275   if (const MCSymbolRefExpr *B = Target.getSymB()) {
00276     assert(Type == MachO::ARM_RELOC_VANILLA && "invalid reloc for 2 symbols");
00277     const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
00278 
00279     if (!B_SD->getFragment())
00280       Asm.getContext().FatalError(Fixup.getLoc(),
00281                          "symbol '" + B->getSymbol().getName() +
00282                          "' can not be undefined in a subtraction expression");
00283 
00284     // Select the appropriate difference relocation type.
00285     Type = MachO::ARM_RELOC_SECTDIFF;
00286     Value2 = Writer->getSymbolAddress(B_SD, Layout);
00287     FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
00288   }
00289 
00290   // Relocations are written out in reverse order, so the PAIR comes first.
00291   if (Type == MachO::ARM_RELOC_SECTDIFF ||
00292       Type == MachO::ARM_RELOC_LOCAL_SECTDIFF) {
00293     MachO::any_relocation_info MRE;
00294     MRE.r_word0 = ((0                     <<  0) |
00295                    (MachO::ARM_RELOC_PAIR << 24) |
00296                    (Log2Size              << 28) |
00297                    (IsPCRel               << 30) |
00298                    MachO::R_SCATTERED);
00299     MRE.r_word1 = Value2;
00300     Writer->addRelocation(Fragment->getParent(), MRE);
00301   }
00302 
00303   MachO::any_relocation_info MRE;
00304   MRE.r_word0 = ((FixupOffset <<  0) |
00305                  (Type        << 24) |
00306                  (Log2Size    << 28) |
00307                  (IsPCRel     << 30) |
00308                  MachO::R_SCATTERED);
00309   MRE.r_word1 = Value;
00310   Writer->addRelocation(Fragment->getParent(), MRE);
00311 }
00312 
00313 bool ARMMachObjectWriter::requiresExternRelocation(MachObjectWriter *Writer,
00314                                                    const MCAssembler &Asm,
00315                                                    const MCFragment &Fragment,
00316                                                    unsigned RelocType,
00317                                                    const MCSymbolData *SD,
00318                                                    uint64_t FixedValue) {
00319   // Most cases can be identified purely from the symbol.
00320   if (Writer->doesSymbolRequireExternRelocation(SD))
00321     return true;
00322   int64_t Value = (int64_t)FixedValue;  // The displacement is signed.
00323   int64_t Range;
00324   switch (RelocType) {
00325   default:
00326     return false;
00327   case MachO::ARM_RELOC_BR24:
00328     // PC pre-adjustment of 8 for these instructions.
00329     Value -= 8;
00330     // ARM BL/BLX has a 25-bit offset.
00331     Range = 0x1ffffff;
00332     break;
00333   case MachO::ARM_THUMB_RELOC_BR22:
00334     // PC pre-adjustment of 4 for these instructions.
00335     Value -= 4;
00336     // Thumb BL/BLX has a 24-bit offset.
00337     Range = 0xffffff;
00338   }
00339   // BL/BLX also use external relocations when an internal relocation
00340   // would result in the target being out of range. This gives the linker
00341   // enough information to generate a branch island.
00342   const MCSectionData &SymSD = Asm.getSectionData(
00343     SD->getSymbol().getSection());
00344   Value += Writer->getSectionAddress(&SymSD);
00345   Value -= Writer->getSectionAddress(Fragment.getParent());
00346   // If the resultant value would be out of range for an internal relocation,
00347   // use an external instead.
00348   if (Value > Range || Value < -(Range + 1))
00349     return true;
00350   return false;
00351 }
00352 
00353 void ARMMachObjectWriter::RecordRelocation(MachObjectWriter *Writer,
00354                                            const MCAssembler &Asm,
00355                                            const MCAsmLayout &Layout,
00356                                            const MCFragment *Fragment,
00357                                            const MCFixup &Fixup,
00358                                            MCValue Target,
00359                                            uint64_t &FixedValue) {
00360   unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
00361   unsigned Log2Size;
00362   unsigned RelocType = MachO::ARM_RELOC_VANILLA;
00363   if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size))
00364     // If we failed to get fixup kind info, it's because there's no legal
00365     // relocation type for the fixup kind. This happens when it's a fixup that's
00366     // expected to always be resolvable at assembly time and not have any
00367     // relocations needed.
00368     Asm.getContext().FatalError(Fixup.getLoc(),
00369                                 "unsupported relocation on symbol");
00370 
00371   // If this is a difference or a defined symbol plus an offset, then we need a
00372   // scattered relocation entry.  Differences always require scattered
00373   // relocations.
00374   if (Target.getSymB()) {
00375     if (RelocType == MachO::ARM_RELOC_HALF)
00376       return RecordARMScatteredHalfRelocation(Writer, Asm, Layout, Fragment,
00377                                               Fixup, Target, FixedValue);
00378     return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
00379                                         Target, RelocType, Log2Size,
00380                                         FixedValue);
00381   }
00382 
00383   // Get the symbol data, if any.
00384   const MCSymbolData *SD = nullptr;
00385   if (Target.getSymA())
00386     SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
00387 
00388   // FIXME: For other platforms, we need to use scattered relocations for
00389   // internal relocations with offsets.  If this is an internal relocation with
00390   // an offset, it also needs a scattered relocation entry.
00391   //
00392   // Is this right for ARM?
00393   uint32_t Offset = Target.getConstant();
00394   if (IsPCRel && RelocType == MachO::ARM_RELOC_VANILLA)
00395     Offset += 1 << Log2Size;
00396   if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD))
00397     return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
00398                                         Target, RelocType, Log2Size,
00399                                         FixedValue);
00400 
00401   // See <reloc.h>.
00402   uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
00403   unsigned Index = 0;
00404   unsigned IsExtern = 0;
00405   unsigned Type = 0;
00406 
00407   if (Target.isAbsolute()) { // constant
00408     // FIXME!
00409     report_fatal_error("FIXME: relocations to absolute targets "
00410                        "not yet implemented");
00411   } else {
00412     // Resolve constant variables.
00413     if (SD->getSymbol().isVariable()) {
00414       int64_t Res;
00415       if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute(
00416             Res, Layout, Writer->getSectionAddressMap())) {
00417         FixedValue = Res;
00418         return;
00419       }
00420     }
00421 
00422     // Check whether we need an external or internal relocation.
00423     if (requiresExternRelocation(Writer, Asm, *Fragment, RelocType, SD,
00424                                  FixedValue)) {
00425       IsExtern = 1;
00426       Index = SD->getIndex();
00427 
00428       // For external relocations, make sure to offset the fixup value to
00429       // compensate for the addend of the symbol address, if it was
00430       // undefined. This occurs with weak definitions, for example.
00431       if (!SD->Symbol->isUndefined())
00432         FixedValue -= Layout.getSymbolOffset(SD);
00433     } else {
00434       // The index is the section ordinal (1-based).
00435       const MCSectionData &SymSD = Asm.getSectionData(
00436         SD->getSymbol().getSection());
00437       Index = SymSD.getOrdinal() + 1;
00438       FixedValue += Writer->getSectionAddress(&SymSD);
00439     }
00440     if (IsPCRel)
00441       FixedValue -= Writer->getSectionAddress(Fragment->getParent());
00442 
00443     // The type is determined by the fixup kind.
00444     Type = RelocType;
00445   }
00446 
00447   // struct relocation_info (8 bytes)
00448   MachO::any_relocation_info MRE;
00449   MRE.r_word0 = FixupOffset;
00450   MRE.r_word1 = ((Index     <<  0) |
00451                  (IsPCRel   << 24) |
00452                  (Log2Size  << 25) |
00453                  (IsExtern  << 27) |
00454                  (Type      << 28));
00455 
00456   // Even when it's not a scattered relocation, movw/movt always uses
00457   // a PAIR relocation.
00458   if (Type == MachO::ARM_RELOC_HALF) {
00459     // The other-half value only gets populated for the movt and movw
00460     // relocation entries.
00461     uint32_t Value = 0;
00462     switch ((unsigned)Fixup.getKind()) {
00463     default: break;
00464     case ARM::fixup_arm_movw_lo16:
00465     case ARM::fixup_t2_movw_lo16:
00466       Value = (FixedValue >> 16) & 0xffff;
00467       break;
00468     case ARM::fixup_arm_movt_hi16:
00469     case ARM::fixup_t2_movt_hi16:
00470       Value = FixedValue & 0xffff;
00471       break;
00472     }
00473     MachO::any_relocation_info MREPair;
00474     MREPair.r_word0 = Value;
00475     MREPair.r_word1 = ((0xffffff              <<  0) |
00476                        (Log2Size              << 25) |
00477                        (MachO::ARM_RELOC_PAIR << 28));
00478 
00479     Writer->addRelocation(Fragment->getParent(), MREPair);
00480   }
00481 
00482   Writer->addRelocation(Fragment->getParent(), MRE);
00483 }
00484 
00485 MCObjectWriter *llvm::createARMMachObjectWriter(raw_ostream &OS,
00486                                                 bool Is64Bit,
00487                                                 uint32_t CPUType,
00488                                                 uint32_t CPUSubtype) {
00489   return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit,
00490                                                         CPUType,
00491                                                         CPUSubtype),
00492                                 OS, /*IsLittleEndian=*/true);
00493 }