summaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp')
-rw-r--r--lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp675
1 files changed, 675 insertions, 0 deletions
diff --git a/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp b/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp
new file mode 100644
index 000000000000..ad4e62e64680
--- /dev/null
+++ b/lib/ReaderWriter/ELF/Mips/MipsAbiInfoHandler.cpp
@@ -0,0 +1,675 @@
+//===- lib/ReaderWriter/ELF/MipsAbiInfoHandler.cpp ------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MipsAbiInfoHandler.h"
+#include "lld/Core/Error.h"
+#include "lld/ReaderWriter/ELFLinkingContext.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/MipsABIFlags.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lld;
+using namespace lld::elf;
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::Mips;
+
+namespace {
+
+// The joined set of MIPS ISAs and MIPS ISA extensions.
+enum MipsISAs {
+ ArchNone,
+
+ // General ISAs
+ Arch1,
+ Arch2,
+ Arch3,
+ Arch4,
+ Arch5,
+ Arch32,
+ Arch32r2,
+ Arch32r3,
+ Arch32r5,
+ Arch32r6,
+ Arch64,
+ Arch64r2,
+ Arch64r3,
+ Arch64r5,
+ Arch64r6,
+
+ // CPU specific ISAs
+ Arch3900,
+ Arch4010,
+ Arch4100,
+ Arch4111,
+ Arch4120,
+ Arch4650,
+ Arch5400,
+ Arch5500,
+ Arch5900,
+ Arch9000,
+ Arch10000,
+ ArchLs2e,
+ ArchLs2f,
+ ArchLs3a,
+ ArchOcteon,
+ ArchOcteonP,
+ ArchOcteon2,
+ ArchOcteon3,
+ ArchSB1,
+ ArchXLR
+};
+
+struct MipsISATreeEdge {
+ MipsISAs child;
+ MipsISAs parent;
+};
+
+struct ElfArchPair {
+ uint32_t _elfFlag;
+ MipsISAs _arch;
+};
+
+struct AbiIsaArchPair {
+ uint8_t _isaLevel;
+ uint8_t _isaRev;
+ uint8_t _isaExt;
+ MipsISAs _arch;
+};
+}
+
+static const MipsISATreeEdge isaTree[] = {
+ // MIPS32R6 and MIPS64R6 are not compatible with other extensions
+
+ // MIPS64R2 extensions.
+ {ArchOcteon3, ArchOcteon2},
+ {ArchOcteon2, ArchOcteonP},
+ {ArchOcteonP, ArchOcteon},
+ {ArchOcteon, Arch64r2},
+ {ArchLs3a, Arch64r2},
+
+ // MIPS64 extensions.
+ {Arch64r2, Arch64},
+ {ArchSB1, Arch64},
+ {ArchXLR, Arch64},
+
+ // MIPS V extensions.
+ {Arch64, Arch5},
+
+ // R5000 extensions.
+ {Arch5500, Arch5400},
+
+ // MIPS IV extensions.
+ {Arch5, Arch4},
+ {Arch5400, Arch4},
+ {Arch9000, Arch4},
+
+ // VR4100 extensions.
+ {Arch4120, Arch4100},
+ {Arch4111, Arch4100},
+
+ // MIPS III extensions.
+ {ArchLs2e, Arch3},
+ {ArchLs2f, Arch3},
+ {Arch4650, Arch3},
+ {Arch4100, Arch3},
+ {Arch4010, Arch3},
+ {Arch5900, Arch3},
+ {Arch4, Arch3},
+
+ // MIPS32 extensions.
+ {Arch32r2, Arch32},
+
+ // MIPS II extensions.
+ {Arch3, Arch2},
+ {Arch32, Arch2},
+
+ // MIPS I extensions.
+ {Arch3900, Arch1},
+ {Arch2, Arch1},
+};
+
+// Conversion ELF arch flags => MipsISAs
+static const ElfArchPair elfArchPairs[] = {
+ {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, Arch3900},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, Arch4010},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, Arch4100},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, Arch4111},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, Arch4120},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, Arch4650},
+ {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, Arch5400},
+ {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, Arch5500},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, Arch5900},
+ {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, Arch9000},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, ArchLs2e},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, ArchLs2f},
+ {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, ArchLs3a},
+ {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, ArchOcteon},
+ {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, ArchOcteon2},
+ {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, ArchOcteon3},
+ {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, ArchSB1},
+ {EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, ArchXLR},
+ {EF_MIPS_ARCH_1, Arch1},
+ {EF_MIPS_ARCH_2, Arch2},
+ {EF_MIPS_ARCH_3, Arch3},
+ {EF_MIPS_ARCH_4, Arch4},
+ {EF_MIPS_ARCH_5, Arch5},
+ {EF_MIPS_ARCH_32, Arch32},
+ {EF_MIPS_ARCH_32R2, Arch32r2},
+ {EF_MIPS_ARCH_32R6, Arch32r6},
+ {EF_MIPS_ARCH_64, Arch64},
+ {EF_MIPS_ARCH_64R2, Arch64r2},
+ {EF_MIPS_ARCH_64R6, Arch64r6}
+};
+
+// Conversion MipsISAs => ELF arch flags
+static const ElfArchPair archElfPairs[] = {
+ {EF_MIPS_ARCH_1, Arch1},
+ {EF_MIPS_ARCH_2, Arch2},
+ {EF_MIPS_ARCH_3, Arch3},
+ {EF_MIPS_ARCH_4, Arch4},
+ {EF_MIPS_ARCH_5, Arch5},
+ {EF_MIPS_ARCH_32, Arch32},
+ {EF_MIPS_ARCH_32R2, Arch32r2},
+ {EF_MIPS_ARCH_32R2, Arch32r3},
+ {EF_MIPS_ARCH_32R2, Arch32r5},
+ {EF_MIPS_ARCH_32R6, Arch32r6},
+ {EF_MIPS_ARCH_64, Arch64},
+ {EF_MIPS_ARCH_64R2, Arch64r2},
+ {EF_MIPS_ARCH_64R2, Arch64r3},
+ {EF_MIPS_ARCH_64R2, Arch64r5},
+ {EF_MIPS_ARCH_64R6, Arch64r6},
+ {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, Arch3900},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, Arch4010},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, Arch4100},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, Arch4111},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, Arch4120},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, Arch4650},
+ {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, Arch5400},
+ {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, Arch5500},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, Arch5900},
+ {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, Arch9000},
+ {EF_MIPS_ARCH_4, Arch10000},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, ArchLs2e},
+ {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, ArchLs2f},
+ {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, ArchLs3a},
+ {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, ArchOcteon},
+ {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, ArchOcteonP},
+ {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, ArchOcteon2},
+ {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, ArchOcteon3},
+ {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, ArchSB1},
+ {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, ArchXLR}
+};
+
+// Conversion .MIPS.abiflags isa/level/extension <=> MipsISAs
+static const AbiIsaArchPair abiIsaArchPair[] = {
+ { 0, 0, 0, ArchNone},
+ { 1, 0, 0, Arch1},
+ { 2, 0, 0, Arch2},
+ { 3, 0, 0, Arch3},
+ { 4, 0, 0, Arch4},
+ { 5, 0, 0, Arch5},
+ {32, 1, 0, Arch32},
+ {32, 2, 0, Arch32r2},
+ {32, 3, 0, Arch32r3},
+ {32, 5, 0, Arch32r5},
+ {32, 6, 0, Arch32r6},
+ {64, 1, 0, Arch64},
+ {64, 2, 0, Arch64r2},
+ {64, 3, 0, Arch64r3},
+ {64, 5, 0, Arch64r5},
+ {64, 6, 0, Arch64r6},
+ { 1, 0, AFL_EXT_3900, Arch3900},
+ { 3, 0, AFL_EXT_4010, Arch4010},
+ { 3, 0, AFL_EXT_4100, Arch4100},
+ { 3, 0, AFL_EXT_4111, Arch4111},
+ { 3, 0, AFL_EXT_4120, Arch4120},
+ { 3, 0, AFL_EXT_4650, Arch4650},
+ { 4, 0, AFL_EXT_5400, Arch5400},
+ { 4, 0, AFL_EXT_5500, Arch5500},
+ { 3, 0, AFL_EXT_5900, Arch5900},
+ { 4, 0, AFL_EXT_10000, Arch10000},
+ { 3, 0, AFL_EXT_LOONGSON_2E, ArchLs2e},
+ { 3, 0, AFL_EXT_LOONGSON_2F, ArchLs2f},
+ {64, 2, AFL_EXT_LOONGSON_3A, ArchLs3a},
+ {64, 2, AFL_EXT_OCTEON, ArchOcteon},
+ {64, 2, AFL_EXT_OCTEON2, ArchOcteon2},
+ {64, 2, AFL_EXT_OCTEON3, ArchOcteon3},
+ {64, 1, AFL_EXT_SB1, ArchSB1},
+ {64, 1, AFL_EXT_XLR, ArchXLR}
+};
+
+static bool matchMipsISA(MipsISAs base, MipsISAs ext) {
+ if (base == ext)
+ return true;
+ if (base == Arch32 && matchMipsISA(Arch64, ext))
+ return true;
+ if (base == Arch32r2 && matchMipsISA(Arch64r2, ext))
+ return true;
+ for (const auto &edge : isaTree) {
+ if (ext == edge.child) {
+ ext = edge.parent;
+ if (ext == base)
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool is32BitElfFlags(unsigned flags) {
+ if (flags & EF_MIPS_32BITMODE)
+ return true;
+
+ unsigned arch = flags & EF_MIPS_ARCH;
+ if (arch == EF_MIPS_ARCH_1 || arch == EF_MIPS_ARCH_2 ||
+ arch == EF_MIPS_ARCH_32 || arch == EF_MIPS_ARCH_32R2 ||
+ arch == EF_MIPS_ARCH_32R6)
+ return true;
+
+ unsigned abi = flags & EF_MIPS_ABI;
+ if (abi == EF_MIPS_ABI_O32 || abi == EF_MIPS_ABI_EABI32)
+ return true;
+
+ return false;
+}
+
+static ErrorOr<MipsISAs> headerFlagsToIsa(uint32_t flags) {
+ uint32_t arch = flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
+ for (const auto &p : elfArchPairs)
+ if (p._elfFlag == arch)
+ return p._arch;
+ return make_dynamic_error_code(
+ StringRef("Unknown EF_MIPS_ARCH | EF_MIPS_MACH flags (0x") +
+ Twine::utohexstr(arch) + ")");
+}
+
+static uint32_t isaToHeaderFlags(unsigned isa) {
+ for (const auto &p : archElfPairs)
+ if (p._arch == isa)
+ return p._elfFlag;
+ llvm_unreachable("Unknown MIPS ISA");
+}
+
+static ErrorOr<uint32_t> flagsToAses(uint32_t flags) {
+ uint32_t ases = flags & EF_MIPS_ARCH_ASE;
+ switch (ases) {
+ case 0:
+ return 0;
+ case EF_MIPS_MICROMIPS:
+ return AFL_ASE_MICROMIPS;
+ case EF_MIPS_ARCH_ASE_M16:
+ return AFL_ASE_MIPS16;
+ case EF_MIPS_ARCH_ASE_MDMX:
+ return AFL_ASE_MDMX;
+ default:
+ return make_dynamic_error_code(
+ StringRef("Unknown EF_MIPS_ARCH_ASE flag (0x") +
+ Twine::utohexstr(ases) + ")");
+ }
+}
+
+static uint32_t asesToFlags(uint32_t ases) {
+ switch (ases) {
+ case AFL_ASE_MICROMIPS:
+ return EF_MIPS_MICROMIPS;
+ case AFL_ASE_MIPS16:
+ return EF_MIPS_ARCH_ASE_M16;
+ case AFL_ASE_MDMX:
+ return EF_MIPS_ARCH_ASE_MDMX;
+ default:
+ return 0;
+ }
+}
+
+static ErrorOr<MipsISAs> sectionFlagsToIsa(uint8_t isaLevel, uint8_t isaRev,
+ uint8_t isaExt) {
+ for (const auto &p : abiIsaArchPair)
+ if (p._isaLevel == isaLevel && p._isaRev == isaRev && p._isaExt == isaExt)
+ return p._arch;
+ return make_dynamic_error_code(
+ StringRef("Unknown ISA level/revision/extension ") + Twine(isaLevel) +
+ "/" + Twine(isaRev) + "/" + Twine(isaExt));
+}
+
+static std::tuple<uint8_t, uint8_t, uint32_t> isaToSectionFlags(unsigned isa) {
+ for (const auto &p : abiIsaArchPair)
+ if (p._arch == isa)
+ return std::make_tuple(p._isaLevel, p._isaRev, p._isaExt);
+ llvm_unreachable("Unknown MIPS ISA");
+}
+
+static bool checkCompatibility(const MipsAbiFlags &hdr,
+ const MipsAbiFlags &sec) {
+ uint32_t secIsa = ArchNone;
+ switch (sec._isa) {
+ case Arch32r3:
+ case Arch32r5:
+ secIsa = Arch32r2;
+ break;
+ case Arch64r3:
+ case Arch64r5:
+ secIsa = Arch64r2;
+ break;
+ default:
+ secIsa = sec._isa;
+ break;
+ }
+ if (secIsa != hdr._isa) {
+ llvm::errs() << "inconsistent ISA between .MIPS.abiflags "
+ "and ELF header e_flags field\n";
+ return false;
+ }
+ if ((sec._ases & hdr._ases) != hdr._ases) {
+ llvm::errs() << "inconsistent ASEs between .MIPS.abiflags "
+ "and ELF header e_flags field\n";
+ return false;
+ }
+ return true;
+}
+
+static int compareFpAbi(uint32_t fpA, uint32_t fpB) {
+ if (fpA == fpB)
+ return 0;
+ if (fpB == Val_GNU_MIPS_ABI_FP_ANY)
+ return 1;
+ if (fpB == Val_GNU_MIPS_ABI_FP_64A && fpA == Val_GNU_MIPS_ABI_FP_64)
+ return 1;
+ if (fpB != Val_GNU_MIPS_ABI_FP_XX)
+ return -1;
+ if (fpA == Val_GNU_MIPS_ABI_FP_DOUBLE || fpA == Val_GNU_MIPS_ABI_FP_64 ||
+ fpA == Val_GNU_MIPS_ABI_FP_64A)
+ return 1;
+ return -1;
+}
+
+static StringRef getFpAbiName(uint32_t fpAbi) {
+ switch (fpAbi) {
+ case Val_GNU_MIPS_ABI_FP_ANY:
+ return "<any>";
+ case Val_GNU_MIPS_ABI_FP_DOUBLE:
+ return "-mdouble-float";
+ case Val_GNU_MIPS_ABI_FP_SINGLE:
+ return "-msingle-float";
+ case Val_GNU_MIPS_ABI_FP_SOFT:
+ return "-msoft-float";
+ case Val_GNU_MIPS_ABI_FP_OLD_64:
+ return "-mips32r2 -mfp64 (old)";
+ case Val_GNU_MIPS_ABI_FP_XX:
+ return "-mfpxx";
+ case Val_GNU_MIPS_ABI_FP_64:
+ return "-mgp32 -mfp64";
+ case Val_GNU_MIPS_ABI_FP_64A:
+ return "-mgp32 -mfp64 -mno-odd-spreg";
+ default:
+ return "<unknown>";
+ }
+}
+
+static uint32_t selectFpAbiFlag(uint32_t oldFp, uint32_t newFp) {
+ if (compareFpAbi(newFp, oldFp) >= 0)
+ return newFp;
+ if (compareFpAbi(oldFp, newFp) < 0)
+ llvm::errs() << "FP ABI " << getFpAbiName(oldFp) << " is incompatible with "
+ << getFpAbiName(newFp) << "\n";
+ return oldFp;
+}
+
+namespace lld {
+namespace elf {
+
+template <class ELFT> bool MipsAbiInfoHandler<ELFT>::isMicroMips() const {
+ assert(_abiFlags.hasValue());
+ return _abiFlags->_ases & AFL_ASE_MICROMIPS;
+}
+
+template <class ELFT> bool MipsAbiInfoHandler<ELFT>::isMipsR6() const {
+ assert(_abiFlags.hasValue());
+ return _abiFlags->_isa == Arch32r6 || _abiFlags->_isa == Arch64r6;
+}
+
+template <class ELFT> bool MipsAbiInfoHandler<ELFT>::isFp64() const {
+ assert(_abiFlags.hasValue());
+ return _abiFlags->_fpAbi == Val_GNU_MIPS_ABI_FP_64 ||
+ _abiFlags->_fpAbi == Val_GNU_MIPS_ABI_FP_64A;
+}
+
+template <class ELFT> bool MipsAbiInfoHandler<ELFT>::isCPicOnly() const {
+ assert(_abiFlags.hasValue());
+ return _abiFlags->_isCPic && !_abiFlags->_isPic;
+}
+
+template <class ELFT> uint32_t MipsAbiInfoHandler<ELFT>::getFlags() const {
+ std::lock_guard<std::mutex> lock(_mutex);
+ uint32_t flags = 0;
+ if (_abiFlags.hasValue()) {
+ flags |= isaToHeaderFlags(_abiFlags->_isa);
+ flags |= asesToFlags(_abiFlags->_ases);
+ flags |= _abiFlags->_abi;
+ flags |= _abiFlags->_isPic ? EF_MIPS_PIC : 0u;
+ flags |= _abiFlags->_isCPic ? EF_MIPS_CPIC : 0u;
+ flags |= _abiFlags->_isNoReorder ? EF_MIPS_NOREORDER : 0u;
+ flags |= _abiFlags->_is32BitMode ? EF_MIPS_32BITMODE : 0u;
+ flags |= _abiFlags->_isNan2008 ? EF_MIPS_NAN2008 : 0u;
+ }
+ return flags;
+}
+
+template <class ELFT>
+llvm::Optional<typename MipsAbiInfoHandler<ELFT>::Elf_Mips_RegInfo>
+MipsAbiInfoHandler<ELFT>::getRegistersMask() const {
+ std::lock_guard<std::mutex> lock(_mutex);
+ return _regMask;
+}
+
+template <class ELFT>
+llvm::Optional<typename MipsAbiInfoHandler<ELFT>::Elf_Mips_ABIFlags>
+MipsAbiInfoHandler<ELFT>::getAbiFlags() const {
+ std::lock_guard<std::mutex> lock(_mutex);
+ if (!_hasAbiSection)
+ return llvm::Optional<Elf_Mips_ABIFlags>();
+
+ Elf_Mips_ABIFlags sec;
+ sec.version = 0;
+ std::tie(sec.isa_level, sec.isa_rev, sec.isa_ext) =
+ isaToSectionFlags(_abiFlags->_isa);
+ sec.gpr_size = _abiFlags->_gprSize;
+ sec.cpr1_size = _abiFlags->_cpr1Size;
+ sec.cpr2_size = _abiFlags->_cpr2Size;
+ sec.fp_abi = _abiFlags->_fpAbi;
+ sec.ases = _abiFlags->_ases;
+ sec.flags1 = _abiFlags->_flags1;
+ sec.flags2 = 0;
+ return sec;
+}
+
+template <class ELFT> MipsAbi MipsAbiInfoHandler<ELFT>::getAbi() const {
+ if (!_abiFlags.hasValue())
+ return ELFT::Is64Bits ? MipsAbi::N64 : MipsAbi::O32;
+ switch (_abiFlags->_abi & (EF_MIPS_ABI_O32 | EF_MIPS_ABI2)) {
+ case EF_MIPS_ABI_O32:
+ return MipsAbi::O32;
+ case EF_MIPS_ABI2:
+ return MipsAbi::N32;
+ case 0:
+ return MipsAbi::N64;
+ default:
+ llvm_unreachable("Unknown ABI flag");
+ }
+}
+
+template <class ELFT>
+std::error_code
+MipsAbiInfoHandler<ELFT>::mergeFlags(uint32_t newFlags,
+ const Elf_Mips_ABIFlags *newSec) {
+ std::lock_guard<std::mutex> lock(_mutex);
+
+ ErrorOr<MipsAbiFlags> abiFlags = createAbiFlags(newFlags, newSec);
+ if (auto ec = abiFlags.getError())
+ return ec;
+
+ // We support three ABI: O32, N32, and N64. The last one does not have
+ // the corresponding ELF flag.
+ if (ELFT::Is64Bits) {
+ if (abiFlags->_abi)
+ return make_dynamic_error_code("Unsupported ABI");
+ } else {
+ if (!(abiFlags->_abi & (EF_MIPS_ABI_O32 | EF_MIPS_ABI2)))
+ return make_dynamic_error_code("Unsupported ABI");
+ }
+
+ // ... and still do not support MIPS-16 extension.
+ if (abiFlags->_ases & AFL_ASE_MIPS16)
+ return make_dynamic_error_code("Unsupported extension: MIPS16");
+
+ // PIC code is inherently CPIC and may not set CPIC flag explicitly.
+ // Ensure that this flag will exist in the linked file.
+ if (abiFlags->_isPic)
+ abiFlags->_isCPic = true;
+
+ // If the old set of flags is empty, use the new one as a result.
+ if (!_abiFlags.hasValue()) {
+ _abiFlags = *abiFlags;
+ return std::error_code();
+ }
+
+ // Check ABI compatibility.
+ if (abiFlags->_abi != _abiFlags->_abi)
+ return make_dynamic_error_code("Linking modules with incompatible ABI");
+
+ // Check PIC / CPIC flags compatibility.
+ if (abiFlags->_isCPic != _abiFlags->_isCPic)
+ llvm::errs() << "lld warning: linking abicalls and non-abicalls files\n";
+
+ if (!abiFlags->_isPic)
+ _abiFlags->_isPic = false;
+ if (abiFlags->_isCPic)
+ _abiFlags->_isCPic = true;
+
+ // Check mixing -mnan=2008 / -mnan=legacy modules.
+ if (abiFlags->_isNan2008 != _abiFlags->_isNan2008)
+ return make_dynamic_error_code(
+ "Linking -mnan=2008 and -mnan=legacy modules");
+
+ // Check ISA compatibility and update the extension flag.
+ if (!matchMipsISA(MipsISAs(abiFlags->_isa), MipsISAs(_abiFlags->_isa))) {
+ if (!matchMipsISA(MipsISAs(_abiFlags->_isa), MipsISAs(abiFlags->_isa)))
+ return make_dynamic_error_code("Linking modules with incompatible ISA");
+ _abiFlags->_isa = abiFlags->_isa;
+ }
+
+ _abiFlags->_ases |= abiFlags->_ases;
+ _abiFlags->_isNoReorder = _abiFlags->_isNoReorder || abiFlags->_isNoReorder;
+ _abiFlags->_is32BitMode = _abiFlags->_is32BitMode || abiFlags->_is32BitMode;
+
+ _abiFlags->_fpAbi = selectFpAbiFlag(_abiFlags->_fpAbi, abiFlags->_fpAbi);
+ _abiFlags->_gprSize = std::max(_abiFlags->_gprSize, abiFlags->_gprSize);
+ _abiFlags->_cpr1Size = std::max(_abiFlags->_cpr1Size, abiFlags->_cpr1Size);
+ _abiFlags->_cpr2Size = std::max(_abiFlags->_cpr2Size, abiFlags->_cpr2Size);
+ _abiFlags->_flags1 |= abiFlags->_flags1;
+
+ return std::error_code();
+}
+
+template <class ELFT>
+void MipsAbiInfoHandler<ELFT>::mergeRegistersMask(
+ const Elf_Mips_RegInfo &info) {
+ std::lock_guard<std::mutex> lock(_mutex);
+ if (!_regMask.hasValue()) {
+ _regMask = info;
+ return;
+ }
+ _regMask->ri_gprmask = _regMask->ri_gprmask | info.ri_gprmask;
+ _regMask->ri_cprmask[0] = _regMask->ri_cprmask[0] | info.ri_cprmask[0];
+ _regMask->ri_cprmask[1] = _regMask->ri_cprmask[1] | info.ri_cprmask[1];
+ _regMask->ri_cprmask[2] = _regMask->ri_cprmask[2] | info.ri_cprmask[2];
+ _regMask->ri_cprmask[3] = _regMask->ri_cprmask[3] | info.ri_cprmask[3];
+}
+
+template <class ELFT>
+ErrorOr<MipsAbiFlags>
+MipsAbiInfoHandler<ELFT>::createAbiFlags(uint32_t flags,
+ const Elf_Mips_ABIFlags *sec) {
+ ErrorOr<MipsAbiFlags> hdrFlags = createAbiFromHeaderFlags(flags);
+ if (auto ec = hdrFlags.getError())
+ return ec;
+ if (!sec)
+ return *hdrFlags;
+ ErrorOr<MipsAbiFlags> secFlags = createAbiFromSection(*sec);
+ if (auto ec = secFlags.getError())
+ return ec;
+ if (!checkCompatibility(*hdrFlags, *secFlags))
+ return *hdrFlags;
+
+ _hasAbiSection = true;
+
+ secFlags->_abi = hdrFlags->_abi;
+ secFlags->_isPic = hdrFlags->_isPic;
+ secFlags->_isCPic = hdrFlags->_isCPic;
+ secFlags->_isNoReorder = hdrFlags->_isNoReorder;
+ secFlags->_is32BitMode = hdrFlags->_is32BitMode;
+ secFlags->_isNan2008 = hdrFlags->_isNan2008;
+ return *secFlags;
+}
+
+template <class ELFT>
+ErrorOr<MipsAbiFlags>
+MipsAbiInfoHandler<ELFT>::createAbiFromHeaderFlags(uint32_t flags) {
+ MipsAbiFlags abi;
+ ErrorOr<MipsISAs> isa = headerFlagsToIsa(flags);
+ if (auto ec = isa.getError())
+ return ec;
+ abi._isa = *isa;
+
+ abi._fpAbi = Val_GNU_MIPS_ABI_FP_ANY;
+ abi._cpr1Size = AFL_REG_NONE;
+ abi._cpr2Size = AFL_REG_NONE;
+ abi._gprSize = is32BitElfFlags(flags) ? AFL_REG_32 : AFL_REG_64;
+
+ ErrorOr<uint32_t> ases = flagsToAses(flags);
+ if (auto ec = ases.getError())
+ return ec;
+ abi._ases = *ases;
+ abi._flags1 = 0;
+ abi._abi = flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
+ abi._isPic = flags & EF_MIPS_PIC;
+ abi._isCPic = flags & EF_MIPS_CPIC;
+ abi._isNoReorder = flags & EF_MIPS_NOREORDER;
+ abi._is32BitMode = flags & EF_MIPS_32BITMODE;
+ abi._isNan2008 = flags & EF_MIPS_NAN2008;
+ return abi;
+}
+
+template <class ELFT>
+ErrorOr<MipsAbiFlags>
+MipsAbiInfoHandler<ELFT>::createAbiFromSection(const Elf_Mips_ABIFlags &sec) {
+ MipsAbiFlags abi;
+ ErrorOr<MipsISAs> isa =
+ sectionFlagsToIsa(sec.isa_level, sec.isa_rev, sec.isa_ext);
+ if (auto ec = isa.getError())
+ return ec;
+ abi._isa = *isa;
+ abi._fpAbi = sec.fp_abi;
+ abi._cpr1Size = sec.cpr1_size;
+ abi._cpr2Size = sec.cpr2_size;
+ abi._gprSize = sec.gpr_size;
+ abi._ases = sec.ases;
+ abi._flags1 = sec.flags1;
+ if (sec.flags2 != 0)
+ return make_dynamic_error_code("unexpected non-zero 'flags2' value");
+ return abi;
+}
+
+template class MipsAbiInfoHandler<ELF32BE>;
+template class MipsAbiInfoHandler<ELF32LE>;
+template class MipsAbiInfoHandler<ELF64BE>;
+template class MipsAbiInfoHandler<ELF64LE>;
+
+}
+}