diff --git a/llvm/tools/llvm-objcopy/CopyConfig.h b/llvm/tools/llvm-objcopy/CopyConfig.h --- a/llvm/tools/llvm-objcopy/CopyConfig.h +++ b/llvm/tools/llvm-objcopy/CopyConfig.h @@ -15,6 +15,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Object/ELFTypes.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Error.h" @@ -29,23 +30,44 @@ enum class FileFormat { Unspecified, ELF, + MachO, Binary, IHex, }; +struct ELFMachineInfo { + uint16_t EMachine; + uint8_t OSABI; +}; + +struct MachOMachineInfo { + MachO::CPUType MachOCPUType; + uint32_t MachOCPUSubType; +}; + // 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. +// lets us map architecture names to format-specific values. struct MachineInfo { + // For ELF targets. MachineInfo(uint16_t EM, uint8_t ABI, bool Is64, bool IsLittle) - : EMachine(EM), OSABI(ABI), Is64Bit(Is64), IsLittleEndian(IsLittle) {} - // Alternative constructor that defaults to NONE for OSABI. - MachineInfo(uint16_t EM, bool Is64, bool IsLittle) - : MachineInfo(EM, ELF::ELFOSABI_NONE, Is64, IsLittle) {} + : ELF({EM, ABI}), MachO({MachO::CPU_TYPE_ANY, 0}), Is64Bit(Is64), + IsLittleEndian(IsLittle) {} + // For MachO targets. + MachineInfo(MachO::CPUType MachOCPUType, uint32_t MachOCPUSubType, bool Is64, + bool IsLittle) + : ELF({0, 0}), MachO({MachOCPUType, MachOCPUSubType}), Is64Bit(Is64), + IsLittleEndian(IsLittle) {} + MachineInfo(ELFMachineInfo ELF, MachOMachineInfo MachO, bool Is64, + bool IsLittle) + : ELF(ELF), MachO(MachO), Is64Bit(Is64), IsLittleEndian(IsLittle) {} // Default constructor for unset fields. - MachineInfo() : MachineInfo(0, 0, false, false) {} - uint16_t EMachine; - uint8_t OSABI; + MachineInfo() + : ELF({0, 0}), MachO({MachO::CPU_TYPE_ANY, 0}), Is64Bit(false), + IsLittleEndian(false) {} + + ELFMachineInfo ELF; + MachOMachineInfo MachO; + // Common values. bool Is64Bit; bool IsLittleEndian; }; diff --git a/llvm/tools/llvm-objcopy/CopyConfig.cpp b/llvm/tools/llvm-objcopy/CopyConfig.cpp --- a/llvm/tools/llvm-objcopy/CopyConfig.cpp +++ b/llvm/tools/llvm-objcopy/CopyConfig.cpp @@ -12,6 +12,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/CommandLine.h" @@ -256,18 +257,29 @@ } static const StringMap ArchMap{ - // Name, {EMachine, 64bit, LittleEndian} - {"aarch64", {ELF::EM_AARCH64, true, true}}, - {"arm", {ELF::EM_ARM, false, true}}, - {"i386", {ELF::EM_386, false, true}}, - {"i386:x86-64", {ELF::EM_X86_64, true, true}}, - {"mips", {ELF::EM_MIPS, false, false}}, - {"powerpc:common64", {ELF::EM_PPC64, true, true}}, - {"riscv:rv32", {ELF::EM_RISCV, false, true}}, - {"riscv:rv64", {ELF::EM_RISCV, true, true}}, - {"sparc", {ELF::EM_SPARC, false, false}}, - {"sparcel", {ELF::EM_SPARC, false, true}}, - {"x86-64", {ELF::EM_X86_64, true, true}}, + // Name, {{EMachine, OSABI}, {MachOCPUType, MachOCPUSubType}, + // 64bit, LittleEndian} + {"aarch64", + {{ELF::EM_AARCH64, 0}, + {MachO::CPU_TYPE_ARM64, MachO::CPU_SUBTYPE_ARM64_ALL}, + true, + true}}, + {"arm", {{ELF::EM_ARM, 0}, {MachO::CPU_TYPE_ANY, 0}, false, true}}, + {"i386", {{ELF::EM_386, 0}, {MachO::CPU_TYPE_ANY, 0}, false, true}}, + {"i386:x86-64", + {{ELF::EM_X86_64, 0}, {MachO::CPU_TYPE_ANY, 0}, true, true}}, + {"mips", {{ELF::EM_MIPS, 0}, {MachO::CPU_TYPE_ANY, 0}, false, false}}, + {"powerpc:common64", + {{ELF::EM_PPC64, 0}, {MachO::CPU_TYPE_ANY, 0}, true, true}}, + {"riscv:rv32", {{ELF::EM_RISCV, 0}, {MachO::CPU_TYPE_ANY, 0}, false, true}}, + {"riscv:rv64", {{ELF::EM_RISCV, 0}, {MachO::CPU_TYPE_ANY, 0}, true, true}}, + {"sparc", {{ELF::EM_SPARC, 0}, {MachO::CPU_TYPE_ANY, 0}, false, false}}, + {"sparcel", {{ELF::EM_SPARC, 0}, {MachO::CPU_TYPE_ANY, 0}, false, true}}, + {"x86-64", + {{ELF::EM_X86_64, 0}, + {MachO::CPU_TYPE_X86_64, MachO::CPU_SUBTYPE_X86_64_ALL}, + true, + true}}, }; static Expected getMachineInfo(StringRef Arch) { @@ -285,43 +297,51 @@ // FIXME: consolidate with the bfd parsing used by lld. static const StringMap TargetMap{ - // Name, {EMachine, 64bit, LittleEndian} + // ELF targets: Name, {EMachine, OSABI, 64bit, LittleEndian} + // Mach-O targets: Name, {CPUType, CPUSubType, 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", {ELF::EM_386, 0, false, true}}, + {"elf32-x86-64", {ELF::EM_X86_64, 0, false, true}}, + {"elf64-x86-64", {ELF::EM_X86_64, 0, true, true}}, + {"mach-o-x86-64", + {MachO::CPU_TYPE_X86_64, MachO::CPU_SUBTYPE_X86_64_ALL, true, true}}, + {"mach-o-arm64", + {MachO::CPU_TYPE_ARM64, MachO::CPU_SUBTYPE_ARM64_ALL, true, true}}, // Intel MCU - {"elf32-iamcu", {ELF::EM_IAMCU, false, true}}, + {"elf32-iamcu", {ELF::EM_IAMCU, 0, false, true}}, // ARM - {"elf32-littlearm", {ELF::EM_ARM, false, true}}, + {"elf32-littlearm", {ELF::EM_ARM, 0, false, true}}, // ARM AArch64 - {"elf64-aarch64", {ELF::EM_AARCH64, true, true}}, - {"elf64-littleaarch64", {ELF::EM_AARCH64, true, true}}, + {"elf64-aarch64", {ELF::EM_AARCH64, 0, true, true}}, + {"elf64-littleaarch64", {ELF::EM_AARCH64, 0, true, true}}, // RISC-V - {"elf32-littleriscv", {ELF::EM_RISCV, false, true}}, - {"elf64-littleriscv", {ELF::EM_RISCV, true, true}}, + {"elf32-littleriscv", {ELF::EM_RISCV, 0, false, true}}, + {"elf64-littleriscv", {ELF::EM_RISCV, 0, 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", {ELF::EM_PPC, 0, false, false}}, + {"elf32-powerpcle", {ELF::EM_PPC, 0, false, true}}, + {"elf64-powerpc", {ELF::EM_PPC64, 0, true, false}}, + {"elf64-powerpcle", {ELF::EM_PPC64, 0, 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", {ELF::EM_MIPS, 0, false, false}}, + {"elf32-ntradbigmips", {ELF::EM_MIPS, 0, false, false}}, + {"elf32-ntradlittlemips", {ELF::EM_MIPS, 0, false, true}}, + {"elf32-tradbigmips", {ELF::EM_MIPS, 0, false, false}}, + {"elf32-tradlittlemips", {ELF::EM_MIPS, 0, false, true}}, + {"elf64-tradbigmips", {ELF::EM_MIPS, 0, true, false}}, + {"elf64-tradlittlemips", {ELF::EM_MIPS, 0, true, true}}, // SPARC - {"elf32-sparc", {ELF::EM_SPARC, false, false}}, - {"elf32-sparcel", {ELF::EM_SPARC, false, true}}, + {"elf32-sparc", {ELF::EM_SPARC, 0, false, false}}, + {"elf32-sparcel", {ELF::EM_SPARC, 0, false, true}}, }; static Expected getOutputTargetInfoByTargetName(StringRef TargetName) { StringRef OriginalTargetName = TargetName; - bool IsFreeBSD = TargetName.consume_back("-freebsd"); + bool IsFreeBSD = false; + if (TargetName.startswith("elf")) + IsFreeBSD = TargetName.consume_back("-freebsd"); + auto Iter = TargetMap.find(TargetName); if (Iter == std::end(TargetMap)) return createStringError(errc::invalid_argument, @@ -329,11 +349,13 @@ OriginalTargetName.str().c_str()); MachineInfo MI = Iter->getValue(); if (IsFreeBSD) - MI.OSABI = ELF::ELFOSABI_FREEBSD; + MI.ELF.OSABI = ELF::ELFOSABI_FREEBSD; FileFormat Format; if (TargetName.startswith("elf")) Format = FileFormat::ELF; + else if (TargetName.startswith("mach-o")) + Format = FileFormat::MachO; else // This should never happen because `TargetName` is valid (it certainly // exists in the TargetMap). diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp --- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -271,8 +271,8 @@ OnlyKeepDWOPred)) return E; if (Config.OutputArch) { - DWOFile->Machine = Config.OutputArch.getValue().EMachine; - DWOFile->OSABI = Config.OutputArch.getValue().OSABI; + DWOFile->Machine = Config.OutputArch.getValue().ELF.EMachine; + DWOFile->OSABI = Config.OutputArch.getValue().ELF.OSABI; } FileBuffer FB(File); auto Writer = createWriter(Config, *DWOFile, FB, OutputElfType); @@ -599,8 +599,8 @@ return E; if (Config.OutputArch) { - Obj.Machine = Config.OutputArch.getValue().EMachine; - Obj.OSABI = Config.OutputArch.getValue().OSABI; + Obj.Machine = Config.OutputArch.getValue().ELF.EMachine; + Obj.OSABI = Config.OutputArch.getValue().ELF.OSABI; } // It is important to remove the sections first. For example, we want to diff --git a/llvm/tools/llvm-objcopy/ELF/Object.cpp b/llvm/tools/llvm-objcopy/ELF/Object.cpp --- a/llvm/tools/llvm-objcopy/ELF/Object.cpp +++ b/llvm/tools/llvm-objcopy/ELF/Object.cpp @@ -1610,7 +1610,7 @@ Reader::~Reader() {} std::unique_ptr BinaryReader::create() const { - return BinaryELFBuilder(MInfo.EMachine, MemBuf).build(); + return BinaryELFBuilder(MInfo.ELF.EMachine, MemBuf).build(); } Expected> IHexReader::parse() const { diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -149,6 +149,9 @@ case FileFormat::IHex: case FileFormat::Unspecified: return elf::executeObjcopyOnRawBinary(Config, In, Out); + case FileFormat::MachO: + return createStringError(object_error::invalid_file_type, + "unsupported output format"); } llvm_unreachable("unsupported output format");