Implement Arm64e on MacOS/AArch64
PAC (Pointer Authentication Code) is an AArch64 hardware feature which provides a set of tools to guard against various types of attacks at the cost of a small performance overhead. For more details see the Arm® Architecture Reference Manual : D5.1.5 Pointer authentication in AArch64 state For a general background see Providing protection for complex software
MacOS on Apple silicon provides an additional ABI named arm64e. It is enabled/disabled on OS boot. More detail of the ABI can be found here. In addition to PAC-RET protection (as provided by GCC/LLVM) it signs function pointers and gives application writers the ability to sign data pointers. Using fat binaries, applications can be compiled for both arm64 and arm64e, allowing binaries to conform to both ABIs. OpenJDK should also conform to this ABI.
Description Provide arm64e support for both the VM and generated JIT code.
- When compiling for MacOS, pass both arm64 and arm64e as the target architectures to the compiler, producing a fat binary. Provide an option to override this.
- When running on MacOS arm64e, emit PAC instructions to sign/authenticate the return address when it is saved to/restored from the stack. This will reuse the code provided by JDK-8264130.
- When running on MacOS arm64e, C++ function pointers are signed. Therefore, generated function entry points must be stored as signed values and generated code will require changes to method calling.
- In addition, it may become apparent that certain data pointers should also be signed.
Due to the Arm64 and Arm64e variants being compiled separately, unlike in the Linux implementation, the decision whether to plant PAC instructions can be made using an #ifdef. The Arm64 version will be required to plant any PAC instructions. This means the Arm64e version is not restricted to only using the PAC NOP instructions.
Testing will include, but not be limited to, regression testing with jtreg and various other benchmark suites. The execution environment will include Apple Silicon as well as any additional hardware that becomes available, in both arm64 and arm64e modes.
Risks and Assumptions
Assumption: Implementing this change will result in an acceptable performance overhead on all MacOS/AArch64 systems.
- The OpenJDK binaries and libraries will double in size. This is due to them being compiled twice, and is standard practice on Apple Silicon.
- On systems booted into Arm64, generated code will not change. Therefore there will be zero performance overhead.
- On systems booted into Arm64e, both the compiled VM code and the generated java code will have:
- Two instructions per non-leaf function/method to sign/authenticate the return address
- Two instructions per function/method call to sign/authenticate the function pointer
- Additional code for handling any signed data pointers
- Plus additional code inside the VM to handle all of the above.
- Performance impact on Arm64e is expected to be at least twice that of PAC-RET on AArch64 Linux.
Assumption: Official OpenJDK releases for for MacOS/AArch64 will be built without disabling fat binary support.
This JEP will reuse code from JEP PAC-RET protection for Linux/AArch64. Future PAC work will be dependant on this JEP.