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