[lld] r277911 - [ELF][MIPS] Produce a correct and complete set of MIPS ELF header flags

Simon Atanasyan via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 5 22:11:42 PDT 2016


Author: atanasyan
Date: Sat Aug  6 00:11:41 2016
New Revision: 277911

URL: http://llvm.org/viewvc/llvm-project?rev=277911&view=rev
Log:
[ELF][MIPS] Produce a correct and complete set of MIPS ELF header flags

The patch extends the `getMipsEFlags` function. Now in that function
we iterate over all object files, parse ELF header flags and merge them.
If a file is incompatible with previously analyzed ones we show an error
or warning. That can happen if, for example, we try to link files with
incompatible ABI, ISA, NAN encoding etc.

There is an alternative solution. We can check and merge flags and
reject incompatible input modules in the `isCompatible` function which
is called from the `SymbolTable::addFile` method. But in that case we
have to save and keep somewhere a merged ELF flags combination to use it
later in the writer.

Differential Revision: http://reviews.llvm.org/D23161

Added:
    lld/trunk/test/ELF/mips-elf-flags-err.s
Modified:
    lld/trunk/ELF/Writer.cpp
    lld/trunk/test/ELF/mips-elf-flags.s

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=277911&r1=277910&r2=277911&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Sat Aug  6 00:11:41 2016
@@ -1138,21 +1138,201 @@ template <class ELFT> void Writer<ELFT>:
   }
 }
 
+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() {

Added: lld/trunk/test/ELF/mips-elf-flags-err.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-elf-flags-err.s?rev=277911&view=auto
==============================================================================
--- lld/trunk/test/ELF/mips-elf-flags-err.s (added)
+++ lld/trunk/test/ELF/mips-elf-flags-err.s Sat Aug  6 00:11:41 2016
@@ -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

Modified: lld/trunk/test/ELF/mips-elf-flags.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/mips-elf-flags.s?rev=277911&r1=277910&r2=277911&view=diff
==============================================================================
--- lld/trunk/test/ELF/mips-elf-flags.s (original)
+++ lld/trunk/test/ELF/mips-elf-flags.s Sat Aug  6 00:11:41 2016
@@ -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: ]




More information about the llvm-commits mailing list