From 31f32fa62aab473aa58291af0a6984aa1a36f2ee Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Mon, 8 Aug 2016 19:39:45 +0000 Subject: [PATCH] Refactor getMipsEFlags. Previously, we incrementally updated the reuslting flag as we check file flags, so it was not very clear who is updating what flags. This patch makes them pure functions -- that has no side effect and don't update arguments to improve readability. Now each function construct a patial result, and all resutls are then bitwise-OR'ed to construct the final result. This patch also creates a new file, Mips.cpp, to move all these MIPS functions to a separate file. Differential Revision: https://reviews.llvm.org/D23249 llvm-svn: 278042 --- lld/ELF/CMakeLists.txt | 1 + lld/ELF/Mips.cpp | 217 ++++++++++++++++++++++++++++++ lld/ELF/Writer.cpp | 197 --------------------------- lld/ELF/Writer.h | 2 + lld/test/ELF/mips-elf-flags-err.s | 2 +- 5 files changed, 221 insertions(+), 198 deletions(-) create mode 100644 lld/ELF/Mips.cpp diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt index cabdd9a09663..4ab303b76b34 100644 --- a/lld/ELF/CMakeLists.txt +++ b/lld/ELF/CMakeLists.txt @@ -13,6 +13,7 @@ add_lld_library(lldELF LTO.cpp LinkerScript.cpp MarkLive.cpp + Mips.cpp OutputSections.cpp Relocations.cpp ScriptParser.cpp diff --git a/lld/ELF/Mips.cpp b/lld/ELF/Mips.cpp new file mode 100644 index 000000000000..fbd1b007f8b5 --- /dev/null +++ b/lld/ELF/Mips.cpp @@ -0,0 +1,217 @@ +//===- 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/Object/ELF.h" +#include "llvm/Support/ELF.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) + warning("linking abicalls code with non-abicalls file: " + F.Filename); + if (!IsPic && IsPic2) + warning("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 + // MIPS64 extensions. + {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64}, + // MIPS V extensions. + {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5}, + // MIPS IV extensions. + {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4}, + // MIPS III extensions. + {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_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 getArchName(uint32_t Flags) { + switch (Flags) { + 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"; + } +} + +static uint32_t getArchFlags(ArrayRef Files) { + uint32_t Ret = Files[0].Flags & EF_MIPS_ARCH; + + for (const FileFlags &F : Files.slice(1)) { + uint32_t New = F.Flags & EF_MIPS_ARCH; + + // 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 (const std::unique_ptr> &F : + Symtab::X->getObjectFiles()) + V.push_back({F->getName(), F->getObj().getHeader()->e_flags}); + + checkFlags(V); + return getMiscFlags(V) | getPicFlags(V) | getArchFlags(V); +} + +template uint32_t elf::getMipsEFlags(); +template uint32_t elf::getMipsEFlags(); +template uint32_t elf::getMipsEFlags(); +template uint32_t elf::getMipsEFlags(); diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 8ab906dfd139..7392480a2b87 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1142,203 +1142,6 @@ template void Writer::setPhdrs() { } } -namespace { -struct MipsIsaTreeEdge { - uint32_t Child; - uint32_t Parent; -}; -} - -static MipsIsaTreeEdge MipsIsaTree[] = { - // MIPS32R6 and MIPS64R6 are not compatible with other extensions - // MIPS64 extensions. - {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64}, - // MIPS V extensions. - {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5}, - // MIPS IV extensions. - {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4}, - // MIPS III extensions. - {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_2, EF_MIPS_ARCH_1}, -}; - -static bool isMipsIsaMatched(uint32_t New, uint32_t Res) { - if (New == Res) - return true; - if (New == EF_MIPS_ARCH_32 && isMipsIsaMatched(EF_MIPS_ARCH_64, Res)) - return true; - if (New == EF_MIPS_ARCH_32R2 && isMipsIsaMatched(EF_MIPS_ARCH_64R2, Res)) - return true; - for (const auto &Edge : MipsIsaTree) { - if (Res == Edge.Child) { - Res = Edge.Parent; - if (Res == New) - return true; - } - } - return false; -} - -static StringRef getMipsIsaName(uint32_t Flags) { - switch (Flags) { - 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"; - } -} - -static StringRef getMipsAbiName(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 getMipsNanName(bool IsNan2008) { - return IsNan2008 ? "2008" : "legacy"; -} - -static StringRef getMipsFpName(bool IsFp64) { return IsFp64 ? "64" : "32"; } - -static uint32_t updateMipsPicFlags(uint32_t ResFlags, uint32_t NewFlags, - StringRef FName) { - uint32_t NewPic = NewFlags & (EF_MIPS_PIC | EF_MIPS_CPIC); - uint32_t ResPic = ResFlags & (EF_MIPS_PIC | EF_MIPS_CPIC); - - // Check PIC / CPIC flags compatibility. - if (NewPic && !ResPic) - warning("linking non-abicalls code with abicalls file: " + FName); - if (!NewPic && ResPic) - warning("linking abicalls code with non-abicalls file: " + FName); - - if (!(NewPic & EF_MIPS_PIC)) - ResFlags &= ~EF_MIPS_PIC; - if (NewPic) - ResFlags |= EF_MIPS_CPIC; - return ResFlags; -} - -static uint32_t updateMipsIsaFlags(uint32_t ResFlags, uint32_t NewFlags, - StringRef FName) { - uint32_t NewIsa = NewFlags & EF_MIPS_ARCH; - uint32_t ResIsa = ResFlags & EF_MIPS_ARCH; - - // Check ISA compatibility. - if (isMipsIsaMatched(NewIsa, ResIsa)) - return ResFlags; - if (!isMipsIsaMatched(ResIsa, NewIsa)) { - error("target isa '" + getMipsIsaName(ResIsa) + "' is incompatible with '" + - getMipsIsaName(NewIsa) + "': " + FName); - return ResFlags; - } - ResFlags &= ~EF_MIPS_ARCH; - ResFlags |= NewIsa; - return ResFlags; -} - -static void checkMipsAbiFlags(uint32_t ResFlags, uint32_t NewFlags, - StringRef FName) { - uint32_t NewAbi = NewFlags & (EF_MIPS_ABI | EF_MIPS_ABI2); - uint32_t ResAbi = ResFlags & (EF_MIPS_ABI | EF_MIPS_ABI2); - // Check ABI compatibility. - if (NewAbi != ResAbi) - error("target ABI '" + getMipsAbiName(ResAbi) + "' is incompatible with '" + - getMipsAbiName(NewAbi) + "': " + FName); -} - -static void checkMipsNanFlags(uint32_t ResFlags, uint32_t NewFlags, - StringRef FName) { - bool NewNan2008 = NewFlags & EF_MIPS_NAN2008; - bool ResNan2008 = ResFlags & EF_MIPS_NAN2008; - // Check -mnan flags compatibility. - if (NewNan2008 != ResNan2008) - error("target -mnan=" + getMipsNanName(ResNan2008) + - " is incompatible with -mnan=" + getMipsNanName(NewNan2008) + ": " + - FName); -} - -static void checkMipsFpFlags(uint32_t ResFlags, uint32_t NewFlags, - StringRef FName) { - bool NewFp64 = NewFlags & EF_MIPS_FP64; - bool ResFp64 = ResFlags & EF_MIPS_FP64; - // Check FP64 compatibility. - if (NewFp64 != ResFp64) - error("target -mfp" + getMipsFpName(ResFp64) + - " is incompatible with -mfp" + getMipsFpName(NewFp64) + ": " + FName); -} - -template static uint32_t getMipsEFlags() { - // Iterates over all object files andretrieve ELF header flags - // to check that ISA, ABI and features declared by these flags - // are compatible with each other. - uint32_t ResFlags = 0; - for (const std::unique_ptr> &F : - Symtab::X->getObjectFiles()) { - uint32_t NewFlags = F->getObj().getHeader()->e_flags; - if (ResFlags == 0) { - if (NewFlags & EF_MIPS_PIC) - // PIC code is inherently CPIC - // and may not set CPIC flag explicitly. - NewFlags |= EF_MIPS_CPIC; - ResFlags = NewFlags; - continue; - } - - ResFlags = updateMipsPicFlags(ResFlags, NewFlags, F->getName()); - ResFlags = updateMipsIsaFlags(ResFlags, NewFlags, F->getName()); - - checkMipsAbiFlags(ResFlags, NewFlags, F->getName()); - checkMipsNanFlags(ResFlags, NewFlags, F->getName()); - checkMipsFpFlags(ResFlags, NewFlags, F->getName()); - - ResFlags |= NewFlags & EF_MIPS_ARCH_ASE; - ResFlags |= NewFlags & EF_MIPS_NOREORDER; - ResFlags |= NewFlags & EF_MIPS_MICROMIPS; - ResFlags |= NewFlags & EF_MIPS_NAN2008; - ResFlags |= NewFlags & EF_MIPS_32BITMODE; - } - return ResFlags; -} - template static typename ELFT::uint getEntryAddr() { if (Symbol *S = Config->EntrySym) return S->body()->getVA(); diff --git a/lld/ELF/Writer.h b/lld/ELF/Writer.h index 9e6e3671c40d..9caf7a7a10e6 100644 --- a/lld/ELF/Writer.h +++ b/lld/ELF/Writer.h @@ -45,6 +45,8 @@ template llvm::StringRef getOutputSectionName(InputSectionBase *S); template void reportDiscarded(InputSectionBase *IS); + +template uint32_t getMipsEFlags(); } } diff --git a/lld/test/ELF/mips-elf-flags-err.s b/lld/test/ELF/mips-elf-flags-err.s index 358608fbda49..bab6ed137b7d 100644 --- a/lld/test/ELF/mips-elf-flags-err.s +++ b/lld/test/ELF/mips-elf-flags-err.s @@ -45,7 +45,7 @@ __start: # R1R2-NEXT: EF_MIPS_CPIC # R1R2-NEXT: ] -# R1R6: target isa 'mips32' is incompatible with 'mips32r6': {{.*}}mips-elf-flags-err.s.tmp2.o +# R1R6: target ISA 'mips32' is incompatible with 'mips32r6': {{.*}}mips-elf-flags-err.s.tmp2.o # N32O32: target ABI 'n32' is incompatible with 'o32': {{.*}}mips-elf-flags-err.s.tmp2.o