AArch64: Cleanup PAC and BTI

Now we finally support modern GCC and binutils, it's time for a cleanup.
Use PAC and BTI instructions unconditionally and use proper assembler syntax.
Remove the PR target/94791 strip_pac workarounds for buggy GCCs.  Remove the
PAC/BTI configure checks - always emit GNU property notes on assembly files.
Change cfi_window_save to the correct cfi_negate_ra_state unwind directive.

Reviewed-by: Matthieu Longo <matthieu.longo@arm.com>
This commit is contained in:
Wilco Dijkstra 2025-05-14 16:32:31 +00:00
parent 96abd59bf2
commit 2c421fc430
20 changed files with 51 additions and 273 deletions

View File

@ -113,12 +113,6 @@
/* AArch64 big endian ABI */
#undef HAVE_AARCH64_BE
/* AArch64 BTI support enabled. */
#define HAVE_AARCH64_BTI 0
/* AArch64 PAC-RET code generation is enabled. */
#define HAVE_AARCH64_PAC_RET 0
/* Assembler support ARMv8.2-A SVE.
This macro becomes obsolete when glibc increased the minimum
required version of GNU 'binutils' to 2.28 or later. */

View File

@ -20,6 +20,7 @@
#include <config.h>
#ifdef __aarch64__
/* GNU_PROPERTY_AARCH64_* macros from elf.h for use in asm code. */
#define FEATURE_1_AND 0xc0000000
#define FEATURE_1_BTI 1
@ -42,8 +43,5 @@
/* Add GNU property note with the supported features to all asm code
where sysdep.h is included. */
#if HAVE_AARCH64_BTI && HAVE_AARCH64_PAC_RET
GNU_PROPERTY (FEATURE_1_AND, FEATURE_1_BTI|FEATURE_1_PAC|FEATURE_1_GCS)
#elif HAVE_AARCH64_BTI
GNU_PROPERTY (FEATURE_1_AND, FEATURE_1_BTI|FEATURE_1_GCS)
#endif

View File

@ -88,10 +88,8 @@ L(save_loop):
L(end):
ret
L(fail):
#if HAVE_AARCH64_PAC_RET
PACIASP
cfi_window_save
#endif
paciasp
cfi_negate_ra_state
stp x29, x30, [sp, -32]!
cfi_adjust_cfa_offset (32)
cfi_rel_offset (x29, 0)

View File

@ -27,10 +27,8 @@ ENTRY (__longjmp)
#if IS_IN(libc)
/* Disable ZA state of SME in libc.a and libc.so, but not in ld.so. */
# if HAVE_AARCH64_PAC_RET
PACIASP
cfi_window_save
# endif
paciasp
cfi_negate_ra_state
stp x29, x30, [sp, -16]!
cfi_adjust_cfa_offset (16)
cfi_rel_offset (x29, 0)
@ -41,10 +39,8 @@ ENTRY (__longjmp)
cfi_adjust_cfa_offset (-16)
cfi_restore (x29)
cfi_restore (x30)
# if HAVE_AARCH64_PAC_RET
AUTIASP
cfi_window_save
# endif
autiasp
cfi_negate_ra_state
#endif
cfi_def_cfa (x0, 0)

View File

