Home | History | Annotate | Download | only in MCTargetDesc
      1 //===-- PPCAsmBackend.cpp - PPC Assembler Backend -------------------------===//
      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 "llvm/MC/MCAsmBackend.h"
     11 #include "MCTargetDesc/PPCMCTargetDesc.h"
     12 #include "MCTargetDesc/PPCFixupKinds.h"
     13 #include "llvm/MC/MCELFObjectWriter.h"
     14 #include "llvm/MC/MCMachObjectWriter.h"
     15 #include "llvm/MC/MCSectionMachO.h"
     16 #include "llvm/MC/MCObjectWriter.h"
     17 #include "llvm/MC/MCValue.h"
     18 #include "llvm/Object/MachOFormat.h"
     19 #include "llvm/Support/ELF.h"
     20 #include "llvm/Support/ErrorHandling.h"
     21 #include "llvm/Support/TargetRegistry.h"
     22 using namespace llvm;
     23 
     24 static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
     25   switch (Kind) {
     26   default:
     27     llvm_unreachable("Unknown fixup kind!");
     28   case FK_Data_1:
     29   case FK_Data_2:
     30   case FK_Data_4:
     31     return Value;
     32   case PPC::fixup_ppc_brcond14:
     33     return Value & 0x3ffc;
     34   case PPC::fixup_ppc_br24:
     35     return Value & 0x3fffffc;
     36 #if 0
     37   case PPC::fixup_ppc_hi16:
     38     return (Value >> 16) & 0xffff;
     39 #endif
     40   case PPC::fixup_ppc_ha16:
     41     return ((Value >> 16) + ((Value & 0x8000) ? 1 : 0)) & 0xffff;
     42   case PPC::fixup_ppc_lo16:
     43     return Value & 0xffff;
     44   }
     45 }
     46 
     47 namespace {
     48 class PPCMachObjectWriter : public MCMachObjectTargetWriter {
     49 public:
     50   PPCMachObjectWriter(bool Is64Bit, uint32_t CPUType,
     51                       uint32_t CPUSubtype)
     52     : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype) {}
     53 
     54   void RecordRelocation(MachObjectWriter *Writer,
     55                         const MCAssembler &Asm, const MCAsmLayout &Layout,
     56                         const MCFragment *Fragment, const MCFixup &Fixup,
     57                         MCValue Target, uint64_t &FixedValue) {}
     58 };
     59 
     60 class PPCELFObjectWriter : public MCELFObjectTargetWriter {
     61 public:
     62   PPCELFObjectWriter(bool Is64Bit, Triple::OSType OSType, uint16_t EMachine,
     63                      bool HasRelocationAddend, bool isLittleEndian)
     64     : MCELFObjectTargetWriter(Is64Bit, OSType, EMachine, HasRelocationAddend) {}
     65 };
     66 
     67 class PPCAsmBackend : public MCAsmBackend {
     68 const Target &TheTarget;
     69 public:
     70   PPCAsmBackend(const Target &T) : MCAsmBackend(), TheTarget(T) {}
     71 
     72   unsigned getNumFixupKinds() const { return PPC::NumTargetFixupKinds; }
     73 
     74   const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const {
     75     const static MCFixupKindInfo Infos[PPC::NumTargetFixupKinds] = {
     76       // name                    offset  bits  flags
     77       { "fixup_ppc_br24",        6,      24,   MCFixupKindInfo::FKF_IsPCRel },
     78       { "fixup_ppc_brcond14",    16,     14,   MCFixupKindInfo::FKF_IsPCRel },
     79       { "fixup_ppc_lo16",        16,     16,   0 },
     80       { "fixup_ppc_ha16",        16,     16,   0 },
     81       { "fixup_ppc_lo14",        16,     14,   0 }
     82     };
     83 
     84     if (Kind < FirstTargetFixupKind)
     85       return MCAsmBackend::getFixupKindInfo(Kind);
     86 
     87     assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
     88            "Invalid kind!");
     89     return Infos[Kind - FirstTargetFixupKind];
     90   }
     91 
     92   bool MayNeedRelaxation(const MCInst &Inst) const {
     93     // FIXME.
     94     return false;
     95   }
     96 
     97   void RelaxInstruction(const MCInst &Inst, MCInst &Res) const {
     98     // FIXME.
     99     assert(0 && "RelaxInstruction() unimplemented");
    100   }
    101 
    102   bool WriteNopData(uint64_t Count, MCObjectWriter *OW) const {
    103     // FIXME: Zero fill for now. That's not right, but at least will get the
    104     // section size right.
    105     for (uint64_t i = 0; i != Count; ++i)
    106       OW->Write8(0);
    107     return true;
    108   }
    109 
    110   unsigned getPointerSize() const {
    111     StringRef Name = TheTarget.getName();
    112     if (Name == "ppc64") return 8;
    113     assert(Name == "ppc32" && "Unknown target name!");
    114     return 4;
    115   }
    116 };
    117 } // end anonymous namespace
    118 
    119 
    120 // FIXME: This should be in a separate file.
    121 namespace {
    122   class DarwinPPCAsmBackend : public PPCAsmBackend {
    123   public:
    124     DarwinPPCAsmBackend(const Target &T) : PPCAsmBackend(T) { }
    125 
    126     void ApplyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
    127                     uint64_t Value) const {
    128       assert(0 && "UNIMP");
    129     }
    130 
    131     MCObjectWriter *createObjectWriter(raw_ostream &OS) const {
    132       bool is64 = getPointerSize() == 8;
    133       return createMachObjectWriter(new PPCMachObjectWriter(
    134                                       /*Is64Bit=*/is64,
    135                                       (is64 ? object::mach::CTM_PowerPC64 :
    136                                        object::mach::CTM_PowerPC),
    137                                       object::mach::CSPPC_ALL),
    138                                     OS, /*IsLittleEndian=*/false);
    139     }
    140 
    141     virtual bool doesSectionRequireSymbols(const MCSection &Section) const {
    142       return false;
    143     }
    144   };
    145 
    146   class ELFPPCAsmBackend : public PPCAsmBackend {
    147     Triple::OSType OSType;
    148   public:
    149     ELFPPCAsmBackend(const Target &T, Triple::OSType OSType) :
    150       PPCAsmBackend(T), OSType(OSType) { }
    151 
    152     void ApplyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
    153                     uint64_t Value) const {
    154       Value = adjustFixupValue(Fixup.getKind(), Value);
    155       if (!Value) return;           // Doesn't change encoding.
    156 
    157       unsigned Offset = Fixup.getOffset();
    158 
    159       // For each byte of the fragment that the fixup touches, mask in the bits from
    160       // the fixup value. The Value has been "split up" into the appropriate
    161       // bitfields above.
    162       for (unsigned i = 0; i != 4; ++i)
    163         Data[Offset + i] |= uint8_t((Value >> ((4 - i - 1)*8)) & 0xff);
    164     }
    165 
    166     MCObjectWriter *createObjectWriter(raw_ostream &OS) const {
    167       bool is64 = getPointerSize() == 8;
    168       return createELFObjectWriter(new PPCELFObjectWriter(
    169                                       /*Is64Bit=*/is64,
    170                                       OSType,
    171                                       is64 ? ELF::EM_PPC64 : ELF::EM_PPC,
    172                                       /*addend*/ true, /*isLittleEndian*/ false),
    173                                    OS, /*IsLittleEndian=*/false);
    174     }
    175 
    176     virtual bool doesSectionRequireSymbols(const MCSection &Section) const {
    177       return false;
    178     }
    179   };
    180 
    181 } // end anonymous namespace
    182 
    183 
    184 
    185 
    186 MCAsmBackend *llvm::createPPCAsmBackend(const Target &T, StringRef TT) {
    187   if (Triple(TT).isOSDarwin())
    188     return new DarwinPPCAsmBackend(T);
    189 
    190   return new ELFPPCAsmBackend(T, Triple(TT).getOS());
    191 }
    192