Home | History | Annotate | Download | only in MCTargetDesc
      1 //===-- PPCMachObjectWriter.cpp - PPC Mach-O 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/PPCMCTargetDesc.h"
     11 #include "MCTargetDesc/PPCFixupKinds.h"
     12 #include "llvm/ADT/Twine.h"
     13 #include "llvm/MC/MCAsmLayout.h"
     14 #include "llvm/MC/MCAssembler.h"
     15 #include "llvm/MC/MCContext.h"
     16 #include "llvm/MC/MCMachObjectWriter.h"
     17 #include "llvm/MC/MCSectionMachO.h"
     18 #include "llvm/MC/MCValue.h"
     19 #include "llvm/Support/ErrorHandling.h"
     20 #include "llvm/Support/Format.h"
     21 #include "llvm/Support/MachO.h"
     22 
     23 using namespace llvm;
     24 
     25 namespace {
     26 class PPCMachObjectWriter : public MCMachObjectTargetWriter {
     27   bool recordScatteredRelocation(MachObjectWriter *Writer,
     28                                  const MCAssembler &Asm,
     29                                  const MCAsmLayout &Layout,
     30                                  const MCFragment *Fragment,
     31                                  const MCFixup &Fixup, MCValue Target,
     32                                  unsigned Log2Size, uint64_t &FixedValue);
     33 
     34   void RecordPPCRelocation(MachObjectWriter *Writer, const MCAssembler &Asm,
     35                            const MCAsmLayout &Layout,
     36                            const MCFragment *Fragment, const MCFixup &Fixup,
     37                            MCValue Target, uint64_t &FixedValue);
     38 
     39 public:
     40   PPCMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype)
     41       : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype) {}
     42 
     43   void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm,
     44                         const MCAsmLayout &Layout, const MCFragment *Fragment,
     45                         const MCFixup &Fixup, MCValue Target,
     46                         uint64_t &FixedValue) override {
     47     if (Writer->is64Bit()) {
     48       report_fatal_error("Relocation emission for MachO/PPC64 unimplemented.");
     49     } else
     50       RecordPPCRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
     51                           FixedValue);
     52   }
     53 };
     54 }
     55 
     56 /// computes the log2 of the size of the relocation,
     57 /// used for relocation_info::r_length.
     58 static unsigned getFixupKindLog2Size(unsigned Kind) {
     59   switch (Kind) {
     60   default:
     61     report_fatal_error("log2size(FixupKind): Unhandled fixup kind!");
     62   case FK_PCRel_1:
     63   case FK_Data_1:
     64     return 0;
     65   case FK_PCRel_2:
     66   case FK_Data_2:
     67     return 1;
     68   case FK_PCRel_4:
     69   case PPC::fixup_ppc_brcond14:
     70   case PPC::fixup_ppc_half16:
     71   case PPC::fixup_ppc_br24:
     72   case FK_Data_4:
     73     return 2;
     74   case FK_PCRel_8:
     75   case FK_Data_8:
     76     return 3;
     77   }
     78   return 0;
     79 }
     80 
     81 /// Translates generic PPC fixup kind to Mach-O/PPC relocation type enum.
     82 /// Outline based on PPCELFObjectWriter::getRelocType().
     83 static unsigned getRelocType(const MCValue &Target,
     84                              const MCFixupKind FixupKind, // from
     85                                                           // Fixup.getKind()
     86                              const bool IsPCRel) {
     87   const MCSymbolRefExpr::VariantKind Modifier =
     88       Target.isAbsolute() ? MCSymbolRefExpr::VK_None
     89                           : Target.getSymA()->getKind();
     90   // determine the type of the relocation
     91   unsigned Type = MachO::GENERIC_RELOC_VANILLA;
     92   if (IsPCRel) { // relative to PC
     93     switch ((unsigned)FixupKind) {
     94     default:
     95       report_fatal_error("Unimplemented fixup kind (relative)");
     96     case PPC::fixup_ppc_br24:
     97       Type = MachO::PPC_RELOC_BR24; // R_PPC_REL24
     98       break;
     99     case PPC::fixup_ppc_brcond14:
    100       Type = MachO::PPC_RELOC_BR14;
    101       break;
    102     case PPC::fixup_ppc_half16:
    103       switch (Modifier) {
    104       default:
    105         llvm_unreachable("Unsupported modifier for half16 fixup");
    106       case MCSymbolRefExpr::VK_PPC_HA:
    107         Type = MachO::PPC_RELOC_HA16;
    108         break;
    109       case MCSymbolRefExpr::VK_PPC_LO:
    110         Type = MachO::PPC_RELOC_LO16;
    111         break;
    112       case MCSymbolRefExpr::VK_PPC_HI:
    113         Type = MachO::PPC_RELOC_HI16;
    114         break;
    115       }
    116       break;
    117     }
    118   } else {
    119     switch ((unsigned)FixupKind) {
    120     default:
    121       report_fatal_error("Unimplemented fixup kind (absolute)!");
    122     case PPC::fixup_ppc_half16:
    123       switch (Modifier) {
    124       default:
    125         llvm_unreachable("Unsupported modifier for half16 fixup");
    126       case MCSymbolRefExpr::VK_PPC_HA:
    127         Type = MachO::PPC_RELOC_HA16_SECTDIFF;
    128         break;
    129       case MCSymbolRefExpr::VK_PPC_LO:
    130         Type = MachO::PPC_RELOC_LO16_SECTDIFF;
    131         break;
    132       case MCSymbolRefExpr::VK_PPC_HI:
    133         Type = MachO::PPC_RELOC_HI16_SECTDIFF;
    134         break;
    135       }
    136       break;
    137     case FK_Data_4:
    138       break;
    139     case FK_Data_2:
    140       break;
    141     }
    142   }
    143   return Type;
    144 }
    145 
    146 static void makeRelocationInfo(MachO::any_relocation_info &MRE,
    147                                const uint32_t FixupOffset, const uint32_t Index,
    148                                const unsigned IsPCRel, const unsigned Log2Size,
    149                                const unsigned IsExtern, const unsigned Type) {
    150   MRE.r_word0 = FixupOffset;
    151   // The bitfield offsets that work (as determined by trial-and-error)
    152   // are different than what is documented in the mach-o manuals.
    153   // This appears to be an endianness issue; reversing the order of the
    154   // documented bitfields in <llvm/Support/MachO.h> fixes this (but
    155   // breaks x86/ARM assembly).
    156   MRE.r_word1 = ((Index << 8) |    // was << 0
    157                  (IsPCRel << 7) |  // was << 24
    158                  (Log2Size << 5) | // was << 25
    159                  (IsExtern << 4) | // was << 27
    160                  (Type << 0));     // was << 28
    161 }
    162 
    163 static void
    164 makeScatteredRelocationInfo(MachO::any_relocation_info &MRE,
    165                             const uint32_t Addr, const unsigned Type,
    166                             const unsigned Log2Size, const unsigned IsPCRel,
    167                             const uint32_t Value2) {
    168   // For notes on bitfield positions and endianness, see:
    169   // https://developer.apple.com/library/mac/documentation/developertools/conceptual/MachORuntime/Reference/reference.html#//apple_ref/doc/uid/20001298-scattered_relocation_entry
    170   MRE.r_word0 = ((Addr << 0) | (Type << 24) | (Log2Size << 28) |
    171                  (IsPCRel << 30) | MachO::R_SCATTERED);
    172   MRE.r_word1 = Value2;
    173 }
    174 
    175 /// Compute fixup offset (address).
    176 static uint32_t getFixupOffset(const MCAsmLayout &Layout,
    177                                const MCFragment *Fragment,
    178                                const MCFixup &Fixup) {
    179   uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
    180   // On Mach-O, ppc_fixup_half16 relocations must refer to the
    181   // start of the instruction, not the second halfword, as ELF does
    182   if (unsigned(Fixup.getKind()) == PPC::fixup_ppc_half16)
    183     FixupOffset &= ~uint32_t(3);
    184   return FixupOffset;
    185 }
    186 
    187 /// \return false if falling back to using non-scattered relocation,
    188 /// otherwise true for normal scattered relocation.
    189 /// based on X86MachObjectWriter::recordScatteredRelocation
    190 /// and ARMMachObjectWriter::recordScatteredRelocation
    191 bool PPCMachObjectWriter::recordScatteredRelocation(
    192     MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout,
    193     const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
    194     unsigned Log2Size, uint64_t &FixedValue) {
    195   // caller already computes these, can we just pass and reuse?
    196   const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup);
    197   const MCFixupKind FK = Fixup.getKind();
    198   const unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, FK);
    199   const unsigned Type = getRelocType(Target, FK, IsPCRel);
    200 
    201   // Is this a local or SECTDIFF relocation entry?
    202   // SECTDIFF relocation entries have symbol subtractions,
    203   // and require two entries, the first for the add-symbol value,
    204   // the second for the subtract-symbol value.
    205 
    206   // See <reloc.h>.
    207   const MCSymbol *A = &Target.getSymA()->getSymbol();
    208 
    209   if (!A->getFragment())
    210     report_fatal_error("symbol '" + A->getName() +
    211                        "' can not be undefined in a subtraction expression");
    212 
    213   uint32_t Value = Writer->getSymbolAddress(*A, Layout);
    214   uint64_t SecAddr = Writer->getSectionAddress(A->getFragment()->getParent());
    215   FixedValue += SecAddr;
    216   uint32_t Value2 = 0;
    217 
    218   if (const MCSymbolRefExpr *B = Target.getSymB()) {
    219     const MCSymbol *SB = &B->getSymbol();
    220 
    221     if (!SB->getFragment())
    222       report_fatal_error("symbol '" + B->getSymbol().getName() +
    223                          "' can not be undefined in a subtraction expression");
    224 
    225     // FIXME: is Type correct? see include/llvm/Support/MachO.h
    226     Value2 = Writer->getSymbolAddress(B->getSymbol(), Layout);
    227     FixedValue -= Writer->getSectionAddress(SB->getFragment()->getParent());
    228   }
    229   // FIXME: does FixedValue get used??
    230 
    231   // Relocations are written out in reverse order, so the PAIR comes first.
    232   if (Type == MachO::PPC_RELOC_SECTDIFF ||
    233       Type == MachO::PPC_RELOC_HI16_SECTDIFF ||
    234       Type == MachO::PPC_RELOC_LO16_SECTDIFF ||
    235       Type == MachO::PPC_RELOC_HA16_SECTDIFF ||
    236       Type == MachO::PPC_RELOC_LO14_SECTDIFF ||
    237       Type == MachO::PPC_RELOC_LOCAL_SECTDIFF) {
    238     // X86 had this piece, but ARM does not
    239     // If the offset is too large to fit in a scattered relocation,
    240     // we're hosed. It's an unfortunate limitation of the MachO format.
    241     if (FixupOffset > 0xffffff) {
    242       char Buffer[32];
    243       format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer));
    244       Asm.getContext().reportError(Fixup.getLoc(),
    245                                   Twine("Section too large, can't encode "
    246                                         "r_address (") +
    247                                       Buffer + ") into 24 bits of scattered "
    248                                                "relocation entry.");
    249       return false;
    250     }
    251 
    252     // Is this supposed to follow MCTarget/PPCAsmBackend.cpp:adjustFixupValue()?
    253     // see PPCMCExpr::evaluateAsRelocatableImpl()
    254     uint32_t other_half = 0;
    255     switch (Type) {
    256     case MachO::PPC_RELOC_LO16_SECTDIFF:
    257       other_half = (FixedValue >> 16) & 0xffff;
    258       // applyFixupOffset longer extracts the high part because it now assumes
    259       // this was already done.
    260       // It looks like this is not true for the FixedValue needed with Mach-O
    261       // relocs.
    262       // So we need to adjust FixedValue again here.
    263       FixedValue &= 0xffff;
    264       break;
    265     case MachO::PPC_RELOC_HA16_SECTDIFF:
    266       other_half = FixedValue & 0xffff;
    267       FixedValue =
    268           ((FixedValue >> 16) + ((FixedValue & 0x8000) ? 1 : 0)) & 0xffff;
    269       break;
    270     case MachO::PPC_RELOC_HI16_SECTDIFF:
    271       other_half = FixedValue & 0xffff;
    272       FixedValue = (FixedValue >> 16) & 0xffff;
    273       break;
    274     default:
    275       llvm_unreachable("Invalid PPC scattered relocation type.");
    276       break;
    277     }
    278 
    279     MachO::any_relocation_info MRE;
    280     makeScatteredRelocationInfo(MRE, other_half, MachO::GENERIC_RELOC_PAIR,
    281                                 Log2Size, IsPCRel, Value2);
    282     Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
    283   } else {
    284     // If the offset is more than 24-bits, it won't fit in a scattered
    285     // relocation offset field, so we fall back to using a non-scattered
    286     // relocation. This is a bit risky, as if the offset reaches out of
    287     // the block and the linker is doing scattered loading on this
    288     // symbol, things can go badly.
    289     //
    290     // Required for 'as' compatibility.
    291     if (FixupOffset > 0xffffff)
    292       return false;
    293   }
    294   MachO::any_relocation_info MRE;
    295   makeScatteredRelocationInfo(MRE, FixupOffset, Type, Log2Size, IsPCRel, Value);
    296   Writer->addRelocation(nullptr, Fragment->getParent(), MRE);
    297   return true;
    298 }
    299 
    300 // see PPCELFObjectWriter for a general outline of cases
    301 void PPCMachObjectWriter::RecordPPCRelocation(
    302     MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout,
    303     const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
    304     uint64_t &FixedValue) {
    305   const MCFixupKind FK = Fixup.getKind(); // unsigned
    306   const unsigned Log2Size = getFixupKindLog2Size(FK);
    307   const bool IsPCRel = Writer->isFixupKindPCRel(Asm, FK);
    308   const unsigned RelocType = getRelocType(Target, FK, IsPCRel);
    309 
    310   // If this is a difference or a defined symbol plus an offset, then we need a
    311   // scattered relocation entry. Differences always require scattered
    312   // relocations.
    313   if (Target.getSymB() &&
    314       // Q: are branch targets ever scattered?
    315       RelocType != MachO::PPC_RELOC_BR24 &&
    316       RelocType != MachO::PPC_RELOC_BR14) {
    317     recordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
    318                               Log2Size, FixedValue);
    319     return;
    320   }
    321 
    322   // this doesn't seem right for RIT_PPC_BR24
    323   // Get the symbol data, if any.
    324   const MCSymbol *A = nullptr;
    325   if (Target.getSymA())
    326     A = &Target.getSymA()->getSymbol();
    327 
    328   // See <reloc.h>.
    329   const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup);
    330   unsigned Index = 0;
    331   unsigned Type = RelocType;
    332 
    333   const MCSymbol *RelSymbol = nullptr;
    334   if (Target.isAbsolute()) { // constant
    335                              // SymbolNum of 0 indicates the absolute section.
    336                              //
    337     // FIXME: Currently, these are never generated (see code below). I cannot
    338     // find a case where they are actually emitted.
    339     report_fatal_error("FIXME: relocations to absolute targets "
    340                        "not yet implemented");
    341     // the above line stolen from ARM, not sure
    342   } else {
    343     // Resolve constant variables.
    344     if (A->isVariable()) {
    345       int64_t Res;
    346       if (A->getVariableValue()->evaluateAsAbsolute(
    347               Res, Layout, Writer->getSectionAddressMap())) {
    348         FixedValue = Res;
    349         return;
    350       }
    351     }
    352 
    353     // Check whether we need an external or internal relocation.
    354     if (Writer->doesSymbolRequireExternRelocation(*A)) {
    355       RelSymbol = A;
    356       // For external relocations, make sure to offset the fixup value to
    357       // compensate for the addend of the symbol address, if it was
    358       // undefined. This occurs with weak definitions, for example.
    359       if (!A->isUndefined())
    360         FixedValue -= Layout.getSymbolOffset(*A);
    361     } else {
    362       // The index is the section ordinal (1-based).
    363       const MCSection &Sec = A->getSection();
    364       Index = Sec.getOrdinal() + 1;
    365       FixedValue += Writer->getSectionAddress(&Sec);
    366     }
    367     if (IsPCRel)
    368       FixedValue -= Writer->getSectionAddress(Fragment->getParent());
    369   }
    370 
    371   // struct relocation_info (8 bytes)
    372   MachO::any_relocation_info MRE;
    373   makeRelocationInfo(MRE, FixupOffset, Index, IsPCRel, Log2Size, false, Type);
    374   Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
    375 }
    376 
    377 MCObjectWriter *llvm::createPPCMachObjectWriter(raw_pwrite_stream &OS,
    378                                                 bool Is64Bit, uint32_t CPUType,
    379                                                 uint32_t CPUSubtype) {
    380   return createMachObjectWriter(
    381       new PPCMachObjectWriter(Is64Bit, CPUType, CPUSubtype), OS,
    382       /*IsLittleEndian=*/false);
    383 }
    384