LCOV - code coverage report
Current view: top level - lib/Target/AArch64/MCTargetDesc - AArch64MachObjectWriter.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 130 155 83.9 %
Date: 2018-06-17 00:07:59 Functions: 5 6 83.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===-- AArch64MachObjectWriter.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/AArch64FixupKinds.h"
      11             : #include "MCTargetDesc/AArch64MCTargetDesc.h"
      12             : #include "llvm/ADT/Twine.h"
      13             : #include "llvm/BinaryFormat/MachO.h"
      14             : #include "llvm/MC/MCAsmInfo.h"
      15             : #include "llvm/MC/MCAsmLayout.h"
      16             : #include "llvm/MC/MCAssembler.h"
      17             : #include "llvm/MC/MCContext.h"
      18             : #include "llvm/MC/MCExpr.h"
      19             : #include "llvm/MC/MCFixup.h"
      20             : #include "llvm/MC/MCFragment.h"
      21             : #include "llvm/MC/MCMachObjectWriter.h"
      22             : #include "llvm/MC/MCSection.h"
      23             : #include "llvm/MC/MCSectionMachO.h"
      24             : #include "llvm/MC/MCSymbol.h"
      25             : #include "llvm/MC/MCValue.h"
      26             : #include "llvm/Support/Casting.h"
      27             : #include "llvm/Support/MathExtras.h"
      28             : #include <cassert>
      29             : #include <cstdint>
      30             : 
      31             : using namespace llvm;
      32             : 
      33             : namespace {
      34             : 
      35         363 : class AArch64MachObjectWriter : public MCMachObjectTargetWriter {
      36             :   bool getAArch64FixupKindMachOInfo(const MCFixup &Fixup, unsigned &RelocType,
      37             :                                   const MCSymbolRefExpr *Sym,
      38             :                                   unsigned &Log2Size, const MCAssembler &Asm);
      39             : 
      40             : public:
      41             :   AArch64MachObjectWriter(uint32_t CPUType, uint32_t CPUSubtype)
      42         367 :       : MCMachObjectTargetWriter(true /* is64Bit */, CPUType, CPUSubtype) {}
      43             : 
      44             :   void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm,
      45             :                         const MCAsmLayout &Layout, const MCFragment *Fragment,
      46             :                         const MCFixup &Fixup, MCValue Target,
      47             :                         uint64_t &FixedValue) override;
      48             : };
      49             : 
      50             : } // end anonymous namespace
      51             : 
      52         237 : bool AArch64MachObjectWriter::getAArch64FixupKindMachOInfo(
      53             :     const MCFixup &Fixup, unsigned &RelocType, const MCSymbolRefExpr *Sym,
      54             :     unsigned &Log2Size, const MCAssembler &Asm) {
      55         237 :   RelocType = unsigned(MachO::ARM64_RELOC_UNSIGNED);
      56         237 :   Log2Size = ~0U;
      57             : 
      58         237 :   switch ((unsigned)Fixup.getKind()) {
      59             :   default:
      60             :     return false;
      61             : 
      62             :   case FK_Data_1:
      63           1 :     Log2Size = Log2_32(1);
      64             :     return true;
      65             :   case FK_Data_2:
      66           1 :     Log2Size = Log2_32(2);
      67             :     return true;
      68             :   case FK_Data_4:
      69          13 :     Log2Size = Log2_32(4);
      70          13 :     if (Sym->getKind() == MCSymbolRefExpr::VK_GOT)
      71           2 :       RelocType = unsigned(MachO::ARM64_RELOC_POINTER_TO_GOT);
      72             :     return true;
      73             :   case FK_Data_8:
      74         107 :     Log2Size = Log2_32(8);
      75         107 :     if (Sym->getKind() == MCSymbolRefExpr::VK_GOT)
      76           2 :       RelocType = unsigned(MachO::ARM64_RELOC_POINTER_TO_GOT);
      77             :     return true;
      78             :   case AArch64::fixup_aarch64_add_imm12:
      79             :   case AArch64::fixup_aarch64_ldst_imm12_scale1:
      80             :   case AArch64::fixup_aarch64_ldst_imm12_scale2:
      81             :   case AArch64::fixup_aarch64_ldst_imm12_scale4:
      82             :   case AArch64::fixup_aarch64_ldst_imm12_scale8:
      83             :   case AArch64::fixup_aarch64_ldst_imm12_scale16:
      84          48 :     Log2Size = Log2_32(4);
      85          48 :     switch (Sym->getKind()) {
      86             :     default:
      87             :       return false;
      88          27 :     case MCSymbolRefExpr::VK_PAGEOFF:
      89          27 :       RelocType = unsigned(MachO::ARM64_RELOC_PAGEOFF12);
      90             :       return true;
      91           7 :     case MCSymbolRefExpr::VK_GOTPAGEOFF:
      92           7 :       RelocType = unsigned(MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12);
      93             :       return true;
      94           2 :     case MCSymbolRefExpr::VK_TLVPPAGEOFF:
      95           2 :       RelocType = unsigned(MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12);
      96             :       return true;
      97             :     }
      98             :   case AArch64::fixup_aarch64_pcrel_adrp_imm21:
      99          32 :     Log2Size = Log2_32(4);
     100             :     // This encompasses the relocation for the whole 21-bit value.
     101          32 :     switch (Sym->getKind()) {
     102           1 :     default:
     103           2 :       Asm.getContext().reportError(Fixup.getLoc(),
     104             :                                    "ADR/ADRP relocations must be GOT relative");
     105             :       return false;
     106          23 :     case MCSymbolRefExpr::VK_PAGE:
     107          23 :       RelocType = unsigned(MachO::ARM64_RELOC_PAGE21);
     108             :       return true;
     109           7 :     case MCSymbolRefExpr::VK_GOTPAGE:
     110           7 :       RelocType = unsigned(MachO::ARM64_RELOC_GOT_LOAD_PAGE21);
     111             :       return true;
     112           1 :     case MCSymbolRefExpr::VK_TLVPPAGE:
     113           1 :       RelocType = unsigned(MachO::ARM64_RELOC_TLVP_LOAD_PAGE21);
     114             :       return true;
     115             :     }
     116             :     return true;
     117             :   case AArch64::fixup_aarch64_pcrel_branch26:
     118             :   case AArch64::fixup_aarch64_pcrel_call26:
     119          34 :     Log2Size = Log2_32(4);
     120          34 :     RelocType = unsigned(MachO::ARM64_RELOC_BRANCH26);
     121             :     return true;
     122             :   }
     123             : }
     124             : 
     125         211 : static bool canUseLocalRelocation(const MCSectionMachO &Section,
     126             :                                   const MCSymbol &Symbol, unsigned Log2Size) {
     127             :   // Debug info sections can use local relocations.
     128         422 :   if (Section.hasAttribute(MachO::S_ATTR_DEBUG))
     129             :     return true;
     130             : 
     131             :   // Otherwise, only pointer sized relocations are supported.
     132         147 :   if (Log2Size != 3)
     133             :     return false;
     134             : 
     135             :   // But only if they don't point to a few forbidden sections.
     136          37 :   if (!Symbol.isInSection())
     137             :     return true;
     138             :   const MCSectionMachO &RefSec = cast<MCSectionMachO>(Symbol.getSection());
     139          60 :   if (RefSec.getType() == MachO::S_CSTRING_LITERALS)
     140             :     return false;
     141             : 
     142             :   if (RefSec.getSegmentName() == "__DATA" &&
     143             :       RefSec.getSectionName() == "__objc_classrefs")
     144             :     return false;
     145             : 
     146             :   // FIXME: ld64 currently handles internal pointer-sized relocations
     147             :   // incorrectly (applying the addend twice). We should be able to return true
     148             :   // unconditionally by this point when that's fixed.
     149             :   return false;
     150             : }
     151             : 
     152         239 : void AArch64MachObjectWriter::recordRelocation(
     153             :     MachObjectWriter *Writer, MCAssembler &Asm, const MCAsmLayout &Layout,
     154             :     const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
     155             :     uint64_t &FixedValue) {
     156         239 :   unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
     157             : 
     158             :   // See <reloc.h>.
     159         239 :   uint32_t FixupOffset = Layout.getFragmentOffset(Fragment);
     160         239 :   unsigned Log2Size = 0;
     161             :   int64_t Value = 0;
     162             :   unsigned Index = 0;
     163         239 :   unsigned Type = 0;
     164         239 :   unsigned Kind = Fixup.getKind();
     165             :   const MCSymbol *RelSymbol = nullptr;
     166             : 
     167         239 :   FixupOffset += Fixup.getOffset();
     168             : 
     169             :   // AArch64 pcrel relocation addends do not include the section offset.
     170         239 :   if (IsPCRel)
     171          69 :     FixedValue += FixupOffset;
     172             : 
     173             :   // ADRP fixups use relocations for the whole symbol value and only
     174             :   // put the addend in the instruction itself. Clear out any value the
     175             :   // generic code figured out from the sybmol definition.
     176         239 :   if (Kind == AArch64::fixup_aarch64_pcrel_adrp_imm21)
     177          32 :     FixedValue = 0;
     178             : 
     179             :   // imm19 relocations are for conditional branches, which require
     180             :   // assembler local symbols. If we got here, that's not what we have,
     181             :   // so complain loudly.
     182         239 :   if (Kind == AArch64::fixup_aarch64_pcrel_branch19) {
     183           2 :     Asm.getContext().reportError(Fixup.getLoc(),
     184             :                                  "conditional branch requires assembler-local"
     185           1 :                                  " label. '" +
     186           4 :                                      Target.getSymA()->getSymbol().getName() +
     187           1 :                                      "' is external.");
     188          20 :     return;
     189             :   }
     190             : 
     191             :   // 14-bit branch relocations should only target internal labels, and so
     192             :   // should never get here.
     193         238 :   if (Kind == AArch64::fixup_aarch64_pcrel_branch14) {
     194           2 :     Asm.getContext().reportError(Fixup.getLoc(),
     195             :                                  "Invalid relocation on conditional branch!");
     196           1 :     return;
     197             :   }
     198             : 
     199         237 :   if (!getAArch64FixupKindMachOInfo(Fixup, Type, Target.getSymA(), Log2Size,
     200             :                                     Asm)) {
     201          28 :     Asm.getContext().reportError(Fixup.getLoc(), "unknown AArch64 fixup kind!");
     202          14 :     return;
     203             :   }
     204             : 
     205         223 :   Value = Target.getConstant();
     206             : 
     207             :   if (Target.isAbsolute()) { // constant
     208             :     // FIXME: Should this always be extern?
     209             :     // SymbolNum of 0 indicates the absolute section.
     210           0 :     Type = MachO::ARM64_RELOC_UNSIGNED;
     211             : 
     212           0 :     if (IsPCRel) {
     213           0 :       Asm.getContext().reportError(Fixup.getLoc(),
     214             :                                    "PC relative absolute relocation!");
     215           0 :       return;
     216             : 
     217             :       // FIXME: x86_64 sets the type to a branch reloc here. Should we do
     218             :       // something similar?
     219             :     }
     220         223 :   } else if (Target.getSymB()) { // A - B + constant
     221          12 :     const MCSymbol *A = &Target.getSymA()->getSymbol();
     222          12 :     const MCSymbol *A_Base = Asm.getAtom(*A);
     223             : 
     224          12 :     const MCSymbol *B = &Target.getSymB()->getSymbol();
     225          12 :     const MCSymbol *B_Base = Asm.getAtom(*B);
     226             : 
     227             :     // Check for "_foo@got - .", which comes through here as:
     228             :     // Ltmp0:
     229             :     //    ... _foo@got - Ltmp0
     230          14 :     if (Target.getSymA()->getKind() == MCSymbolRefExpr::VK_GOT &&
     231          14 :         Target.getSymB()->getKind() == MCSymbolRefExpr::VK_None &&
     232           2 :         Layout.getSymbolOffset(*B) ==
     233           2 :             Layout.getFragmentOffset(Fragment) + Fixup.getOffset()) {
     234             :       // SymB is the PC, so use a PC-rel pointer-to-GOT relocation.
     235           2 :       Type = MachO::ARM64_RELOC_POINTER_TO_GOT;
     236             :       IsPCRel = 1;
     237             :       MachO::any_relocation_info MRE;
     238           2 :       MRE.r_word0 = FixupOffset;
     239           2 :       MRE.r_word1 = (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
     240           2 :       Writer->addRelocation(A_Base, Fragment->getParent(), MRE);
     241             :       return;
     242          20 :     } else if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None ||
     243          10 :                Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None) {
     244             :       // Otherwise, neither symbol can be modified.
     245           0 :       Asm.getContext().reportError(Fixup.getLoc(),
     246             :                                    "unsupported relocation of modified symbol");
     247           0 :       return;
     248             :     }
     249             : 
     250             :     // We don't support PCrel relocations of differences.
     251          10 :     if (IsPCRel) {
     252           0 :       Asm.getContext().reportError(Fixup.getLoc(),
     253             :                                    "unsupported pc-relative relocation of "
     254             :                                    "difference");
     255           0 :       return;
     256             :     }
     257             : 
     258             :     // AArch64 always uses external relocations. If there is no symbol to use as
     259             :     // a base address (a local symbol with no preceding non-local symbol),
     260             :     // error out.
     261             :     //
     262             :     // FIXME: We should probably just synthesize an external symbol and use
     263             :     // that.
     264          10 :     if (!A_Base) {
     265           0 :       Asm.getContext().reportError(
     266             :           Fixup.getLoc(),
     267           0 :           "unsupported relocation of local symbol '" + A->getName() +
     268           0 :               "'. Must have non-local symbol earlier in section.");
     269           0 :       return;
     270             :     }
     271          10 :     if (!B_Base) {
     272           0 :       Asm.getContext().reportError(
     273             :           Fixup.getLoc(),
     274           0 :           "unsupported relocation of local symbol '" + B->getName() +
     275           0 :               "'. Must have non-local symbol earlier in section.");
     276           0 :       return;
     277             :     }
     278             : 
     279          10 :     if (A_Base == B_Base && A_Base) {
     280           0 :       Asm.getContext().reportError(
     281             :           Fixup.getLoc(), "unsupported relocation with identical base");
     282           0 :       return;
     283             :     }
     284             : 
     285          20 :     Value += (!A->getFragment() ? 0 : Writer->getSymbolAddress(*A, Layout)) -
     286          10 :              (!A_Base || !A_Base->getFragment() ? 0 : Writer->getSymbolAddress(
     287             :                                                           *A_Base, Layout));
     288          20 :     Value -= (!B->getFragment() ? 0 : Writer->getSymbolAddress(*B, Layout)) -
     289          10 :              (!B_Base || !B_Base->getFragment() ? 0 : Writer->getSymbolAddress(
     290             :                                                           *B_Base, Layout));
     291             : 
     292          10 :     Type = MachO::ARM64_RELOC_UNSIGNED;
     293             : 
     294             :     MachO::any_relocation_info MRE;
     295          10 :     MRE.r_word0 = FixupOffset;
     296          10 :     MRE.r_word1 = (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
     297          10 :     Writer->addRelocation(A_Base, Fragment->getParent(), MRE);
     298             : 
     299             :     RelSymbol = B_Base;
     300          10 :     Type = MachO::ARM64_RELOC_SUBTRACTOR;
     301             :   } else { // A + constant
     302         211 :     const MCSymbol *Symbol = &Target.getSymA()->getSymbol();
     303             :     const MCSectionMachO &Section =
     304         211 :         static_cast<const MCSectionMachO &>(*Fragment->getParent());
     305             : 
     306             :     bool CanUseLocalRelocation =
     307         211 :         canUseLocalRelocation(Section, *Symbol, Log2Size);
     308         211 :     if (Symbol->isTemporary() && (Value || !CanUseLocalRelocation)) {
     309             :       // Make sure that the symbol is actually in a section here. If it isn't,
     310             :       // emit an error and exit.
     311          14 :       if (!Symbol->isInSection()) {
     312           2 :         Asm.getContext().reportError(
     313             :             Fixup.getLoc(),
     314           2 :             "unsupported relocation of local symbol '" + Symbol->getName() +
     315           1 :                 "'. Must have non-local symbol earlier in section.");
     316           1 :         return;
     317             :       }
     318             :       const MCSection &Sec = Symbol->getSection();
     319          13 :       if (!Asm.getContext().getAsmInfo()->isSectionAtomizableBySymbols(Sec))
     320             :         Symbol->setUsedInReloc();
     321             :     }
     322             : 
     323         210 :     const MCSymbol *Base = Asm.getAtom(*Symbol);
     324             :     // If the symbol is a variable it can either be in a section and
     325             :     // we have a base or it is absolute and should have been expanded.
     326             :     assert(!Symbol->isVariable() || Base);
     327             : 
     328             :     // Relocations inside debug sections always use local relocations when
     329             :     // possible. This seems to be done because the debugger doesn't fully
     330             :     // understand relocation entries and expects to find values that
     331             :     // have already been fixed up.
     332         210 :     if (Symbol->isInSection()) {
     333         302 :       if (Section.hasAttribute(MachO::S_ATTR_DEBUG))
     334             :         Base = nullptr;
     335             :     }
     336             : 
     337             :     // AArch64 uses external relocations as much as possible. For debug
     338             :     // sections, and for pointer-sized relocations (.quad), we allow section
     339             :     // relocations.  It's code sections that run into trouble.
     340         147 :     if (Base) {
     341             :       RelSymbol = Base;
     342             : 
     343             :       // Add the local offset, if needed.
     344         147 :       if (Base != Symbol)
     345           2 :         Value +=
     346           2 :             Layout.getSymbolOffset(*Symbol) - Layout.getSymbolOffset(*Base);
     347          63 :     } else if (Symbol->isInSection()) {
     348          63 :       if (!CanUseLocalRelocation) {
     349           0 :         Asm.getContext().reportError(
     350             :             Fixup.getLoc(),
     351           0 :             "unsupported relocation of local symbol '" + Symbol->getName() +
     352           0 :                 "'. Must have non-local symbol earlier in section.");
     353           0 :         return;
     354             :       }
     355             :       // Adjust the relocation to be section-relative.
     356             :       // The index is the section ordinal (1-based).
     357             :       const MCSection &Sec = Symbol->getSection();
     358          63 :       Index = Sec.getOrdinal() + 1;
     359          63 :       Value += Writer->getSymbolAddress(*Symbol, Layout);
     360             : 
     361          63 :       if (IsPCRel)
     362           0 :         Value -= Writer->getFragmentAddress(Fragment, Layout) +
     363           0 :                  Fixup.getOffset() + (1ULL << Log2Size);
     364             :     } else {
     365           0 :       llvm_unreachable(
     366             :           "This constant variable should have been expanded during evaluation");
     367             :     }
     368             :   }
     369             : 
     370             :   // If the relocation kind is Branch26, Page21, or Pageoff12, any addend
     371             :   // is represented via an Addend relocation, not encoded directly into
     372             :   // the instruction.
     373         220 :   if ((Type == MachO::ARM64_RELOC_BRANCH26 ||
     374         220 :        Type == MachO::ARM64_RELOC_PAGE21 ||
     375          83 :        Type == MachO::ARM64_RELOC_PAGEOFF12) &&
     376             :       Value) {
     377             :     assert((Value & 0xff000000) == 0 && "Added relocation out of range!");
     378             : 
     379             :     MachO::any_relocation_info MRE;
     380           6 :     MRE.r_word0 = FixupOffset;
     381           6 :     MRE.r_word1 =
     382           6 :         (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
     383           6 :     Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
     384             : 
     385             :     // Now set up the Addend relocation.
     386           6 :     Type = MachO::ARM64_RELOC_ADDEND;
     387           6 :     Index = Value;
     388             :     RelSymbol = nullptr;
     389             :     IsPCRel = 0;
     390           6 :     Log2Size = 2;
     391             : 
     392             :     // Put zero into the instruction itself. The addend is in the relocation.
     393             :     Value = 0;
     394             :   }
     395             : 
     396             :   // If there's any addend left to handle, encode it in the instruction.
     397         220 :   FixedValue = Value;
     398             : 
     399             :   // struct relocation_info (8 bytes)
     400             :   MachO::any_relocation_info MRE;
     401         220 :   MRE.r_word0 = FixupOffset;
     402         220 :   MRE.r_word1 =
     403         220 :       (Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | (Type << 28);
     404         220 :   Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
     405             : }
     406             : 
     407             : std::unique_ptr<MCObjectTargetWriter>
     408         367 : llvm::createAArch64MachObjectWriter(uint32_t CPUType, uint32_t CPUSubtype) {
     409         734 :   return llvm::make_unique<AArch64MachObjectWriter>(CPUType, CPUSubtype);
     410             : }

Generated by: LCOV version 1.13