Index: llvm/tools/llvm-objcopy/CopyConfig.h =================================================================== --- llvm/tools/llvm-objcopy/CopyConfig.h +++ llvm/tools/llvm-objcopy/CopyConfig.h @@ -26,6 +26,13 @@ namespace llvm { namespace objcopy { +enum class FileFormat { + Unspecified, + ELF, + Binary, + IHex, +}; + // This type keeps track of the machine info for various architectures. This // lets us map architecture names to ELF types and the e_machine value of the // ELF file. @@ -104,9 +111,9 @@ struct CopyConfig { // Main input/output options StringRef InputFilename; - StringRef InputFormat; + FileFormat InputFormat; StringRef OutputFilename; - StringRef OutputFormat; + FileFormat OutputFormat; // Only applicable for --input-format=binary MachineInfo BinaryArch; Index: llvm/tools/llvm-objcopy/CopyConfig.cpp =================================================================== --- llvm/tools/llvm-objcopy/CopyConfig.cpp +++ llvm/tools/llvm-objcopy/CopyConfig.cpp @@ -276,49 +276,52 @@ } // FIXME: consolidate with the bfd parsing used by lld. -static const StringMap OutputFormatMap{ - // Name, {EMachine, 64bit, LittleEndian} +static const StringMap> FileFormatMap{ + // Name, {FileFormat, {EMachine, 64bit, LittleEndian}} // x86 - {"elf32-i386", {ELF::EM_386, false, true}}, - {"elf32-x86-64", {ELF::EM_X86_64, false, true}}, - {"elf64-x86-64", {ELF::EM_X86_64, true, true}}, + {"elf32-i386", {FileFormat::ELF, {ELF::EM_386, false, true}}}, + {"elf32-x86-64", {FileFormat::ELF, {ELF::EM_X86_64, false, true}}}, + {"elf64-x86-64", {FileFormat::ELF, {ELF::EM_X86_64, true, true}}}, // Intel MCU - {"elf32-iamcu", {ELF::EM_IAMCU, false, true}}, + {"elf32-iamcu", {FileFormat::ELF, {ELF::EM_IAMCU, false, true}}}, // ARM - {"elf32-littlearm", {ELF::EM_ARM, false, true}}, + {"elf32-littlearm", {FileFormat::ELF, {ELF::EM_ARM, false, true}}}, // ARM AArch64 - {"elf64-aarch64", {ELF::EM_AARCH64, true, true}}, - {"elf64-littleaarch64", {ELF::EM_AARCH64, true, true}}, + {"elf64-aarch64", {FileFormat::ELF, {ELF::EM_AARCH64, true, true}}}, + {"elf64-littleaarch64", {FileFormat::ELF, {ELF::EM_AARCH64, true, true}}}, // RISC-V - {"elf32-littleriscv", {ELF::EM_RISCV, false, true}}, - {"elf64-littleriscv", {ELF::EM_RISCV, true, true}}, + {"elf32-littleriscv", {FileFormat::ELF, {ELF::EM_RISCV, false, true}}}, + {"elf64-littleriscv", {FileFormat::ELF, {ELF::EM_RISCV, true, true}}}, // PowerPC - {"elf32-powerpc", {ELF::EM_PPC, false, false}}, - {"elf32-powerpcle", {ELF::EM_PPC, false, true}}, - {"elf64-powerpc", {ELF::EM_PPC64, true, false}}, - {"elf64-powerpcle", {ELF::EM_PPC64, true, true}}, + {"elf32-powerpc", {FileFormat::ELF, {ELF::EM_PPC, false, false}}}, + {"elf32-powerpcle", {FileFormat::ELF, {ELF::EM_PPC, false, true}}}, + {"elf64-powerpc", {FileFormat::ELF, {ELF::EM_PPC64, true, false}}}, + {"elf64-powerpcle", {FileFormat::ELF, {ELF::EM_PPC64, true, true}}}, // MIPS - {"elf32-bigmips", {ELF::EM_MIPS, false, false}}, - {"elf32-ntradbigmips", {ELF::EM_MIPS, false, false}}, - {"elf32-ntradlittlemips", {ELF::EM_MIPS, false, true}}, - {"elf32-tradbigmips", {ELF::EM_MIPS, false, false}}, - {"elf32-tradlittlemips", {ELF::EM_MIPS, false, true}}, - {"elf64-tradbigmips", {ELF::EM_MIPS, true, false}}, - {"elf64-tradlittlemips", {ELF::EM_MIPS, true, true}}, + {"elf32-bigmips", {FileFormat::ELF, {ELF::EM_MIPS, false, false}}}, + {"elf32-ntradbigmips", {FileFormat::ELF, {ELF::EM_MIPS, false, false}}}, + {"elf32-ntradlittlemips", {FileFormat::ELF, {ELF::EM_MIPS, false, true}}}, + {"elf32-tradbigmips", {FileFormat::ELF, {ELF::EM_MIPS, false, false}}}, + {"elf32-tradlittlemips", {FileFormat::ELF, {ELF::EM_MIPS, false, true}}}, + {"elf64-tradbigmips", {FileFormat::ELF, {ELF::EM_MIPS, true, false}}}, + {"elf64-tradlittlemips", {FileFormat::ELF, {ELF::EM_MIPS, true, true}}}, + // SPARC + {"elf32-sparc", {FileFormat::ELF, {ELF::EM_SPARC, false, true}}}, }; -static Expected getOutputFormatMachineInfo(StringRef Format) { +static Expected> +getFileFormatAndMachineInfoByTargetName(StringRef Format) { StringRef OriginalFormat = Format; bool IsFreeBSD = Format.consume_back("-freebsd"); - auto Iter = OutputFormatMap.find(Format); - if (Iter == std::end(OutputFormatMap)) + auto Iter = FileFormatMap.find(Format); + if (Iter == std::end(FileFormatMap)) return createStringError(errc::invalid_argument, "Invalid output format: '%s'", OriginalFormat.str().c_str()); - MachineInfo MI = Iter->getValue(); + auto Pair = Iter->getValue(); if (IsFreeBSD) - MI.OSABI = ELF::ELFOSABI_FREEBSD; - return {MI}; + Pair.second.OSABI = ELF::ELFOSABI_FREEBSD; + return {Pair}; } static Error addSymbolsFromFile(std::vector &Symbols, @@ -440,14 +443,18 @@ "--target cannot be used with --input-target or --output-target"); bool UseRegex = InputArgs.hasArg(OBJCOPY_regex); + StringRef InputFormat, OutputFormat; if (InputArgs.hasArg(OBJCOPY_target)) { - Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_target); - Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target); + InputFormat = InputArgs.getLastArgValue(OBJCOPY_target); + OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target); } else { - Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target); - Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target); + InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target); + OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target); } - if (Config.InputFormat == "binary") { + if (InputFormat.empty()) + Config.InputFormat = FileFormat::Unspecified; + else if (InputFormat == "binary") { + Config.InputFormat = FileFormat::Binary; auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture); if (BinaryArch.empty()) return createStringError( @@ -457,13 +464,24 @@ if (!MI) return MI.takeError(); Config.BinaryArch = *MI; - } - if (!Config.OutputFormat.empty() && Config.OutputFormat != "binary" && - Config.OutputFormat != "ihex") { - Expected MI = getOutputFormatMachineInfo(Config.OutputFormat); - if (!MI) - return MI.takeError(); - Config.OutputArch = *MI; + } else + return createStringError(errc::invalid_argument, + "unsupported input format: '%s'", + InputFormat.str().c_str()); + + if (OutputFormat.empty()) + Config.OutputFormat = FileFormat::Unspecified; + else if (OutputFormat == "binary") + Config.OutputFormat = FileFormat::Binary; + else if (OutputFormat == "ihex") + Config.OutputFormat = FileFormat::IHex; + else { + Expected> Pair = + getFileFormatAndMachineInfoByTargetName(OutputFormat); + if (!Pair) + return Pair.takeError(); + Config.OutputFormat = Pair->first; + Config.OutputArch = Pair->second; } if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections, Index: llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp =================================================================== --- llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -154,12 +154,14 @@ static std::unique_ptr createWriter(const CopyConfig &Config, Object &Obj, Buffer &Buf, ElfType OutputElfType) { - using Functor = std::function()>; - return StringSwitch(Config.OutputFormat) - .Case("binary", [&] { return llvm::make_unique(Obj, Buf); }) - .Case("ihex", [&] { return llvm::make_unique(Obj, Buf); }) - .Default( - [&] { return createELFWriter(Config, Obj, Buf, OutputElfType); })(); + switch (Config.OutputFormat) { + case FileFormat::Binary: + return llvm::make_unique(Obj, Buf); + case FileFormat::IHex: + return llvm::make_unique(Obj, Buf); + default: + return createELFWriter(Config, Obj, Buf, OutputElfType); + } } template Index: llvm/tools/llvm-objcopy/llvm-objcopy.cpp =================================================================== --- llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -29,6 +29,7 @@ #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" @@ -127,11 +128,16 @@ /// of the output specified by the command line options. static Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In, Buffer &Out) { - // TODO: llvm-objcopy should parse CopyConfig.OutputFormat to recognize - // formats other than ELF / "binary" and invoke - // elf::executeObjcopyOnRawBinary, macho::executeObjcopyOnRawBinary or - // coff::executeObjcopyOnRawBinary accordingly. - return elf::executeObjcopyOnRawBinary(Config, In, Out); + switch (Config.OutputFormat) { + case FileFormat::ELF: + // FIXME: Currently, we call elf::executeObjcopyOnRawBinary even if the + // output format is binary/ihex or it's not given. This behavior differs from + // GNU objcopy. Refer https://bugs.llvm.org/show_bug.cgi?id=42171 + case FileFormat::Binary: + case FileFormat::IHex: + case FileFormat::Unspecified: + return elf::executeObjcopyOnRawBinary(Config, In, Out); + } } /// The function executeObjcopyOnBinary does the dispatch based on the format @@ -210,7 +216,7 @@ if (auto EC = sys::fs::status(Config.InputFilename, Stat)) return createFileError(Config.InputFilename, EC); - if (Config.InputFormat == "binary") { + if (Config.InputFormat == FileFormat::Binary) { auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename); if (!BufOrErr) return createFileError(Config.InputFilename, BufOrErr.getError());