Home | History | Annotate | Download | only in MCTargetDesc
      1 //===-- MipsELFObjectWriter.cpp - Mips 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/MipsBaseInfo.h"
     11 #include "MCTargetDesc/MipsFixupKinds.h"
     12 #include "MCTargetDesc/MipsMCTargetDesc.h"
     13 #include "llvm/MC/MCAssembler.h"
     14 #include "llvm/MC/MCELFObjectWriter.h"
     15 #include "llvm/MC/MCExpr.h"
     16 #include "llvm/MC/MCSection.h"
     17 #include "llvm/MC/MCValue.h"
     18 #include "llvm/Support/ErrorHandling.h"
     19 #include <list>
     20 
     21 using namespace llvm;
     22 
     23 namespace {
     24   struct RelEntry {
     25     RelEntry(const ELFRelocationEntry &R, const MCSymbol *S, int64_t O) :
     26       Reloc(R), Sym(S), Offset(O) {}
     27     ELFRelocationEntry Reloc;
     28     const MCSymbol *Sym;
     29     int64_t Offset;
     30   };
     31 
     32   typedef std::list<RelEntry> RelLs;
     33   typedef RelLs::iterator RelLsIter;
     34 
     35   class MipsELFObjectWriter : public MCELFObjectTargetWriter {
     36   public:
     37     MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI);
     38 
     39     virtual ~MipsELFObjectWriter();
     40 
     41     virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
     42                                   bool IsPCRel, bool IsRelocWithSymbol,
     43                                   int64_t Addend) const;
     44     virtual unsigned getEFlags() const;
     45     virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm,
     46                                            const MCValue &Target,
     47                                            const MCFragment &F,
     48                                            const MCFixup &Fixup,
     49                                            bool IsPCRel) const;
     50     virtual void sortRelocs(const MCAssembler &Asm,
     51                             std::vector<ELFRelocationEntry> &Relocs);
     52   };
     53 }
     54 
     55 MipsELFObjectWriter::MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI)
     56   : MCELFObjectTargetWriter(_is64Bit, OSABI, ELF::EM_MIPS,
     57                             /*HasRelocationAddend*/ false) {}
     58 
     59 MipsELFObjectWriter::~MipsELFObjectWriter() {}
     60 
     61 // FIXME: get the real EABI Version from the Subtarget class.
     62 unsigned MipsELFObjectWriter::getEFlags() const {
     63 
     64   // FIXME: We can't tell if we are PIC (dynamic) or CPIC (static)
     65   unsigned Flag = ELF::EF_MIPS_NOREORDER;
     66 
     67   if (is64Bit())
     68     Flag |= ELF::EF_MIPS_ARCH_64R2;
     69   else
     70     Flag |= ELF::EF_MIPS_ARCH_32R2;
     71   return Flag;
     72 }
     73 
     74 const MCSymbol *MipsELFObjectWriter::ExplicitRelSym(const MCAssembler &Asm,
     75                                                     const MCValue &Target,
     76                                                     const MCFragment &F,
     77                                                     const MCFixup &Fixup,
     78                                                     bool IsPCRel) const {
     79   assert(Target.getSymA() && "SymA cannot be 0.");
     80   const MCSymbol &Sym = Target.getSymA()->getSymbol().AliasedSymbol();
     81 
     82   if (Sym.getSection().getKind().isMergeableCString() ||
     83       Sym.getSection().getKind().isMergeableConst())
     84     return &Sym;
     85 
     86   return NULL;
     87 }
     88 
     89 unsigned MipsELFObjectWriter::GetRelocType(const MCValue &Target,
     90                                            const MCFixup &Fixup,
     91                                            bool IsPCRel,
     92                                            bool IsRelocWithSymbol,
     93                                            int64_t Addend) const {
     94   // determine the type of the relocation
     95   unsigned Type = (unsigned)ELF::R_MIPS_NONE;
     96   unsigned Kind = (unsigned)Fixup.getKind();
     97 
     98   switch (Kind) {
     99   default:
    100     llvm_unreachable("invalid fixup kind!");
    101   case FK_Data_4:
    102     Type = ELF::R_MIPS_32;
    103     break;
    104   case FK_GPRel_4:
    105     Type = ELF::R_MIPS_GPREL32;
    106     break;
    107   case Mips::fixup_Mips_GPREL16:
    108     Type = ELF::R_MIPS_GPREL16;
    109     break;
    110   case Mips::fixup_Mips_26:
    111     Type = ELF::R_MIPS_26;
    112     break;
    113   case Mips::fixup_Mips_CALL16:
    114     Type = ELF::R_MIPS_CALL16;
    115     break;
    116   case Mips::fixup_Mips_GOT_Global:
    117   case Mips::fixup_Mips_GOT_Local:
    118     Type = ELF::R_MIPS_GOT16;
    119     break;
    120   case Mips::fixup_Mips_HI16:
    121     Type = ELF::R_MIPS_HI16;
    122     break;
    123   case Mips::fixup_Mips_LO16:
    124     Type = ELF::R_MIPS_LO16;
    125     break;
    126   case Mips::fixup_Mips_TLSGD:
    127     Type = ELF::R_MIPS_TLS_GD;
    128     break;
    129   case Mips::fixup_Mips_GOTTPREL:
    130     Type = ELF::R_MIPS_TLS_GOTTPREL;
    131     break;
    132   case Mips::fixup_Mips_TPREL_HI:
    133     Type = ELF::R_MIPS_TLS_TPREL_HI16;
    134     break;
    135   case Mips::fixup_Mips_TPREL_LO:
    136     Type = ELF::R_MIPS_TLS_TPREL_LO16;
    137     break;
    138   case Mips::fixup_Mips_TLSLDM:
    139     Type = ELF::R_MIPS_TLS_LDM;
    140     break;
    141   case Mips::fixup_Mips_DTPREL_HI:
    142     Type = ELF::R_MIPS_TLS_DTPREL_HI16;
    143     break;
    144   case Mips::fixup_Mips_DTPREL_LO:
    145     Type = ELF::R_MIPS_TLS_DTPREL_LO16;
    146     break;
    147   case Mips::fixup_Mips_Branch_PCRel:
    148   case Mips::fixup_Mips_PC16:
    149     Type = ELF::R_MIPS_PC16;
    150     break;
    151   }
    152 
    153   return Type;
    154 }
    155 
    156 // Return true if R is either a GOT16 against a local symbol or HI16.
    157 static bool NeedsMatchingLo(const MCAssembler &Asm, const RelEntry &R) {
    158   if (!R.Sym)
    159     return false;
    160 
    161   MCSymbolData &SD = Asm.getSymbolData(R.Sym->AliasedSymbol());
    162 
    163   return ((R.Reloc.Type == ELF::R_MIPS_GOT16) && !SD.isExternal()) ||
    164     (R.Reloc.Type == ELF::R_MIPS_HI16);
    165 }
    166 
    167 static bool HasMatchingLo(const MCAssembler &Asm, RelLsIter I, RelLsIter Last) {
    168   if (I == Last)
    169     return false;
    170 
    171   RelLsIter Hi = I++;
    172 
    173   return (I->Reloc.Type == ELF::R_MIPS_LO16) && (Hi->Sym == I->Sym) &&
    174     (Hi->Offset == I->Offset);
    175 }
    176 
    177 static bool HasSameSymbol(const RelEntry &R0, const RelEntry &R1) {
    178   return R0.Sym == R1.Sym;
    179 }
    180 
    181 static int CompareOffset(const RelEntry &R0, const RelEntry &R1) {
    182   return (R0.Offset > R1.Offset) ? 1 : ((R0.Offset == R1.Offset) ? 0 : -1);
    183 }
    184 
    185 void MipsELFObjectWriter::sortRelocs(const MCAssembler &Asm,
    186                                      std::vector<ELFRelocationEntry> &Relocs) {
    187   // Call the defualt function first. Relocations are sorted in descending
    188   // order of r_offset.
    189   MCELFObjectTargetWriter::sortRelocs(Asm, Relocs);
    190 
    191   RelLs RelocLs;
    192   std::vector<RelLsIter> Unmatched;
    193 
    194   // Fill RelocLs. Traverse Relocs backwards so that relocations in RelocLs
    195   // are in ascending order of r_offset.
    196   for (std::vector<ELFRelocationEntry>::reverse_iterator R = Relocs.rbegin();
    197        R != Relocs.rend(); ++R) {
    198      std::pair<const MCSymbolRefExpr*, int64_t> P =
    199        MipsGetSymAndOffset(*R->Fixup);
    200      RelocLs.push_back(RelEntry(*R, P.first ? &P.first->getSymbol() : 0,
    201                                 P.second));
    202   }
    203 
    204   // Get list of unmatched HI16 and GOT16.
    205   for (RelLsIter R = RelocLs.begin(); R != RelocLs.end(); ++R)
    206     if (NeedsMatchingLo(Asm, *R) && !HasMatchingLo(Asm, R, --RelocLs.end()))
    207       Unmatched.push_back(R);
    208 
    209   // Insert unmatched HI16 and GOT16 immediately before their matching LO16.
    210   for (std::vector<RelLsIter>::iterator U = Unmatched.begin();
    211        U != Unmatched.end(); ++U) {
    212     RelLsIter LoPos = RelocLs.end(), HiPos = *U;
    213     bool MatchedLo = false;
    214 
    215     for (RelLsIter R = RelocLs.begin(); R != RelocLs.end(); ++R) {
    216       if ((R->Reloc.Type == ELF::R_MIPS_LO16) && HasSameSymbol(*HiPos, *R) &&
    217           (CompareOffset(*R, *HiPos) >= 0) &&
    218           ((LoPos == RelocLs.end()) || ((CompareOffset(*R, *LoPos) < 0)) ||
    219            (!MatchedLo && !CompareOffset(*R, *LoPos))))
    220         LoPos = R;
    221 
    222       MatchedLo = NeedsMatchingLo(Asm, *R) &&
    223         HasMatchingLo(Asm, R, --RelocLs.end());
    224     }
    225 
    226     // If a matching LoPos was found, move HiPos and insert it before LoPos.
    227     // Make the offsets of HiPos and LoPos match.
    228     if (LoPos != RelocLs.end()) {
    229       HiPos->Offset = LoPos->Offset;
    230       RelocLs.insert(LoPos, *HiPos);
    231       RelocLs.erase(HiPos);
    232     }
    233   }
    234 
    235   // Put the sorted list back in reverse order.
    236   assert(Relocs.size() == RelocLs.size());
    237   unsigned I = RelocLs.size();
    238 
    239   for (RelLsIter R = RelocLs.begin(); R != RelocLs.end(); ++R)
    240     Relocs[--I] = R->Reloc;
    241 }
    242 
    243 MCObjectWriter *llvm::createMipsELFObjectWriter(raw_ostream &OS,
    244                                                 uint8_t OSABI,
    245                                                 bool IsLittleEndian,
    246                                                 bool Is64Bit) {
    247   MCELFObjectTargetWriter *MOTW = new MipsELFObjectWriter(Is64Bit, OSABI);
    248   return createELFObjectWriter(MOTW, OS, IsLittleEndian);
    249 }
    250