@ -185,93 +185,6 @@ else
default-abi = lp64"
fi
# Only consider BTI supported if -mbranch-protection=bti is
# on by default in the compiler and the linker produces
# binaries with GNU property notes in PT_GNU_PROPERTY segment.
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BTI support" >&5
printf %s "checking for BTI support... " >&6; }
if test ${libc_cv_aarch64_bti+y}
then :
printf %s "(cached) " >&6
else case e in #(
e) cat > conftest.c <<EOF
void foo (void) { }
EOF
libc_cv_aarch64_bti=no
if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -nostdlib -nostartfiles $no_ssp -shared -fPIC -o conftest.so conftest.c'
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
(eval $ac_try) 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; } \
&& { ac_try='$READELF -lW conftest.so | grep -q GNU_PROPERTY'
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
(eval $ac_try) 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; } \
&& { ac_try='$READELF -nW conftest.so | grep -q "NT_GNU_PROPERTY_TYPE_0.*AArch64 feature:.* BTI"'
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
(eval $ac_try) 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; }
then
libc_cv_aarch64_bti=yes
fi
rm -rf conftest.* ;;
esac
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_aarch64_bti" >&5
printf "%s\n" "$libc_cv_aarch64_bti" >&6; }
config_vars="$config_vars
aarch64-bti = $libc_cv_aarch64_bti"
if test $libc_cv_aarch64_bti = yes; then
printf "%s\n" "#define HAVE_AARCH64_BTI 1" >>confdefs.h
fi
# Check if glibc is built with return address signing, i.e.
# if -mbranch-protection=pac-ret is on. We need this because
# pac-ret relies on unwinder support so it's not safe to use
# it in assembly code unconditionally, but there is no
# feature test macro for it in gcc.
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if pac-ret is enabled" >&5
printf %s "checking if pac-ret is enabled... " >&6; }
if test ${libc_cv_aarch64_pac_ret+y}
then :
printf %s "(cached) " >&6
else case e in #(
e) cat > conftest.c <<EOF
int bar (void);
int foo (void) { return bar () + 1; }
EOF
libc_cv_aarch64_pac_ret=no
if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -S -o conftest.s conftest.c'
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
(eval $ac_try) 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; } \
&& { ac_try='grep -q -E '\''(hint( | )+25|paciasp)'\'' conftest.s'
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
(eval $ac_try) 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; }
then
libc_cv_aarch64_pac_ret=yes
fi
rm -rf conftest.* ;;
esac
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_aarch64_pac_ret" >&5
printf "%s\n" "$libc_cv_aarch64_pac_ret" >&6; }
if test $libc_cv_aarch64_pac_ret = yes; then
printf "%s\n" "#define HAVE_AARCH64_PAC_RET 1" >>confdefs.h
fi
# Check if binutils supports variant PCS symbols.
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for variant PCS support" >&5
printf %s "checking for variant PCS support... " >&6; }

View File

