Home | History | Annotate | Download | only in Mips
      1 //===- MipsAbiFlags.cpp ---------------------------------------------------===//
      2 //
      3 //                     The MCLinker Project
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 #include "MipsAbiFlags.h"
     10 
     11 #include "mcld/Fragment/RegionFragment.h"
     12 #include "mcld/LD/LDSection.h"
     13 #include "mcld/LD/SectionData.h"
     14 #include "mcld/MC/Input.h"
     15 #include "mcld/Support/MsgHandling.h"
     16 
     17 #include <llvm/Support/Casting.h>
     18 #include <llvm/Support/MipsABIFlags.h>
     19 
     20 namespace mcld {
     21 
     22 // SHT_MIPS_ABIFLAGS has the same format for both 32/64-bit targets.
     23 // We do not support linking of big-endian code now so 32-bit LE
     24 // combination is Okay.
     25 typedef llvm::object::ELFType<llvm::support::little, false> ELF32LE;
     26 typedef llvm::object::Elf_Mips_ABIFlags<ELF32LE> ElfMipsAbiFlags;
     27 
     28 uint64_t MipsAbiFlags::size() {
     29   return sizeof(ElfMipsAbiFlags);
     30 }
     31 
     32 uint64_t MipsAbiFlags::emit(const MipsAbiFlags& pInfo, MemoryRegion& pRegion) {
     33   auto* buf = reinterpret_cast<ElfMipsAbiFlags*>(pRegion.begin());
     34   buf->version = 0;
     35   buf->isa_level = pInfo.m_IsaLevel;
     36   buf->isa_rev = pInfo.m_IsaRev;
     37   buf->gpr_size = pInfo.m_GprSize;
     38   buf->cpr1_size = pInfo.m_Cpr1Size;
     39   buf->cpr2_size = pInfo.m_Cpr2Size;
     40   buf->fp_abi = pInfo.m_FpAbi;
     41   buf->isa_ext = pInfo.m_IsaExt;
     42   buf->ases = pInfo.m_Ases;
     43   buf->flags1 = pInfo.m_Flags1;
     44   buf->flags2 = 0;
     45   return size();
     46 }
     47 
     48 bool MipsAbiFlags::fillBySection(const Input& pInput, const LDSection& pSection,
     49                                  MipsAbiFlags& mipsAbi) {
     50   assert(pSection.type() == llvm::ELF::SHT_MIPS_ABIFLAGS &&
     51          "Unexpected section type");
     52 
     53   if (pSection.size() != size()) {
     54     error(diag::error_Mips_abiflags_invalid_size) << pInput.name();
     55     return false;
     56   }
     57 
     58   const SectionData* secData = pSection.getSectionData();
     59   if (secData->size() != 2 || !llvm::isa<RegionFragment>(secData->front())) {
     60     error(diag::error_Mips_abiflags_invalid_size) << pInput.name();
     61     return false;
     62   }
     63 
     64   const auto& frag = llvm::cast<RegionFragment>(secData->front());
     65   auto* data =
     66       reinterpret_cast<const ElfMipsAbiFlags*>(frag.getRegion().data());
     67   if (data->version != 0) {
     68     error(diag::error_Mips_abiflags_invalid_version) << int(data->version)
     69                                                      << pInput.name();
     70     return false;
     71   }
     72 
     73   mipsAbi.m_IsaLevel = data->isa_level;
     74   mipsAbi.m_IsaRev = data->isa_rev;
     75   mipsAbi.m_GprSize = data->gpr_size;
     76   mipsAbi.m_Cpr1Size = data->cpr1_size;
     77   mipsAbi.m_Cpr2Size = data->cpr2_size;
     78   mipsAbi.m_FpAbi = data->fp_abi;
     79   mipsAbi.m_IsaExt = data->isa_ext;
     80   mipsAbi.m_Ases = data->ases;
     81   mipsAbi.m_Flags1 = data->flags1;
     82   return true;
     83 }
     84 
     85 static unsigned getIsaLevel(uint64_t flags) {
     86   switch (flags & llvm::ELF::EF_MIPS_ARCH) {
     87     case llvm::ELF::EF_MIPS_ARCH_1:
     88       return 1;
     89     case llvm::ELF::EF_MIPS_ARCH_2:
     90       return 2;
     91     case llvm::ELF::EF_MIPS_ARCH_3:
     92       return 3;
     93     case llvm::ELF::EF_MIPS_ARCH_4:
     94       return 4;
     95     case llvm::ELF::EF_MIPS_ARCH_5:
     96       return 5;
     97     case llvm::ELF::EF_MIPS_ARCH_32:
     98     case llvm::ELF::EF_MIPS_ARCH_32R2:
     99     case llvm::ELF::EF_MIPS_ARCH_32R6:
    100       return 32;
    101     case llvm::ELF::EF_MIPS_ARCH_64:
    102     case llvm::ELF::EF_MIPS_ARCH_64R2:
    103     case llvm::ELF::EF_MIPS_ARCH_64R6:
    104       return 64;
    105     default:
    106       // We check ELF flags and show error in case
    107       // of unknown value in other place.
    108       llvm_unreachable("Unknown MIPS architecture flag");
    109   }
    110 }
    111 
    112 static unsigned getIsaRev(uint64_t flags) {
    113   switch (flags & llvm::ELF::EF_MIPS_ARCH) {
    114     case llvm::ELF::EF_MIPS_ARCH_1:
    115     case llvm::ELF::EF_MIPS_ARCH_2:
    116     case llvm::ELF::EF_MIPS_ARCH_3:
    117     case llvm::ELF::EF_MIPS_ARCH_4:
    118     case llvm::ELF::EF_MIPS_ARCH_5:
    119       return 0;
    120     case llvm::ELF::EF_MIPS_ARCH_32:
    121     case llvm::ELF::EF_MIPS_ARCH_64:
    122       return 1;
    123     case llvm::ELF::EF_MIPS_ARCH_32R2:
    124     case llvm::ELF::EF_MIPS_ARCH_64R2:
    125       return 2;
    126     case llvm::ELF::EF_MIPS_ARCH_32R6:
    127     case llvm::ELF::EF_MIPS_ARCH_64R6:
    128       return 6;
    129     default:
    130       // We check ELF flags and show error in case
    131       // of unknown value in other place.
    132       llvm_unreachable("Unknown MIPS architecture flag");
    133   }
    134 }
    135 
    136 static unsigned getIsaExt(uint64_t flags) {
    137   switch (flags & llvm::ELF::EF_MIPS_MACH) {
    138     case 0:
    139       return llvm::Mips::AFL_EXT_NONE;
    140     case llvm::ELF::EF_MIPS_MACH_3900: return llvm::Mips::AFL_EXT_3900;
    141     case llvm::ELF::EF_MIPS_MACH_4010: return llvm::Mips::AFL_EXT_4010;
    142     case llvm::ELF::EF_MIPS_MACH_4100: return llvm::Mips::AFL_EXT_4010;
    143     case llvm::ELF::EF_MIPS_MACH_4111: return llvm::Mips::AFL_EXT_4111;
    144     case llvm::ELF::EF_MIPS_MACH_4120: return llvm::Mips::AFL_EXT_4120;
    145     case llvm::ELF::EF_MIPS_MACH_4650: return llvm::Mips::AFL_EXT_4650;
    146     case llvm::ELF::EF_MIPS_MACH_5400: return llvm::Mips::AFL_EXT_5400;
    147     case llvm::ELF::EF_MIPS_MACH_5500: return llvm::Mips::AFL_EXT_5500;
    148     case llvm::ELF::EF_MIPS_MACH_5900: return llvm::Mips::AFL_EXT_5900;
    149     case llvm::ELF::EF_MIPS_MACH_SB1: return llvm::Mips::AFL_EXT_SB1;
    150     case llvm::ELF::EF_MIPS_MACH_LS2E: return llvm::Mips::AFL_EXT_LOONGSON_2E;
    151     case llvm::ELF::EF_MIPS_MACH_LS2F: return llvm::Mips::AFL_EXT_LOONGSON_2F;
    152     case llvm::ELF::EF_MIPS_MACH_LS3A: return llvm::Mips::AFL_EXT_LOONGSON_3A;
    153     case llvm::ELF::EF_MIPS_MACH_OCTEON3: return llvm::Mips::AFL_EXT_OCTEON3;
    154     case llvm::ELF::EF_MIPS_MACH_OCTEON2: return llvm::Mips::AFL_EXT_OCTEON2;
    155     case llvm::ELF::EF_MIPS_MACH_OCTEON: return llvm::Mips::AFL_EXT_OCTEON;
    156     case llvm::ELF::EF_MIPS_MACH_XLR: return llvm::Mips::AFL_EXT_XLR;
    157     default:
    158       // We check ELF flags and show error in case
    159       // of unknown value in other place.
    160       llvm_unreachable("Unknown MIPS extension flag");
    161   }
    162 }
    163 
    164 static bool is32BitElfFlags(uint64_t flags) {
    165   if (flags & llvm::ELF::EF_MIPS_32BITMODE)
    166     return true;
    167 
    168   uint64_t arch = flags & llvm::ELF::EF_MIPS_ARCH;
    169   if (arch == llvm::ELF::EF_MIPS_ARCH_1 ||
    170       arch == llvm::ELF::EF_MIPS_ARCH_2 ||
    171       arch == llvm::ELF::EF_MIPS_ARCH_32 ||
    172       arch == llvm::ELF::EF_MIPS_ARCH_32R2 ||
    173       arch == llvm::ELF::EF_MIPS_ARCH_32R6)
    174     return true;
    175 
    176   uint64_t abi = flags & llvm::ELF::EF_MIPS_ABI;
    177   if (abi == llvm::ELF::EF_MIPS_ABI_O32 || abi == llvm::ELF::EF_MIPS_ABI_EABI32)
    178     return true;
    179 
    180   return false;
    181 }
    182 
    183 bool MipsAbiFlags::fillByElfFlags(const Input& pInput, uint64_t elfFlags,
    184                                   MipsAbiFlags& mipsAbi) {
    185   mipsAbi.m_IsaLevel = getIsaLevel(elfFlags);
    186   mipsAbi.m_IsaRev = getIsaRev(elfFlags);
    187   mipsAbi.m_IsaExt = getIsaExt(elfFlags);
    188 
    189   mipsAbi.m_GprSize = is32BitElfFlags(elfFlags) ?
    190                       llvm::Mips::AFL_REG_32 : llvm::Mips::AFL_REG_64;
    191 
    192   mipsAbi.m_Cpr1Size = llvm::Mips::AFL_REG_NONE;
    193   mipsAbi.m_Cpr2Size = llvm::Mips::AFL_REG_NONE;
    194   mipsAbi.m_FpAbi = llvm::Mips::Val_GNU_MIPS_ABI_FP_ANY;
    195 
    196   mipsAbi.m_Ases = 0;
    197   if (elfFlags & llvm::ELF::EF_MIPS_MICROMIPS)
    198     mipsAbi.m_Ases |= llvm::Mips::AFL_ASE_MICROMIPS;
    199   if (elfFlags & llvm::ELF::EF_MIPS_ARCH_ASE_M16)
    200     mipsAbi.m_Ases |= llvm::Mips::AFL_ASE_MIPS16;
    201   if (elfFlags & llvm::ELF::EF_MIPS_ARCH_ASE_MDMX)
    202     mipsAbi.m_Ases |= llvm::Mips::AFL_ASE_MDMX;
    203 
    204   mipsAbi.m_Flags1 = 0;
    205   return true;
    206 }
    207 
    208 bool MipsAbiFlags::isCompatible(const Input& pInput, const MipsAbiFlags& elf,
    209                                 const MipsAbiFlags& abi) {
    210   unsigned isaRev = abi.m_IsaRev;
    211   if (isaRev == 3 || isaRev == 5)
    212     isaRev = 2;
    213   if (abi.m_IsaLevel != elf.m_IsaLevel || isaRev != elf.m_IsaRev) {
    214     warning(diag::warn_Mips_isa_incompatible) << pInput.name();
    215     return false;
    216   }
    217   if (abi.m_IsaExt != elf.m_IsaExt) {
    218     warning(diag::warn_Mips_isa_ext_incompatible) << pInput.name();
    219     return false;
    220   }
    221   if ((abi.m_Ases & elf.m_Ases) != elf.m_Ases) {
    222     warning(diag::warn_Mips_ases_incompatible) << pInput.name();
    223     return false;
    224   }
    225   return true;
    226 }
    227 
    228 static bool isFpGreater(uint64_t fpA, uint64_t fpB) {
    229   if (fpB == llvm::Mips::Val_GNU_MIPS_ABI_FP_ANY)
    230     return true;
    231   if (fpB == llvm::Mips::Val_GNU_MIPS_ABI_FP_64A &&
    232       fpA == llvm::Mips::Val_GNU_MIPS_ABI_FP_64)
    233     return true;
    234   if (fpB != llvm::Mips::Val_GNU_MIPS_ABI_FP_XX)
    235     return false;
    236   return fpA == llvm::Mips::Val_GNU_MIPS_ABI_FP_DOUBLE ||
    237          fpA == llvm::Mips::Val_GNU_MIPS_ABI_FP_64 ||
    238          fpA == llvm::Mips::Val_GNU_MIPS_ABI_FP_64A;
    239 }
    240 
    241 static llvm::StringRef getFpAbiName(uint64_t abi) {
    242   switch (abi) {
    243     case llvm::Mips::Val_GNU_MIPS_ABI_FP_ANY:
    244       return "<any>";
    245     case llvm::Mips::Val_GNU_MIPS_ABI_FP_DOUBLE:
    246       return "-mdouble-float";
    247     case llvm::Mips::Val_GNU_MIPS_ABI_FP_SINGLE:
    248       return "-msingle-float";
    249     case llvm::Mips::Val_GNU_MIPS_ABI_FP_SOFT:
    250       return "-msoft-float";
    251     case llvm::Mips::Val_GNU_MIPS_ABI_FP_OLD_64:
    252       return "-mips32r2 -mfp64 (old)";
    253     case llvm::Mips::Val_GNU_MIPS_ABI_FP_XX:
    254       return "-mfpxx";
    255     case llvm::Mips::Val_GNU_MIPS_ABI_FP_64:
    256       return "-mgp32 -mfp64";
    257     case llvm::Mips::Val_GNU_MIPS_ABI_FP_64A:
    258       return "-mgp32 -mfp64 -mno-odd-spreg";
    259     default:
    260       return "<unknown>";
    261   }
    262 }
    263 
    264 bool MipsAbiFlags::merge(const Input& pInput, MipsAbiFlags& oldFlags,
    265                          const MipsAbiFlags& newFlags) {
    266   if (oldFlags.m_IsaLevel == 0) {
    267     oldFlags = newFlags;
    268     return true;
    269   }
    270 
    271   if (newFlags.m_IsaLevel > oldFlags.m_IsaLevel)
    272     oldFlags.m_IsaLevel = newFlags.m_IsaLevel;
    273 
    274   oldFlags.m_IsaRev = std::max(oldFlags.m_IsaRev, newFlags.m_IsaRev);
    275   oldFlags.m_GprSize = std::max(oldFlags.m_GprSize, newFlags.m_GprSize);
    276   oldFlags.m_Cpr1Size = std::max(oldFlags.m_Cpr1Size, newFlags.m_Cpr1Size);
    277   oldFlags.m_Cpr2Size = std::max(oldFlags.m_Cpr2Size, newFlags.m_Cpr2Size);
    278   oldFlags.m_Ases |= newFlags.m_Ases;
    279   oldFlags.m_Flags1 |= newFlags.m_Flags1;
    280 
    281   if (oldFlags.m_FpAbi == newFlags.m_FpAbi)
    282     return true;
    283 
    284   if (isFpGreater(newFlags.m_FpAbi, oldFlags.m_FpAbi)) {
    285     oldFlags.m_FpAbi = newFlags.m_FpAbi;
    286     return true;
    287   }
    288 
    289   if (isFpGreater(oldFlags.m_FpAbi, newFlags.m_FpAbi))
    290     return true;
    291 
    292   llvm::StringRef oldAbiName = getFpAbiName(oldFlags.m_FpAbi);
    293   llvm::StringRef newAbiName = getFpAbiName(newFlags.m_FpAbi);
    294   warning(diag::warn_Mips_fp_abi_incompatible) << oldAbiName << newAbiName
    295                                                << pInput.name();
    296   return false;
    297 }
    298 }  // namespace mcld
    299