[PATCH 1 of 1 v10] aarch64: Support PAC and BTI
Niels Möller
nisse at lysator.liu.se
Fri Sep 18 21:46:59 CEST 2026
Bill Roberts <bill.roberts at arm.com> writes:
> Testing was done under the following CFLAGS and
> CXXFLAGS for all combinations:
> 1. -mbranch-protection=none
> 2. -mbranch-protection=standard
> 3. -mbranch-protection=pac-ret
> 4. -mbranch-protection=pac-ret+b-key
> 5. -mbranch-protection=bti
Question for Torbjörn: Which of the gmp machines (if any) would be
suitable for running tests?
> --- a/configure.ac Sun Sep 06 19:15:00 2026 +0200
> +++ b/configure.ac Wed Sep 16 15:00:02 2026 -0500
> @@ -3421,14 +3421,14 @@
> CPUVEC_SETUP="$CPUVEC_SETUP decided_cpuvec.$tmp_fbase = __gmpn_${tmp_fbase}_${tmp_suffix}; \\
> "
> # Ditto for any preinv variant (preinv_divrem_1, preinv_mod_1).
> - if grep "^PROLOGUE(mpn_preinv_$tmp_fn)" $tmp_file >/dev/null; then
> + if grep "^PROLOGUE_\(NONLEAF\)?(mpn_preinv_$tmp_fn)" $tmp_file >/dev/null; then
> echo "DECL_preinv_$tmp_fbase (__gmpn_preinv_${tmp_fbase}_$tmp_suffix);" >>fat.h
> CPUVEC_SETUP="$CPUVEC_SETUP decided_cpuvec.preinv_$tmp_fbase = __gmpn_preinv_${tmp_fbase}_${tmp_suffix}; \\
> "
> fi
>
> # Ditto for any mod_1...cps variant
> - if grep "^PROLOGUE(mpn_${tmp_fbase}_cps)" $tmp_file >/dev/null; then
> + if grep "^PROLOGUE_\(_NONLEAF\)?(mpn_${tmp_fbase}_cps)" $tmp_file >/dev/null; then
> echo "DECL_${tmp_fbase}_cps (__gmpn_${tmp_fbase}_cps_$tmp_suffix);" >>fat.h
> CPUVEC_SETUP="$CPUVEC_SETUP decided_cpuvec.${tmp_fbase}_cps = __gmpn_${tmp_fbase}_cps_${tmp_suffix}; \\
> "
> @@ -3561,6 +3561,7 @@
> gmp_ep=[`
> sed -n 's/^[ ]*MULFUNC_PROLOGUE(\(.*\))/\1/p' $tmp_file ;
> sed -n 's/^[ ]*PROLOGUE(\([^,]*\).*)/\1/p' $tmp_file
> + sed -n 's/^[ ]*NONLEAF_PROLOGUE(\([^,]*\).*)/\1/p' $tmp_file
There appears to be some confusion about NONLEAF_PROLOGUE (here) and
PROLOGUE_NONLEAF (above). Probably makes most sense to use
NONLEAF_PROLOGUE everywhere, for consistency with MULFUNC_PROLOGUE.
> `]
> for gmp_tmp in $gmp_ep; do
> AC_DEFINE_UNQUOTED(HAVE_NATIVE_$gmp_tmp)
> @@ -3767,7 +3768,77 @@
> *-*-darwin*)
> GMP_INCLUDE_MPN(arm64/darwin.m4) ;;
> *)
> - GMP_INCLUDE_MPN(arm64/arm64-defs.m4) ;;
> + GMP_INCLUDE_MPN(arm64/arm64-defs.m4)
> +
> + AC_CACHE_CHECK([if Armv8.5-A BTI is enabled],
> + [gmp_cv_asm_arm64_bti],
> + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
> + #if !(defined __ARM_FEATURE_BTI_DEFAULT)
> + #error Armv8.5-A BTI is not enabled
> + #endif
> + ]], [[]])],
> + [gmp_cv_asm_arm64_bti=yes],
> + [gmp_cv_asm_arm64_bti=no])])
> + # Convert yes no values to BTI value, yes no is nice for the output message on the screen
> + # Example: checking if Armv8.5-A BTI is enabled... yes
> + AS_IF([test "$gmp_cv_asm_arm64_bti" = yes],
> + [ARM64_FEATURE_BTI_DEFAULT=1], [ARM64_FEATURE_BTI_DEFAULT=0])
> +
> + GMP_DEFINE_RAW(["define(<ARM64_FEATURE_BTI_DEFAULT>,$ARM64_FEATURE_BTI_DEFAULT)"])
> + AC_SUBST([ARM64_FEATURE_BTI_DEFAULT])
>From the docs, it seems GMP_DEFINE_RAW adds a definition to config.m4.
You combine with AC_SUBST, so you want ARM64_FEATURE_BTI_DEFAULT to go
into both config.m4 and other substituted files, e.g, Makefile? And same
for other variables.
> + AS_IF([test "$gmp_cv_asm_arm64_pac" = yes], [
> + AC_CACHE_CHECK([if PAC is using A or B key],
> + [gmp_cv_asm_arm64_pac_key],
> + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
> + #if __ARM_FEATURE_PAC_DEFAULT & 1
> + // Armv8.3-A PAC A Key enabled else B Key enabled
> + #endif
> + ]], [[]])],
> + [gmp_cv_asm_arm64_pac_key=A],
> + [gmp_cv_asm_arm64_pac_key=B])])
> + ])
This test looks weird, should that C++-style comment be an #error
instead?
> + AC_CACHE_CHECK([whether __ELF__ is defined],
> + [gmp_cv_asm_arm64_have_elf],
> + [AC_PREPROC_IFELSE(
> + [AC_LANG_SOURCE([[
> + #ifdef __ELF__
> + int main(void) { return 0; }
> + #else
> + #error "__ELF__ not defined"
> + #endif
> + ]])],
If this is just a test running the preprocessor, having the main
function seems unnecessary. For consistency, I think it would make sense
to use AC_COMPILE_IFELSE and same style as the other tests above.
> + [gmp_cv_asm_arm64_have_elf=yes],
> + [gmp_cv_asm_arm64_have_elf=no])])
> +
> + if test "$gmp_cv_asm_arm64_have_elf" = yes; then
> + gmp_cv_asm_arm64_have_elf_value=1
> + else
> + gmp_cv_asm_arm64_have_elf_value=0
> + fi
> +
> + GMP_DEFINE_RAW(["define(<ARM64_ELF>,$gmp_cv_asm_arm64_have_elf_value)"])
> + ;;
> esac
> ;;
> esac
> @@ -4058,6 +4129,9 @@
> AC_PROG_YACC
> AM_PROG_LEX
>
> +AM_CONDITIONAL([ARM64_PAC_OR_BTI],
> + [test $ARM64_FEATURE_BTI_DEFAULT -ne 0 || test $ARM64_FEATURE_BTI_DEFAULT])
> +
I think it would make sense to move this closer to the tests that set
these variables.
> +#define(`NONLEAF_PROLOGUE', `indir(`PROLOGUE', $1, true)')
> +define(`PROLOGUE_NONLEAF', `PROLOGUE($1, true)')
More naming.
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/tests/mpn/t-arm64_bti.c Wed Sep 16 15:00:02 2026 -0500
> +int
> +main (int argc, char **argv)
> +{
> + unsigned long hwcap2 = getauxval(AT_HWCAP2);
> + if (!(hwcap2 & HWCAP2_BTI)) {
> + fprintf(stderr, "Hardware does not support BTI\n");
> + return SKIP;
> + }
> +
> + /*
> + * 0x1001 is the value we will left shift by one, we expect 0x2002 as
> + * the valid result.
> + */
> + mp_limb_t xp = 0x1001, wp;
> +
> + fn_mpn_lshift fn = dlsym(RTLD_DEFAULT, "__gmpn_lshift");
> + if (!fn) {
> + fprintf(stderr, "Could not find the symbol __gmpn_lshift\n");
> + return 0;
> + }
I would expect this symbol lookup to fail in a static build. Maybe it
should be SKIP instead?
> + /* should work as this will land on a BTI landing pad as expected */
> + fn (&wp, &xp, (mp_size_t) 1, 1);
> + /* And provide the proper result 0x1001 << 1 = 0x2002 */
> + ASSERT_ALWAYS (wp == 0x2002);
Since this is an XFAIL test, hitting this assert will look like an
expected failure, right? I find XFAIL generally a bit confusing, it
would be nicer if the test could detect if an exception was raised, and
return success when things are as expected. E.g., installing a signal
handler for the expected signal just before running the code that is
expected to raise that exception, and have the exception handler just
call exit (0).
Regards,
/Niels
--
Niels Möller. PGP key CB4962D070D77D7FCB8BA36271D8F1FF368C6677.
Internet email is subject to wholesale government surveillance.
More information about the gmp-devel
mailing list