I would like to propose adding support for multi-architecture object files that contain both ARM64EC and AArch64 object files as the result of compilation with -marm64x.
Together with ARM64EC, Windows on ARM introduced ARM64X image files, which are binaries containing both ARM64EC and AArch64 code. In MSVC, this is implemented entirely as a linker feature. Users are expected to compile sources separately for both targets and then pass both sets of object files to the linker ( Build Arm64X Files | Microsoft Learn ). We already support this workflow in both Clang and LLD. The build process typically looks like this:
clang -target aarch64-windows -c foo.c -o foo-aarch64.o
clang -target arm64ec-windows -c foo.c -o foo-arm64ec.o
clang -marm64x -o bar.exe foo-aarch64.o foo-arm64ec.o
This differs significantly from a typical build process. The requirement to produce two object files for every source file is challenging for build systems such as CMake, autoconf or Meson. I believe this can be significantly simplified by moving more of the logic into the toolchain itself. Ideally, the above example could instead become:
clang -marm64x -c foo.c -o foo.o
clang -marm64x -o bar.exe foo.o
This is straightforward for build systems to understand and is effectively equivalent to CFLAGS=-marm64x LDFLAGS=-marm64x.
This requires foo.o to contain both AArch64 and ARM64EC object files. The concept is not entirely new; Mach-O has supported multi-architecture binaries for years. With Mach-O, users typically have two options: build separate images and merge them afterward or build each source file into a multi-architecture object file. The former approach is not feasible for ARM64X due to format constraints, so I would like to provide an experience similar to Mach-O multi-architecture object files.
For the format of such multi-architecture object files, I propose using an archive file. A regular archive would be sufficient for most cases, so existing linkers would understand such files. To avoid behavioral differences between linking an object file and linking an archive, a small archive extension is needed. I created a separate RFC for that: [RFC] Introduce a -wholearchive marker embedded in archives themselves .
The -marm64x argument already exists in Clang, but it is currently used only during linking to pass -machine:arm64x to the linker. With the changes I am proposing, it would also affect compilation. The Clang driver would construct two intermediate assembly jobs and merge their outputs by invoking llvm-ar.
PR implementing driver changes: [clang][ARM64X] Support compiling both native and EC objects with -marm64x by cjacek · Pull Request #195836 · llvm/llvm-project · GitHub