LLVM API Documentation

PPCMachObjectWriter.cpp
Go to the documentation of this file.
00001 //===-- PPCMachObjectWriter.cpp - PPC Mach-O 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/PPCMCTargetDesc.h"
00011 #include "MCTargetDesc/PPCFixupKinds.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/MCMachObjectWriter.h"
00017 #include "llvm/MC/MCSectionMachO.h"
00018 #include "llvm/MC/MCValue.h"
00019 #include "llvm/Support/ErrorHandling.h"
00020 #include "llvm/Support/Format.h"
00021 #include "llvm/Support/MachO.h"
00022 
00023 using namespace llvm;
00024 
00025 namespace {
00026 class PPCMachObjectWriter : public MCMachObjectTargetWriter {
00027   bool RecordScatteredRelocation(MachObjectWriter *Writer,
00028                                  const MCAssembler &Asm,
00029                                  const MCAsmLayout &Layout,
00030                                  const MCFragment *Fragment,
00031                                  const MCFixup &Fixup, MCValue Target,
00032                                  unsigned Log2Size, uint64_t &FixedValue);
00033 
00034   void RecordPPCRelocation(MachObjectWriter *Writer, const MCAssembler &Asm,
00035                            const MCAsmLayout &Layout,
00036                            const MCFragment *Fragment, const MCFixup &Fixup,
00037                            MCValue Target, uint64_t &FixedValue);
00038 
00039 public:
00040   PPCMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype)
00041       : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype,
00042                                  /*UseAggressiveSymbolFolding=*/Is64Bit) {}
00043 
00044   void RecordRelocation(MachObjectWriter *Writer, const MCAssembler &Asm,
00045                         const MCAsmLayout &Layout, const MCFragment *Fragment,
00046                         const MCFixup &Fixup, MCValue Target,
00047                         uint64_t &FixedValue) override {
00048     if (Writer->is64Bit()) {
00049       report_fatal_error("Relocation emission for MachO/PPC64 unimplemented.");
00050     } else
00051       RecordPPCRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
00052                           FixedValue);
00053   }
00054 };
00055 }
00056 
00057 /// computes the log2 of the size of the relocation,
00058 /// used for relocation_info::r_length.
00059 static unsigned getFixupKindLog2Size(unsigned Kind) {
00060   switch (Kind) {
00061   default:
00062     report_fatal_error("log2size(FixupKind): Unhandled fixup kind!");
00063   case FK_PCRel_1:
00064   case FK_Data_1:
00065     return 0;
00066   case FK_PCRel_2:
00067   case FK_Data_2:
00068     return 1;
00069   case FK_PCRel_4:
00070   case PPC::fixup_ppc_brcond14:
00071   case PPC::fixup_ppc_half16:
00072   case PPC::fixup_ppc_br24:
00073   case FK_Data_4:
00074     return 2;
00075   case FK_PCRel_8:
00076   case FK_Data_8:
00077     return 3;
00078   }
00079   return 0;
00080 }
00081 
00082 /// Translates generic PPC fixup kind to Mach-O/PPC relocation type enum.
00083 /// Outline based on PPCELFObjectWriter::GetRelocType().
00084 static unsigned getRelocType(const MCValue &Target,
00085                              const MCFixupKind FixupKind, // from
00086                                                           // Fixup.getKind()
00087                              const bool IsPCRel) {
00088   const MCSymbolRefExpr::VariantKind Modifier =
00089       Target.isAbsolute() ? MCSymbolRefExpr::VK_None
00090                           : Target.getSymA()->getKind();
00091   // determine the type of the relocation
00092   unsigned Type = MachO::GENERIC_RELOC_VANILLA;
00093   if (IsPCRel) { // relative to PC
00094     switch ((unsigned)FixupKind) {
00095     default:
00096       report_fatal_error("Unimplemented fixup kind (relative)");
00097     case PPC::fixup_ppc_br24:
00098       Type = MachO::PPC_RELOC_BR24; // R_PPC_REL24
00099       break;
00100     case PPC::fixup_ppc_brcond14:
00101       Type = MachO::PPC_RELOC_BR14;
00102       break;
00103     case PPC::fixup_ppc_half16:
00104       switch (Modifier) {
00105       default:
00106         llvm_unreachable("Unsupported modifier for half16 fixup");
00107       case MCSymbolRefExpr::VK_PPC_HA:
00108         Type = MachO::PPC_RELOC_HA16;
00109         break;
00110       case MCSymbolRefExpr::VK_PPC_LO:
00111         Type = MachO::PPC_RELOC_LO16;
00112         break;
00113       case MCSymbolRefExpr::VK_PPC_HI:
00114         Type = MachO::PPC_RELOC_HI16;
00115         break;
00116       }
00117       break;
00118     }
00119   } else {
00120     switch ((unsigned)FixupKind) {
00121     default:
00122       report_fatal_error("Unimplemented fixup kind (absolute)!");
00123     case PPC::fixup_ppc_half16:
00124       switch (Modifier) {
00125       default:
00126         llvm_unreachable("Unsupported modifier for half16 fixup");
00127       case MCSymbolRefExpr::VK_PPC_HA:
00128         Type = MachO::PPC_RELOC_HA16_SECTDIFF;
00129         break;
00130       case MCSymbolRefExpr::VK_PPC_LO:
00131         Type = MachO::PPC_RELOC_LO16_SECTDIFF;
00132         break;
00133       case MCSymbolRefExpr::VK_PPC_HI:
00134         Type = MachO::PPC_RELOC_HI16_SECTDIFF;
00135         break;
00136       }
00137       break;
00138     case FK_Data_4:
00139       break;
00140     case FK_Data_2:
00141       break;
00142     }
00143   }
00144   return Type;
00145 }
00146 
00147 static void makeRelocationInfo(MachO::any_relocation_info &MRE,
00148                                const uint32_t FixupOffset, const uint32_t Index,
00149                                const unsigned IsPCRel, const unsigned Log2Size,
00150                                const unsigned IsExtern, const unsigned Type) {
00151   MRE.r_word0 = FixupOffset;
00152   // The bitfield offsets that work (as determined by trial-and-error)
00153   // are different than what is documented in the mach-o manuals.
00154   // This appears to be an endianness issue; reversing the order of the
00155   // documented bitfields in <llvm/Support/MachO.h> fixes this (but
00156   // breaks x86/ARM assembly).
00157   MRE.r_word1 = ((Index << 8) |    // was << 0
00158                  (IsPCRel << 7) |  // was << 24
00159                  (Log2Size << 5) | // was << 25
00160                  (IsExtern << 4) | // was << 27
00161                  (Type << 0));     // was << 28
00162 }
00163 
00164 static void
00165 makeScatteredRelocationInfo(MachO::any_relocation_info &MRE,
00166                             const uint32_t Addr, const unsigned Type,
00167                             const unsigned Log2Size, const unsigned IsPCRel,
00168                             const uint32_t Value2) {
00169   // For notes on bitfield positions and endianness, see:
00170   // https://developer.apple.com/library/mac/documentation/developertools/conceptual/MachORuntime/Reference/reference.html#//apple_ref/doc/uid/20001298-scattered_relocation_entry
00171   MRE.r_word0 = ((Addr << 0) | (Type << 24) | (Log2Size << 28) |
00172                  (IsPCRel << 30) | MachO::R_SCATTERED);
00173   MRE.r_word1 = Value2;
00174 }
00175 
00176 /// Compute fixup offset (address).
00177 static uint32_t getFixupOffset(const MCAsmLayout &Layout,
00178                                const MCFragment *Fragment,
00179                                const MCFixup &Fixup) {
00180   uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
00181   // On Mach-O, ppc_fixup_half16 relocations must refer to the
00182   // start of the instruction, not the second halfword, as ELF does
00183   if (unsigned(Fixup.getKind()) == PPC::fixup_ppc_half16)
00184     FixupOffset &= ~uint32_t(3);
00185   return FixupOffset;
00186 }
00187 
00188 /// \return false if falling back to using non-scattered relocation,
00189 /// otherwise true for normal scattered relocation.
00190 /// based on X86MachObjectWriter::RecordScatteredRelocation
00191 /// and ARMMachObjectWriter::RecordScatteredRelocation
00192 bool PPCMachObjectWriter::RecordScatteredRelocation(
00193     MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout,
00194     const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
00195     unsigned Log2Size, uint64_t &FixedValue) {
00196   // caller already computes these, can we just pass and reuse?
00197   const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup);
00198   const MCFixupKind FK = Fixup.getKind();
00199   const unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, FK);
00200   const unsigned Type = getRelocType(Target, FK, IsPCRel);
00201 
00202   // Is this a local or SECTDIFF relocation entry?
00203   // SECTDIFF relocation entries have symbol subtractions,
00204   // and require two entries, the first for the add-symbol value,
00205   // the second for the subtract-symbol value.
00206 
00207   // See <reloc.h>.
00208   const MCSymbol *A = &Target.getSymA()->getSymbol();
00209   const MCSymbolData *A_SD = &Asm.getSymbolData(*A);
00210 
00211   if (!A_SD->getFragment())
00212     report_fatal_error("symbol '" + A->getName() +
00213                        "' can not be undefined in a subtraction expression");
00214 
00215   uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
00216   uint64_t SecAddr =
00217       Writer->getSectionAddress(A_SD->getFragment()->getParent());
00218   FixedValue += SecAddr;
00219   uint32_t Value2 = 0;
00220 
00221   if (const MCSymbolRefExpr *B = Target.getSymB()) {
00222     const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
00223 
00224     if (!B_SD->getFragment())
00225       report_fatal_error("symbol '" + B->getSymbol().getName() +
00226                          "' can not be undefined in a subtraction expression");
00227 
00228     // FIXME: is Type correct? see include/llvm/Support/MachO.h
00229     Value2 = Writer->getSymbolAddress(B_SD, Layout);
00230     FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
00231   }
00232   // FIXME: does FixedValue get used??
00233 
00234   // Relocations are written out in reverse order, so the PAIR comes first.
00235   if (Type == MachO::PPC_RELOC_SECTDIFF ||
00236       Type == MachO::PPC_RELOC_HI16_SECTDIFF ||
00237       Type == MachO::PPC_RELOC_LO16_SECTDIFF ||
00238       Type == MachO::PPC_RELOC_HA16_SECTDIFF ||
00239       Type == MachO::PPC_RELOC_LO14_SECTDIFF ||
00240       Type == MachO::PPC_RELOC_LOCAL_SECTDIFF) {
00241     // X86 had this piece, but ARM does not
00242     // If the offset is too large to fit in a scattered relocation,
00243     // we're hosed. It's an unfortunate limitation of the MachO format.
00244     if (FixupOffset > 0xffffff) {
00245       char Buffer[32];
00246       format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer));
00247       Asm.getContext().FatalError(Fixup.getLoc(),
00248                                   Twine("Section too large, can't encode "
00249                                         "r_address (") +
00250                                       Buffer + ") into 24 bits of scattered "
00251                                                "relocation entry.");
00252       llvm_unreachable("fatal error returned?!");
00253     }
00254 
00255     // Is this supposed to follow MCTarget/PPCAsmBackend.cpp:adjustFixupValue()?
00256     // see PPCMCExpr::EvaluateAsRelocatableImpl()
00257     uint32_t other_half = 0;
00258     switch (Type) {
00259     case MachO::PPC_RELOC_LO16_SECTDIFF:
00260       other_half = (FixedValue >> 16) & 0xffff;
00261       // applyFixupOffset longer extracts the high part because it now assumes
00262       // this was already done.
00263       // It looks like this is not true for the FixedValue needed with Mach-O
00264       // relocs.
00265       // So we need to adjust FixedValue again here.
00266       FixedValue &= 0xffff;
00267       break;
00268     case MachO::PPC_RELOC_HA16_SECTDIFF:
00269       other_half = FixedValue & 0xffff;
00270       FixedValue =
00271           ((FixedValue >> 16) + ((FixedValue & 0x8000) ? 1 : 0)) & 0xffff;
00272       break;
00273     case MachO::PPC_RELOC_HI16_SECTDIFF:
00274       other_half = FixedValue & 0xffff;
00275       FixedValue = (FixedValue >> 16) & 0xffff;
00276       break;
00277     default:
00278       llvm_unreachable("Invalid PPC scattered relocation type.");
00279       break;
00280     }
00281 
00282     MachO::any_relocation_info MRE;
00283     makeScatteredRelocationInfo(MRE, other_half, MachO::GENERIC_RELOC_PAIR,
00284                                 Log2Size, IsPCRel, Value2);
00285     Writer->addRelocation(Fragment->getParent(), MRE);
00286   } else {
00287     // If the offset is more than 24-bits, it won't fit in a scattered
00288     // relocation offset field, so we fall back to using a non-scattered
00289     // relocation. This is a bit risky, as if the offset reaches out of
00290     // the block and the linker is doing scattered loading on this
00291     // symbol, things can go badly.
00292     //
00293     // Required for 'as' compatibility.
00294     if (FixupOffset > 0xffffff)
00295       return false;
00296   }
00297   MachO::any_relocation_info MRE;
00298   makeScatteredRelocationInfo(MRE, FixupOffset, Type, Log2Size, IsPCRel, Value);
00299   Writer->addRelocation(Fragment->getParent(), MRE);
00300   return true;
00301 }
00302 
00303 // see PPCELFObjectWriter for a general outline of cases
00304 void PPCMachObjectWriter::RecordPPCRelocation(
00305     MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout,
00306     const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
00307     uint64_t &FixedValue) {
00308   const MCFixupKind FK = Fixup.getKind(); // unsigned
00309   const unsigned Log2Size = getFixupKindLog2Size(FK);
00310   const bool IsPCRel = Writer->isFixupKindPCRel(Asm, FK);
00311   const unsigned RelocType = getRelocType(Target, FK, IsPCRel);
00312 
00313   // If this is a difference or a defined symbol plus an offset, then we need a
00314   // scattered relocation entry. Differences always require scattered
00315   // relocations.
00316   if (Target.getSymB() &&
00317       // Q: are branch targets ever scattered?
00318       RelocType != MachO::PPC_RELOC_BR24 &&
00319       RelocType != MachO::PPC_RELOC_BR14) {
00320     RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
00321                               Log2Size, FixedValue);
00322     return;
00323   }
00324 
00325   // this doesn't seem right for RIT_PPC_BR24
00326   // Get the symbol data, if any.
00327   const MCSymbolData *SD = nullptr;
00328   if (Target.getSymA())
00329     SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
00330 
00331   // See <reloc.h>.
00332   const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup);
00333   unsigned Index = 0;
00334   unsigned IsExtern = 0;
00335   unsigned Type = RelocType;
00336 
00337   if (Target.isAbsolute()) { // constant
00338                              // SymbolNum of 0 indicates the absolute section.
00339                              //
00340     // FIXME: Currently, these are never generated (see code below). I cannot
00341     // find a case where they are actually emitted.
00342     report_fatal_error("FIXME: relocations to absolute targets "
00343                        "not yet implemented");
00344     // the above line stolen from ARM, not sure
00345   } else {
00346     // Resolve constant variables.
00347     if (SD->getSymbol().isVariable()) {
00348       int64_t Res;
00349       if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute(
00350               Res, Layout, Writer->getSectionAddressMap())) {
00351         FixedValue = Res;
00352         return;
00353       }
00354     }
00355 
00356     // Check whether we need an external or internal relocation.
00357     if (Writer->doesSymbolRequireExternRelocation(SD)) {
00358       IsExtern = 1;
00359       Index = SD->getIndex();
00360       // For external relocations, make sure to offset the fixup value to
00361       // compensate for the addend of the symbol address, if it was
00362       // undefined. This occurs with weak definitions, for example.
00363       if (!SD->Symbol->isUndefined())
00364         FixedValue -= Layout.getSymbolOffset(SD);
00365     } else {
00366       // The index is the section ordinal (1-based).
00367       const MCSectionData &SymSD =
00368           Asm.getSectionData(SD->getSymbol().getSection());
00369       Index = SymSD.getOrdinal() + 1;
00370       FixedValue += Writer->getSectionAddress(&SymSD);
00371     }
00372     if (IsPCRel)
00373       FixedValue -= Writer->getSectionAddress(Fragment->getParent());
00374   }
00375 
00376   // struct relocation_info (8 bytes)
00377   MachO::any_relocation_info MRE;
00378   makeRelocationInfo(MRE, FixupOffset, Index, IsPCRel, Log2Size, IsExtern,
00379                      Type);
00380   Writer->addRelocation(Fragment->getParent(), MRE);
00381 }
00382 
00383 MCObjectWriter *llvm::createPPCMachObjectWriter(raw_ostream &OS, bool Is64Bit,
00384                                                 uint32_t CPUType,
00385                                                 uint32_t CPUSubtype) {
00386   return createMachObjectWriter(
00387       new PPCMachObjectWriter(Is64Bit, CPUType, CPUSubtype), OS,
00388       /*IsLittleEndian=*/false);
00389 }