'How does ARM64EC Code get executed on ARM?

Im currently trying to understand how Windows on ARM works. Im having trouble understanding how the ARM64EC ABI can work on an ARM chip. Microsoft says the ARM64EC is based on AArch64 with some changes to make it compatible to x64 including calling conventions, stack usage and data alignment [1]. In my mind this would mean it can be executed on an x64 chip and i can not find the reason this would make it run on an ARM chip if it follows x64 conventions.

Also they say the x64 code is beeing emulated (i guess using an extended version of the x86 to ARM emulator) but then the ARM64EC is running natively. But why do we have to differentiate if they are both interoperable? Is the OS then changing everything internally to comply to AArch64?

Is there something im missing? I stumbled across the ISA but i couldnt find anything about what ABIs would be compatible with the A64 ISA. But i also have some trouble understanding the relationship of the ISA and ABIs?

Im sry if this is a stupid question but i think im just missing or missunderstanding samothing and microsoft is quite sparse with details.

[1] https://blogs.windows.com/windowsdeveloper/2021/06/28/announcing-arm64ec-building-native-and-interoperable-apps-for-windows-11-on-arm/



Solution 1:[1]

In my mind this would mean it can be executed on an x64 chip [...].

You're confusing ABI with instruction set. ARM64EC still uses the A64 instruction set (which an x64 CPU is incapable of executing), but it uses registers and stack in a way that is easy to map onto x64 registers, conceptually.

I wasn't able to find an actual specification for ARM64EC, but I imagine one thing could be the return address.
In normal ARM64 code a function is called with bl func_name, which puts the return address into x30, and then the callee uses ret, which will jump to the address in x30. Compare this to x64 where call pushes the return address onto the stack and ret pops it from there.
Again, I don't know if ARM64EC actually does this, but if I were designing it, then one thing I'd do would be to make function calls look like this:

// call site
adr x30, 1f
str x30, [sp, -8]!
b func_name
1:
// ...

func_name:
// ...
ldr x30, [sp], 8
ret

If you didn't do this, then translated x64 code would expect things in different places than were put in by native code, and vice versa.

Solution 2:[2]

MSFT has recently published some details on ARM64EC and how it works: https://docs.microsoft.com/en-us/windows/uwp/porting/arm64ec-abi

To summarize an ARM64EC binary is mostly ARM64 code, but using registers in a way that allows to map the state 1:1 on x64 and all functions which are exported or marked accordingly will get a short x64 wrapper called a FFS, this allows you to hook this functions with x64 hooks despite most of the code to be ARM64. And ensures that when you import a library it does not mater if its x64 or arm64ec your application being x64 or arm64ec will be able to use it seamlessly.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Siguza
Solution 2 DavidXanatos