Home | History | Annotate | Download | only in MCTargetDesc
      1 //===-- SystemZMCObjectWriter.cpp - SystemZ ELF 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/SystemZMCTargetDesc.h"
     11 #include "MCTargetDesc/SystemZMCFixups.h"
     12 #include "llvm/MC/MCELFObjectWriter.h"
     13 #include "llvm/MC/MCExpr.h"
     14 #include "llvm/MC/MCValue.h"
     15 
     16 using namespace llvm;
     17 
     18 namespace {
     19 class SystemZObjectWriter : public MCELFObjectTargetWriter {
     20 public:
     21   SystemZObjectWriter(uint8_t OSABI);
     22 
     23   virtual ~SystemZObjectWriter();
     24 
     25 protected:
     26   // Override MCELFObjectTargetWriter.
     27   virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
     28                                 bool IsPCRel, bool IsRelocWithSymbol,
     29                                 int64_t Addend) const LLVM_OVERRIDE;
     30   virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm,
     31                                          const MCValue &Target,
     32                                          const MCFragment &F,
     33                                          const MCFixup &Fixup,
     34                                          bool IsPCRel) const LLVM_OVERRIDE;
     35 };
     36 } // end anonymouse namespace
     37 
     38 SystemZObjectWriter::SystemZObjectWriter(uint8_t OSABI)
     39   : MCELFObjectTargetWriter(/*Is64Bit=*/true, OSABI, ELF::EM_S390,
     40                             /*HasRelocationAddend=*/ true) {}
     41 
     42 SystemZObjectWriter::~SystemZObjectWriter() {
     43 }
     44 
     45 // Return the relocation type for an absolute value of MCFixupKind Kind.
     46 static unsigned getAbsoluteReloc(unsigned Kind) {
     47   switch (Kind) {
     48   case FK_Data_1: return ELF::R_390_8;
     49   case FK_Data_2: return ELF::R_390_16;
     50   case FK_Data_4: return ELF::R_390_32;
     51   case FK_Data_8: return ELF::R_390_64;
     52   }
     53   llvm_unreachable("Unsupported absolute address");
     54 }
     55 
     56 // Return the relocation type for a PC-relative value of MCFixupKind Kind.
     57 static unsigned getPCRelReloc(unsigned Kind) {
     58   switch (Kind) {
     59   case FK_Data_2:                return ELF::R_390_PC16;
     60   case FK_Data_4:                return ELF::R_390_PC32;
     61   case FK_Data_8:                return ELF::R_390_PC64;
     62   case SystemZ::FK_390_PC16DBL:  return ELF::R_390_PC16DBL;
     63   case SystemZ::FK_390_PC32DBL:  return ELF::R_390_PC32DBL;
     64   case SystemZ::FK_390_PLT16DBL: return ELF::R_390_PLT16DBL;
     65   case SystemZ::FK_390_PLT32DBL: return ELF::R_390_PLT32DBL;
     66   }
     67   llvm_unreachable("Unsupported PC-relative address");
     68 }
     69 
     70 // Return the R_390_TLS_LE* relocation type for MCFixupKind Kind.
     71 static unsigned getTLSLEReloc(unsigned Kind) {
     72   switch (Kind) {
     73   case FK_Data_4: return ELF::R_390_TLS_LE32;
     74   case FK_Data_8: return ELF::R_390_TLS_LE64;
     75   }
     76   llvm_unreachable("Unsupported absolute address");
     77 }
     78 
     79 // Return the PLT relocation counterpart of MCFixupKind Kind.
     80 static unsigned getPLTReloc(unsigned Kind) {
     81   switch (Kind) {
     82   case SystemZ::FK_390_PC16DBL: return ELF::R_390_PLT16DBL;
     83   case SystemZ::FK_390_PC32DBL: return ELF::R_390_PLT32DBL;
     84   }
     85   llvm_unreachable("Unsupported absolute address");
     86 }
     87 
     88 unsigned SystemZObjectWriter::GetRelocType(const MCValue &Target,
     89                                            const MCFixup &Fixup,
     90                                            bool IsPCRel,
     91                                            bool IsRelocWithSymbol,
     92                                            int64_t Addend) const {
     93   MCSymbolRefExpr::VariantKind Modifier = (Target.isAbsolute() ?
     94                                            MCSymbolRefExpr::VK_None :
     95                                            Target.getSymA()->getKind());
     96   unsigned Kind = Fixup.getKind();
     97   switch (Modifier) {
     98   case MCSymbolRefExpr::VK_None:
     99     if (IsPCRel)
    100       return getPCRelReloc(Kind);
    101     return getAbsoluteReloc(Kind);
    102 
    103   case MCSymbolRefExpr::VK_NTPOFF:
    104     assert(!IsPCRel && "NTPOFF shouldn't be PC-relative");
    105     return getTLSLEReloc(Kind);
    106 
    107   case MCSymbolRefExpr::VK_GOT:
    108     if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL)
    109       return ELF::R_390_GOTENT;
    110     llvm_unreachable("Only PC-relative GOT accesses are supported for now");
    111 
    112   case MCSymbolRefExpr::VK_PLT:
    113     assert(IsPCRel && "@PLT shouldt be PC-relative");
    114     return getPLTReloc(Kind);
    115 
    116   default:
    117     llvm_unreachable("Modifier not supported");
    118   }
    119 }
    120 
    121 const MCSymbol *SystemZObjectWriter::ExplicitRelSym(const MCAssembler &Asm,
    122                                                     const MCValue &Target,
    123                                                     const MCFragment &F,
    124                                                     const MCFixup &Fixup,
    125                                                     bool IsPCRel) const {
    126   // The addend in a PC-relative R_390_* relocation is always applied to
    127   // the PC-relative part of the address.  If some kind of indirection
    128   // is applied to the symbol first, we can't use an addend there too.
    129   if (!Target.isAbsolute() &&
    130       Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None &&
    131       IsPCRel)
    132     return &Target.getSymA()->getSymbol().AliasedSymbol();
    133   return NULL;
    134 }
    135 
    136 MCObjectWriter *llvm::createSystemZObjectWriter(raw_ostream &OS,
    137                                                 uint8_t OSABI) {
    138   MCELFObjectTargetWriter *MOTW = new SystemZObjectWriter(OSABI);
    139   return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/false);
    140 }
    141