Index: lld/trunk/ELF/Config.h =================================================================== --- lld/trunk/ELF/Config.h +++ lld/trunk/ELF/Config.h @@ -11,12 +11,21 @@ #define LLD_ELF_CONFIG_H #include "llvm/ADT/StringRef.h" +#include "llvm/Support/ELF.h" #include <vector> namespace lld { namespace elf2 { +enum ELFKind { + ELFNoneKind, + ELF32LEKind, + ELF32BEKind, + ELF64LEKind, + ELF64BEKind +}; + struct Configuration { llvm::StringRef DynamicLinker; llvm::StringRef Entry; @@ -38,6 +47,8 @@ bool Shared; bool Static = false; bool WholeArchive = false; + ELFKind ElfKind = ELFNoneKind; + uint16_t EMachine = llvm::ELF::EM_NONE; }; extern Configuration *Config; Index: lld/trunk/ELF/Driver.h =================================================================== --- lld/trunk/ELF/Driver.h +++ lld/trunk/ELF/Driver.h @@ -38,6 +38,9 @@ void addFile(StringRef Path); private: + template <template <class> class T> + std::unique_ptr<ELFFileBase> createELFInputFile(MemoryBufferRef MB); + SymbolTable Symtab; ArgParser Parser; std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs; Index: lld/trunk/ELF/Driver.cpp =================================================================== --- lld/trunk/ELF/Driver.cpp +++ lld/trunk/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"); } } Index: lld/trunk/ELF/InputFiles.h =================================================================== --- lld/trunk/ELF/InputFiles.h +++ lld/trunk/ELF/InputFiles.h @@ -10,6 +10,7 @@ #ifndef LLD_ELF_INPUT_FILES_H #define LLD_ELF_INPUT_FILES_H +#include "Config.h" #include "InputSection.h" #include "Error.h" #include "Symbols.h" @@ -49,8 +50,6 @@ const Kind FileKind; }; -enum ELFKind { ELF32LEKind, ELF32BEKind, ELF64LEKind, ELF64BEKind }; - class ELFFileBase : public InputFile { public: ELFFileBase(Kind K, ELFKind EKind, MemoryBufferRef M) @@ -60,7 +59,6 @@ return K == ObjectKind || K == SharedKind; } - bool isCompatibleWith(const ELFFileBase &Other) const; ELFKind getELFKind() const { return EKind; } uint16_t getEMachine() const; Index: lld/trunk/ELF/InputFiles.cpp =================================================================== --- lld/trunk/ELF/InputFiles.cpp +++ lld/trunk/ELF/InputFiles.cpp @@ -38,13 +38,9 @@ return ::getEMachine<ELF64BE>(*this); case ELF64LEKind: return ::getEMachine<ELF64LE>(*this); + default: + llvm_unreachable("Invalid kind"); } - llvm_unreachable("Invalid kind"); -} - -bool ELFFileBase::isCompatibleWith(const ELFFileBase &Other) const { - return getELFKind() == Other.getELFKind() && - getEMachine() == Other.getEMachine(); } namespace { Index: lld/trunk/ELF/Options.td =================================================================== --- lld/trunk/ELF/Options.td +++ lld/trunk/ELF/Options.td @@ -47,6 +47,9 @@ def l : Joined<["-"], "l">, MetaVarName<"<libName>">, HelpText<"Root name of library to use">; +def m : Separate<["-"], "m">, + HelpText<"Set target emulation">; + def no_allow_shlib_undefined : Flag<["--"], "no-allow-shlib-undefined">; def no_whole_archive : Flag<["--"], "no-whole-archive">, @@ -105,7 +108,6 @@ def end_group : Flag<["--"], "end-group">; def gc_sections : Flag<["--"], "gc-sections">; def hash_style : Joined<["--"], "hash-style=">; -def m : Separate<["-"], "m">; def no_add_needed : Flag<["--"], "no-add-needed">; def no_as_needed : Flag<["--"], "no-as-needed">; def no_fatal_warnings : Flag<["--"], "no-fatal-warnings">; Index: lld/trunk/ELF/SymbolTable.cpp =================================================================== --- lld/trunk/ELF/SymbolTable.cpp +++ lld/trunk/ELF/SymbolTable.cpp @@ -84,6 +84,8 @@ case ELF64BEKind: addUndefinedSym<ELF64BE>(Name); break; + default: + llvm_unreachable("Invalid kind"); } } @@ -138,9 +140,6 @@ template <class ELFT> void SymbolTable::addELFFile(ELFFileBase *File) { const ELFFileBase *Old = getFirstELF(); - if (Old && !Old->isCompatibleWith(*File)) - error(Twine(Old->getName() + " is incompatible with " + File->getName())); - if (auto *O = dyn_cast<ObjectFileBase>(File)) ObjectFiles.emplace_back(O); else if (auto *S = dyn_cast<SharedFile<ELFT>>(File)) @@ -174,6 +173,8 @@ case ELF64BEKind: addELFFile<ELF64BE>(File); break; + default: + llvm_unreachable("Invalid kind"); } } Index: lld/trunk/test/elf2/basic.s =================================================================== --- lld/trunk/test/elf2/basic.s +++ lld/trunk/test/elf2/basic.s @@ -205,3 +205,6 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t # RUN: not lld -flavor gnu2 %t %t -o %t2 2>&1 | FileCheck --check-prefix=DUP %s # DUP: duplicate symbol: _start in {{.*}} and {{.*}} + +# RUN: not lld -flavor gnu2 %t -o %t -m wrong_emul 2>&1 | FileCheck --check-prefix=UNKNOWN_EMUL %s +# UNKNOWN_EMUL: Unknown emulation: wrong_emul Index: lld/trunk/test/elf2/emulation.s =================================================================== --- lld/trunk/test/elf2/emulation.s +++ lld/trunk/test/elf2/emulation.s @@ -0,0 +1,128 @@ +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tx64 +# RUN: lld -flavor gnu2 -m elf_x86_64 %tx64 -o %t2x64 +# RUN: llvm-readobj -file-headers %t2x64 | FileCheck --check-prefix=X86-64 %s +# RUN: lld -flavor gnu2 %tx64 -o %t3x64 +# RUN: llvm-readobj -file-headers %t3x64 | FileCheck --check-prefix=X86-64 %s +# X86-64: ElfHeader { +# X86-64-NEXT: Ident { +# X86-64-NEXT: Magic: (7F 45 4C 46) +# X86-64-NEXT: Class: 64-bit (0x2) +# X86-64-NEXT: DataEncoding: LittleEndian (0x1) +# X86-64-NEXT: FileVersion: 1 +# X86-64-NEXT: OS/ABI: SystemV (0x0) +# X86-64-NEXT: ABIVersion: 0 +# X86-64-NEXT: Unused: (00 00 00 00 00 00 00) +# X86-64-NEXT: } +# X86-64-NEXT: Type: Executable (0x2) +# X86-64-NEXT: Machine: EM_X86_64 (0x3E) +# X86-64-NEXT: Version: 1 +# X86-64-NEXT: Entry: 0x11000 +# X86-64-NEXT: ProgramHeaderOffset: 0x40 +# X86-64-NEXT: SectionHeaderOffset: 0x1060 +# X86-64-NEXT: Flags [ (0x0) +# X86-64-NEXT: ] +# X86-64-NEXT: HeaderSize: 64 +# X86-64-NEXT: ProgramHeaderEntrySize: 56 +# X86-64-NEXT: ProgramHeaderCount: 1 +# X86-64-NEXT: SectionHeaderEntrySize: 64 +# X86-64-NEXT: SectionHeaderCount: 6 +# X86-64-NEXT: StringTableSectionIndex: 5 +# X86-64-NEXT: } + +# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %tx86 +# RUN: lld -flavor gnu2 -m elf_i386 %tx86 -o %t2x86 +# RUN: llvm-readobj -file-headers %t2x86 | FileCheck --check-prefix=X86 %s +# RUN: lld -flavor gnu2 %tx86 -o %t3x86 +# RUN: llvm-readobj -file-headers %t3x86 | FileCheck --check-prefix=X86 %s +# X86: ElfHeader { +# X86-NEXT: Ident { +# X86-NEXT: Magic: (7F 45 4C 46) +# X86-NEXT: Class: 32-bit (0x1) +# X86-NEXT: DataEncoding: LittleEndian (0x1) +# X86-NEXT: FileVersion: 1 +# X86-NEXT: OS/ABI: SystemV (0x0) +# X86-NEXT: ABIVersion: 0 +# X86-NEXT: Unused: (00 00 00 00 00 00 00) +# X86-NEXT: } +# X86-NEXT: Type: Executable (0x2) +# X86-NEXT: Machine: EM_386 (0x3) +# X86-NEXT: Version: 1 +# X86-NEXT: Entry: 0x11000 +# X86-NEXT: ProgramHeaderOffset: 0x34 +# X86-NEXT: SectionHeaderOffset: 0x104C +# X86-NEXT: Flags [ (0x0) +# X86-NEXT: ] +# X86-NEXT: HeaderSize: 52 +# X86-NEXT: ProgramHeaderEntrySize: 32 +# X86-NEXT: ProgramHeaderCount: 1 +# X86-NEXT: SectionHeaderEntrySize: 40 +# X86-NEXT: SectionHeaderCount: 6 +# X86-NEXT: StringTableSectionIndex: 5 +# X86-NEXT: } + +# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %tppc64 +# RUN: lld -flavor gnu2 -m elf64ppc %tppc64 -o %t2ppc64 +# RUN: llvm-readobj -file-headers %t2ppc64 | FileCheck --check-prefix=PPC64 %s +# RUN: lld -flavor gnu2 %tppc64 -o %t3ppc64 +# RUN: llvm-readobj -file-headers %t3ppc64 | FileCheck --check-prefix=PPC64 %s +# PPC64: ElfHeader { +# PPC64-NEXT: Ident { +# PPC64-NEXT: Magic: (7F 45 4C 46) +# PPC64-NEXT: Class: 64-bit (0x2) +# PPC64-NEXT: DataEncoding: BigEndian (0x2) +# PPC64-NEXT: FileVersion: 1 +# PPC64-NEXT: OS/ABI: SystemV (0x0) +# PPC64-NEXT: ABIVersion: 0 +# PPC64-NEXT: Unused: (00 00 00 00 00 00 00) +# PPC64-NEXT: } +# PPC64-NEXT: Type: Executable (0x2) +# PPC64-NEXT: Machine: EM_PPC64 (0x15) +# PPC64-NEXT: Version: 1 +# PPC64-NEXT: Entry: 0x11000 +# PPC64-NEXT: ProgramHeaderOffset: 0x40 +# PPC64-NEXT: SectionHeaderOffset: 0x1060 +# PPC64-NEXT: Flags [ (0x0) +# PPC64-NEXT: ] +# PPC64-NEXT: HeaderSize: 64 +# PPC64-NEXT: ProgramHeaderEntrySize: 56 +# PPC64-NEXT: ProgramHeaderCount: 1 +# PPC64-NEXT: SectionHeaderEntrySize: 64 +# PPC64-NEXT: SectionHeaderCount: 6 +# PPC64-NEXT: StringTableSectionIndex: 5 +# PPC64-NEXT: } + +# RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-linux %s -o %tppc +# RUN: lld -flavor gnu2 -m elf32ppc %tppc -o %t2ppc +# RUN: llvm-readobj -file-headers %t2ppc | FileCheck --check-prefix=PPC %s +# RUN: lld -flavor gnu2 %tppc -o %t3ppc +# RUN: llvm-readobj -file-headers %t3ppc | FileCheck --check-prefix=PPC %s +# PPC: ElfHeader { +# PPC-NEXT: Ident { +# PPC-NEXT: Magic: (7F 45 4C 46) +# PPC-NEXT: Class: 32-bit (0x1) +# PPC-NEXT: DataEncoding: BigEndian (0x2) +# PPC-NEXT: FileVersion: 1 +# PPC-NEXT: OS/ABI: SystemV (0x0) +# PPC-NEXT: ABIVersion: 0 +# PPC-NEXT: Unused: (00 00 00 00 00 00 00) +# PPC-NEXT: } +# PPC-NEXT: Type: Executable (0x2) +# PPC-NEXT: Machine: EM_PPC (0x14) +# PPC-NEXT: Version: 1 +# PPC-NEXT: Entry: 0x11000 +# PPC-NEXT: ProgramHeaderOffset: 0x34 +# PPC-NEXT: SectionHeaderOffset: 0x104C +# PPC-NEXT: Flags [ (0x0) +# PPC-NEXT: ] +# PPC-NEXT: HeaderSize: 52 +# PPC-NEXT: ProgramHeaderEntrySize: 32 +# PPC-NEXT: ProgramHeaderCount: 1 +# PPC-NEXT: SectionHeaderEntrySize: 40 +# PPC-NEXT: SectionHeaderCount: 6 +# PPC-NEXT: StringTableSectionIndex: 5 +# PPC-NEXT: } + +# REQUIRES: x86,ppc + +.globl _start; +_start: Index: lld/trunk/test/elf2/incompatible.s =================================================================== --- lld/trunk/test/elf2/incompatible.s +++ lld/trunk/test/elf2/incompatible.s @@ -5,22 +5,42 @@ // RUN: not lld -flavor gnu2 %ta.o %tb.o -o %t 2>&1 | \ // RUN: FileCheck --check-prefix=A-AND-B %s -// A-AND-B: a.o is incompatible with {{.*}}b.o +// A-AND-B: b.o is incompatible with {{.*}}a.o // RUN: not lld -flavor gnu2 %tb.o %tc.o -o %t 2>&1 | \ // RUN: FileCheck --check-prefix=B-AND-C %s -// B-AND-C: b.o is incompatible with {{.*}}c.o +// B-AND-C: c.o is incompatible with {{.*}}b.o // RUN: not lld -flavor gnu2 %ta.o %ti686.so -o %t 2>&1 | \ // RUN: FileCheck --check-prefix=A-AND-SO %s -// A-AND-SO: a.o is incompatible with {{.*}}i686.so +// A-AND-SO: i686.so is incompatible with {{.*}}a.o // RUN: not lld -flavor gnu2 %tc.o %ti686.so -o %t 2>&1 | \ // RUN: FileCheck --check-prefix=C-AND-SO %s -// C-AND-SO: c.o is incompatible with {{.*}}i686.so +// C-AND-SO: i686.so is incompatible with {{.*}}c.o // RUN: not lld -flavor gnu2 %ti686.so %tc.o -o %t 2>&1 | \ // RUN: FileCheck --check-prefix=SO-AND-C %s -// SO-AND-C: i686.so is incompatible with {{.*}}c.o +// SO-AND-C: c.o is incompatible with {{.*}}i686.so + +// RUN: not lld -flavor gnu2 -m elf64ppc %ta.o -o %t 2>&1 | \ +// RUN: FileCheck --check-prefix=A-ONLY %s +// A-ONLY: a.o is incompatible with target architecture + +// RUN: not lld -flavor gnu2 -m elf64ppc %tb.o -o %t 2>&1 | \ +// RUN: FileCheck --check-prefix=B-ONLY %s +// B-ONLY: b.o is incompatible with target architecture + +// RUN: not lld -flavor gnu2 -m elf64ppc %tc.o -o %t 2>&1 | \ +// RUN: FileCheck --check-prefix=C-ONLY %s +// C-ONLY: c.o is incompatible with target architecture + +// RUN: not lld -flavor gnu2 -m elf_i386 %tc.o %ti686.so -o %t 2>&1 | \ +// RUN: FileCheck --check-prefix=C-AND-SO-I386 %s +// C-AND-SO-I386: c.o is incompatible with target architecture + +// RUN: not lld -flavor gnu2 -m elf_i386 %ti686.so %tc.o -o %t 2>&1 | \ +// RUN: FileCheck --check-prefix=SO-AND-C-I386 %s +// SO-AND-C-I386: c.o is incompatible with {{.*}}i686.so // REQUIRES: x86,arm