brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.0 KiB · 9158859 Raw
393 lines · cpp
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-exception6//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 20using namespace llvm;21using namespace llvm::object;22using namespace llvm::ELF;23 24using namespace lld;25using namespace lld::elf;26 27namespace {28struct ArchTreeEdge {29  uint32_t child;30  uint32_t parent;31};32 33struct FileFlags {34  InputFile *file;35  uint32_t flags;36};37} // namespace38 39static 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 58static StringRef getNanName(bool isNan2008) {59  return isNan2008 ? "2008" : "legacy";60}61 62static StringRef getFpName(bool isFp64) { return isFp64 ? "64" : "32"; }63 64static 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(abi2)78               << "' is incompatible with target ABI '" << getAbiName(abi)79               << "'";80 81    bool nan2 = f.flags & EF_MIPS_NAN2008;82    if (nan != nan2)83      Err(ctx) << f.file << ": -mnan=" << getNanName(nan2)84               << " is incompatible with target -mnan=" << getNanName(nan);85 86    bool fp2 = f.flags & EF_MIPS_FP64;87    if (fp != fp2)88      Err(ctx) << f.file << ": -mfp" << getFpName(fp2)89               << " is incompatible with target -mfp" << getFpName(fp);90  }91}92 93static 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 102static 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(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(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 126static ArchTreeEdge archTree[] = {127    // MIPS32R6 and MIPS64R6 are not compatible with other extensions128    // MIPS64R2 extensions.129    {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, EF_MIPS_ARCH_64R2},130    {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, EF_MIPS_ARCH_64R2},131    {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, EF_MIPS_ARCH_64R2},132    {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, EF_MIPS_ARCH_64R2},133    // MIPS64 extensions.134    {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, EF_MIPS_ARCH_64},135    {EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, EF_MIPS_ARCH_64},136    {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64},137    // MIPS V extensions.138    {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5},139    // R5000 extensions.140    {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400},141    // MIPS IV extensions.142    {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, EF_MIPS_ARCH_4},143    {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, EF_MIPS_ARCH_4},144    {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4},145    // VR4100 extensions.146    {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100},147    {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100},148    // MIPS III extensions.149    {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, EF_MIPS_ARCH_3},150    {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, EF_MIPS_ARCH_3},151    {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, EF_MIPS_ARCH_3},152    {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, EF_MIPS_ARCH_3},153    {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, EF_MIPS_ARCH_3},154    {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, EF_MIPS_ARCH_3},155    {EF_MIPS_ARCH_4, EF_MIPS_ARCH_3},156    // MIPS32 extensions.157    {EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32},158    // MIPS II extensions.159    {EF_MIPS_ARCH_3, EF_MIPS_ARCH_2},160    {EF_MIPS_ARCH_32, EF_MIPS_ARCH_2},161    // MIPS I extensions.162    {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, EF_MIPS_ARCH_1},163    {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1},164};165 166static bool isArchMatched(uint32_t newFlags, uint32_t res) {167  if (newFlags == res)168    return true;169  if (newFlags == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, res))170    return true;171  if (newFlags == EF_MIPS_ARCH_32R2 && isArchMatched(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 183static 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 228static 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 257static 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 relationships266// can be represented as a forest. If all input files have ISAs which267// 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 mips32272// are incompatible because nor mips3 is a parent for misp32, nor mips32273// is a parent for mips3.274static 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(1)) {278    uint32_t newFlags = f.flags & (EF_MIPS_ARCH | EF_MIPS_MACH);279 280    // Check ISA compatibility.281    if (isArchMatched(newFlags, ret))282      continue;283    if (!isArchMatched(ret, newFlags)) {284      Err(ctx) << "incompatible target ISA:\n>>> " << files[0].file << ": "285               << getFullArchName(ret) << "\n>>> " << f.file << ": "286               << getFullArchName(newFlags);287      return 0;288    }289    ret = newFlags;290  }291  return ret;292}293 294template <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 information300    // we can derive from emulation information, since this at least gets us301    // 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, v);307  return getMiscFlags(v) | getPicFlags(ctx, v) | getArchFlags(ctx, v);308}309 310static 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 327static 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 350uint8_t elf::getMipsFpAbiFlag(Ctx &ctx, InputFile *file, uint8_t oldFlag,351                              uint8_t newFlag) {352  if (compareMipsFpAbi(newFlag, oldFlag) >= 0)353    return newFlag;354  if (compareMipsFpAbi(oldFlag, newFlag) < 0)355    Err(ctx) << file << ": floating point ABI '" << getMipsFpAbiName(newFlag)356             << "' is incompatible with target floating point ABI '"357             << getMipsFpAbiName(oldFlag) << "'";358  return oldFlag;359}360 361template <class ELFT> static bool isN32Abi(const InputFile &f) {362  if (auto *ef = dyn_cast<ELFFileBase>(&f))363    return ef->template getObj<ELFT>().getHeader().e_flags & EF_MIPS_ABI2;364  return false;365}366 367bool 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 382bool elf::isMicroMips(Ctx &ctx) { return ctx.arg.eflags & EF_MIPS_MICROMIPS; }383 384bool 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 389template uint32_t elf::calcMipsEFlags<ELF32LE>(Ctx &);390template uint32_t elf::calcMipsEFlags<ELF32BE>(Ctx &);391template uint32_t elf::calcMipsEFlags<ELF64LE>(Ctx &);392template uint32_t elf::calcMipsEFlags<ELF64BE>(Ctx &);393