diff --git a/llvm/include/llvm/BinaryFormat/COFF.h b/llvm/include/llvm/BinaryFormat/COFF.h --- a/llvm/include/llvm/BinaryFormat/COFF.h +++ b/llvm/include/llvm/BinaryFormat/COFF.h @@ -99,6 +99,7 @@ IMAGE_FILE_MACHINE_ARMNT = 0x1C4, IMAGE_FILE_MACHINE_ARM64 = 0xAA64, IMAGE_FILE_MACHINE_ARM64EC = 0xA641, + IMAGE_FILE_MACHINE_ARM64X = 0xA64E, IMAGE_FILE_MACHINE_EBC = 0xEBC, IMAGE_FILE_MACHINE_I386 = 0x14C, IMAGE_FILE_MACHINE_IA64 = 0x200, @@ -120,6 +121,15 @@ IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169 }; +template bool isArm64EC(T Machine) { + return Machine == IMAGE_FILE_MACHINE_ARM64EC || + Machine == IMAGE_FILE_MACHINE_ARM64X; +} + +template bool isArm64(T Machine) { + return Machine == IMAGE_FILE_MACHINE_ARM64 || isArm64EC(Machine); +} + enum Characteristics : unsigned { C_Invalid = 0, diff --git a/llvm/lib/BinaryFormat/Magic.cpp b/llvm/lib/BinaryFormat/Magic.cpp --- a/llvm/lib/BinaryFormat/Magic.cpp +++ b/llvm/lib/BinaryFormat/Magic.cpp @@ -246,6 +246,11 @@ return file_magic::coff_object; break; + case 0x4e: // ARM64X windows + if (Magic[1] == char(0xA6)) + return file_magic::coff_object; + break; + default: break; } diff --git a/llvm/lib/Object/COFFImportFile.cpp b/llvm/lib/Object/COFFImportFile.cpp --- a/llvm/lib/Object/COFFImportFile.cpp +++ b/llvm/lib/Object/COFFImportFile.cpp @@ -39,6 +39,7 @@ llvm_unreachable("unsupported machine"); case IMAGE_FILE_MACHINE_ARM64: case IMAGE_FILE_MACHINE_ARM64EC: + case IMAGE_FILE_MACHINE_ARM64X: case IMAGE_FILE_MACHINE_AMD64: return false; case IMAGE_FILE_MACHINE_ARMNT: @@ -57,6 +58,7 @@ return IMAGE_REL_ARM_ADDR32NB; case IMAGE_FILE_MACHINE_ARM64: case IMAGE_FILE_MACHINE_ARM64EC: + case IMAGE_FILE_MACHINE_ARM64X: return IMAGE_REL_ARM64_ADDR32NB; case IMAGE_FILE_MACHINE_I386: return IMAGE_REL_I386_DIR32NB; diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp --- a/llvm/lib/Object/COFFObjectFile.cpp +++ b/llvm/lib/Object/COFFObjectFile.cpp @@ -1016,6 +1016,8 @@ return "COFF-ARM64"; case COFF::IMAGE_FILE_MACHINE_ARM64EC: return "COFF-ARM64EC"; + case COFF::IMAGE_FILE_MACHINE_ARM64X: + return "COFF-ARM64X"; default: return "COFF-"; } @@ -1031,6 +1033,7 @@ return Triple::thumb; case COFF::IMAGE_FILE_MACHINE_ARM64: case COFF::IMAGE_FILE_MACHINE_ARM64EC: + case COFF::IMAGE_FILE_MACHINE_ARM64X: return Triple::aarch64; default: return Triple::UnknownArch; @@ -1318,6 +1321,7 @@ break; case COFF::IMAGE_FILE_MACHINE_ARM64: case COFF::IMAGE_FILE_MACHINE_ARM64EC: + case COFF::IMAGE_FILE_MACHINE_ARM64X: switch (Type) { LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ABSOLUTE); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32); @@ -1901,6 +1905,7 @@ break; case COFF::IMAGE_FILE_MACHINE_ARM64: case COFF::IMAGE_FILE_MACHINE_ARM64EC: + case COFF::IMAGE_FILE_MACHINE_ARM64X: RVAReloc = COFF::IMAGE_REL_ARM64_ADDR32NB; break; default: diff --git a/llvm/lib/Object/WindowsMachineFlag.cpp b/llvm/lib/Object/WindowsMachineFlag.cpp --- a/llvm/lib/Object/WindowsMachineFlag.cpp +++ b/llvm/lib/Object/WindowsMachineFlag.cpp @@ -27,6 +27,7 @@ .Case("arm", COFF::IMAGE_FILE_MACHINE_ARMNT) .Case("arm64", COFF::IMAGE_FILE_MACHINE_ARM64) .Case("arm64ec", COFF::IMAGE_FILE_MACHINE_ARM64EC) + .Case("arm64x", COFF::IMAGE_FILE_MACHINE_ARM64X) .Default(COFF::IMAGE_FILE_MACHINE_UNKNOWN); } @@ -38,6 +39,8 @@ return "arm64"; case COFF::IMAGE_FILE_MACHINE_ARM64EC: return "arm64ec"; + case COFF::IMAGE_FILE_MACHINE_ARM64X: + return "arm64x"; case COFF::IMAGE_FILE_MACHINE_AMD64: return "x64"; case COFF::IMAGE_FILE_MACHINE_I386: diff --git a/llvm/lib/Object/WindowsResource.cpp b/llvm/lib/Object/WindowsResource.cpp --- a/llvm/lib/Object/WindowsResource.cpp +++ b/llvm/lib/Object/WindowsResource.cpp @@ -990,6 +990,7 @@ break; case COFF::IMAGE_FILE_MACHINE_ARM64: case COFF::IMAGE_FILE_MACHINE_ARM64EC: + case COFF::IMAGE_FILE_MACHINE_ARM64X: Reloc->Type = COFF::IMAGE_REL_ARM64_ADDR32NB; break; default: diff --git a/llvm/lib/ObjectYAML/COFFEmitter.cpp b/llvm/lib/ObjectYAML/COFFEmitter.cpp --- a/llvm/lib/ObjectYAML/COFFEmitter.cpp +++ b/llvm/lib/ObjectYAML/COFFEmitter.cpp @@ -50,8 +50,7 @@ bool isPE() const { return Obj.OptionalHeader.has_value(); } bool is64Bit() const { return Obj.Header.Machine == COFF::IMAGE_FILE_MACHINE_AMD64 || - Obj.Header.Machine == COFF::IMAGE_FILE_MACHINE_ARM64 || - Obj.Header.Machine == COFF::IMAGE_FILE_MACHINE_ARM64EC; + COFF::isArm64(Obj.Header.Machine); } uint32_t getFileAlignment() const { diff --git a/llvm/lib/ObjectYAML/COFFYAML.cpp b/llvm/lib/ObjectYAML/COFFYAML.cpp --- a/llvm/lib/ObjectYAML/COFFYAML.cpp +++ b/llvm/lib/ObjectYAML/COFFYAML.cpp @@ -66,6 +66,7 @@ ECase(IMAGE_FILE_MACHINE_ARMNT); ECase(IMAGE_FILE_MACHINE_ARM64); ECase(IMAGE_FILE_MACHINE_ARM64EC); + ECase(IMAGE_FILE_MACHINE_ARM64X); ECase(IMAGE_FILE_MACHINE_EBC); ECase(IMAGE_FILE_MACHINE_I386); ECase(IMAGE_FILE_MACHINE_IA64); @@ -430,8 +431,7 @@ MappingNormalization, uint16_t> NT( IO, Rel.Type); IO.mapRequired("Type", NT->Type); - } else if (H.Machine == COFF::IMAGE_FILE_MACHINE_ARM64 || - H.Machine == COFF::IMAGE_FILE_MACHINE_ARM64EC) { + } else if (COFF::isArm64(H.Machine)) { MappingNormalization, uint16_t> NT( IO, Rel.Type); IO.mapRequired("Type", NT->Type); diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp --- a/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp +++ b/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp @@ -167,6 +167,7 @@ break; case COFF::IMAGE_FILE_MACHINE_ARM64: case COFF::IMAGE_FILE_MACHINE_ARM64EC: + case COFF::IMAGE_FILE_MACHINE_ARM64X: CpuType = CPUType::ARM64; break; } diff --git a/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp b/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp --- a/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp +++ b/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp @@ -167,9 +167,7 @@ uint16_t Machine = (*Obj)->getMachine(); if (Machine != COFF::IMAGE_FILE_MACHINE_I386 && Machine != COFF::IMAGE_FILE_MACHINE_AMD64 && - Machine != COFF::IMAGE_FILE_MACHINE_ARMNT && - Machine != COFF::IMAGE_FILE_MACHINE_ARM64 && - Machine != COFF::IMAGE_FILE_MACHINE_ARM64EC) { + Machine != COFF::IMAGE_FILE_MACHINE_ARMNT && !COFF::isArm64(Machine)) { return createStringError(inconvertibleErrorCode(), "unknown machine: " + std::to_string(Machine)); } @@ -205,9 +203,16 @@ return true; // ARM64EC mode allows both pure ARM64, ARM64EC and X64 objects to be mixed in // the archive. - return LibMachine == COFF::IMAGE_FILE_MACHINE_ARM64EC && - (FileMachine == COFF::IMAGE_FILE_MACHINE_ARM64 || - FileMachine == COFF::IMAGE_FILE_MACHINE_AMD64); + switch (LibMachine) { + case COFF::IMAGE_FILE_MACHINE_ARM64: + return FileMachine == COFF::IMAGE_FILE_MACHINE_ARM64X; + case COFF::IMAGE_FILE_MACHINE_ARM64EC: + case COFF::IMAGE_FILE_MACHINE_ARM64X: + return COFF::isArm64(FileMachine) || + FileMachine == COFF::IMAGE_FILE_MACHINE_AMD64; + default: + return false; + } } static void appendFile(std::vector &Members, @@ -482,7 +487,8 @@ /*WriteSymtab=*/true, Thin ? object::Archive::K_GNU : object::Archive::K_COFF, /*Deterministic*/ true, Thin, nullptr, - LibMachine == COFF::IMAGE_FILE_MACHINE_ARM64EC)) { + LibMachine == COFF::IMAGE_FILE_MACHINE_ARM64EC || + LibMachine == COFF::IMAGE_FILE_MACHINE_ARM64X)) { handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) { llvm::errs() << OutputPath << ": " << EI.message() << "\n"; }); diff --git a/llvm/test/tools/llvm-cvtres/machine.test b/llvm/test/tools/llvm-cvtres/machine.test --- a/llvm/test/tools/llvm-cvtres/machine.test +++ b/llvm/test/tools/llvm-cvtres/machine.test @@ -25,6 +25,12 @@ RUN: llvm-cvtres /machine:ARM64 /out:%t %p/Inputs/test_resource.res RUN: llvm-readobj -h -r %t | FileCheck %s -check-prefix=ARM64 +RUN: llvm-cvtres /machine:ARM64EC /out:%t %p/Inputs/test_resource.res +RUN: llvm-readobj -h -r %t | FileCheck %s -check-prefix=ARM64EC + +RUN: llvm-cvtres /machine:ARM64X /out:%t %p/Inputs/test_resource.res +RUN: llvm-readobj -h -r %t | FileCheck %s -check-prefix=ARM64X + X86: Machine: IMAGE_FILE_MACHINE_I386 (0x14C) X86-DAG: Relocations [ X86-DAG: .rsrc$01 { @@ -72,3 +78,27 @@ ARM64-NEXT: 0x1F8 IMAGE_REL_ARM64_ADDR32NB $R000005 ARM64-NEXT: 0x1B8 IMAGE_REL_ARM64_ADDR32NB $R000006 ARM64-NEXT: 0x188 IMAGE_REL_ARM64_ADDR32NB $R000007 + +ARM64EC: Machine: IMAGE_FILE_MACHINE_ARM64EC (0xA641) +ARM64EC-DAG: Relocations [ +ARM64EC-DAG: .rsrc$01 { +ARM64EC-NEXT: 0x1E8 IMAGE_REL_ARM64_ADDR32NB $R000000 +ARM64EC-NEXT: 0x198 IMAGE_REL_ARM64_ADDR32NB $R000001 +ARM64EC-NEXT: 0x1A8 IMAGE_REL_ARM64_ADDR32NB $R000002 +ARM64EC-NEXT: 0x1C8 IMAGE_REL_ARM64_ADDR32NB $R000003 +ARM64EC-NEXT: 0x1D8 IMAGE_REL_ARM64_ADDR32NB $R000004 +ARM64EC-NEXT: 0x1F8 IMAGE_REL_ARM64_ADDR32NB $R000005 +ARM64EC-NEXT: 0x1B8 IMAGE_REL_ARM64_ADDR32NB $R000006 +ARM64EC-NEXT: 0x188 IMAGE_REL_ARM64_ADDR32NB $R000007 + +ARM64X: Machine: IMAGE_FILE_MACHINE_ARM64X (0xA64E) +ARM64X-DAG: Relocations [ +ARM64X-DAG: .rsrc$01 { +ARM64X-NEXT: 0x1E8 IMAGE_REL_ARM64_ADDR32NB $R000000 +ARM64X-NEXT: 0x198 IMAGE_REL_ARM64_ADDR32NB $R000001 +ARM64X-NEXT: 0x1A8 IMAGE_REL_ARM64_ADDR32NB $R000002 +ARM64X-NEXT: 0x1C8 IMAGE_REL_ARM64_ADDR32NB $R000003 +ARM64X-NEXT: 0x1D8 IMAGE_REL_ARM64_ADDR32NB $R000004 +ARM64X-NEXT: 0x1F8 IMAGE_REL_ARM64_ADDR32NB $R000005 +ARM64X-NEXT: 0x1B8 IMAGE_REL_ARM64_ADDR32NB $R000006 +ARM64X-NEXT: 0x188 IMAGE_REL_ARM64_ADDR32NB $R000007 diff --git a/llvm/test/tools/llvm-lib/Inputs/arm64x.yaml b/llvm/test/tools/llvm-lib/Inputs/arm64x.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-lib/Inputs/arm64x.yaml @@ -0,0 +1,23 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_ARM64X + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '' +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 1 +... diff --git a/llvm/test/tools/llvm-lib/machine-mismatch.test b/llvm/test/tools/llvm-lib/machine-mismatch.test --- a/llvm/test/tools/llvm-lib/machine-mismatch.test +++ b/llvm/test/tools/llvm-lib/machine-mismatch.test @@ -8,6 +8,7 @@ RUN: llvm-as -o %t/i386.bc %S/Inputs/i386.ll RUN: llvm-as -o %t/x86_64.bc %S/Inputs/x86_64.ll RUN: llvm-as -o %t/arm64.bc %S/Inputs/arm64.ll +RUN: yaml2obj -o %t/arm64x.obj %S/Inputs/arm64x.yaml Mixing bitcode and normal object files with the same machine type is ok: @@ -49,15 +50,26 @@ Mixing arm64 and x86_64 is possible using arm64ec: -RUN: llvm-lib -machine:arm64ec %t/arm64.bc %t/x86_64.bc %t/arm64.obj %t/x86_64.obj %t/arm64ec.obj +RUN: llvm-lib -machine:arm64ec %t/arm64.bc %t/x86_64.bc %t/arm64.obj %t/x86_64.obj %t/arm64ec.obj %t/arm64x.obj +RUN: llvm-lib -machine:arm64x %t/arm64.bc %t/x86_64.bc %t/arm64.obj %t/x86_64.obj %t/arm64ec.obj %t/arm64x.obj +RUN: llvm-lib -machine:arm64 %t/arm64.bc %t/arm64.obj %t/arm64x.obj RUN: not llvm-lib %t/arm64ec.obj 2>&1 | FileCheck --check-prefix=NOEC %s NOEC: arm64ec.obj: file machine type arm64ec conflicts with inferred library machine type, use /machine:arm64ec or /machine:arm64x RUN: not llvm-lib -machine:arm64ec %t/arm64ec.obj %t/i386.obj 2>&1 | \ RUN: FileCheck --check-prefix=OBJEC %s +RUN: not llvm-lib -machine:arm64x %t/arm64ec.obj %t/i386.obj 2>&1 | \ +RUN: FileCheck --check-prefix=OBJX %s +RUN: not llvm-lib -machine:x64 %t/x86_64.obj %t/arm64x.obj 2>&1 | \ +RUN: FileCheck --check-prefix=OBJX2 %s OBJEC: i386.obj: file machine type x86 conflicts with library machine type arm64ec (from '/machine:arm64ec' flag) +OBJX: i386.obj: file machine type x86 conflicts with library machine type arm64x (from '/machine:arm64x' flag) +OBJX2: arm64x.obj: file machine type arm64x conflicts with library machine type x64 (from '/machine:x64' flag) RUN: not llvm-lib -machine:arm64ec %t/arm64.bc %t/x86_64.bc %t/i386.bc 2>&1 | \ RUN: FileCheck --check-prefix=BCEC %s +RUN: not llvm-lib -machine:arm64x %t/arm64.bc %t/x86_64.bc %t/i386.bc 2>&1 | \ +RUN: FileCheck --check-prefix=BCX %s BCEC: i386.bc: file machine type x86 conflicts with library machine type arm64ec (from '/machine:arm64ec' flag) +BCX: i386.bc: file machine type x86 conflicts with library machine type arm64x (from '/machine:arm64x' flag) diff --git a/llvm/test/tools/llvm-readobj/COFF/arm64x.yaml b/llvm/test/tools/llvm-readobj/COFF/arm64x.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/COFF/arm64x.yaml @@ -0,0 +1,27 @@ +# RUN: yaml2obj < %s | llvm-readobj - --file-headers | FileCheck %s +# Check we can process a simple arm64x file. +# CHECK: Format: COFF-ARM64X +# CHECK: Machine: IMAGE_FILE_MACHINE_ARM64X (0xA64E) +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_ARM64X + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '' +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 1 +... diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp --- a/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -344,6 +344,7 @@ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM64 ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM64EC ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM64X ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMNT ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_EBC ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_I386 ), @@ -1671,6 +1672,7 @@ } case COFF::IMAGE_FILE_MACHINE_ARM64: case COFF::IMAGE_FILE_MACHINE_ARM64EC: + case COFF::IMAGE_FILE_MACHINE_ARM64X: case COFF::IMAGE_FILE_MACHINE_ARMNT: { ARM::WinEH::Decoder Decoder(W, Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_ARMNT);