Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -11,12 +11,21 @@ #define LLD_ELF_CONFIG_H #include "llvm/ADT/StringRef.h" +#include "llvm/Support/ELF.h" #include namespace lld { namespace elf2 { +enum ELFKind { + ELFNoneKind, + ELF32LEKind, + ELF32BEKind, + ELF64LEKind, + ELF64BEKind +}; + struct Configuration { llvm::StringRef DynamicLinker; llvm::StringRef Entry; @@ -31,6 +40,8 @@ bool ExportDynamic; bool NoInhibitExec; bool Shared; + ELFKind ElfKind = ELFNoneKind; + uint16_t EMachine = llvm::ELF::EM_NONE; }; extern Configuration *Config; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ 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; @@ -50,6 +51,26 @@ } } +static std::unique_ptr createTargetFile(MemoryBufferRef MB) { + std::unique_ptr File = createFile(MB); + ELFFileBase *ELFFile = dyn_cast(File.get()); + if (!ELFFile) + return File; + + const ELFKind ElfKind = ELFFile->getELFKind(); + const uint16_t EMachine = ELFFile->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 nullptr; + return File; +} + // 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. @@ -88,6 +109,30 @@ return identify_magic(MB.getBuffer()) == file_magic::unknown; } +static void applyEmulation(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); +} + void LinkerDriver::link(ArrayRef ArgsArr) { // Parse command line options. opt::InputArgList Args = Parser.parse(ArgsArr); @@ -113,6 +158,12 @@ if (auto *Arg = Args.getLastArg(OPT_entry)) Config->Entry = Arg->getValue(); + bool HasEmulation = false; + if (auto *Arg = Args.getLastArg(OPT_emulation)) { + applyEmulation(Arg->getValue()); + HasEmulation = true; + } + Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition); Config->DiscardAll = Args.hasArg(OPT_discard_all); Config->DiscardLocals = Args.hasArg(OPT_discard_locals); @@ -134,7 +185,12 @@ readLinkerScript(&Symtab, MB); continue; } - Symtab.addFile(createFile(MB)); + if (auto File = createTargetFile(MB)) + Symtab.addFile(std::move(File)); + else + error(Twine(MB.getBufferIdentifier() + " is incompatible with " + + (HasEmulation ? "target architecture" + : Symtab.getFirstELF()->getName()))); } if (Symtab.getObjectFiles().empty()) @@ -155,5 +211,7 @@ case ELF64BEKind: writeResult(&Symtab); return; + default: + llvm_unreachable("Invalid kind"); } } Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ 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" @@ -51,8 +52,6 @@ const Kind FileKind; }; -enum ELFKind { ELF32LEKind, ELF32BEKind, ELF64LEKind, ELF64BEKind }; - class ELFFileBase : public InputFile { public: ELFFileBase(Kind K, ELFKind EKind, MemoryBufferRef M) Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -47,8 +47,9 @@ return ::getEMachine(*this); case ELF64LEKind: return ::getEMachine(*this); + default: + llvm_unreachable("Invalid kind"); } - llvm_unreachable("Invalid kind"); } bool ELFFileBase::isCompatibleWith(const ELFFileBase &Other) const { Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -18,6 +18,9 @@ def dynamic_linker : Separate<["-"], "dynamic-linker">, HelpText<"Which dynamic linker to use">; +def emulation : Separate<["-"], "m">, + HelpText<"Set target emulation">; + def entry : Separate<["--", "-"], "entry">, MetaVarName<"">, HelpText<"Name of entry point symbol">; @@ -54,6 +57,5 @@ def build_id : Flag<["--"], "build-id">; def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">; def hash_style : Joined<["--"], "hash-style=">; -def m : Separate<["-"], "m">; def no_as_needed : Flag<["--"], "no-as-needed">; def z : Separate<["-"], "z">; Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -132,6 +132,8 @@ case ELF64BEKind: addELFFile(File); break; + default: + llvm_unreachable("Invalid kind"); } } Index: test/elf2/basic.s =================================================================== --- test/elf2/basic.s +++ 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: test/elf2/emulation.s =================================================================== --- /dev/null +++ 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: test/elf2/incompatible.s =================================================================== --- test/elf2/incompatible.s +++ 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 target architecture // REQUIRES: x86,arm