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