Index: ELF/Arch/Mips.cpp =================================================================== --- ELF/Arch/Mips.cpp +++ ELF/Arch/Mips.cpp @@ -11,11 +11,15 @@ #include "InputFiles.h" #include "OutputSections.h" #include "Symbols.h" +#include "SymbolTable.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" +#include "Writer.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/MipsABIFlags.h" using namespace llvm; using namespace llvm::object; @@ -420,3 +424,344 @@ template TargetInfo *elf::getMipsTargetInfo(); template TargetInfo *elf::getMipsTargetInfo(); template TargetInfo *elf::getMipsTargetInfo(); + +namespace { +struct ArchTreeEdge { + uint32_t Child; + uint32_t Parent; +}; + +struct FileFlags { + StringRef Filename; + uint32_t Flags; +}; +} + +static StringRef getAbiName(uint32_t Flags) { + switch (Flags) { + case 0: + return "n64"; + case EF_MIPS_ABI2: + return "n32"; + case EF_MIPS_ABI_O32: + return "o32"; + case EF_MIPS_ABI_O64: + return "o64"; + case EF_MIPS_ABI_EABI32: + return "eabi32"; + case EF_MIPS_ABI_EABI64: + return "eabi64"; + default: + return "unknown"; + } +} + +static StringRef getNanName(bool IsNan2008) { + return IsNan2008 ? "2008" : "legacy"; +} + +static StringRef getFpName(bool IsFp64) { return IsFp64 ? "64" : "32"; } + +static void checkFlags(ArrayRef Files) { + uint32_t ABI = Files[0].Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); + bool Nan = Files[0].Flags & EF_MIPS_NAN2008; + bool Fp = Files[0].Flags & EF_MIPS_FP64; + + for (const FileFlags &F : Files.slice(1)) { + uint32_t ABI2 = F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); + if (ABI != ABI2) + error("target ABI '" + getAbiName(ABI) + "' is incompatible with '" + + getAbiName(ABI2) + "': " + F.Filename); + + bool Nan2 = F.Flags & EF_MIPS_NAN2008; + if (Nan != Nan2) + error("target -mnan=" + getNanName(Nan) + " is incompatible with -mnan=" + + getNanName(Nan2) + ": " + F.Filename); + + bool Fp2 = F.Flags & EF_MIPS_FP64; + if (Fp != Fp2) + error("target -mfp" + getFpName(Fp) + " is incompatible with -mfp" + + getFpName(Fp2) + ": " + F.Filename); + } +} + +static uint32_t getMiscFlags(ArrayRef Files) { + uint32_t Ret = 0; + for (const FileFlags &F : Files) + Ret |= F.Flags & + (EF_MIPS_ABI | EF_MIPS_ABI2 | EF_MIPS_ARCH_ASE | EF_MIPS_NOREORDER | + EF_MIPS_MICROMIPS | EF_MIPS_NAN2008 | EF_MIPS_32BITMODE); + return Ret; +} + +static uint32_t getPicFlags(ArrayRef Files) { + // Check PIC/non-PIC compatibility. + bool IsPic = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); + for (const FileFlags &F : Files.slice(1)) { + bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); + if (IsPic && !IsPic2) + warn("linking abicalls code with non-abicalls file: " + F.Filename); + if (!IsPic && IsPic2) + warn("linking non-abicalls code with abicalls file: " + F.Filename); + } + + // Compute the result PIC/non-PIC flag. + uint32_t Ret = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); + for (const FileFlags &F : Files.slice(1)) + Ret &= F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); + + // PIC code is inherently CPIC and may not set CPIC flag explicitly. + if (Ret & EF_MIPS_PIC) + Ret |= EF_MIPS_CPIC; + return Ret; +} + +static ArchTreeEdge ArchTree[] = { + // MIPS32R6 and MIPS64R6 are not compatible with other extensions + // MIPS64R2 extensions. + {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, EF_MIPS_ARCH_64R2}, + {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, EF_MIPS_ARCH_64R2}, + {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, EF_MIPS_ARCH_64R2}, + {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, EF_MIPS_ARCH_64R2}, + // MIPS64 extensions. + {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, EF_MIPS_ARCH_64}, + {EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, EF_MIPS_ARCH_64}, + {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64}, + // MIPS V extensions. + {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5}, + // R5000 extensions. + {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400}, + // MIPS IV extensions. + {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, EF_MIPS_ARCH_4}, + {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, EF_MIPS_ARCH_4}, + {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4}, + // VR4100 extensions. + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, + // MIPS III extensions. + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, EF_MIPS_ARCH_3}, + {EF_MIPS_ARCH_4, EF_MIPS_ARCH_3}, + // MIPS32 extensions. + {EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32}, + // MIPS II extensions. + {EF_MIPS_ARCH_3, EF_MIPS_ARCH_2}, + {EF_MIPS_ARCH_32, EF_MIPS_ARCH_2}, + // MIPS I extensions. + {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, EF_MIPS_ARCH_1}, + {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1}, +}; + +static bool isArchMatched(uint32_t New, uint32_t Res) { + if (New == Res) + return true; + if (New == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, Res)) + return true; + if (New == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, Res)) + return true; + for (const auto &Edge : ArchTree) { + if (Res == Edge.Child) { + Res = Edge.Parent; + if (Res == New) + return true; + } + } + return false; +} + +static StringRef getMachName(uint32_t Flags) { + switch (Flags & EF_MIPS_MACH) { + case EF_MIPS_MACH_NONE: + return ""; + case EF_MIPS_MACH_3900: + return "r3900"; + case EF_MIPS_MACH_4010: + return "r4010"; + case EF_MIPS_MACH_4100: + return "r4100"; + case EF_MIPS_MACH_4650: + return "r4650"; + case EF_MIPS_MACH_4120: + return "r4120"; + case EF_MIPS_MACH_4111: + return "r4111"; + case EF_MIPS_MACH_5400: + return "vr5400"; + case EF_MIPS_MACH_5900: + return "vr5900"; + case EF_MIPS_MACH_5500: + return "vr5500"; + case EF_MIPS_MACH_9000: + return "rm9000"; + case EF_MIPS_MACH_LS2E: + return "loongson2e"; + case EF_MIPS_MACH_LS2F: + return "loongson2f"; + case EF_MIPS_MACH_LS3A: + return "loongson3a"; + case EF_MIPS_MACH_OCTEON: + return "octeon"; + case EF_MIPS_MACH_OCTEON2: + return "octeon2"; + case EF_MIPS_MACH_OCTEON3: + return "octeon3"; + case EF_MIPS_MACH_SB1: + return "sb1"; + case EF_MIPS_MACH_XLR: + return "xlr"; + default: + return "unknown machine"; + } +} + +static StringRef getArchName(uint32_t Flags) { + StringRef S = getMachName(Flags); + if (!S.empty()) + return S; + + switch (Flags & EF_MIPS_ARCH) { + case EF_MIPS_ARCH_1: + return "mips1"; + case EF_MIPS_ARCH_2: + return "mips2"; + case EF_MIPS_ARCH_3: + return "mips3"; + case EF_MIPS_ARCH_4: + return "mips4"; + case EF_MIPS_ARCH_5: + return "mips5"; + case EF_MIPS_ARCH_32: + return "mips32"; + case EF_MIPS_ARCH_64: + return "mips64"; + case EF_MIPS_ARCH_32R2: + return "mips32r2"; + case EF_MIPS_ARCH_64R2: + return "mips64r2"; + case EF_MIPS_ARCH_32R6: + return "mips32r6"; + case EF_MIPS_ARCH_64R6: + return "mips64r6"; + default: + return "unknown arch"; + } +} + +// There are (arguably too) many MIPS ISAs out there. Their relationships +// can be represented as a forest. If all input files have ISAs which +// reachable by repeated proceeding from the single child to the parent, +// these input files are compatible. In that case we need to return "highest" +// ISA. If there are incompatible input files, we show an error. +// For example, mips1 is a "parent" of mips2 and such files are compatible. +// Output file gets EF_MIPS_ARCH_2 flag. From the other side mips3 and mips32 +// are incompatible because nor mips3 is a parent for misp32, nor mips32 +// is a parent for mips3. +static uint32_t getArchFlags(ArrayRef Files) { + uint32_t Ret = Files[0].Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); + + for (const FileFlags &F : Files.slice(1)) { + uint32_t New = F.Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); + + // Check ISA compatibility. + if (isArchMatched(New, Ret)) + continue; + if (!isArchMatched(Ret, New)) { + error("target ISA '" + getArchName(Ret) + "' is incompatible with '" + + getArchName(New) + "': " + F.Filename); + return 0; + } + Ret = New; + } + return Ret; +} + +template uint32_t elf::getMipsEFlags() { + std::vector V; + for (elf::ObjectFile *F : Symtab::X->getObjectFiles()) + V.push_back({F->getName(), F->getObj().getHeader()->e_flags}); + if (V.empty()) + return 0; + checkFlags(V); + return getMiscFlags(V) | getPicFlags(V) | getArchFlags(V); +} + +static int compareMipsFpAbi(uint8_t FpA, uint8_t FpB) { + if (FpA == FpB) + return 0; + if (FpB == Mips::Val_GNU_MIPS_ABI_FP_ANY) + return 1; + if (FpB == Mips::Val_GNU_MIPS_ABI_FP_64A && + FpA == Mips::Val_GNU_MIPS_ABI_FP_64) + return 1; + if (FpB != Mips::Val_GNU_MIPS_ABI_FP_XX) + return -1; + if (FpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE || + FpA == Mips::Val_GNU_MIPS_ABI_FP_64 || + FpA == Mips::Val_GNU_MIPS_ABI_FP_64A) + return 1; + return -1; +} + +static StringRef getMipsFpAbiName(uint8_t FpAbi) { + switch (FpAbi) { + case Mips::Val_GNU_MIPS_ABI_FP_ANY: + return "any"; + case Mips::Val_GNU_MIPS_ABI_FP_DOUBLE: + return "-mdouble-float"; + case Mips::Val_GNU_MIPS_ABI_FP_SINGLE: + return "-msingle-float"; + case Mips::Val_GNU_MIPS_ABI_FP_SOFT: + return "-msoft-float"; + case Mips::Val_GNU_MIPS_ABI_FP_OLD_64: + return "-mips32r2 -mfp64 (old)"; + case Mips::Val_GNU_MIPS_ABI_FP_XX: + return "-mfpxx"; + case Mips::Val_GNU_MIPS_ABI_FP_64: + return "-mgp32 -mfp64"; + case Mips::Val_GNU_MIPS_ABI_FP_64A: + return "-mgp32 -mfp64 -mno-odd-spreg"; + default: + return "unknown"; + } +} + +uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag, + StringRef FileName) { + if (compareMipsFpAbi(NewFlag, OldFlag) >= 0) + return NewFlag; + if (compareMipsFpAbi(OldFlag, NewFlag) < 0) + error("target floating point ABI '" + getMipsFpAbiName(OldFlag) + + "' is incompatible with '" + getMipsFpAbiName(NewFlag) + "': " + + FileName); + return OldFlag; +} + +template static bool isN32Abi(const InputFile *F) { + if (auto *EF = dyn_cast>(F)) + return EF->getObj().getHeader()->e_flags & EF_MIPS_ABI2; + return false; +} + +bool elf::isMipsN32Abi(const InputFile *F) { + switch (Config->EKind) { + case ELF32LEKind: + return isN32Abi(F); + case ELF32BEKind: + return isN32Abi(F); + case ELF64LEKind: + return isN32Abi(F); + case ELF64BEKind: + return isN32Abi(F); + default: + llvm_unreachable("unknown Config->EKind"); + } +} + +template uint32_t elf::getMipsEFlags(); +template uint32_t elf::getMipsEFlags(); +template uint32_t elf::getMipsEFlags(); +template uint32_t elf::getMipsEFlags(); Index: ELF/CMakeLists.txt =================================================================== --- ELF/CMakeLists.txt +++ ELF/CMakeLists.txt @@ -29,7 +29,6 @@ LinkerScript.cpp MapFile.cpp MarkLive.cpp - Mips.cpp OutputSections.cpp Relocations.cpp ScriptLexer.cpp Index: ELF/Mips.cpp =================================================================== --- ELF/Mips.cpp +++ ELF/Mips.cpp @@ -1,369 +0,0 @@ -//===- Mips.cpp ----------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===---------------------------------------------------------------------===// -// -// This file contains a helper function for the Writer. -// -//===---------------------------------------------------------------------===// - -#include "Error.h" -#include "InputFiles.h" -#include "SymbolTable.h" -#include "Writer.h" - -#include "llvm/BinaryFormat/ELF.h" -#include "llvm/Object/ELF.h" -#include "llvm/Support/MipsABIFlags.h" - -using namespace llvm; -using namespace llvm::object; -using namespace llvm::ELF; - -using namespace lld; -using namespace lld::elf; - -namespace { -struct ArchTreeEdge { - uint32_t Child; - uint32_t Parent; -}; - -struct FileFlags { - StringRef Filename; - uint32_t Flags; -}; -} - -static StringRef getAbiName(uint32_t Flags) { - switch (Flags) { - case 0: - return "n64"; - case EF_MIPS_ABI2: - return "n32"; - case EF_MIPS_ABI_O32: - return "o32"; - case EF_MIPS_ABI_O64: - return "o64"; - case EF_MIPS_ABI_EABI32: - return "eabi32"; - case EF_MIPS_ABI_EABI64: - return "eabi64"; - default: - return "unknown"; - } -} - -static StringRef getNanName(bool IsNan2008) { - return IsNan2008 ? "2008" : "legacy"; -} - -static StringRef getFpName(bool IsFp64) { return IsFp64 ? "64" : "32"; } - -static void checkFlags(ArrayRef Files) { - uint32_t ABI = Files[0].Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); - bool Nan = Files[0].Flags & EF_MIPS_NAN2008; - bool Fp = Files[0].Flags & EF_MIPS_FP64; - - for (const FileFlags &F : Files.slice(1)) { - uint32_t ABI2 = F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); - if (ABI != ABI2) - error("target ABI '" + getAbiName(ABI) + "' is incompatible with '" + - getAbiName(ABI2) + "': " + F.Filename); - - bool Nan2 = F.Flags & EF_MIPS_NAN2008; - if (Nan != Nan2) - error("target -mnan=" + getNanName(Nan) + " is incompatible with -mnan=" + - getNanName(Nan2) + ": " + F.Filename); - - bool Fp2 = F.Flags & EF_MIPS_FP64; - if (Fp != Fp2) - error("target -mfp" + getFpName(Fp) + " is incompatible with -mfp" + - getFpName(Fp2) + ": " + F.Filename); - } -} - -static uint32_t getMiscFlags(ArrayRef Files) { - uint32_t Ret = 0; - for (const FileFlags &F : Files) - Ret |= F.Flags & - (EF_MIPS_ABI | EF_MIPS_ABI2 | EF_MIPS_ARCH_ASE | EF_MIPS_NOREORDER | - EF_MIPS_MICROMIPS | EF_MIPS_NAN2008 | EF_MIPS_32BITMODE); - return Ret; -} - -static uint32_t getPicFlags(ArrayRef Files) { - // Check PIC/non-PIC compatibility. - bool IsPic = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); - for (const FileFlags &F : Files.slice(1)) { - bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); - if (IsPic && !IsPic2) - warn("linking abicalls code with non-abicalls file: " + F.Filename); - if (!IsPic && IsPic2) - warn("linking non-abicalls code with abicalls file: " + F.Filename); - } - - // Compute the result PIC/non-PIC flag. - uint32_t Ret = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); - for (const FileFlags &F : Files.slice(1)) - Ret &= F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); - - // PIC code is inherently CPIC and may not set CPIC flag explicitly. - if (Ret & EF_MIPS_PIC) - Ret |= EF_MIPS_CPIC; - return Ret; -} - -static ArchTreeEdge ArchTree[] = { - // MIPS32R6 and MIPS64R6 are not compatible with other extensions - // MIPS64R2 extensions. - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, EF_MIPS_ARCH_64R2}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, EF_MIPS_ARCH_64R2}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, EF_MIPS_ARCH_64R2}, - {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, EF_MIPS_ARCH_64R2}, - // MIPS64 extensions. - {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, EF_MIPS_ARCH_64}, - {EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, EF_MIPS_ARCH_64}, - {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64}, - // MIPS V extensions. - {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5}, - // R5000 extensions. - {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400}, - // MIPS IV extensions. - {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, EF_MIPS_ARCH_4}, - {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, EF_MIPS_ARCH_4}, - {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4}, - // VR4100 extensions. - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, - // MIPS III extensions. - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, EF_MIPS_ARCH_3}, - {EF_MIPS_ARCH_4, EF_MIPS_ARCH_3}, - // MIPS32 extensions. - {EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32}, - // MIPS II extensions. - {EF_MIPS_ARCH_3, EF_MIPS_ARCH_2}, - {EF_MIPS_ARCH_32, EF_MIPS_ARCH_2}, - // MIPS I extensions. - {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, EF_MIPS_ARCH_1}, - {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1}, -}; - -static bool isArchMatched(uint32_t New, uint32_t Res) { - if (New == Res) - return true; - if (New == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, Res)) - return true; - if (New == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, Res)) - return true; - for (const auto &Edge : ArchTree) { - if (Res == Edge.Child) { - Res = Edge.Parent; - if (Res == New) - return true; - } - } - return false; -} - -static StringRef getMachName(uint32_t Flags) { - switch (Flags & EF_MIPS_MACH) { - case EF_MIPS_MACH_NONE: - return ""; - case EF_MIPS_MACH_3900: - return "r3900"; - case EF_MIPS_MACH_4010: - return "r4010"; - case EF_MIPS_MACH_4100: - return "r4100"; - case EF_MIPS_MACH_4650: - return "r4650"; - case EF_MIPS_MACH_4120: - return "r4120"; - case EF_MIPS_MACH_4111: - return "r4111"; - case EF_MIPS_MACH_5400: - return "vr5400"; - case EF_MIPS_MACH_5900: - return "vr5900"; - case EF_MIPS_MACH_5500: - return "vr5500"; - case EF_MIPS_MACH_9000: - return "rm9000"; - case EF_MIPS_MACH_LS2E: - return "loongson2e"; - case EF_MIPS_MACH_LS2F: - return "loongson2f"; - case EF_MIPS_MACH_LS3A: - return "loongson3a"; - case EF_MIPS_MACH_OCTEON: - return "octeon"; - case EF_MIPS_MACH_OCTEON2: - return "octeon2"; - case EF_MIPS_MACH_OCTEON3: - return "octeon3"; - case EF_MIPS_MACH_SB1: - return "sb1"; - case EF_MIPS_MACH_XLR: - return "xlr"; - default: - return "unknown machine"; - } -} - -static StringRef getArchName(uint32_t Flags) { - StringRef S = getMachName(Flags); - if (!S.empty()) - return S; - - switch (Flags & EF_MIPS_ARCH) { - case EF_MIPS_ARCH_1: - return "mips1"; - case EF_MIPS_ARCH_2: - return "mips2"; - case EF_MIPS_ARCH_3: - return "mips3"; - case EF_MIPS_ARCH_4: - return "mips4"; - case EF_MIPS_ARCH_5: - return "mips5"; - case EF_MIPS_ARCH_32: - return "mips32"; - case EF_MIPS_ARCH_64: - return "mips64"; - case EF_MIPS_ARCH_32R2: - return "mips32r2"; - case EF_MIPS_ARCH_64R2: - return "mips64r2"; - case EF_MIPS_ARCH_32R6: - return "mips32r6"; - case EF_MIPS_ARCH_64R6: - return "mips64r6"; - default: - return "unknown arch"; - } -} - -// There are (arguably too) many MIPS ISAs out there. Their relationships -// can be represented as a forest. If all input files have ISAs which -// reachable by repeated proceeding from the single child to the parent, -// these input files are compatible. In that case we need to return "highest" -// ISA. If there are incompatible input files, we show an error. -// For example, mips1 is a "parent" of mips2 and such files are compatible. -// Output file gets EF_MIPS_ARCH_2 flag. From the other side mips3 and mips32 -// are incompatible because nor mips3 is a parent for misp32, nor mips32 -// is a parent for mips3. -static uint32_t getArchFlags(ArrayRef Files) { - uint32_t Ret = Files[0].Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); - - for (const FileFlags &F : Files.slice(1)) { - uint32_t New = F.Flags & (EF_MIPS_ARCH | EF_MIPS_MACH); - - // Check ISA compatibility. - if (isArchMatched(New, Ret)) - continue; - if (!isArchMatched(Ret, New)) { - error("target ISA '" + getArchName(Ret) + "' is incompatible with '" + - getArchName(New) + "': " + F.Filename); - return 0; - } - Ret = New; - } - return Ret; -} - -template uint32_t elf::getMipsEFlags() { - std::vector V; - for (elf::ObjectFile *F : Symtab::X->getObjectFiles()) - V.push_back({F->getName(), F->getObj().getHeader()->e_flags}); - if (V.empty()) - return 0; - checkFlags(V); - return getMiscFlags(V) | getPicFlags(V) | getArchFlags(V); -} - -static int compareMipsFpAbi(uint8_t FpA, uint8_t FpB) { - if (FpA == FpB) - return 0; - if (FpB == Mips::Val_GNU_MIPS_ABI_FP_ANY) - return 1; - if (FpB == Mips::Val_GNU_MIPS_ABI_FP_64A && - FpA == Mips::Val_GNU_MIPS_ABI_FP_64) - return 1; - if (FpB != Mips::Val_GNU_MIPS_ABI_FP_XX) - return -1; - if (FpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE || - FpA == Mips::Val_GNU_MIPS_ABI_FP_64 || - FpA == Mips::Val_GNU_MIPS_ABI_FP_64A) - return 1; - return -1; -} - -static StringRef getMipsFpAbiName(uint8_t FpAbi) { - switch (FpAbi) { - case Mips::Val_GNU_MIPS_ABI_FP_ANY: - return "any"; - case Mips::Val_GNU_MIPS_ABI_FP_DOUBLE: - return "-mdouble-float"; - case Mips::Val_GNU_MIPS_ABI_FP_SINGLE: - return "-msingle-float"; - case Mips::Val_GNU_MIPS_ABI_FP_SOFT: - return "-msoft-float"; - case Mips::Val_GNU_MIPS_ABI_FP_OLD_64: - return "-mips32r2 -mfp64 (old)"; - case Mips::Val_GNU_MIPS_ABI_FP_XX: - return "-mfpxx"; - case Mips::Val_GNU_MIPS_ABI_FP_64: - return "-mgp32 -mfp64"; - case Mips::Val_GNU_MIPS_ABI_FP_64A: - return "-mgp32 -mfp64 -mno-odd-spreg"; - default: - return "unknown"; - } -} - -uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag, - StringRef FileName) { - if (compareMipsFpAbi(NewFlag, OldFlag) >= 0) - return NewFlag; - if (compareMipsFpAbi(OldFlag, NewFlag) < 0) - error("target floating point ABI '" + getMipsFpAbiName(OldFlag) + - "' is incompatible with '" + getMipsFpAbiName(NewFlag) + "': " + - FileName); - return OldFlag; -} - -template static bool isN32Abi(const InputFile *F) { - if (auto *EF = dyn_cast>(F)) - return EF->getObj().getHeader()->e_flags & EF_MIPS_ABI2; - return false; -} - -bool elf::isMipsN32Abi(const InputFile *F) { - switch (Config->EKind) { - case ELF32LEKind: - return isN32Abi(F); - case ELF32BEKind: - return isN32Abi(F); - case ELF64LEKind: - return isN32Abi(F); - case ELF64BEKind: - return isN32Abi(F); - default: - llvm_unreachable("unknown Config->EKind"); - } -} - -template uint32_t elf::getMipsEFlags(); -template uint32_t elf::getMipsEFlags(); -template uint32_t elf::getMipsEFlags(); -template uint32_t elf::getMipsEFlags();