@ -24,47 +24,6 @@ else
LIBC_CONFIG_VAR([default-abi], [lp64])
fi
# Only consider BTI supported if -mbranch-protection=bti is
# on by default in the compiler and the linker produces
# binaries with GNU property notes in PT_GNU_PROPERTY segment.
AC_CACHE_CHECK([for BTI support], [libc_cv_aarch64_bti], [dnl
cat > conftest.c <<EOF
void foo (void) { }
EOF
libc_cv_aarch64_bti=no
if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -nostdlib -nostartfiles $no_ssp -shared -fPIC -o conftest.so conftest.c]) \
&& AC_TRY_COMMAND([$READELF -lW conftest.so | grep -q GNU_PROPERTY]) \
&& AC_TRY_COMMAND([$READELF -nW conftest.so | grep -q "NT_GNU_PROPERTY_TYPE_0.*AArch64 feature:.* BTI"])
then
libc_cv_aarch64_bti=yes
fi
rm -rf conftest.*])
LIBC_CONFIG_VAR([aarch64-bti], [$libc_cv_aarch64_bti])
if test $libc_cv_aarch64_bti = yes; then
AC_DEFINE(HAVE_AARCH64_BTI)
fi
# Check if glibc is built with return address signing, i.e.
# if -mbranch-protection=pac-ret is on. We need this because
# pac-ret relies on unwinder support so it's not safe to use
# it in assembly code unconditionally, but there is no
# feature test macro for it in gcc.
AC_CACHE_CHECK([if pac-ret is enabled], [libc_cv_aarch64_pac_ret], [dnl
cat > conftest.c <<EOF
int bar (void);
int foo (void) { return bar () + 1; }
EOF
libc_cv_aarch64_pac_ret=no
if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -S -o conftest.s conftest.c]) \
&& AC_TRY_COMMAND([grep -q -E '\''(hint( | )+25|paciasp)'\'' conftest.s])
then
libc_cv_aarch64_pac_ret=yes
fi
rm -rf conftest.*])
if test $libc_cv_aarch64_pac_ret = yes; then
AC_DEFINE(HAVE_AARCH64_PAC_RET)
fi
# Check if binutils supports variant PCS symbols.
AC_CACHE_CHECK([for variant PCS support], [libc_cv_aarch64_variant_pcs], [dnl
cat > conftest.S <<EOF

View File

@ -65,7 +65,7 @@ call_weak_fn:
cbz x0, 1f
b PREINIT_FUNCTION
1:
RET
ret
.size call_weak_fn, .-call_weak_fn
#endif
@ -75,11 +75,7 @@ call_weak_fn:
.hidden _init
.type _init, %function
_init:
#if HAVE_AARCH64_PAC_RET
PACIASP
#else
BTI_C
#endif
paciasp
stp x29, x30, [sp, -16]!
mov x29, sp
#if PREINIT_FUNCTION_WEAK
@ -94,10 +90,6 @@ _init:
.hidden _fini
.type _fini, %function
_fini:
#if HAVE_AARCH64_PAC_RET
PACIASP
#else
BTI_C
#endif
paciasp
stp x29, x30, [sp, -16]!
mov x29, sp

View File

@ -41,14 +41,10 @@
.section .init,"ax",%progbits
ldp x29, x30, [sp], 16
#if HAVE_AARCH64_PAC_RET
AUTIASP
#endif
RET
autiasp
ret
.section .fini,"ax",%progbits
ldp x29, x30, [sp], 16
#if HAVE_AARCH64_PAC_RET
AUTIASP
#endif
RET
autiasp
ret

View File

@ -74,9 +74,9 @@
cfi_startproc
.align 2
_dl_tlsdesc_return:
BTI_C
bti c
ldr x0, [x0, 8]
RET
ret
cfi_endproc
.size _dl_tlsdesc_return, .-_dl_tlsdesc_return
@ -95,7 +95,7 @@ _dl_tlsdesc_return:
cfi_startproc
.align 2
_dl_tlsdesc_undefweak:
BTI_C
bti c
str x1, [sp, #-16]!
cfi_adjust_cfa_offset (16)
ldr x0, [x0, 8]
@ -103,7 +103,7 @@ _dl_tlsdesc_undefweak:
sub x0, x0, x1
ldr x1, [sp], #16
cfi_adjust_cfa_offset (-16)
RET
ret
cfi_endproc
.size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
@ -141,12 +141,8 @@ _dl_tlsdesc_undefweak:
cfi_startproc
.align 2
_dl_tlsdesc_dynamic:
# if HAVE_AARCH64_PAC_RET
PACIASP
cfi_window_save
# else
BTI_C
# endif
paciasp
cfi_negate_ra_state
/* Save just enough registers to support fast path, if we fall
into slow path we will save additional registers. */
@ -177,12 +173,10 @@ _dl_tlsdesc_dynamic:
1:
ldp x3, x4, [sp, #16]
ldp x1, x2, [sp], #32
# if HAVE_AARCH64_PAC_RET
AUTIASP
cfi_window_save
# endif
autiasp
cfi_negate_ra_state
cfi_adjust_cfa_offset (-32)
RET
ret
2:
/* This is the slow path. We need to call __tls_get_addr() which
means we need to save and restore all the register that the

View File

@ -34,7 +34,7 @@
cfi_startproc
.align 2
_dl_runtime_resolve:
BTI_C
bti c
/* AArch64 we get called with:
ip0 &PLTGOT[2]
ip1 temp(dl resolver entry point)
@ -127,12 +127,8 @@ _dl_runtime_resolve:
cfi_startproc
.align 2
_dl_runtime_profile:
# if HAVE_AARCH64_PAC_RET
PACIASP
cfi_window_save
# else
BTI_C
# endif
paciasp
cfi_negate_ra_state
/* AArch64 we get called with:
ip0 &PLTGOT[2]
ip1 temp(dl resolver entry point)
@ -251,17 +247,12 @@ _dl_runtime_profile:
cfi_restore(x29)
cfi_restore(x30)
# if HAVE_AARCH64_PAC_RET
add sp, sp, SF_SIZE
cfi_adjust_cfa_offset (-SF_SIZE)
AUTIASP
cfi_window_save
autiasp
cfi_negate_ra_state
add sp, sp, 16
cfi_adjust_cfa_offset (-16)
# else
add sp, sp, SF_SIZE + 16
cfi_adjust_cfa_offset (- SF_SIZE - 16)
# endif
/* Jump to the newly found address. */
br ip0
@ -321,10 +312,8 @@ _dl_runtime_profile:
/* LR from within La_aarch64_reg */
ldr lr, [x29, #OFFSET_RG + DL_OFFSET_RG_LR]
cfi_restore(lr)
# if HAVE_AARCH64_PAC_RET
/* Note: LR restored from La_aarch64_reg has no PAC. */
cfi_window_save
# endif
cfi_negate_ra_state
mov sp, x29
cfi_def_cfa_register (sp)
ldr x29, [x29, #0]

View File

@ -27,9 +27,8 @@ static void mcount_internal (u_long frompc, u_long selfpc);
#define _MCOUNT_DECL(frompc, selfpc) \
static inline void mcount_internal (u_long frompc, u_long selfpc)
/* Note: strip_pac is needed for frompc because of gcc PR target/94791. */
#define MCOUNT \
void __mcount (void *frompc) \
{ \
mcount_internal ((u_long) strip_pac (frompc), (u_long) RETURN_ADDRESS (0)); \
mcount_internal ((u_long) frompc, (u_long) RETURN_ADDRESS (0)); \
}

View File

@ -37,7 +37,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
IFUNC_IMPL (i, name, memcpy,
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_oryon1)
#if HAVE_AARCH64_SVE_ASM
IFUNC_IMPL_ADD (array, i, memcpy, sve && !bti, __memcpy_a64fx)
IFUNC_IMPL_ADD (array, i, memcpy, sve, __memcpy_a64fx)
IFUNC_IMPL_ADD (array, i, memcpy, sve, __memcpy_sve)
#endif
IFUNC_IMPL_ADD (array, i, memcpy, mops, __memcpy_mops)
@ -45,7 +45,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
IFUNC_IMPL (i, name, memmove,
IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_oryon1)
#if HAVE_AARCH64_SVE_ASM
IFUNC_IMPL_ADD (array, i, memmove, sve && !bti, __memmove_a64fx)
IFUNC_IMPL_ADD (array, i, memmove, sve, __memmove_a64fx)
IFUNC_IMPL_ADD (array, i, memmove, sve, __memmove_sve)
#endif
IFUNC_IMPL_ADD (array, i, memmove, mops, __memmove_mops)
@ -56,7 +56,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
IFUNC_IMPL_ADD (array, i, memset, 1, __memset_emag)
IFUNC_IMPL_ADD (array, i, memset, 1, __memset_kunpeng)
#if HAVE_AARCH64_SVE_ASM
IFUNC_IMPL_ADD (array, i, memset, sve && !bti && zva_size == 256, __memset_a64fx)
IFUNC_IMPL_ADD (array, i, memset, sve && zva_size == 256, __memset_a64fx)
IFUNC_IMPL_ADD (array, i, memset, sve && zva_size == 64, __memset_sve_zva64)
#endif
IFUNC_IMPL_ADD (array, i, memset, mops, __memset_mops)

View File

@ -31,7 +31,7 @@
unsigned __attribute__((unused)) zva_size = \
GLRO(dl_aarch64_cpu_features).zva_size; \
bool __attribute__((unused)) bti = \
HAVE_AARCH64_BTI && GLRO(dl_aarch64_cpu_features).bti; \
GLRO(dl_aarch64_cpu_features).bti; \
bool __attribute__((unused)) mte = \
MTE_ENABLED (); \
bool __attribute__((unused)) sve = \

View File

@ -19,9 +19,6 @@
#include <sysdep.h>
#undef BTI_C
#define BTI_C
/* Assumptions:
*
* ARMv8.2-a, AArch64, unaligned accesses, sve
@ -91,9 +88,6 @@
st1b z7.b, p0, [dst, 7, mul vl]
.endm
#undef BTI_C
#define BTI_C
ENTRY (__memcpy_a64fx)
cntb vlen

View File

@ -50,10 +50,6 @@
.endif
.endm
#undef BTI_C
#define BTI_C
ENTRY (__memset_a64fx)
cntb vector_length

View File

@ -38,10 +38,8 @@ ENTRY_ALIGN (__sigsetjmp, 2)
#if IS_IN(libc)
/* Disable ZA state of SME in libc.a and libc.so, but not in ld.so. */
# if HAVE_AARCH64_PAC_RET
PACIASP
cfi_window_save
# endif
paciasp
cfi_negate_ra_state
stp x29, x30, [sp, -16]!
cfi_adjust_cfa_offset (16)
cfi_rel_offset (x29, 0)
@ -52,10 +50,8 @@ ENTRY_ALIGN (__sigsetjmp, 2)
cfi_adjust_cfa_offset (-16)
cfi_restore (x29)
cfi_restore (x30)
# if HAVE_AARCH64_PAC_RET
AUTIASP
cfi_window_save
# endif
autiasp
cfi_negate_ra_state
#endif
stp x19, x20, [x0, #JB_X19<<3]
@ -96,7 +92,7 @@ L(gcs_done):
#if IS_IN (rtld)
/* In ld.so we never save the signal mask */
mov w0, #0
RET
ret
#else
b C_SYMBOL_NAME(__sigjmp_save)
#endif

View File

@ -108,7 +108,7 @@ ENTRY(_start)
because crt1.o and rcrt1.o share code and the later must avoid the
use of GOT relocations before __libc_start_main is called. */
__wrap_main:
BTI_C
bti c
b main
#endif
END(_start)

View File

@ -21,43 +21,15 @@
#include <sysdeps/generic/sysdep.h>
#ifndef __ASSEMBLER__
/* Strip pointer authentication code from pointer p. */
static inline void *
strip_pac (void *p)
{
register void *ra asm ("x30") = (p);
asm ("hint 7 // xpaclri" : "+r"(ra));
return ra;
}
/* This is needed when glibc is built with -mbranch-protection=pac-ret
with a gcc that is affected by PR target/94891. */
# if HAVE_AARCH64_PAC_RET
# undef RETURN_ADDRESS
# define RETURN_ADDRESS(n) strip_pac (__builtin_return_address (n))
# endif
#endif
#ifdef __ASSEMBLER__
/* CFI directive for return address. */
#define cfi_negate_ra_state .cfi_negate_ra_state
/* Syntactic details of assembler. */
#define ASM_SIZE_DIRECTIVE(name) .size name,.-name
/* Branch Target Identitication support. */
#if HAVE_AARCH64_BTI
# define BTI_C hint 34
# define BTI_J hint 36
#else
# define BTI_C nop
# define BTI_J nop
#endif
/* Return address signing support (pac-ret). */
#define PACIASP hint 25
#define AUTIASP hint 29
/* Guarded Control Stack support. */
#define CHKFEAT_X16 hint 40
#define MRS_GCSPR(x) mrs x, s3_3_c2_c5_1
@ -87,11 +59,7 @@ strip_pac (void *p)
/* Add GNU property note with the supported features to all asm code
where sysdep.h is included. */
#if HAVE_AARCH64_BTI && HAVE_AARCH64_PAC_RET
GNU_PROPERTY (FEATURE_1_AND, FEATURE_1_BTI|FEATURE_1_PAC|FEATURE_1_GCS)
#elif HAVE_AARCH64_BTI
GNU_PROPERTY (FEATURE_1_AND, FEATURE_1_BTI|FEATURE_1_GCS)
#endif
/* Define an entry point visible from C. */
#define ENTRY(name) \
@ -100,7 +68,7 @@ GNU_PROPERTY (FEATURE_1_AND, FEATURE_1_BTI|FEATURE_1_GCS)
.p2align 6; \
C_LABEL(name) \
cfi_startproc; \
BTI_C; \
bti c; \
CALL_MCOUNT
/* Define an entry point visible from C. */
@ -110,7 +78,7 @@ GNU_PROPERTY (FEATURE_1_AND, FEATURE_1_BTI|FEATURE_1_GCS)
.p2align align; \
C_LABEL(name) \
cfi_startproc; \
BTI_C; \
bti c; \
CALL_MCOUNT
/* Define an entry point visible from C with a specified alignment and
@ -127,7 +95,7 @@ GNU_PROPERTY (FEATURE_1_AND, FEATURE_1_BTI|FEATURE_1_GCS)
.endr; \
C_LABEL(name) \
cfi_startproc; \
BTI_C; \
bti c; \
CALL_MCOUNT
#undef END

View File

@ -49,10 +49,8 @@ ENTRY (__setcontext)
b C_SYMBOL_NAME (__syscall_error)
1:
/* Disable ZA of SME. */
#if HAVE_AARCH64_PAC_RET
PACIASP
cfi_window_save
#endif
paciasp
cfi_negate_ra_state
stp x29, x30, [sp, -16]!
cfi_adjust_cfa_offset (16)
cfi_rel_offset (x29, 0)
@ -63,10 +61,8 @@ ENTRY (__setcontext)
cfi_adjust_cfa_offset (-16)
cfi_restore (x29)
cfi_restore (x30)
#if HAVE_AARCH64_PAC_RET
AUTIASP
cfi_window_save
#endif
autiasp
cfi_negate_ra_state
/* Restore the general purpose registers. */
mov x0, x9
cfi_def_cfa (x0, 0)

View File

@ -119,7 +119,7 @@ L(gcs_done):
2:
/* The oucp context is restored here via an indirect branch,
x1 must be restored too which has the real return address. */
BTI_J
bti j
mov x30, x1
RET
PSEUDO_END (__swapcontext)