gcc/testsuite/ChangeLog: * g++.target/aarch64/pr94515-1.C: Improve test documentation. * g++.target/aarch64/pr94515-2.C: Same. --- gcc/testsuite/g++.target/aarch64/pr94515-1.C | 8 ++++ gcc/testsuite/g++.target/aarch64/pr94515-2.C | 39 +++++++++++++++++--- 2 files changed, 41 insertions(+), 6 deletions(-)
diff --git a/gcc/testsuite/g++.target/aarch64/pr94515-1.C b/gcc/testsuite/g++.target/aarch64/pr94515-1.C index d5c114a83a8..359039e1753 100644 --- a/gcc/testsuite/g++.target/aarch64/pr94515-1.C +++ b/gcc/testsuite/g++.target/aarch64/pr94515-1.C @@ -15,12 +15,20 @@ void unwind (void) __attribute__((noinline, noipa, target("branch-protection=pac-ret"))) int test (int z) { + // paciasp -> cfi_negate_ra_state: RA_no_signing -> RA_signing_SP if (z) { asm volatile ("":::"x20","x21"); unwind (); + // autiasp -> cfi_negate_ra_state: RA_signing_SP -> RA_no_signing return 1; } else { + // 2nd cfi_negate_ra_state because the CFI directives are processed linearily. + // At this point, the unwinder would believe that the address is not signed + // due to the previous return. That's why the compiler has to emit second + // cfi_negate_ra_state to mean that the return address is still signed. + // cfi_negate_ra_state: RA_no_signing -> RA_signing_SP unwind (); + // autiasp -> cfi_negate_ra_state: RA_signing_SP -> RA_no_signing return 2; } } diff --git a/gcc/testsuite/g++.target/aarch64/pr94515-2.C b/gcc/testsuite/g++.target/aarch64/pr94515-2.C index f4a3333beed..bdb65411a08 100644 --- a/gcc/testsuite/g++.target/aarch64/pr94515-2.C +++ b/gcc/testsuite/g++.target/aarch64/pr94515-2.C @@ -6,6 +6,7 @@ volatile int zero = 0; int global = 0; +/* This is a leaf function, so no .cfi_negate_ra_state directive is expected. */ __attribute__((noinline)) int bar(void) { @@ -13,29 +14,55 @@ int bar(void) return 0; } +/* This function does not return normally, so the address is signed but no + * authentication code is emitted. It means that only one CFI directive is + * supposed to be emitted at signing time. */ __attribute__((noinline, noreturn)) void unwind (void) { throw 42; } +/* This function has several return instructions, and alternates different RA + * states. 4 .cfi_negate_ra_state and a .cfi_remember_state/.cfi_restore_state + * should be emitted. + * + * Expected layout: + * A: path to return 0 without assignment to global + * B: global=y + branch back into A + * C: return 2 + * D: unwind + * Which gives with return pointer authentication: + * A: sign -> authenticate [2 negate_ra_states + remember_state for B] + * B: signed [restore_state] + * C: unsigned [negate_ra_state] + * D: signed [negate_ra_state] + */ __attribute__((noinline, noipa)) int test(int x) { - if (x==1) return 2; /* This return path may not use the stack. */ + // This return path may not use the stack. This means that the return address + // won't be signed. + if (x==1) return 2; + + // All the return paths of the code below must have RA mangle state set, and + // the return address must be signed. int y = bar(); if (y > global) global=y; - if (y==3) unwind(); /* This return path must have RA mangle state set. */ - return 0; + if (y==3) unwind(); // authentication of the return address is not required. + return 0; // authentication of the return address is required. } +/* This function requires only 2 .cfi_negate_ra_state. */ int main () { + // paciasp -> cfi_negate_ra_state: RA_no_signing -> RA_signing_SP try { test (zero); - __builtin_abort (); + __builtin_abort (); // authentication of the return address is not required. } catch (...) { + // autiasp -> cfi_negate_ra_state: RA_signing_SP -> RA_no_signing return 0; } - __builtin_abort (); -} + __builtin_abort (); // authentication of the return address is not required. +} \ No newline at end of file -- 2.46.0