mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-30 16:17:05 +00:00 
			
		
		
		
	On x86_64 this brings it from 80 bytes to 64 bytes. Also make any member variables private and clean up uses to go through the existing accessors. NFC. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@219573 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			390 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			390 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //===-- PPCMachObjectWriter.cpp - PPC Mach-O Writer -----------------------===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "MCTargetDesc/PPCMCTargetDesc.h"
 | |
| #include "MCTargetDesc/PPCFixupKinds.h"
 | |
| #include "llvm/ADT/Twine.h"
 | |
| #include "llvm/MC/MCAsmLayout.h"
 | |
| #include "llvm/MC/MCAssembler.h"
 | |
| #include "llvm/MC/MCContext.h"
 | |
| #include "llvm/MC/MCMachObjectWriter.h"
 | |
| #include "llvm/MC/MCSectionMachO.h"
 | |
| #include "llvm/MC/MCValue.h"
 | |
| #include "llvm/Support/ErrorHandling.h"
 | |
| #include "llvm/Support/Format.h"
 | |
| #include "llvm/Support/MachO.h"
 | |
| 
 | |
| using namespace llvm;
 | |
| 
 | |
| namespace {
 | |
| class PPCMachObjectWriter : public MCMachObjectTargetWriter {
 | |
|   bool RecordScatteredRelocation(MachObjectWriter *Writer,
 | |
|                                  const MCAssembler &Asm,
 | |
|                                  const MCAsmLayout &Layout,
 | |
|                                  const MCFragment *Fragment,
 | |
|                                  const MCFixup &Fixup, MCValue Target,
 | |
|                                  unsigned Log2Size, uint64_t &FixedValue);
 | |
| 
 | |
|   void RecordPPCRelocation(MachObjectWriter *Writer, const MCAssembler &Asm,
 | |
|                            const MCAsmLayout &Layout,
 | |
|                            const MCFragment *Fragment, const MCFixup &Fixup,
 | |
|                            MCValue Target, uint64_t &FixedValue);
 | |
| 
 | |
| public:
 | |
|   PPCMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype)
 | |
|       : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype,
 | |
|                                  /*UseAggressiveSymbolFolding=*/Is64Bit) {}
 | |
| 
 | |
|   void RecordRelocation(MachObjectWriter *Writer, const MCAssembler &Asm,
 | |
|                         const MCAsmLayout &Layout, const MCFragment *Fragment,
 | |
|                         const MCFixup &Fixup, MCValue Target,
 | |
|                         uint64_t &FixedValue) override {
 | |
|     if (Writer->is64Bit()) {
 | |
|       report_fatal_error("Relocation emission for MachO/PPC64 unimplemented.");
 | |
|     } else
 | |
|       RecordPPCRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
 | |
|                           FixedValue);
 | |
|   }
 | |
| };
 | |
| }
 | |
| 
 | |
| /// computes the log2 of the size of the relocation,
 | |
| /// used for relocation_info::r_length.
 | |
