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