LLVM API Documentation

AArch64MachObjectWriter.cpp
Go to the documentation of this file.
00001 //===-- AArch64MachObjectWriter.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/AArch64FixupKinds.h"
00011 #include "MCTargetDesc/AArch64MCTargetDesc.h"
00012 #include "llvm/ADT/Twine.h"
00013 #include "llvm/MC/MCAsmLayout.h"
00014 #include "llvm/MC/MCAssembler.h"
00015 #include "llvm/MC/MCContext.h"
00016 #include "llvm/MC/MCExpr.h"
00017 #include "llvm/MC/MCFixup.h"
00018 #include "llvm/MC/MCMachObjectWriter.h"
00019 #include "llvm/MC/MCSectionMachO.h"
00020 #include "llvm/MC/MCValue.h"
00021 #include "llvm/Support/ErrorHandling.h"
00022 #include "llvm/Support/MachO.h"
00023 using namespace llvm;
00024 
00025 namespace {
00026 class AArch64MachObjectWriter : public MCMachObjectTargetWriter {
00027   bool getAArch64FixupKindMachOInfo(const MCFixup &Fixup, unsigned &RelocType,
00028                                   const MCSymbolRefExpr *Sym,
00029                                   unsigned &Log2Size, const MCAssembler &Asm);
00030 
00031 public:
00032   AArch64MachObjectWriter(uint32_t CPUType, uint32_t CPUSubtype)
00033       : MCMachObjectTargetWriter(true /* is64Bit */, CPUType, CPUSubtype,
00034                                  /*UseAggressiveSymbolFolding=*/true) {}
00035 
00036   void RecordRelocation(MachObjectWriter *Writer, const MCAssembler &Asm,
00037                         const MCAsmLayout &Layout, const MCFragment *Fragment,
00038                         const MCFixup &Fixup, MCValue Target,
00039                         uint64_t &FixedValue) override;
00040 };
00041 }
00042 
00043 bool AArch64MachObjectWriter::getAArch64FixupKindMachOInfo(
00044     const MCFixup &Fixup, unsigned &RelocType, const MCSymbolRefExpr *Sym,
00045     unsigned &Log2Size, const MCAssembler &Asm) {
00046   RelocType = unsigned(MachO::ARM64_RELOC_UNSIGNED);
00047   Log2Size = ~0U;
00048 
00049   switch ((unsigned)Fixup.getKind()) {
00050   default:
00051     return false;
00052 
00053   case FK_Data_1:
00054     Log2Size = llvm::Log2_32(1);
00055     return true;
00056   case FK_Data_2:
00057     Log2Size = llvm::Log2_32(2);
00058     return true;
00059   case FK_Data_4:
00060     Log2Size = llvm::Log2_32(4);
00061     if (Sym->getKind() == MCSymbolRefExpr::VK_GOT)
00062       RelocType = unsigned(MachO::ARM64_RELOC_POINTER_TO_GOT);
00063     return true;
00064   case FK_Data_8:
00065     Log2Size = llvm::Log2_32(8);
00066     if (Sym->getKind() == MCSymbolRefExpr::VK_GOT)
00067       RelocType = unsigned(MachO::ARM64_RELOC_POINTER_TO_GOT);
00068     return true;
00069   case AArch64::fixup_aarch64_add_imm12:
00070   case AArch64::fixup_aarch64_ldst_imm12_scale1:
00071   case AArch64::fixup_aarch64_ldst_imm12_scale2:
00072   case AArch64::fixup_aarch64_ldst_imm12_scale4:
00073   case AArch64::fixup_aarch64_ldst_imm12_scale8:
00074   case AArch64::fixup_aarch64_ldst_imm12_scale16:
00075     Log2Size = llvm::Log2_32(4);
00076     switch (Sym->getKind()) {
00077     default:
00078       llvm_unreachable("Unexpected symbol reference variant kind!");
00079     case MCSymbolRefExpr::VK_PAGEOFF:
00080       RelocType = unsigned(MachO::ARM64_RELOC_PAGEOFF12);
00081       return true;
00082     case MCSymbolRefExpr::VK_GOTPAGEOFF:
00083       RelocType = unsigned(MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12);
00084       return true;
00085     case MCSymbolRefExpr::VK_TLVPPAGEOFF:
00086       RelocType = unsigned(MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12);
00087       return true;
00088     }
00089   case AArch64::fixup_aarch64_pcrel_adrp_imm21:
00090     Log2Size = llvm::Log2_32(4);
00091     // This encompasses the relocation for the whole 21-bit value.
00092     switch (Sym->getKind()) {
00093     default:
00094       Asm.getContext().FatalError(Fixup.getLoc(),
00095                                   "ADR/ADRP relocations must be GOT relative");
00096     case MCSymbolRefExpr::VK_PAGE:
00097       RelocType = unsigned(MachO::ARM64_RELOC_PAGE21);
00098       return true;
00099     case MCSymbolRefExpr::VK_GOTPAGE:
00100       RelocType = unsigned(MachO::ARM64_RELOC_GOT_LOAD_PAGE21);
00101       return true;
00102     case MCSymbolRefExpr::VK_TLVPPAGE:
00103       RelocType = unsigned(MachO::ARM64_RELOC_TLVP_LOAD_PAGE21);
00104       return true;
00105     }
00106     return true;
00107   case AArch64::fixup_aarch64_pcrel_branch26:
00108   case AArch64::fixup_aarch64_pcrel_call26:
00109     Log2Size = llvm::Log2_32(4);
00110     RelocType = unsigned(MachO::ARM64_RELOC_BRANCH26);
00111     return true;
00112   }
00113 }
00114 
00115 void AArch64MachObjectWriter::RecordRelocation(
00116     MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout,
00117     const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
00118     uint64_t &FixedValue) {
00119   unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
00120 
00121   // See <reloc.h>.
00122   uint32_t FixupOffset = Layout.getFragmentOffset(Fragment);
00123   unsigned Log2Size = 0;
00124   int64_t Value = 0;
00125   unsigned Index = 0;
00126   unsigned IsExtern = 0;
00127   unsigned Type = 0;
00128   unsigned Kind = Fixup.getKind();
00129 
00130   FixupOffset += Fixup.getOffset();
00131 
00132   // AArch64 pcrel relocation addends do not include the section offset.
00133   if (IsPCRel)
00134     FixedValue += FixupOffset;
00135 
00136   // ADRP fixups use relocations for the whole symbol value and only
00137   // put the addend in the instruction itself. Clear out any value the
00138   // generic code figured out from the sybmol definition.
00139   if (Kind == AArch64::fixup_aarch64_pcrel_adrp_imm21)
00140     FixedValue = 0;
00141 
00142   // imm19 relocations are for conditional branches, which require
00143   // assembler local symbols. If we got here, that's not what we have,
00144   // so complain loudly.
00145   if (Kind == AArch64::fixup_aarch64_pcrel_branch19) {
00146     Asm.getContext().FatalError(Fixup.getLoc(),
00147                                 "conditional branch requires assembler-local"
00148                                 " label. '" +
00149                                     Target.getSymA()->getSymbol().getName() +
00150                                     "' is external.");
00151     return;
00152   }
00153 
00154   // 14-bit branch relocations should only target internal labels, and so
00155   // should never get here.
00156   if (Kind == AArch64::fixup_aarch64_pcrel_branch14) {
00157     Asm.getContext().FatalError(Fixup.getLoc(),
00158                                 "Invalid relocation on conditional branch!");
00159     return;
00160   }
00161 
00162   if (!getAArch64FixupKindMachOInfo(Fixup, Type, Target.getSymA(), Log2Size,
00163                                   Asm)) {
00164     Asm.getContext().FatalError(Fixup.getLoc(), "unknown AArch64 fixup kind!");
00165     return;
00166   }
00167 
00168   Value = Target.getConstant();
00169 
00170   if (Target.isAbsolute()) { // constant
00171     // FIXME: Should this always be extern?
00172     // SymbolNum of 0 indicates the absolute section.
00173     Type = MachO::ARM64_RELOC_UNSIGNED;
00174     Index = 0;
00175 
00176     if (IsPCRel) {
00177       IsExtern = 1;
00178       Asm.getContext().FatalError(Fixup.getLoc(),
00179                                   "PC relative absolute relocation!");
00180 
00181       // FIXME: x86_64 sets the type to a branch reloc here. Should we do
00182       // something similar?
00183     }
00184   } else if (Target.getSymB()) { // A - B + constant
00185     const MCSymbol *A = &Target.getSymA()->getSymbol();
00186     const MCSymbolData &A_SD = Asm.getSymbolData(*A);
00187     const MCSymbolData *A_Base = Asm.getAtom(&A_SD);
00188 
00189     const MCSymbol *B = &Target.getSymB()->getSymbol();
00190     const MCSymbolData &B_SD = Asm.getSymbolData(*B);
00191     const MCSymbolData *B_Base = Asm.getAtom(&B_SD);
00192 
00193     // Check for "_foo@got - .", which comes through here as:
00194     // Ltmp0:
00195     //    ... _foo@got - Ltmp0
00196     if (Target.getSymA()->getKind() == MCSymbolRefExpr::VK_GOT &&
00197         Target.getSymB()->getKind() == MCSymbolRefExpr::VK_None &&
00198         Layout.getSymbolOffset(&B_SD) ==
00199             Layout.getFragmentOffset(Fragment) + Fixup.getOffset()) {
00200       // SymB is the PC, so use a PC-rel pointer-to-GOT relocation.
00201       Index = A_Base->getIndex();
00202       IsExtern = 1;
00203       Type = MachO::ARM64_RELOC_POINTER_TO_GOT;
00204       IsPCRel = 1;
00205       MachO::any_relocation_info MRE;
00206       MRE.r_word0 = FixupOffset;
00207       MRE.r_word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) |
00208                      (IsExtern << 27) | (Type << 28));
00209       Writer->addRelocation(Fragment->getParent(), MRE);
00210       return;
00211     } else if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None ||
00212                Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None)
00213       // Otherwise, neither symbol can be modified.
00214       Asm.getContext().FatalError(Fixup.getLoc(),
00215                                   "unsupported relocation of modified symbol");
00216 
00217     // We don't support PCrel relocations of differences.
00218     if (IsPCRel)
00219       Asm.getContext().FatalError(Fixup.getLoc(),
00220                                   "unsupported pc-relative relocation of "
00221                                   "difference");
00222 
00223     // AArch64 always uses external relocations. If there is no symbol to use as
00224     // a base address (a local symbol with no preceding non-local symbol),
00225     // error out.
00226     //
00227     // FIXME: We should probably just synthesize an external symbol and use
00228     // that.
00229     if (!A_Base)
00230       Asm.getContext().FatalError(
00231           Fixup.getLoc(),
00232           "unsupported relocation of local symbol '" + A->getName() +
00233               "'. Must have non-local symbol earlier in section.");
00234     if (!B_Base)
00235       Asm.getContext().FatalError(
00236           Fixup.getLoc(),
00237           "unsupported relocation of local symbol '" + B->getName() +
00238               "'. Must have non-local symbol earlier in section.");
00239 
00240     if (A_Base == B_Base && A_Base)
00241       Asm.getContext().FatalError(Fixup.getLoc(),
00242                                   "unsupported relocation with identical base");
00243 
00244     Value += (!A_SD.getFragment() ? 0
00245                                   : Writer->getSymbolAddress(&A_SD, Layout)) -
00246              (!A_Base || !A_Base->getFragment()
00247                   ? 0
00248                   : Writer->getSymbolAddress(A_Base, Layout));
00249     Value -= (!B_SD.getFragment() ? 0
00250                                   : Writer->getSymbolAddress(&B_SD, Layout)) -
00251              (!B_Base || !B_Base->getFragment()
00252                   ? 0
00253                   : Writer->getSymbolAddress(B_Base, Layout));
00254 
00255     Index = A_Base->getIndex();
00256     IsExtern = 1;
00257     Type = MachO::ARM64_RELOC_UNSIGNED;
00258 
00259     MachO::any_relocation_info MRE;
00260     MRE.r_word0 = FixupOffset;
00261     MRE.r_word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) |
00262                    (IsExtern << 27) | (Type << 28));
00263     Writer->addRelocation(Fragment->getParent(), MRE);
00264 
00265     Index = B_Base->getIndex();
00266     IsExtern = 1;
00267     Type = MachO::ARM64_RELOC_SUBTRACTOR;
00268   } else { // A + constant
00269     const MCSymbol *Symbol = &Target.getSymA()->getSymbol();
00270     const MCSymbolData &SD = Asm.getSymbolData(*Symbol);
00271     const MCSymbolData *Base = Asm.getAtom(&SD);
00272     const MCSectionMachO &Section = static_cast<const MCSectionMachO &>(
00273         Fragment->getParent()->getSection());
00274 
00275     // If the symbol is a variable and we weren't able to get a Base for it
00276     // (i.e., it's not in the symbol table associated with a section) resolve
00277     // the relocation based its expansion instead.
00278     if (Symbol->isVariable() && !Base) {
00279       // If the evaluation is an absolute value, just use that directly
00280       // to keep things easy.
00281       int64_t Res;
00282       if (SD.getSymbol().getVariableValue()->EvaluateAsAbsolute(
00283               Res, Layout, Writer->getSectionAddressMap())) {
00284         FixedValue = Res;
00285         return;
00286       }
00287 
00288       // FIXME: Will the Target we already have ever have any data in it
00289       // we need to preserve and merge with the new Target? How about
00290       // the FixedValue?
00291       if (!Symbol->getVariableValue()->EvaluateAsRelocatable(Target, &Layout,
00292                                                              &Fixup))
00293         Asm.getContext().FatalError(Fixup.getLoc(),
00294                                     "unable to resolve variable '" +
00295                                         Symbol->getName() + "'");
00296       return RecordRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
00297                               FixedValue);
00298     }
00299 
00300     // Relocations inside debug sections always use local relocations when
00301     // possible. This seems to be done because the debugger doesn't fully
00302     // understand relocation entries and expects to find values that
00303     // have already been fixed up.
00304     if (Symbol->isInSection()) {
00305       if (Section.hasAttribute(MachO::S_ATTR_DEBUG))
00306         Base = nullptr;
00307     }
00308 
00309     // AArch64 uses external relocations as much as possible. For debug
00310     // sections, and for pointer-sized relocations (.quad), we allow section
00311     // relocations.  It's code sections that run into trouble.
00312     if (Base) {
00313       Index = Base->getIndex();
00314       IsExtern = 1;
00315 
00316       // Add the local offset, if needed.
00317       if (Base != &SD)
00318         Value += Layout.getSymbolOffset(&SD) - Layout.getSymbolOffset(Base);
00319     } else if (Symbol->isInSection()) {
00320       // Pointer-sized relocations can use a local relocation. Otherwise,
00321       // we have to be in a debug info section.
00322       if (!Section.hasAttribute(MachO::S_ATTR_DEBUG) && Log2Size != 3)
00323         Asm.getContext().FatalError(
00324             Fixup.getLoc(),
00325             "unsupported relocation of local symbol '" + Symbol->getName() +
00326                 "'. Must have non-local symbol earlier in section.");
00327       // Adjust the relocation to be section-relative.
00328       // The index is the section ordinal (1-based).
00329       const MCSectionData &SymSD =
00330           Asm.getSectionData(SD.getSymbol().getSection());
00331       Index = SymSD.getOrdinal() + 1;
00332       IsExtern = 0;
00333       Value += Writer->getSymbolAddress(&SD, Layout);
00334 
00335       if (IsPCRel)
00336         Value -= Writer->getFragmentAddress(Fragment, Layout) +
00337                  Fixup.getOffset() + (1ULL << Log2Size);
00338     } else {
00339       // Resolve constant variables.
00340       if (SD.getSymbol().isVariable()) {
00341         int64_t Res;
00342         if (SD.getSymbol().getVariableValue()->EvaluateAsAbsolute(
00343                 Res, Layout, Writer->getSectionAddressMap())) {
00344           FixedValue = Res;
00345           return;
00346         }
00347       }
00348       Asm.getContext().FatalError(Fixup.getLoc(),
00349                                   "unsupported relocation of variable '" +
00350                                       Symbol->getName() + "'");
00351     }
00352   }
00353 
00354   // If the relocation kind is Branch26, Page21, or Pageoff12, any addend
00355   // is represented via an Addend relocation, not encoded directly into
00356   // the instruction.
00357   if ((Type == MachO::ARM64_RELOC_BRANCH26 ||
00358        Type == MachO::ARM64_RELOC_PAGE21 ||
00359        Type == MachO::ARM64_RELOC_PAGEOFF12) &&
00360       Value) {
00361     assert((Value & 0xff000000) == 0 && "Added relocation out of range!");
00362 
00363     MachO::any_relocation_info MRE;
00364     MRE.r_word0 = FixupOffset;
00365     MRE.r_word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) |
00366                    (IsExtern << 27) | (Type << 28));
00367     Writer->addRelocation(Fragment->getParent(), MRE);
00368 
00369     // Now set up the Addend relocation.
00370     Type = MachO::ARM64_RELOC_ADDEND;
00371     Index = Value;
00372     IsPCRel = 0;
00373     Log2Size = 2;
00374     IsExtern = 0;
00375 
00376     // Put zero into the instruction itself. The addend is in the relocation.
00377     Value = 0;
00378   }
00379 
00380   // If there's any addend left to handle, encode it in the instruction.
00381   FixedValue = Value;
00382 
00383   // struct relocation_info (8 bytes)
00384   MachO::any_relocation_info MRE;
00385   MRE.r_word0 = FixupOffset;
00386   MRE.r_word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) |
00387                  (IsExtern << 27) | (Type << 28));
00388   Writer->addRelocation(Fragment->getParent(), MRE);
00389 }
00390 
00391 MCObjectWriter *llvm::createAArch64MachObjectWriter(raw_ostream &OS,
00392                                                   uint32_t CPUType,
00393                                                   uint32_t CPUSubtype) {
00394   return createMachObjectWriter(
00395       new AArch64MachObjectWriter(CPUType, CPUSubtype), OS,
00396       /*IsLittleEndian=*/true);
00397 }