Implement unknown function support for ARM64EC#1929
Conversation
Wires up the build for Windows on Arm arm64ec/arm64x targets (KhronosGroup#1884): - CMakeLists: derive SYSTEM_PROCESSOR from CMAKE_GENERATOR_PLATFORM (the -A target) when set, so cross-targeting picks the right assembler; fall back to host otherwise - update_deps.py: accept the arm64ec architecture - asm_offset.c: treat _M_ARM64EC as 64-bit ARM The adjustor thunks in unknown_ext_chain_marmasm.asm are still TODO.
Completes unknown-function support for arm64ec/arm64x (KhronosGroup#1884). The trampolines forward unknown device and physical-device extension calls without knowing their signature. On arm64ec they can be entered from emulated x64 code, so each one becomes an adjustor thunk: a custom entry thunk for the x64-caller path plus the signature-less body for the arm64ec-caller path. The arm64ec variants are guarded by _ARM64EC_ and use the SDK ksarm64.h macros (A64NAME, NESTED_ENTRY, ARM64EC_CUSTOM_ENTRY_THUNK); the arm64 and arm32 paths are unchanged. The entry thunk loads the real target and tail-jumps __os_arm64x_x64_jump so the target's own entry thunk performs the calling-convention work. It is emitted before the body so __AddEntryThunkPointer wires the two together, and the body is non-COMDAT so that wiring is generated. The body routes the target through __os_arm64x_check_icall (leaving the caller-provided exit thunk in x10 untouched; the dispatch-table offset uses an immediate rather than x10) and tail-branches to it, saving and restoring fp/lr with writeback around the checker call so the caller's return address survives. Validated on Windows-on-Arm: the full loader test suite passes when built with -A arm64ec.
|
Author BoiledElectricity not on autobuild list. Waiting for curator authorization before starting CI build. |
1 similar comment
|
Author BoiledElectricity not on autobuild list. Waiting for curator authorization before starting CI build. |
|
CI Vulkan-Loader build queued with queue ID 766241. |
|
CI Vulkan-Loader build # 3544 running. |
|
CI Vulkan-Loader build # 3544 passed. |
|
So I haven't done a full review, but I did want to share my efforts to properly test the change in github actions. The current code doesn't build an native arm64x binary, that requires 2 steps. I have added the necessary CMake code and added a github actions ci job that exercises it, plus build the repo as x64 and runs the tests using the arm64x binary to validate everything works. https://github.com/charles-lunarg/Vulkan-Loader/tree/add_arm64x_ci_test The test failures are in tests that query for various functions with different mechanisms and check that the function pointer is the same. These failures could imply something with the PR is wrong, or that those tests are faulty in an arm64x mode as functions queried from Github actions run link: https://github.com/charles-lunarg/Vulkan-Loader/actions/runs/27234600513/job/80423918750 |
On arm64x the loader has two views of each entry point: GetProcAddress hands an x64 caller (an arm64ec build, or an x64 process emulated on an Arm64 host) an export's x64 fast-forward-sequence thunk, while the loader resolves its own name to the native arm64ec function. Same command, different address, and the Vulkan spec doesn't require them to match. The proc-addr tests asserted raw pointer identity between the two, which fails on arm64x. Compare behavior instead (both non-null, both resolve a known command to the same pointer, unknown commands return null) when running on an Arm64 host, and keep strict identity everywhere else.
CMake's MARMASM compiler detection (CMakeDetermineASM_MARMASMCompiler.cmake) only matches "ARM64", so for an arm64ec target it selects the 32-bit armasm, which cannot assemble arm64ec code. It also leaves CMAKE_ASM_MARMASM_COMPILER as a bare "armasm64", which the assembler check runs directly and so fails when the dev tools are not on PATH (e.g. a stock CI configure). Either way the check fails and unknown function support gets silently disabled. Find armasm64 next to the C compiler and point the language at its full path so a plain `-A arm64`/`-A arm64ec` configure works without a manual -DCMAKE_ASM_MARMASM_COMPILER override or a developer command prompt. Drop this once CMake's detection matches ARM64EC (KhronosGroup#1884).
Add a windows_arm job on the native windows-11-arm runners that builds and runs the test suite for the arm64 and arm64ec targets. These exercise the MARMASM assembler paths in unknown_ext_chain_marmasm.asm (including the arm64ec adjustor thunks) that the existing x64 Windows jobs cannot reach (KhronosGroup#1884).
d7bdc5c to
775cbca
Compare
|
Author BoiledElectricity not on autobuild list. Waiting for curator authorization before starting CI build. |
1 similar comment
|
Author BoiledElectricity not on autobuild list. Waiting for curator authorization before starting CI build. |
|
@charles-lunarg Thanks for digging into this and testing a real arm64x binary. Turns out there was a gap on my side. Yeah my CI was testing only standalone arm64 and arm64ec builds. I never actually ran the x64 process + ARM64X loader case you were testing. The failure was the proc-addr tests still doing a strict pointer identity check there. I switched that to a runtime check using IsWow64Process2 so it handles arm64x properly. I also pulled in your arm64x build support and added a windows_arm64x CI job. Everything's green now. x64 passes 642/642 against the ARM64X binary both locally and in CI. |
|
Rather than cherry-pick my branch's commits onto yours, you just created new commits with the same content. |
@charles-lunarg I’m so sorry that was 100% my fault, I wasn’t even thinking about preserving the commit history. I had made another copy of the repo with your changes pulled, and then just copied over not even thinking. and then just started moving forward. I didn’t mean anything by it. I’m not home right now, but when I am, I will fix. Again, I’m sorry. |
Since building arm64x is a two step process, we use CMake to cache the binary artifacts from the first build step so it can apply them during the second build step. (cherry picked from commit 3bde50c)
775cbca to
7a352c8
Compare
(cherry picked from commit 6e9edf7)
The cherry-picked job came in at the 2-space indent it had as the only job on its source branch. Bump it to 4 spaces so it sits alongside the existing jobs.
7a352c8 to
480416b
Compare
|
Author BoiledElectricity not on autobuild list. Waiting for curator authorization before starting CI build. |
1 similar comment
|
Author BoiledElectricity not on autobuild list. Waiting for curator authorization before starting CI build. |
|
CI Vulkan-Loader build queued with queue ID 767931. |
|
CI Vulkan-Loader build # 3547 running. |
|
CI Vulkan-Loader build # 3547 passed. |
Fixes #1884.
The loader's unknown-function trampolines (the phys-dev and device extension chains) didn't have an ARM64EC path, so unknown entrypoints would fall over on Windows on Arm. This adds one.
What's here:
__os_arm64x_x64_jump, while ARM64EC callers come in through__os_arm64x_check_icall. The implementation uses theksarm64.hhelpers under_ARM64EC_.SYSTEM_PROCESSORnow comes from the generator platform,update_deps.pylearns the arm64ec architecture, and_M_ARM64ECmaps to the 64-bit assembly offsets. Also resolvesarmasm64by full path since CMake's MARMASM detection only recognizes plainARM64.GetProcAddressreturns an x64 fast-forward-sequence stub, while the loader's internal&fnpoints at the native ARM64EC implementation. Both are valid entrypoints, but they aren't required to be bit-identical, so the proc-addr tests compare behavior rather than raw pointer identity on ARM64EC and remain strict everywhere else.This ended up touching a little more than just the trampoline assembly. Getting ARM64EC support fully wired through required build-system updates, test fixes for the expected pointer-identity split, and CI coverage to keep it from regressing.