@@ -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;
}
}
@@ -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