| //===- 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>; |
| |
| } |
| } |