PPCMachObjectWriter.cpp revision 280031
143410Snewton//===-- PPCMachObjectWriter.cpp - PPC Mach-O Writer -----------------------===//
243410Snewton//
343410Snewton//                     The LLVM Compiler Infrastructure
443410Snewton//
543410Snewton// This file is distributed under the University of Illinois Open Source
643410Snewton// License. See LICENSE.TXT for details.
743410Snewton//
843410Snewton//===----------------------------------------------------------------------===//
943410Snewton
1043410Snewton#include "MCTargetDesc/PPCMCTargetDesc.h"
1143410Snewton#include "MCTargetDesc/PPCFixupKinds.h"
1243410Snewton#include "llvm/ADT/Twine.h"
1343410Snewton#include "llvm/MC/MCAsmLayout.h"
1443410Snewton#include "llvm/MC/MCAssembler.h"
1543410Snewton#include "llvm/MC/MCContext.h"
1643410Snewton#include "llvm/MC/MCMachObjectWriter.h"
1743410Snewton#include "llvm/MC/MCSectionMachO.h"
1843410Snewton#include "llvm/MC/MCValue.h"
1943410Snewton#include "llvm/Support/ErrorHandling.h"
2043410Snewton#include "llvm/Support/Format.h"
2143410Snewton#include "llvm/Support/MachO.h"
2243410Snewton
2343410Snewtonusing namespace llvm;
2443410Snewton
2543410Snewtonnamespace {
2643410Snewtonclass PPCMachObjectWriter : public MCMachObjectTargetWriter {
2743410Snewton  bool RecordScatteredRelocation(MachObjectWriter *Writer,
2843410Snewton                                 const MCAssembler &Asm,
2943410Snewton                                 const MCAsmLayout &Layout,
3043410Snewton                                 const MCFragment *Fragment,
3143410Snewton                                 const MCFixup &Fixup, MCValue Target,
3249263Snewton                                 unsigned Log2Size, uint64_t &FixedValue);
3350477Speter
3443410Snewton  void RecordPPCRelocation(MachObjectWriter *Writer, const MCAssembler &Asm,
3543410Snewton                           const MCAsmLayout &Layout,
3643410Snewton                           const MCFragment *Fragment, const MCFixup &Fixup,
3743410Snewton                           MCValue Target, uint64_t &FixedValue);
3843410Snewton
3943410Snewtonpublic:
4043410Snewton  PPCMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype)
4143410Snewton      : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype,
4243410Snewton                                 /*UseAggressiveSymbolFolding=*/Is64Bit) {}
4343410Snewton
4443410Snewton  void RecordRelocation(MachObjectWriter *Writer, const MCAssembler &Asm,
4543410Snewton                        const MCAsmLayout &Layout, const MCFragment *Fragment,
4643410Snewton                        const MCFixup &Fixup, MCValue Target,
4743410Snewton                        uint64_t &FixedValue) override {
4843410Snewton    if (Writer->is64Bit()) {
4943410Snewton      report_fatal_error("Relocation emission for MachO/PPC64 unimplemented.");
5043410Snewton    } else
5143410Snewton      RecordPPCRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
5243410Snewton                          FixedValue);
5343410Snewton  }
5443410Snewton};
5543410Snewton}
5643410Snewton
5765314Sobrien/// computes the log2 of the size of the relocation,
5865314Sobrien/// used for relocation_info::r_length.
5965314Sobrienstatic unsigned getFixupKindLog2Size(unsigned Kind) {
6065314Sobrien  switch (Kind) {
6165314Sobrien  default:
6265314Sobrien    report_fatal_error("log2size(FixupKind): Unhandled fixup kind!");
6343410Snewton  case FK_PCRel_1:
6492739Salfred  case FK_Data_1:
6592739Salfred    return 0;
6643410Snewton  case FK_PCRel_2:
6743410Snewton  case FK_Data_2:
6843410Snewton    return 1;
6943410Snewton  case FK_PCRel_4:
7043410Snewton  case PPC::fixup_ppc_brcond14:
7143410Snewton  case PPC::fixup_ppc_half16:
7243410Snewton  case PPC::fixup_ppc_br24:
7343410Snewton  case FK_Data_4:
7460938Sjake    return 2;
7543410Snewton  case FK_PCRel_8:
7643410Snewton  case FK_Data_8:
7760938Sjake    return 3;
7843410Snewton  }
7943410Snewton  return 0;
8043410Snewton}
8143410Snewton
8243410Snewton/// Translates generic PPC fixup kind to Mach-O/PPC relocation type enum.
8343410Snewton/// Outline based on PPCELFObjectWriter::GetRelocType().
8443410Snewtonstatic unsigned getRelocType(const MCValue &Target,
8543410Snewton                             const MCFixupKind FixupKind, // from
8643410Snewton                                                          // Fixup.getKind()
8743410Snewton                             const bool IsPCRel) {
8843410Snewton  const MCSymbolRefExpr::VariantKind Modifier =
8943410Snewton      Target.isAbsolute() ? MCSymbolRefExpr::VK_None
9043410Snewton                          : Target.getSymA()->getKind();
9143410Snewton  // determine the type of the relocation
9243410Snewton  unsigned Type = MachO::GENERIC_RELOC_VANILLA;
9343410Snewton  if (IsPCRel) { // relative to PC
9443410Snewton    switch ((unsigned)FixupKind) {
9543410Snewton    default:
9643410Snewton      report_fatal_error("Unimplemented fixup kind (relative)");
9743410Snewton    case PPC::fixup_ppc_br24:
9889059Smsmith      Type = MachO::PPC_RELOC_BR24; // R_PPC_REL24
9952114Snewton      break;
10052114Snewton    case PPC::fixup_ppc_brcond14:
10143410Snewton      Type = MachO::PPC_RELOC_BR14;
102108235Sphk      break;
10372521Sjlemon    case PPC::fixup_ppc_half16:
10443410Snewton      switch (Modifier) {
10543410Snewton      default:
10643410Snewton        llvm_unreachable("Unsupported modifier for half16 fixup");
10743410Snewton      case MCSymbolRefExpr::VK_PPC_HA:
108111815Sphk        Type = MachO::PPC_RELOC_HA16;
109111815Sphk        break;
110111815Sphk      case MCSymbolRefExpr::VK_PPC_LO:
11147625Sphk        Type = MachO::PPC_RELOC_LO16;
11243410Snewton        break;
11343410Snewton      case MCSymbolRefExpr::VK_PPC_HI:
11443410Snewton        Type = MachO::PPC_RELOC_HI16;
11543410Snewton        break;
11643410Snewton      }
11743410Snewton      break;
11843410Snewton    }
11943410Snewton  } else {
12043410Snewton    switch ((unsigned)FixupKind) {
12144208Snewton    default:
12244208Snewton      report_fatal_error("Unimplemented fixup kind (absolute)!");
12344208Snewton    case PPC::fixup_ppc_half16:
12444208Snewton      switch (Modifier) {
12544208Snewton      default:
12649344Snewton        llvm_unreachable("Unsupported modifier for half16 fixup");
12752114Snewton      case MCSymbolRefExpr::VK_PPC_HA:
12852114Snewton        Type = MachO::PPC_RELOC_HA16_SECTDIFF;
12952114Snewton        break;
13052114Snewton      case MCSymbolRefExpr::VK_PPC_LO:
13152114Snewton        Type = MachO::PPC_RELOC_LO16_SECTDIFF;
13252114Snewton        break;
13352114Snewton      case MCSymbolRefExpr::VK_PPC_HI:
13452114Snewton        Type = MachO::PPC_RELOC_HI16_SECTDIFF;
13552114Snewton        break;
13652114Snewton      }
13752114Snewton      break;
13852114Snewton    case FK_Data_4:
13952114Snewton      break;
14052114Snewton    case FK_Data_2:
14152114Snewton      break;
14252114Snewton    }
14352114Snewton  }
14452114Snewton  return Type;
14552114Snewton}
14652114Snewton
14752114Snewtonstatic void makeRelocationInfo(MachO::any_relocation_info &MRE,
14852114Snewton                               const uint32_t FixupOffset, const uint32_t Index,
14952114Snewton                               const unsigned IsPCRel, const unsigned Log2Size,
15052114Snewton                               const unsigned IsExtern, const unsigned Type) {
15152114Snewton  MRE.r_word0 = FixupOffset;
15252114Snewton  // The bitfield offsets that work (as determined by trial-and-error)
15352114Snewton  // are different than what is documented in the mach-o manuals.
15444208Snewton  // This appears to be an endianness issue; reversing the order of the
15544208Snewton  // documented bitfields in <llvm/Support/MachO.h> fixes this (but
15649344Snewton  // breaks x86/ARM assembly).
15753000Sphk  MRE.r_word1 = ((Index << 8) |    // was << 0
15853000Sphk                 (IsPCRel << 7) |  // was << 24
15953000Sphk                 (Log2Size << 5) | // was << 25
16053000Sphk                 (IsExtern << 4) | // was << 27
16153000Sphk                 (Type << 0));     // was << 28
16253000Sphk}
16353000Sphk
16453000Sphkstatic void
16553000SphkmakeScatteredRelocationInfo(MachO::any_relocation_info &MRE,
16653000Sphk                            const uint32_t Addr, const unsigned Type,
16752114Snewton                            const unsigned Log2Size, const unsigned IsPCRel,
16844208Snewton                            const uint32_t Value2) {
16944208Snewton  // For notes on bitfield positions and endianness, see:
17044208Snewton  // https://developer.apple.com/library/mac/documentation/developertools/conceptual/MachORuntime/Reference/reference.html#//apple_ref/doc/uid/20001298-scattered_relocation_entry
17144208Snewton  MRE.r_word0 = ((Addr << 0) | (Type << 24) | (Log2Size << 28) |
17244208Snewton                 (IsPCRel << 30) | MachO::R_SCATTERED);
17344208Snewton  MRE.r_word1 = Value2;
17444208Snewton}
17544208Snewton
17644208Snewton/// Compute fixup offset (address).
17744208Snewtonstatic uint32_t getFixupOffset(const MCAsmLayout &Layout,
17844208Snewton                               const MCFragment *Fragment,
17944208Snewton                               const MCFixup &Fixup) {
18044208Snewton  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
18160060Sgreen  // On Mach-O, ppc_fixup_half16 relocations must refer to the
18244208Snewton  // start of the instruction, not the second halfword, as ELF does
18343410Snewton  if (unsigned(Fixup.getKind()) == PPC::fixup_ppc_half16)
18443410Snewton    FixupOffset &= ~uint32_t(3);
18543410Snewton  return FixupOffset;
18643410Snewton}
18743410Snewton
18843410Snewton/// \return false if falling back to using non-scattered relocation,
18943410Snewton/// otherwise true for normal scattered relocation.
19043410Snewton/// based on X86MachObjectWriter::RecordScatteredRelocation
19183366Sjulian/// and ARMMachObjectWriter::RecordScatteredRelocation
19243410Snewtonbool PPCMachObjectWriter::RecordScatteredRelocation(
19343410Snewton    MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout,
19443410Snewton    const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
19543410Snewton    unsigned Log2Size, uint64_t &FixedValue) {
19643410Snewton  // caller already computes these, can we just pass and reuse?
19743410Snewton  const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup);
19843410Snewton  const MCFixupKind FK = Fixup.getKind();
19983366Sjulian  const unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, FK);
20043410Snewton  const unsigned Type = getRelocType(Target, FK, IsPCRel);
20171448Sjhb
20283366Sjulian  // Is this a local or SECTDIFF relocation entry?
20371448Sjhb  // SECTDIFF relocation entries have symbol subtractions,
20443410Snewton  // and require two entries, the first for the add-symbol value,
20571448Sjhb  // the second for the subtract-symbol value.
20671448Sjhb
20743410Snewton  // See <reloc.h>.
20843410Snewton  const MCSymbol *A = &Target.getSymA()->getSymbol();
20943410Snewton  const MCSymbolData *A_SD = &Asm.getSymbolData(*A);
21043410Snewton
21143410Snewton  if (!A_SD->getFragment())
21243410Snewton    report_fatal_error("symbol '" + A->getName() +
21343410Snewton                       "' can not be undefined in a subtraction expression");
21443410Snewton
21543410Snewton  uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
21643410Snewton  uint64_t SecAddr =
21743410Snewton      Writer->getSectionAddress(A_SD->getFragment()->getParent());
21843410Snewton  FixedValue += SecAddr;
21943410Snewton  uint32_t Value2 = 0;
22043410Snewton
22143410Snewton  if (const MCSymbolRefExpr *B = Target.getSymB()) {
22243410Snewton    const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
22343410Snewton
22443410Snewton    if (!B_SD->getFragment())
22543410Snewton      report_fatal_error("symbol '" + B->getSymbol().getName() +
22643410Snewton                         "' can not be undefined in a subtraction expression");
22743410Snewton
22843410Snewton    // FIXME: is Type correct? see include/llvm/Support/MachO.h
22943410Snewton    Value2 = Writer->getSymbolAddress(B_SD, Layout);
23043410Snewton    FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
23143410Snewton  }
23243410Snewton  // FIXME: does FixedValue get used??
23343410Snewton
23443410Snewton  // Relocations are written out in reverse order, so the PAIR comes first.
23543410Snewton  if (Type == MachO::PPC_RELOC_SECTDIFF ||
23643410Snewton      Type == MachO::PPC_RELOC_HI16_SECTDIFF ||
23743410Snewton      Type == MachO::PPC_RELOC_LO16_SECTDIFF ||
23843410Snewton      Type == MachO::PPC_RELOC_HA16_SECTDIFF ||
23943410Snewton      Type == MachO::PPC_RELOC_LO14_SECTDIFF ||
24043410Snewton      Type == MachO::PPC_RELOC_LOCAL_SECTDIFF) {
24143410Snewton    // X86 had this piece, but ARM does not
24243410Snewton    // If the offset is too large to fit in a scattered relocation,
24343410Snewton    // we're hosed. It's an unfortunate limitation of the MachO format.
24443410Snewton    if (FixupOffset > 0xffffff) {
24543410Snewton      char Buffer[32];
24643410Snewton      format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer));
24743410Snewton      Asm.getContext().FatalError(Fixup.getLoc(),
24883366Sjulian                                  Twine("Section too large, can't encode "
24943410Snewton                                        "r_address (") +
25043410Snewton                                      Buffer + ") into 24 bits of scattered "
25143410Snewton                                               "relocation entry.");
25243410Snewton      llvm_unreachable("fatal error returned?!");
25343410Snewton    }
25483366Sjulian
25543410Snewton    // Is this supposed to follow MCTarget/PPCAsmBackend.cpp:adjustFixupValue()?
25643410Snewton    // see PPCMCExpr::EvaluateAsRelocatableImpl()
25788739Srwatson    uint32_t other_half = 0;
25891406Sjhb    switch (Type) {
25989306Salfred    case MachO::PPC_RELOC_LO16_SECTDIFF:
26043410Snewton      other_half = (FixedValue >> 16) & 0xffff;
26189306Salfred      // applyFixupOffset longer extracts the high part because it now assumes
26243410Snewton      // this was already done.
26343410Snewton      // It looks like this is not true for the FixedValue needed with Mach-O
26443410Snewton      // relocs.
26543410Snewton      // So we need to adjust FixedValue again here.
26689306Salfred      FixedValue &= 0xffff;
267109153Sdillon      break;
26843410Snewton    case MachO::PPC_RELOC_HA16_SECTDIFF:
26949413Sgreen      other_half = FixedValue & 0xffff;
27043410Snewton      FixedValue =
27189306Salfred          ((FixedValue >> 16) + ((FixedValue & 0x8000) ? 1 : 0)) & 0xffff;
27243410Snewton      break;
27343410Snewton    case MachO::PPC_RELOC_HI16_SECTDIFF:
27471448Sjhb      other_half = FixedValue & 0xffff;
27583366Sjulian      FixedValue = (FixedValue >> 16) & 0xffff;
27671448Sjhb      break;
27743410Snewton    default:
27843410Snewton      llvm_unreachable("Invalid PPC scattered relocation type.");
27943410Snewton      break;
28043410Snewton    }
28183366Sjulian
28283366Sjulian    MachO::any_relocation_info MRE;
28343410Snewton    makeScatteredRelocationInfo(MRE, other_half, MachO::GENERIC_RELOC_PAIR,
28483366Sjulian                                Log2Size, IsPCRel, Value2);
28543410Snewton    Writer->addRelocation(Fragment->getParent(), MRE);
28643410Snewton  } else {
28743410Snewton    // If the offset is more than 24-bits, it won't fit in a scattered
28843410Snewton    // relocation offset field, so we fall back to using a non-scattered
28943410Snewton    // relocation. This is a bit risky, as if the offset reaches out of
29043410Snewton    // the block and the linker is doing scattered loading on this
29143410Snewton    // symbol, things can go badly.
29243410Snewton    //
29343410Snewton    // Required for 'as' compatibility.
29443410Snewton    if (FixupOffset > 0xffffff)
29543410Snewton      return false;
29643410Snewton  }
29743410Snewton  MachO::any_relocation_info MRE;
29843410Snewton  makeScatteredRelocationInfo(MRE, FixupOffset, Type, Log2Size, IsPCRel, Value);
29943410Snewton  Writer->addRelocation(Fragment->getParent(), MRE);
30043410Snewton  return true;
30143410Snewton}
30243410Snewton
30343410Snewton// see PPCELFObjectWriter for a general outline of cases
30443410Snewtonvoid PPCMachObjectWriter::RecordPPCRelocation(
30543410Snewton    MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout,
30643410Snewton    const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
30743410Snewton    uint64_t &FixedValue) {
308107849Salfred  const MCFixupKind FK = Fixup.getKind(); // unsigned
309107849Salfred  const unsigned Log2Size = getFixupKindLog2Size(FK);
310107849Salfred  const bool IsPCRel = Writer->isFixupKindPCRel(Asm, FK);
31143410Snewton  const unsigned RelocType = getRelocType(Target, FK, IsPCRel);
31243410Snewton
31343410Snewton  // If this is a difference or a defined symbol plus an offset, then we need a
31443410Snewton  // scattered relocation entry. Differences always require scattered
31543410Snewton  // relocations.
31643410Snewton  if (Target.getSymB() &&
31743410Snewton      // Q: are branch targets ever scattered?
31843410Snewton      RelocType != MachO::PPC_RELOC_BR24 &&
31983366Sjulian      RelocType != MachO::PPC_RELOC_BR14) {
32043410Snewton    RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
32143410Snewton                              Log2Size, FixedValue);
32243410Snewton    return;
32343410Snewton  }
32471448Sjhb
32583366Sjulian  // this doesn't seem right for RIT_PPC_BR24
32671448Sjhb  // Get the symbol data, if any.
32743410Snewton  const MCSymbolData *SD = nullptr;
32843410Snewton  if (Target.getSymA())
32943410Snewton    SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
33043410Snewton
33143410Snewton  // See <reloc.h>.
33243410Snewton  const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup);
33343410Snewton  unsigned Index = 0;
33443410Snewton  unsigned IsExtern = 0;
33543410Snewton  unsigned Type = RelocType;
33643410Snewton
33743410Snewton  if (Target.isAbsolute()) { // constant
33843410Snewton                             // SymbolNum of 0 indicates the absolute section.
33943410Snewton                             //
34043410Snewton    // FIXME: Currently, these are never generated (see code below). I cannot
34143410Snewton    // find a case where they are actually emitted.
34243410Snewton    report_fatal_error("FIXME: relocations to absolute targets "
34343410Snewton                       "not yet implemented");
34443410Snewton    // the above line stolen from ARM, not sure
34543410Snewton  } else {
34643410Snewton    // Resolve constant variables.
34743410Snewton    if (SD->getSymbol().isVariable()) {
34843410Snewton      int64_t Res;
34943410Snewton      if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute(
350109153Sdillon              Res, Layout, Writer->getSectionAddressMap())) {
35143410Snewton        FixedValue = Res;
35289306Salfred        return;
35389306Salfred      }
35489306Salfred    }
35589306Salfred
35643410Snewton    // Check whether we need an external or internal relocation.
35789306Salfred    if (Writer->doesSymbolRequireExternRelocation(SD)) {
35843410Snewton      IsExtern = 1;
35943410Snewton      Index = SD->getIndex();
360111119Simp      // For external relocations, make sure to offset the fixup value to
36143410Snewton      // compensate for the addend of the symbol address, if it was
36243410Snewton      // undefined. This occurs with weak definitions, for example.
36343410Snewton      if (!SD->getSymbol().isUndefined())
36443410Snewton        FixedValue -= Layout.getSymbolOffset(SD);
36589306Salfred    } else {
36689306Salfred      // The index is the section ordinal (1-based).
36789306Salfred      const MCSectionData &SymSD =
36889306Salfred          Asm.getSectionData(SD->getSymbol().getSection());
36989306Salfred      Index = SymSD.getOrdinal() + 1;
37089306Salfred      FixedValue += Writer->getSectionAddress(&SymSD);
37189306Salfred    }
37289306Salfred    if (IsPCRel)
37389306Salfred      FixedValue -= Writer->getSectionAddress(Fragment->getParent());
37489306Salfred  }
37589306Salfred
37689306Salfred  // struct relocation_info (8 bytes)
37789306Salfred  MachO::any_relocation_info MRE;
37843410Snewton  makeRelocationInfo(MRE, FixupOffset, Index, IsPCRel, Log2Size, IsExtern,
37943410Snewton                     Type);
38043410Snewton  Writer->addRelocation(Fragment->getParent(), MRE);
38143410Snewton}
38243410Snewton
38343410SnewtonMCObjectWriter *llvm::createPPCMachObjectWriter(raw_ostream &OS, bool Is64Bit,
38443410Snewton                                                uint32_t CPUType,
38543410Snewton                                                uint32_t CPUSubtype) {
38643410Snewton  return createMachObjectWriter(
38743410Snewton      new PPCMachObjectWriter(Is64Bit, CPUType, CPUSubtype), OS,
388109153Sdillon      /*IsLittleEndian=*/false);
38943410Snewton}
39071448Sjhb