| static unsigned getFixupKindLog2Size(unsigned Kind) {
 | |
|   switch (Kind) {
 | |
|   default:
 | |
|     report_fatal_error("log2size(FixupKind): Unhandled fixup kind!");
 | |
|   case FK_PCRel_1:
 | |
|   case FK_Data_1:
 | |
|     return 0;
 | |
|   case FK_PCRel_2:
 | |
|   case FK_Data_2:
 | |
|     return 1;
 | |
|   case FK_PCRel_4:
 | |
|   case PPC::fixup_ppc_brcond14:
 | |
|   case PPC::fixup_ppc_half16:
 | |
|   case PPC::fixup_ppc_br24:
 | |
|   case FK_Data_4:
 | |
|     return 2;
 | |
|   case FK_PCRel_8:
 | |
|   case FK_Data_8:
 | |
|     return 3;
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /// Translates generic PPC fixup kind to Mach-O/PPC relocation type enum.
 | |
| /// Outline based on PPCELFObjectWriter::GetRelocType().
 | |
| static unsigned getRelocType(const MCValue &Target,
 | |
|                              const MCFixupKind FixupKind, // from
 | |
|                                                           // Fixup.getKind()
 | |
|                              const bool IsPCRel) {
 | |
|   const MCSymbolRefExpr::VariantKind Modifier =
 | |
|       Target.isAbsolute() ? MCSymbolRefExpr::VK_None
 | |
|                           : Target.getSymA()->getKind();
 | |
|   // determine the type of the relocation
 | |
|   unsigned Type = MachO::GENERIC_RELOC_VANILLA;
 | |
|   if (IsPCRel) { // relative to PC
 | |
|     switch ((unsigned)FixupKind) {
 | |
|     default:
 | |
|       report_fatal_error("Unimplemented fixup kind (relative)");
 | |
|     case PPC::fixup_ppc_br24:
 | |
|       Type = MachO::PPC_RELOC_BR24; // R_PPC_REL24
 | |
|       break;
 | |
|     case PPC::fixup_ppc_brcond14:
 | |
|       Type = MachO::PPC_RELOC_BR14;
 | |
|       break;
 | |
|     case PPC::fixup_ppc_half16:
 | |
|       switch (Modifier) {
 | |
|       default:
 | |
|         llvm_unreachable("Unsupported modifier for half16 fixup");
 | |
|       case MCSymbolRefExpr::VK_PPC_HA:
 | |
|         Type = MachO::PPC_RELOC_HA16;
 | |
|         break;
 | |
|       case MCSymbolRefExpr::VK_PPC_LO:
 | |
|         Type = MachO::PPC_RELOC_LO16;
 | |
|         break;
 | |
|       case MCSymbolRefExpr::VK_PPC_HI:
 | |
|         Type = MachO::PPC_RELOC_HI16;
 | |
|         break;
 | |
|       }
 | |
|       break;
 | |
|     }
 | |
|   } else {
 | |
|     switch ((unsigned)FixupKind) {
 | |
|     default:
 | |
|       report_fatal_error("Unimplemented fixup kind (absolute)!");
 | |
|     case PPC::fixup_ppc_half16:
 | |
|       switch (Modifier) {
 | |
|       default:
 | |
|         llvm_unreachable("Unsupported modifier for half16 fixup");
 | |
|       case MCSymbolRefExpr::VK_PPC_HA:
 | |
|         Type = MachO::PPC_RELOC_HA16_SECTDIFF;
 | |
|         break;
 | |
|       case MCSymbolRefExpr::VK_PPC_LO:
 | |
|         Type = MachO::PPC_RELOC_LO16_SECTDIFF;
 | |
|         break;
 | |
|       case MCSymbolRefExpr::VK_PPC_HI:
 | |
|         Type = MachO::PPC_RELOC_HI16_SECTDIFF;
 | |
|         break;
 | |
|       }
 | |
|       break;
 | |
|     case FK_Data_4:
 | |
|       break;
 | |
|     case FK_Data_2:
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
|   return Type;
 | |
| }
 | |
| 
 | |
| static void makeRelocationInfo(MachO::any_relocation_info &MRE,
 | |
|                                const uint32_t FixupOffset, const uint32_t Index,
 | |
|                                const unsigned IsPCRel, const unsigned Log2Size,
 | |
|                                const unsigned IsExtern, const unsigned Type) {
 | |
|   MRE.r_word0 = FixupOffset;
 | |
|   // The bitfield offsets that work (as determined by trial-and-error)
 | |
|   // are different than what is documented in the mach-o manuals.
 | |
|   // This appears to be an endianness issue; reversing the order of the
 | |
|   // documented bitfields in <llvm/Support/MachO.h> fixes this (but
 | |
|   // breaks x86/ARM assembly).
 | |
|   MRE.r_word1 = ((Index << 8) |    // was << 0
 | |
|                  (IsPCRel << 7) |  // was << 24
 | |
|                  (Log2Size << 5) | // was << 25
 | |
|                  (IsExtern << 4) | // was << 27
 | |
|                  (Type << 0));     // was << 28
 | |
| }
 | |
| 
 | |
| static void
 | |
| makeScatteredRelocationInfo(MachO::any_relocation_info &MRE,
 | |
|                             const uint32_t Addr, const unsigned Type,
 | |
|                             const unsigned Log2Size, const unsigned IsPCRel,
 | |
|                             const uint32_t Value2) {
 | |
|   // For notes on bitfield positions and endianness, see:
 | |
|   // https://developer.apple.com/library/mac/documentation/developertools/conceptual/MachORuntime/Reference/reference.html#//apple_ref/doc/uid/20001298-scattered_relocation_entry
 | |
|   MRE.r_word0 = ((Addr << 0) | (Type << 24) | (Log2Size << 28) |
 | |
|                  (IsPCRel << 30) | MachO::R_SCATTERED);
 | |
|   MRE.r_word1 = Value2;
 | |
| }
 | |
| 
 | |
| /// Compute fixup offset (address).
 | |
| static uint32_t getFixupOffset(const MCAsmLayout &Layout,
 | |
|                                const MCFragment *Fragment,
 | |
|                                const MCFixup &Fixup) {
 | |
|   uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
 | |
|   // On Mach-O, ppc_fixup_half16 relocations must refer to the
 | |
|   // start of the instruction, not the second halfword, as ELF does
 | |
|   if (unsigned(Fixup.getKind()) == PPC::fixup_ppc_half16)
 | |
|     FixupOffset &= ~uint32_t(3);
 | |
|   return FixupOffset;
 | |
| }
 | |
| 
 | |
| /// \return false if falling back to using non-scattered relocation,
 | |
| /// otherwise true for normal scattered relocation.
 | |
| /// based on X86MachObjectWriter::RecordScatteredRelocation
 | |
| /// and ARMMachObjectWriter::RecordScatteredRelocation
 | |
| bool PPCMachObjectWriter::RecordScatteredRelocation(
 | |
|     MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout,
 | |
|     const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
 | |
|     unsigned Log2Size, uint64_t &FixedValue) {
 | |
|   // caller already computes these, can we just pass and reuse?
 | |
|   const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup);
 | |
|   const MCFixupKind FK = Fixup.getKind();
 | |
|   const unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, FK);
 | |
|   const unsigned Type = getRelocType(Target, FK, IsPCRel);
 | |
| 
 | |
|   // Is this a local or SECTDIFF relocation entry?
 | |
|   // SECTDIFF relocation entries have symbol subtractions,
 | |
|   // and require two entries, the first for the add-symbol value,
 | |
|   // the second for the subtract-symbol value.
 | |
| 
 | |
|   // See <reloc.h>.
 | |
|   const MCSymbol *A = &Target.getSymA()->getSymbol();
 | |
|   const MCSymbolData *A_SD = &Asm.getSymbolData(*A);
 | |
| 
 | |
|   if (!A_SD->getFragment())
 | |
|     report_fatal_error("symbol '" + A->getName() +
 | |
|                        "' can not be undefined in a subtraction expression");
 | |
| 
 | |
|   uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
 | |
|   uint64_t SecAddr =
 | |
|       Writer->getSectionAddress(A_SD->getFragment()->getParent());
 | |
|   FixedValue += SecAddr;
 | |
|   uint32_t Value2 = 0;
 | |
| 
 | |
|   if (const MCSymbolRefExpr *B = Target.getSymB()) {
 | |
|     const MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
 | |
| 
 | |
|     if (!B_SD->getFragment())
 | |
|       report_fatal_error("symbol '" + B->getSymbol().getName() +
 | |
|                          "' can not be undefined in a subtraction expression");
 | |
| 
 | |
|     // FIXME: is Type correct? see include/llvm/Support/MachO.h
 | |
|     Value2 = Writer->getSymbolAddress(B_SD, Layout);
 | |
|     FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
 | |
|   }
 | |
|   // FIXME: does FixedValue get used??
 | |
| 
 | |
|   // Relocations are written out in reverse order, so the PAIR comes first.
 | |
|   if (Type == MachO::PPC_RELOC_SECTDIFF ||
 | |
|       Type == MachO::PPC_RELOC_HI16_SECTDIFF ||
 | |
|       Type == MachO::PPC_RELOC_LO16_SECTDIFF ||
 | |
|       Type == MachO::PPC_RELOC_HA16_SECTDIFF ||
 | |
|       Type == MachO::PPC_RELOC_LO14_SECTDIFF ||
 | |
|       Type == MachO::PPC_RELOC_LOCAL_SECTDIFF) {
 | |
|     // X86 had this piece, but ARM does not
 | |
|     // If the offset is too large to fit in a scattered relocation,
 | |
|     // we're hosed. It's an unfortunate limitation of the MachO format.
 | |
|     if (FixupOffset > 0xffffff) {
 | |
|       char Buffer[32];
 | |
|       format("0x%x", FixupOffset).print(Buffer, sizeof(Buffer));
 | |
|       Asm.getContext().FatalError(Fixup.getLoc(),
 | |
|                                   Twine("Section too large, can't encode "
 | |
|                                         "r_address (") +
 | |
|                                       Buffer + ") into 24 bits of scattered "
 | |
|                                                "relocation entry.");
 | |
|       llvm_unreachable("fatal error returned?!");
 | |
|     }
 | |
| 
 | |
|     // Is this supposed to follow MCTarget/PPCAsmBackend.cpp:adjustFixupValue()?
 | |
|     // see PPCMCExpr::EvaluateAsRelocatableImpl()
 | |
|     uint32_t other_half = 0;
 | |
|     switch (Type) {
 | |
|     case MachO::PPC_RELOC_LO16_SECTDIFF:
 | |
|       other_half = (FixedValue >> 16) & 0xffff;
 | |
|       // applyFixupOffset longer extracts the high part because it now assumes
 | |
|       // this was already done.
 | |
|       // It looks like this is not true for the FixedValue needed with Mach-O
 | |
|       // relocs.
 | |
|       // So we need to adjust FixedValue again here.
 | |
|       FixedValue &= 0xffff;
 | |
|       break;
 | |
|     case MachO::PPC_RELOC_HA16_SECTDIFF:
 | |
|       other_half = FixedValue & 0xffff;
 | |
|       FixedValue =
 | |
|           ((FixedValue >> 16) + ((FixedValue & 0x8000) ? 1 : 0)) & 0xffff;
 | |
|       break;
 | |
|     case MachO::PPC_RELOC_HI16_SECTDIFF:
 | |
|       other_half = FixedValue & 0xffff;
 | |
|       FixedValue = (FixedValue >> 16) & 0xffff;
 | |
|       break;
 | |
|     default:
 | |
|       llvm_unreachable("Invalid PPC scattered relocation type.");
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     MachO::any_relocation_info MRE;
 | |
|     makeScatteredRelocationInfo(MRE, other_half, MachO::GENERIC_RELOC_PAIR,
 | |
|                                 Log2Size, IsPCRel, Value2);
 | |
|     Writer->addRelocation(Fragment->getParent(), MRE);
 | |
|   } else {
 | |
|     // If the offset is more than 24-bits, it won't fit in a scattered
 | |
|     // relocation offset field, so we fall back to using a non-scattered
 | |
|     // relocation. This is a bit risky, as if the offset reaches out of
 | |
|     // the block and the linker is doing scattered loading on this
 | |
|     // symbol, things can go badly.
 | |
|     //
 | |
|     // Required for 'as' compatibility.
 | |
|     if (FixupOffset > 0xffffff)
 | |
|       return false;
 | |
|   }
 | |
|   MachO::any_relocation_info MRE;
 | |
|   makeScatteredRelocationInfo(MRE, FixupOffset, Type, Log2Size, IsPCRel, Value);
 | |
|   Writer->addRelocation(Fragment->getParent(), MRE);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // see PPCELFObjectWriter for a general outline of cases
 | |
| void PPCMachObjectWriter::RecordPPCRelocation(
 | |
|     MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout,
 | |
|     const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
 | |
|     uint64_t &FixedValue) {
 | |
|   const MCFixupKind FK = Fixup.getKind(); // unsigned
 | |
|   const unsigned Log2Size = getFixupKindLog2Size(FK);
 | |
|   const bool IsPCRel = Writer->isFixupKindPCRel(Asm, FK);
 | |
|   const unsigned RelocType = getRelocType(Target, FK, IsPCRel);
 | |
| 
 | |
|   // If this is a difference or a defined symbol plus an offset, then we need a
 | |
|   // scattered relocation entry. Differences always require scattered
 | |
|   // relocations.
 | |
|   if (Target.getSymB() &&
 | |
|       // Q: are branch targets ever scattered?
 | |
|       RelocType != MachO::PPC_RELOC_BR24 &&
 | |
|       RelocType != MachO::PPC_RELOC_BR14) {
 | |
|     RecordScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup, Target,
 | |
|                               Log2Size, FixedValue);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // this doesn't seem right for RIT_PPC_BR24
 | |
|   // Get the symbol data, if any.
 | |
|   const MCSymbolData *SD = nullptr;
 | |
|   if (Target.getSymA())
 | |
|     SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
 | |
| 
 | |
|   // See <reloc.h>.
 | |
|   const uint32_t FixupOffset = getFixupOffset(Layout, Fragment, Fixup);
 | |
|   unsigned Index = 0;
 | |
|   unsigned IsExtern = 0;
 | |
|   unsigned Type = RelocType;
 | |
| 
 | |
|   if (Target.isAbsolute()) { // constant
 | |
|                              // SymbolNum of 0 indicates the absolute section.
 | |
|                              //
 | |
|     // FIXME: Currently, these are never generated (see code below). I cannot
 | |
|     // find a case where they are actually emitted.
 | |
|     report_fatal_error("FIXME: relocations to absolute targets "
 | |
|                        "not yet implemented");
 | |
|     // the above line stolen from ARM, not sure
 | |
|   } else {
 | |
|     // Resolve constant variables.
 | |
|     if (SD->getSymbol().isVariable()) {
 | |
|       int64_t Res;
 | |
|       if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute(
 | |
|               Res, Layout, Writer->getSectionAddressMap())) {
 | |
|         FixedValue = Res;
 | |
|         return;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // Check whether we need an external or internal relocation.
 | |
|     if (Writer->doesSymbolRequireExternRelocation(SD)) {
 | |
|       IsExtern = 1;
 | |
|       Index = SD->getIndex();
 | |
|       // For external relocations, make sure to offset the fixup value to
 | |
|       // compensate for the addend of the symbol address, if it was
 | |
|       // undefined. This occurs with weak definitions, for example.
 | |
|       if (!SD->getSymbol().isUndefined())
 | |
|         FixedValue -= Layout.getSymbolOffset(SD);
 | |
|     } else {
 | |
|       // The index is the section ordinal (1-based).
 | |
|       const MCSectionData &SymSD =
 | |
|           Asm.getSectionData(SD->getSymbol().getSection());
 | |
|       Index = SymSD.getOrdinal() + 1;
 | |
|       FixedValue += Writer->getSectionAddress(&SymSD);
 | |
|     }
 | |
|     if (IsPCRel)
 | |
|       FixedValue -= Writer->getSectionAddress(Fragment->getParent());
 | |
|   }
 | |
| 
 | |
|   // struct relocation_info (8 bytes)
 | |
|   MachO::any_relocation_info MRE;
 | |
|   makeRelocationInfo(MRE, FixupOffset, Index, IsPCRel, Log2Size, IsExtern,
 | |
|                      Type);
 | |
|   Writer->addRelocation(Fragment->getParent(), MRE);
 | |
| }
 | |
| 
 | |
| MCObjectWriter *llvm::createPPCMachObjectWriter(raw_ostream &OS, bool Is64Bit,
 | |
|                                                 uint32_t CPUType,
 | |
|                                                 uint32_t CPUSubtype) {
 | |
|   return createMachObjectWriter(
 | |
|       new PPCMachObjectWriter(Is64Bit, CPUType, CPUSubtype), OS,
 | |
|       /*IsLittleEndian=*/false);
 | |
| }
 |