[ELF2] Handle -m option

Parse and apply emulation given with -m option.
Check input files to match ELF type and machine architecture provided with -m.

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

llvm-svn: 249529
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index fb76f6a..a8170b1 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -19,6 +19,7 @@
 #include "llvm/Support/Path.h"
 
 using namespace llvm;
+using namespace llvm::ELF;
 
 using namespace lld;
 using namespace lld::elf2;
@@ -34,6 +35,30 @@
   Driver->link(Args.slice(1));
 }
 
+static void setELFType(StringRef Emul) {
+  if (Emul == "elf_i386") {
+    Config->ElfKind = ELF32LEKind;
+    Config->EMachine = EM_386;
+    return;
+  }
+  if (Emul == "elf_x86_64") {
+    Config->ElfKind = ELF64LEKind;
+    Config->EMachine = EM_X86_64;
+    return;
+  }
+  if (Emul == "elf32ppc") {
+    Config->ElfKind = ELF32BEKind;
+    Config->EMachine = EM_PPC;
+    return;
+  }
+  if (Emul == "elf64ppc") {
+    Config->ElfKind = ELF64BEKind;
+    Config->EMachine = EM_PPC64;
+    return;
+  }
+  error(Twine("Unknown emulation: ") + Emul);
+}
+
 // Makes a path by concatenating Dir and File.
 // If Dir starts with '=' the result will be preceded by Sysroot,
 // which can be set with --sysroot command line switch.
@@ -67,6 +92,28 @@
   error(Twine("Unable to find library -l") + Path);
 }
 
+template <template <class> class T>
+std::unique_ptr<ELFFileBase>
+LinkerDriver::createELFInputFile(MemoryBufferRef MB) {
+  std::unique_ptr<ELFFileBase> File = createELFFile<T>(MB);
+  const ELFKind ElfKind = File->getELFKind();
+  const uint16_t EMachine = File->getEMachine();
+
+  // Grab target from the first input file if wasn't set by -m option.
+  if (Config->ElfKind == ELFNoneKind) {
+    Config->ElfKind = ElfKind;
+    Config->EMachine = EMachine;
+    return File;
+  }
+  if (ElfKind == Config->ElfKind && EMachine == Config->EMachine)
+    return File;
+
+  if (const ELFFileBase *First = Symtab.getFirstELF())
+    error(MB.getBufferIdentifier() + " is incompatible with " +
+          First->getName());
+  error(MB.getBufferIdentifier() + " is incompatible with target architecture");
+}
+
 // Opens and parses a file. Path has to be resolved already.
 // Newly created memory buffers are owned by this driver.
 void LinkerDriver::addFile(StringRef Path) {
@@ -85,10 +132,10 @@
     Symtab.addFile(make_unique<ArchiveFile>(MBRef));
     return;
   case file_magic::elf_shared_object:
-    Symtab.addFile(createELFFile<SharedFile>(MBRef));
+    Symtab.addFile(createELFInputFile<SharedFile>(MBRef));
     return;
   default:
-    Symtab.addFile(createELFFile<ObjectFile>(MBRef));
+    Symtab.addFile(createELFInputFile<ObjectFile>(MBRef));
   }
 }
 
@@ -126,6 +173,9 @@
   if (auto *Arg = Args.getLastArg(OPT_soname))
     Config->SoName = Arg->getValue();
 
+  if (auto *Arg = Args.getLastArg(OPT_m))
+    setELFType(Arg->getValue());
+
   Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition);
   Config->DiscardAll = Args.hasArg(OPT_discard_all);
   Config->DiscardLocals = Args.hasArg(OPT_discard_locals);
@@ -185,5 +235,7 @@
   case ELF64BEKind:
     writeResult<object::ELF64BE>(&Symtab);
     return;
+  default:
+    llvm_unreachable("Invalid kind");
   }
 }