summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/Writer.cpp206
-rw-r--r--lld/test/ELF/mips-elf-flags-err.s52
-rw-r--r--lld/test/ELF/mips-elf-flags.s7
3 files changed, 250 insertions, 15 deletions
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index dd28c68ce8d..f98530b94eb 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1138,21 +1138,201 @@ template <class ELFT> void Writer<ELFT>::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 <class ELFT> static uint32_t getMipsEFlags() {
- // FIXME: ELF flags depends on ELF flags of all input object files and
- // selected emulation. For now pick the arch flag from the fisrt input file
- // and use hard coded values for other flags.
- uint32_t FirstElfFlags =
- cast<ELFFileBase<ELFT>>(Config->FirstElf)->getObj().getHeader()->e_flags;
- uint32_t ElfFlags = FirstElfFlags & EF_MIPS_ARCH;
- if (ELFT::Is64Bits)
- ElfFlags |= EF_MIPS_CPIC | EF_MIPS_PIC;
- else {
- ElfFlags |= EF_MIPS_CPIC | EF_MIPS_ABI_O32;
- if (Config->Shared)
- ElfFlags |= EF_MIPS_PIC;
+ // 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<elf::ObjectFile<ELFT>> &F :
+ Symtab<ELFT>::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 ElfFlags;
+ return ResFlags;
}
template <class ELFT> static typename ELFT::uint getEntryAddr() {
diff --git a/lld/test/ELF/mips-elf-flags-err.s b/lld/test/ELF/mips-elf-flags-err.s
new file mode 100644
index 00000000000..358608fbda4
--- /dev/null
+++ b/lld/test/ELF/mips-elf-flags-err.s
@@ -0,0 +1,52 @@
+# Check MIPS ELF ISA flag calculation if input files have different ISAs.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: -mcpu=mips32 %S/Inputs/mips-dynamic.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: -mcpu=mips32r2 %s -o %t2.o
+# RUN: ld.lld %t1.o %t2.o -o %t.exe
+# RUN: llvm-readobj -h %t.exe | FileCheck -check-prefix=R1R2 %s
+
+# Check that lld does not allow to link incompatible ISAs.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: -mcpu=mips32 %S/Inputs/mips-dynamic.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: -mcpu=mips32r6 %s -o %t2.o
+# RUN: not ld.lld %t1.o %t2.o -o %t.exe 2>&1 | FileCheck -check-prefix=R1R6 %s
+
+# Check that lld does not allow to link incompatible ABIs.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: -target-abi n32 %S/Inputs/mips-dynamic.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: -target-abi o32 %s -o %t2.o
+# RUN: not ld.lld %t1.o %t2.o -o %t.exe 2>&1 | FileCheck -check-prefix=N32O32 %s
+
+# Check that lld does not allow to link modules with incompatible NAN flags.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: -mattr=+nan2008 %S/Inputs/mips-dynamic.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: %s -o %t2.o
+# RUN: not ld.lld %t1.o %t2.o -o %t.exe 2>&1 | FileCheck -check-prefix=NAN %s
+
+# REQUIRES: mips
+
+ .option pic0
+ .text
+ .global __start
+__start:
+ nop
+
+# R1R2: Flags [
+# R1R2-NEXT: EF_MIPS_ABI_O32
+# R1R2-NEXT: EF_MIPS_ARCH_32R2
+# R1R2-NEXT: EF_MIPS_CPIC
+# R1R2-NEXT: ]
+
+# 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
+
+# NAN: target -mnan=2008 is incompatible with -mnan=legacy: {{.*}}mips-elf-flags-err.s.tmp2.o
diff --git a/lld/test/ELF/mips-elf-flags.s b/lld/test/ELF/mips-elf-flags.s
index c71e2b181cc..ecd4f22ba1c 100644
--- a/lld/test/ELF/mips-elf-flags.s
+++ b/lld/test/ELF/mips-elf-flags.s
@@ -1,8 +1,10 @@
# Check generation of MIPS specific ELF header flags.
-# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
-# RUN: ld.lld %t.o -shared -o %t.so
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: %S/Inputs/mips-dynamic.s -o %t-so.o
+# RUN: ld.lld %t-so.o -shared -o %t.so
# RUN: llvm-readobj -h %t.so | FileCheck -check-prefix=SO %s
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
# RUN: ld.lld %t.o -o %t.exe
# RUN: llvm-readobj -h %t.exe | FileCheck -check-prefix=EXE %s
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
@@ -44,4 +46,5 @@ __start:
# EXE-R6-NEXT: EF_MIPS_ABI_O32
# EXE-R6-NEXT: EF_MIPS_ARCH_32R6
# EXE-R6-NEXT: EF_MIPS_CPIC
+# EXE-R6-NEXT: EF_MIPS_NAN2008
# EXE-R6-NEXT: ]
OpenPOWER on IntegriCloud