| 1 | //===- MipsArchTree.cpp --------------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===---------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file contains a helper function for the Writer. |
| 10 | // |
| 11 | //===---------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "InputFiles.h" |
| 14 | #include "SymbolTable.h" |
| 15 | #include "Target.h" |
| 16 | |
| 17 | #include "llvm/BinaryFormat/ELF.h" |
| 18 | #include "llvm/Support/MipsABIFlags.h" |
| 19 | |
| 20 | using namespace llvm; |
| 21 | using namespace llvm::object; |
| 22 | using namespace llvm::ELF; |
| 23 | |
| 24 | using namespace lld; |
| 25 | using namespace lld::elf; |
| 26 | |
| 27 | namespace { |
| 28 | struct ArchTreeEdge { |
| 29 | uint32_t child; |
| 30 | uint32_t parent; |
| 31 | }; |
| 32 | |
| 33 | struct FileFlags { |
| 34 | InputFile *file; |
| 35 | uint32_t flags; |
| 36 | }; |
| 37 | } // namespace |
| 38 | |
| 39 | static StringRef getAbiName(uint32_t flags) { |
| 40 | switch (flags) { |
| 41 | case 0: |
| 42 | return "n64" ; |
| 43 | case EF_MIPS_ABI2: |
| 44 | return "n32" ; |
| 45 | case EF_MIPS_ABI_O32: |
| 46 | return "o32" ; |
| 47 | case EF_MIPS_ABI_O64: |
| 48 | return "o64" ; |
| 49 | case EF_MIPS_ABI_EABI32: |
| 50 | return "eabi32" ; |
| 51 | case EF_MIPS_ABI_EABI64: |
| 52 | return "eabi64" ; |
| 53 | default: |
| 54 | return "unknown" ; |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | static StringRef getNanName(bool isNan2008) { |
| 59 | return isNan2008 ? "2008" : "legacy" ; |
| 60 | } |
| 61 | |
| 62 | static StringRef getFpName(bool isFp64) { return isFp64 ? "64" : "32" ; } |
| 63 | |
| 64 | static void checkFlags(Ctx &ctx, ArrayRef<FileFlags> files) { |
| 65 | assert(!files.empty() && "expected non-empty file list" ); |
| 66 | |
| 67 | uint32_t abi = files[0].flags & (EF_MIPS_ABI | EF_MIPS_ABI2); |
| 68 | bool nan = files[0].flags & EF_MIPS_NAN2008; |
| 69 | bool fp = files[0].flags & EF_MIPS_FP64; |
| 70 | |
| 71 | for (const FileFlags &f : files) { |
| 72 | if (ctx.arg.is64 && f.flags & EF_MIPS_MICROMIPS) |
| 73 | Err(ctx) << f.file << ": microMIPS 64-bit is not supported" ; |
| 74 | |
| 75 | uint32_t abi2 = f.flags & (EF_MIPS_ABI | EF_MIPS_ABI2); |
| 76 | if (abi != abi2) |
| 77 | Err(ctx) << f.file << ": ABI '" << getAbiName(flags: abi2) |
| 78 | << "' is incompatible with target ABI '" << getAbiName(flags: abi) |
| 79 | << "'" ; |
| 80 | |
| 81 | bool nan2 = f.flags & EF_MIPS_NAN2008; |
| 82 | if (nan != nan2) |
| 83 | Err(ctx) << f.file << ": -mnan=" << getNanName(isNan2008: nan2) |
| 84 | << " is incompatible with target -mnan=" << getNanName(isNan2008: nan); |
| 85 | |
| 86 | bool fp2 = f.flags & EF_MIPS_FP64; |
| 87 | if (fp != fp2) |
| 88 | Err(ctx) << f.file << ": -mfp" << getFpName(isFp64: fp2) |
| 89 | << " is incompatible with target -mfp" << getFpName(isFp64: fp); |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | static uint32_t getMiscFlags(ArrayRef<FileFlags> files) { |
| 94 | uint32_t ret = 0; |
| 95 | for (const FileFlags &f : files) |
| 96 | ret |= f.flags & |
| 97 | (EF_MIPS_ABI | EF_MIPS_ABI2 | EF_MIPS_ARCH_ASE | EF_MIPS_NOREORDER | |
| 98 | EF_MIPS_MICROMIPS | EF_MIPS_NAN2008 | EF_MIPS_32BITMODE); |
| 99 | return ret; |
| 100 | } |
| 101 | |
| 102 | static uint32_t getPicFlags(Ctx &ctx, ArrayRef<FileFlags> files) { |
| 103 | // Check PIC/non-PIC compatibility. |
| 104 | bool isPic = files[0].flags & (EF_MIPS_PIC | EF_MIPS_CPIC); |
| 105 | for (const FileFlags &f : files.slice(N: 1)) { |
| 106 | bool isPic2 = f.flags & (EF_MIPS_PIC | EF_MIPS_CPIC); |
| 107 | if (isPic && !isPic2) |
| 108 | Warn(ctx) << f.file << ": linking non-abicalls code with abicalls code " |
| 109 | << files[0].file; |
| 110 | if (!isPic && isPic2) |
| 111 | Warn(ctx) << f.file << ": linking abicalls code with non-abicalls code " |
| 112 | << files[0].file; |
| 113 | } |
| 114 | |
| 115 | // Compute the result PIC/non-PIC flag. |
| 116 | uint32_t ret = files[0].flags & (EF_MIPS_PIC | EF_MIPS_CPIC); |
| 117 | for (const FileFlags &f : files.slice(N: 1)) |
| 118 | ret &= f.flags & (EF_MIPS_PIC | EF_MIPS_CPIC); |
| 119 | |
| 120 | // PIC code is inherently CPIC and may not set CPIC flag explicitly. |
| 121 | if (ret & EF_MIPS_PIC) |
| 122 | ret |= EF_MIPS_CPIC; |
| 123 | return ret; |
| 124 | } |
| 125 | |
| 126 | static ArchTreeEdge archTree[] = { |
| 127 | // MIPS32R6 and MIPS64R6 are not compatible with other extensions |
| 128 | // MIPS64R2 extensions. |
| 129 | {.child: EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, .parent: EF_MIPS_ARCH_64R2}, |
| 130 | {.child: EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, .parent: EF_MIPS_ARCH_64R2}, |
| 131 | {.child: EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, .parent: EF_MIPS_ARCH_64R2}, |
| 132 | {.child: EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, .parent: EF_MIPS_ARCH_64R2}, |
| 133 | // MIPS64 extensions. |
| 134 | {.child: EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, .parent: EF_MIPS_ARCH_64}, |
| 135 | {.child: EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, .parent: EF_MIPS_ARCH_64}, |
| 136 | {.child: EF_MIPS_ARCH_64R2, .parent: EF_MIPS_ARCH_64}, |
| 137 | // MIPS V extensions. |
| 138 | {.child: EF_MIPS_ARCH_64, .parent: EF_MIPS_ARCH_5}, |
| 139 | // R5000 extensions. |
| 140 | {.child: EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, .parent: EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400}, |
| 141 | // MIPS IV extensions. |
| 142 | {.child: EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, .parent: EF_MIPS_ARCH_4}, |
| 143 | {.child: EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, .parent: EF_MIPS_ARCH_4}, |
| 144 | {.child: EF_MIPS_ARCH_5, .parent: EF_MIPS_ARCH_4}, |
| 145 | // VR4100 extensions. |
| 146 | {.child: EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, .parent: EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, |
| 147 | {.child: EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, .parent: EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, |
| 148 | // MIPS III extensions. |
| 149 | {.child: EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, .parent: EF_MIPS_ARCH_3}, |
| 150 | {.child: EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, .parent: EF_MIPS_ARCH_3}, |
| 151 | {.child: EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, .parent: EF_MIPS_ARCH_3}, |
| 152 | {.child: EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, .parent: EF_MIPS_ARCH_3}, |
| 153 | {.child: EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, .parent: EF_MIPS_ARCH_3}, |
| 154 | {.child: EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, .parent: EF_MIPS_ARCH_3}, |
| 155 | {.child: EF_MIPS_ARCH_4, .parent: EF_MIPS_ARCH_3}, |
| 156 | // MIPS32 extensions. |
| 157 | {.child: EF_MIPS_ARCH_32R2, .parent: EF_MIPS_ARCH_32}, |
| 158 | // MIPS II extensions. |
| 159 | {.child: EF_MIPS_ARCH_3, .parent: EF_MIPS_ARCH_2}, |
| 160 | {.child: EF_MIPS_ARCH_32, .parent: EF_MIPS_ARCH_2}, |
| 161 | // MIPS I extensions. |
| 162 | {.child: EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, .parent: EF_MIPS_ARCH_1}, |
| 163 | {.child: EF_MIPS_ARCH_2, .parent: EF_MIPS_ARCH_1}, |
| 164 | }; |
| 165 | |
| 166 | static bool isArchMatched(uint32_t newFlags, uint32_t res) { |
| 167 | if (newFlags == res) |
| 168 | return true; |
| 169 | if (newFlags == EF_MIPS_ARCH_32 && isArchMatched(newFlags: EF_MIPS_ARCH_64, res)) |
| 170 | return true; |
| 171 | if (newFlags == EF_MIPS_ARCH_32R2 && isArchMatched(newFlags: EF_MIPS_ARCH_64R2, res)) |
| 172 | return true; |
| 173 | for (const auto &edge : archTree) { |
| 174 | if (res == edge.child) { |
| 175 | res = edge.parent; |
| 176 | if (res == newFlags) |
| 177 | return true; |
| 178 | } |
| 179 | } |
| 180 | return false; |
| 181 | } |
| 182 | |
| 183 | static StringRef getMachName(uint32_t flags) { |
| 184 | switch (flags & EF_MIPS_MACH) { |
| 185 | case EF_MIPS_MACH_NONE: |
| 186 | return "" ; |
| 187 | case EF_MIPS_MACH_3900: |
| 188 | return "r3900" ; |
| 189 | case EF_MIPS_MACH_4010: |
| 190 | return "r4010" ; |
| 191 | case EF_MIPS_MACH_4100: |
| 192 | return "r4100" ; |
| 193 | case EF_MIPS_MACH_4650: |
| 194 | return "r4650" ; |
| 195 | case EF_MIPS_MACH_4120: |
| 196 | return "r4120" ; |
| 197 | case EF_MIPS_MACH_4111: |
| 198 | return "r4111" ; |
| 199 | case EF_MIPS_MACH_5400: |
| 200 | return "vr5400" ; |
| 201 | case EF_MIPS_MACH_5900: |
| 202 | return "vr5900" ; |
| 203 | case EF_MIPS_MACH_5500: |
| 204 | return "vr5500" ; |
| 205 | case EF_MIPS_MACH_9000: |
| 206 | return "rm9000" ; |
| 207 | case EF_MIPS_MACH_LS2E: |
| 208 | return "loongson2e" ; |
| 209 | case EF_MIPS_MACH_LS2F: |
| 210 | return "loongson2f" ; |
| 211 | case EF_MIPS_MACH_LS3A: |
| 212 | return "loongson3a" ; |
| 213 | case EF_MIPS_MACH_OCTEON: |
| 214 | return "octeon" ; |
| 215 | case EF_MIPS_MACH_OCTEON2: |
| 216 | return "octeon2" ; |
| 217 | case EF_MIPS_MACH_OCTEON3: |
| 218 | return "octeon3" ; |
| 219 | case EF_MIPS_MACH_SB1: |
| 220 | return "sb1" ; |
| 221 | case EF_MIPS_MACH_XLR: |
| 222 | return "xlr" ; |
| 223 | default: |
| 224 | return "unknown machine" ; |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | static StringRef getArchName(uint32_t flags) { |
| 229 | switch (flags & EF_MIPS_ARCH) { |
| 230 | case EF_MIPS_ARCH_1: |
| 231 | return "mips1" ; |
| 232 | case EF_MIPS_ARCH_2: |
| 233 | return "mips2" ; |
| 234 | case EF_MIPS_ARCH_3: |
| 235 | return "mips3" ; |
| 236 | case EF_MIPS_ARCH_4: |
| 237 | return "mips4" ; |
| 238 | case EF_MIPS_ARCH_5: |
| 239 | return "mips5" ; |
| 240 | case EF_MIPS_ARCH_32: |
| 241 | return "mips32" ; |
| 242 | case EF_MIPS_ARCH_64: |
| 243 | return "mips64" ; |
| 244 | case EF_MIPS_ARCH_32R2: |
| 245 | return "mips32r2" ; |
| 246 | case EF_MIPS_ARCH_64R2: |
| 247 | return "mips64r2" ; |
| 248 | case EF_MIPS_ARCH_32R6: |
| 249 | return "mips32r6" ; |
| 250 | case EF_MIPS_ARCH_64R6: |
| 251 | return "mips64r6" ; |
| 252 | default: |
| 253 | return "unknown arch" ; |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | static std::string getFullArchName(uint32_t flags) { |
| 258 | StringRef arch = getArchName(flags); |
| 259 | StringRef mach = getMachName(flags); |
| 260 | if (mach.empty()) |
| 261 | return arch.str(); |
| 262 | return (arch + " (" + mach + ")" ).str(); |
| 263 | } |
| 264 | |
| 265 | // There are (arguably too) many MIPS ISAs out there. Their relationships |
| 266 | // can be represented as a forest. If all input files have ISAs which |
| 267 | // reachable by repeated proceeding from the single child to the parent, |
| 268 | // these input files are compatible. In that case we need to return "highest" |
| 269 | // ISA. If there are incompatible input files, we show an error. |
| 270 | // For example, mips1 is a "parent" of mips2 and such files are compatible. |
| 271 | // Output file gets EF_MIPS_ARCH_2 flag. From the other side mips3 and mips32 |
| 272 | // are incompatible because nor mips3 is a parent for misp32, nor mips32 |
| 273 | // is a parent for mips3. |
| 274 | static uint32_t getArchFlags(Ctx &ctx, ArrayRef<FileFlags> files) { |
| 275 | uint32_t ret = files[0].flags & (EF_MIPS_ARCH | EF_MIPS_MACH); |
| 276 | |
| 277 | for (const FileFlags &f : files.slice(N: 1)) { |
| 278 | uint32_t newFlags = f.flags & (EF_MIPS_ARCH | EF_MIPS_MACH); |
| 279 | |
| 280 | // Check ISA compatibility. |
| 281 | if (isArchMatched(newFlags, res: ret)) |
| 282 | continue; |
| 283 | if (!isArchMatched(newFlags: ret, res: newFlags)) { |
| 284 | Err(ctx) << "incompatible target ISA:\n>>> " << files[0].file << ": " |
| 285 | << getFullArchName(flags: ret) << "\n>>> " << f.file << ": " |
| 286 | << getFullArchName(flags: newFlags); |
| 287 | return 0; |
| 288 | } |
| 289 | ret = newFlags; |
| 290 | } |
| 291 | return ret; |
| 292 | } |
| 293 | |
| 294 | template <class ELFT> uint32_t elf::calcMipsEFlags(Ctx &ctx) { |
| 295 | std::vector<FileFlags> v; |
| 296 | for (InputFile *f : ctx.objectFiles) |
| 297 | v.push_back({f, cast<ObjFile<ELFT>>(f)->getObj().getHeader().e_flags}); |
| 298 | if (v.empty()) { |
| 299 | // If we don't have any input files, we'll have to rely on the information |
| 300 | // we can derive from emulation information, since this at least gets us |
| 301 | // ABI. |
| 302 | if (ctx.arg.emulation.empty() || ctx.arg.is64) |
| 303 | return 0; |
| 304 | return ctx.arg.mipsN32Abi ? EF_MIPS_ABI2 : EF_MIPS_ABI_O32; |
| 305 | } |
| 306 | checkFlags(ctx, files: v); |
| 307 | return getMiscFlags(files: v) | getPicFlags(ctx, files: v) | getArchFlags(ctx, files: v); |
| 308 | } |
| 309 | |
| 310 | static int compareMipsFpAbi(uint8_t fpA, uint8_t fpB) { |
| 311 | if (fpA == fpB) |
| 312 | return 0; |
| 313 | if (fpB == Mips::Val_GNU_MIPS_ABI_FP_ANY) |
| 314 | return 1; |
| 315 | if (fpB == Mips::Val_GNU_MIPS_ABI_FP_64A && |
| 316 | fpA == Mips::Val_GNU_MIPS_ABI_FP_64) |
| 317 | return 1; |
| 318 | if (fpB != Mips::Val_GNU_MIPS_ABI_FP_XX) |
| 319 | return -1; |
| 320 | if (fpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE || |
| 321 | fpA == Mips::Val_GNU_MIPS_ABI_FP_64 || |
| 322 | fpA == Mips::Val_GNU_MIPS_ABI_FP_64A) |
| 323 | return 1; |
| 324 | return -1; |
| 325 | } |
| 326 | |
| 327 | static StringRef getMipsFpAbiName(uint8_t fpAbi) { |
| 328 | switch (fpAbi) { |
| 329 | case Mips::Val_GNU_MIPS_ABI_FP_ANY: |
| 330 | return "any" ; |
| 331 | case Mips::Val_GNU_MIPS_ABI_FP_DOUBLE: |
| 332 | return "-mdouble-float" ; |
| 333 | case Mips::Val_GNU_MIPS_ABI_FP_SINGLE: |
| 334 | return "-msingle-float" ; |
| 335 | case Mips::Val_GNU_MIPS_ABI_FP_SOFT: |
| 336 | return "-msoft-float" ; |
| 337 | case Mips::Val_GNU_MIPS_ABI_FP_OLD_64: |
| 338 | return "-mgp32 -mfp64 (old)" ; |
| 339 | case Mips::Val_GNU_MIPS_ABI_FP_XX: |
| 340 | return "-mfpxx" ; |
| 341 | case Mips::Val_GNU_MIPS_ABI_FP_64: |
| 342 | return "-mgp32 -mfp64" ; |
| 343 | case Mips::Val_GNU_MIPS_ABI_FP_64A: |
| 344 | return "-mgp32 -mfp64 -mno-odd-spreg" ; |
| 345 | default: |
| 346 | return "unknown" ; |
| 347 | } |
| 348 | } |
| 349 | |
| 350 | uint8_t elf::getMipsFpAbiFlag(Ctx &ctx, InputFile *file, uint8_t oldFlag, |
| 351 | uint8_t newFlag) { |
| 352 | if (compareMipsFpAbi(fpA: newFlag, fpB: oldFlag) >= 0) |
| 353 | return newFlag; |
| 354 | if (compareMipsFpAbi(fpA: oldFlag, fpB: newFlag) < 0) |
| 355 | Err(ctx) << file << ": floating point ABI '" << getMipsFpAbiName(fpAbi: newFlag) |
| 356 | << "' is incompatible with target floating point ABI '" |
| 357 | << getMipsFpAbiName(fpAbi: oldFlag) << "'" ; |
| 358 | return oldFlag; |
| 359 | } |
| 360 | |
| 361 | template <class ELFT> static bool isN32Abi(const InputFile &f) { |
| 362 | if (auto *ef = dyn_cast<ELFFileBase>(Val: &f)) |
| 363 | return ef->template getObj<ELFT>().getHeader().e_flags & EF_MIPS_ABI2; |
| 364 | return false; |
| 365 | } |
| 366 | |
| 367 | bool elf::isMipsN32Abi(Ctx &ctx, const InputFile &f) { |
| 368 | switch (ctx.arg.ekind) { |
| 369 | case ELF32LEKind: |
| 370 | return isN32Abi<ELF32LE>(f); |
| 371 | case ELF32BEKind: |
| 372 | return isN32Abi<ELF32BE>(f); |
| 373 | case ELF64LEKind: |
| 374 | return isN32Abi<ELF64LE>(f); |
| 375 | case ELF64BEKind: |
| 376 | return isN32Abi<ELF64BE>(f); |
| 377 | default: |
| 378 | llvm_unreachable("unknown ctx.arg.ekind" ); |
| 379 | } |
| 380 | } |
| 381 | |
| 382 | bool elf::isMicroMips(Ctx &ctx) { return ctx.arg.eflags & EF_MIPS_MICROMIPS; } |
| 383 | |
| 384 | bool elf::isMipsR6(Ctx &ctx) { |
| 385 | uint32_t arch = ctx.arg.eflags & EF_MIPS_ARCH; |
| 386 | return arch == EF_MIPS_ARCH_32R6 || arch == EF_MIPS_ARCH_64R6; |
| 387 | } |
| 388 | |
| 389 | template uint32_t elf::calcMipsEFlags<ELF32LE>(Ctx &); |
| 390 | template uint32_t elf::calcMipsEFlags<ELF32BE>(Ctx &); |
| 391 | template uint32_t elf::calcMipsEFlags<ELF64LE>(Ctx &); |
| 392 | template uint32_t elf::calcMipsEFlags<ELF64BE>(Ctx &); |
| 393 | |