Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -468,15 +468,6 @@ if (!RPaths.empty()) Config->RPath = llvm::join(RPaths.begin(), RPaths.end(), ":"); - if (auto *Arg = Args.getLastArg(OPT_m)) { - // Parse ELF{32,64}{LE,BE} and CPU type. - StringRef S = Arg->getValue(); - std::tie(Config->EKind, Config->EMachine, Config->OSABI) = - parseEmulation(S); - Config->MipsN32Abi = (S == "elf32btsmipn32" || S == "elf32ltsmipn32"); - Config->Emulation = S; - } - Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition); Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic); Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions); @@ -509,6 +500,7 @@ Config->WarnCommon = Args.hasArg(OPT_warn_common); Config->DynamicLinker = getString(Args, OPT_dynamic_linker); + Config->Emulation = getString(Args, OPT_m); Config->Entry = getString(Args, OPT_entry); Config->Fini = getString(Args, OPT_fini, "_fini"); Config->Init = getString(Args, OPT_init, "_init"); @@ -695,11 +687,9 @@ error("no input files"); } -// If -m was not given, infer it from object files. +// Try to infer machine type from objects. If it is not possible, take it from +// -m command line option. void LinkerDriver::inferMachineType() { - if (Config->EKind != ELFNoneKind) - return; - for (InputFile *F : Files) { if (F->EKind == ELFNoneKind) continue; @@ -709,7 +699,13 @@ Config->MipsN32Abi = Config->EMachine == EM_MIPS && isMipsN32Abi(F); return; } - error("target emulation unknown: -m or at least one .o file required"); + + if (Config->Emulation.empty()) + error("target emulation unknown: -m or at least one .o file required"); + + std::tie(Config->EKind, Config->EMachine, Config->OSABI) = + parseEmulation(Config->Emulation); + Config->MipsN32Abi = isMipsN32AbiEmulation(Config->Emulation); } // Parse -z max-page-size=. The default value is defined by @@ -742,12 +738,34 @@ return V; } +// Create target. If emulation option specified then replace +// target's default parameters with emulated target parameters. +static TargetInfo *createEmulation() { + TargetInfo *Target = createTarget(Config->EKind, Config->EMachine); + if (Config->Emulation.empty()) + return Target; + + ELFKind EmuKind; + uint16_t EmuMachine; + uint8_t EmuOSABI; + std::tie(EmuKind, EmuMachine, EmuOSABI) = parseEmulation(Config->Emulation); + + // OSABI is overriden when emulation is specified. + Config->OSABI = EmuOSABI; + + TargetInfo *EmuTarget = createTarget(EmuKind, EmuMachine); + Target->PageSize = EmuTarget->PageSize; + Target->DefaultMaxPageSize = EmuTarget->DefaultMaxPageSize; + Target->DefaultImageBase = EmuTarget->DefaultImageBase; + return Target; +} + // Do actual linking. Note that when this function is called, // all linker scripts have already been parsed. template void LinkerDriver::link(opt::InputArgList &Args) { SymbolTable Symtab; elf::Symtab::X = &Symtab; - Target = createTarget(); + Target = createEmulation(); ScriptBase = Script::X = make>(); Config->Rela = Index: ELF/Mips.cpp =================================================================== --- ELF/Mips.cpp +++ ELF/Mips.cpp @@ -363,6 +363,10 @@ } } +bool elf::isMipsN32AbiEmulation(StringRef S) { + return S == "elf32btsmipn32" || S == "elf32ltsmipn32"; +} + template uint32_t elf::getMipsEFlags(); template uint32_t elf::getMipsEFlags(); template uint32_t elf::getMipsEFlags(); Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -39,14 +39,19 @@ if (F->EKind == Config->EKind && F->EMachine == Config->EMachine) { if (Config->EMachine != EM_MIPS) return true; - if (isMipsN32Abi(F) == Config->MipsN32Abi) + + bool IsN32Abi = isMipsN32Abi(F); + if (!Config->Emulation.empty() && + isMipsN32AbiEmulation(Config->Emulation) != IsN32Abi) { + error(toString(F) + " is incompatible with " + Config->Emulation); + return false; + } + + if (IsN32Abi == Config->MipsN32Abi) return true; } - if (!Config->Emulation.empty()) - error(toString(F) + " is incompatible with " + Config->Emulation); - else - error(toString(F) + " is incompatible with " + toString(Config->FirstElf)); + error(toString(F) + " is incompatible with " + toString(Config->FirstElf)); return false; } Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -108,7 +108,7 @@ uint64_t getAArch64Page(uint64_t Expr); extern TargetInfo *Target; -TargetInfo *createTarget(); +TargetInfo *createTarget(ELFKind Kind, uint16_t Machine); } std::string toString(uint32_t RelType); Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -248,8 +248,8 @@ }; } // anonymous namespace -TargetInfo *createTarget() { - switch (Config->EMachine) { +TargetInfo *createTarget(ELFKind Kind, uint16_t Machine) { + switch (Machine) { case EM_386: case EM_IAMCU: return make(); @@ -260,7 +260,7 @@ case EM_ARM: return make(); case EM_MIPS: - switch (Config->EKind) { + switch (Kind) { case ELF32LEKind: return make>(); case ELF32BEKind: Index: ELF/Writer.h =================================================================== --- ELF/Writer.h +++ ELF/Writer.h @@ -60,6 +60,7 @@ llvm::StringRef FileName); bool isMipsN32Abi(const InputFile *F); +bool isMipsN32AbiEmulation(llvm::StringRef S); } } Index: test/ELF/driver.test =================================================================== --- test/ELF/driver.test +++ test/ELF/driver.test @@ -5,9 +5,9 @@ # UNKNOWN: unknown argument: --unknown1 # UNKNOWN: unknown argument: --unknown2 -# UNKNOWN: unknown emulation: foo # UNKNOWN: cannot open /no/such/file # UNKNOWN: unable to find library -lnosuchlib +# UNKNOWN: unknown emulation: foo # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t # RUN: not ld.lld %t -o /no/such/file 2>&1 | FileCheck -check-prefix=MISSING %s Index: test/ELF/emulation-override.s =================================================================== --- test/ELF/emulation-override.s +++ test/ELF/emulation-override.s @@ -0,0 +1,24 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o + +## Show target output without emulation. +# RUN: ld.lld %t.o -o %t1 +# RUN: llvm-readobj -program-headers %t1 | FileCheck %s +# CHECK: ProgramHeader { +# CHECK: Type: PT_LOAD +# CHECK-NEXT: Offset: +# CHECK-NEXT: VirtualAddress: 0x10000 + +## Check that we are able to apply elf_x86_64 emulation for i386 object +## and target parameters are emulated. +# RUN: ld.lld -m elf_x86_64 %t.o -o %t2 +# RUN: llvm-readobj -program-headers %t2 | FileCheck %s --check-prefix=OVERRIDE +# OVERRIDE: ProgramHeader { +# OVERRIDE: Type: PT_LOAD +# OVERRIDE-NEXT: Offset: +# OVERRIDE-NEXT: VirtualAddress: 0x200000 + +.globl _start +_start: + nop + Index: test/ELF/incompatible.s =================================================================== --- test/ELF/incompatible.s +++ test/ELF/incompatible.s @@ -23,27 +23,6 @@ // RUN: FileCheck --check-prefix=SO-AND-C %s // SO-AND-C: c.o is incompatible with {{.*}}i686.so -// RUN: not ld.lld -m elf64ppc %ta.o -o %t 2>&1 | \ -// RUN: FileCheck --check-prefix=A-ONLY %s -// A-ONLY: a.o is incompatible with elf64ppc - -// RUN: not ld.lld -m elf64ppc %tb.o -o %t 2>&1 | \ -// RUN: FileCheck --check-prefix=B-ONLY %s -// B-ONLY: b.o is incompatible with elf64ppc - -// RUN: not ld.lld -m elf64ppc %tc.o -o %t 2>&1 | \ -// RUN: FileCheck --check-prefix=C-ONLY %s -// C-ONLY: c.o is incompatible with elf64ppc - -// RUN: not ld.lld -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 elf_i386 - -// RUN: not ld.lld -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 elf_i386 - - // We used to fail to identify this incompatibility and crash trying to // read a 64 bit file as a 32 bit one. // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/archive2.s -o %ta.o