diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c index 902d7c16334..acee87f2a5b 100644 --- a/bfd/elf-eh-frame.c +++ b/bfd/elf-eh-frame.c @@ -359,6 +359,7 @@ skip_cfa_op (bfd_byte **iter, bfd_byte *end, unsigned int encoded_ptr_width) case DW_CFA_remember_state: case DW_CFA_restore_state: case DW_CFA_GNU_window_save: + case DW_CFA_AARCH64_negate_ra_state_with_pc: /* No arguments. */ return true; diff --git a/binutils/dwarf.c b/binutils/dwarf.c index 972bb920161..7e4a4427095 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -10358,6 +10358,11 @@ display_debug_frames (struct dwarf_section *section, fc->pc_begin += ofs; break; + case DW_CFA_AARCH64_negate_ra_state_with_pc: + if (! do_debug_frames_interp) + printf (" DW_CFA_AARCH64_negate_ra_state_with_pc\n"); + break; + case DW_CFA_GNU_window_save: if (! do_debug_frames_interp) printf (" %s\n", DW_CFA_GNU_window_save_name[is_aarch64]); diff --git a/gas/dw2gencfi.c b/gas/dw2gencfi.c index db0261dd187..936cf7eb4b0 100644 --- a/gas/dw2gencfi.c +++ b/gas/dw2gencfi.c @@ -718,6 +718,7 @@ const pseudo_typeS cfi_pseudo_table[] = { "cfi_restore_state", dot_cfi, DW_CFA_restore_state }, { "cfi_window_save", dot_cfi, DW_CFA_GNU_window_save }, { "cfi_negate_ra_state", dot_cfi, DW_CFA_AARCH64_negate_ra_state }, + { "cfi_negate_ra_state_with_pc", dot_cfi, DW_CFA_AARCH64_negate_ra_state_with_pc }, { "cfi_escape", dot_cfi_escape, 0 }, { "cfi_signal_frame", dot_cfi, CFI_signal_frame }, { "cfi_personality", dot_cfi_personality, 0 }, @@ -918,6 +919,10 @@ dot_cfi (int arg) cfi_add_CFA_insn (DW_CFA_GNU_window_save); break; + case DW_CFA_AARCH64_negate_ra_state_with_pc: + cfi_add_CFA_insn (DW_CFA_AARCH64_negate_ra_state_with_pc); + break; + case CFI_signal_frame: frchain_now->frch_cfi_data->cur_fde_data->signal_frame = 1; break; @@ -1758,6 +1763,10 @@ output_cfi_insn (struct cfi_insn_data *insn) out_one (DW_CFA_GNU_window_save); break; + case DW_CFA_AARCH64_negate_ra_state_with_pc: + out_one (DW_CFA_AARCH64_negate_ra_state_with_pc); + break; + case CFI_escape: { struct cfi_escape_data *e; @@ -2216,6 +2225,7 @@ cfi_change_reg_numbers (struct cfi_insn_data *insn, segT ccseg) case DW_CFA_remember_state: case DW_CFA_restore_state: case DW_CFA_GNU_window_save: + case DW_CFA_AARCH64_negate_ra_state_with_pc: case CFI_escape: case CFI_label: break; diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c index 247b65a37d0..77870dde166 100644 --- a/gas/gen-sframe.c +++ b/gas/gen-sframe.c @@ -928,7 +928,7 @@ sframe_row_entry_initialize (struct sframe_row_entry *cur_fre, cur_fre->ra_loc = prev_fre->ra_loc; cur_fre->ra_offset = prev_fre->ra_offset; /* Treat RA mangling as a sticky bit. It retains its value until another - .cfi_negate_ra_state is seen. */ + .cfi_negate_ra_state or .cfi_negate_ra_state_with_pc is seen. */ cur_fre->ra_signing_info = prev_fre->ra_signing_info; } @@ -1306,6 +1306,26 @@ sframe_xlate_do_gnu_window_save (struct sframe_xlate_ctx *xlate_ctx, return SFRAME_XLATE_ERR_NOTREPRESENTED; /* Not represented. */ } +/* Translate DW_CFA_AARCH64_negate_ra_state_with_pc into SFrame context. + Return SFRAME_XLATE_OK if success. */ + +static int +sframe_xlate_do_aarch64_negate_ra_state_with_pc (struct sframe_xlate_ctx *xlate_ctx, + struct cfi_insn_data *cfi_insn ATTRIBUTE_UNUSED) +{ + struct sframe_row_entry *cur_fre = xlate_ctx->cur_fre; + + gas_assert (cur_fre); + /* Toggle the mangled RA status bit. */ + cur_fre->ra_signing_info + = ((cur_fre->ra_signing_info == RA_no_signing) + ? RA_signing_SP_PC + : RA_no_signing); + cur_fre->merge_candidate = false; + + return SFRAME_XLATE_OK; +} + /* Returns the DWARF call frame instruction name or fake CFI name for the specified CFI opcode, or NULL if the value is not recognized. */ @@ -1396,6 +1416,9 @@ sframe_do_cfi_insn (struct sframe_xlate_ctx *xlate_ctx, case DW_CFA_GNU_window_save: err = sframe_xlate_do_gnu_window_save (xlate_ctx, cfi_insn); break; + case DW_CFA_AARCH64_negate_ra_state_with_pc: + err = sframe_xlate_do_aarch64_negate_ra_state_with_pc (xlate_ctx, cfi_insn); + break; case DW_CFA_register: err = sframe_xlate_do_register (xlate_ctx, cfi_insn); break; diff --git a/gas/gen-sframe.h b/gas/gen-sframe.h index db1e5de968f..81c99bfc263 100644 --- a/gas/gen-sframe.h +++ b/gas/gen-sframe.h @@ -43,8 +43,9 @@ typedef enum ATTRIBUTE_PACKED { - RA_no_signing = 0x0, - RA_signing_SP = 0x1, + RA_no_signing = 0x0, + RA_signing_SP = 0x1, + RA_signing_SP_PC = 0x3, } RA_signing_method_t; struct sframe_row_entry diff --git a/gas/scfidw2gen.c b/gas/scfidw2gen.c index 2b018fac8bd..1fd0cd832e5 100644 --- a/gas/scfidw2gen.c +++ b/gas/scfidw2gen.c @@ -113,6 +113,7 @@ const pseudo_typeS scfi_pseudo_table[] = { "cfi_restore_state", dot_scfi_ignore, 0 }, { "cfi_window_save", dot_scfi_ignore, 0 }, { "cfi_negate_ra_state", dot_scfi_ignore, 0 }, + { "cfi_negate_ra_state_with_pc", dot_scfi_ignore, 0 }, { "cfi_escape", dot_scfi_ignore, 0 }, { "cfi_personality", dot_scfi_ignore, 0 }, { "cfi_personality_id", dot_scfi_ignore, 0 }, diff --git a/gas/testsuite/gas/aarch64/pac_negate_ra_state_with_pc.d b/gas/testsuite/gas/aarch64/pac_negate_ra_state_with_pc.d new file mode 100644 index 00000000000..e3ffc9eb494 --- /dev/null +++ b/gas/testsuite/gas/aarch64/pac_negate_ra_state_with_pc.d @@ -0,0 +1,64 @@ +#source: pac_negate_ra_state_with_pc.s +#as: -march=armv9.4-a+pauth-lr +#objdump: --dwarf=frames +# This test is only valid on ELF based ports. +#notarget: *-*-*coff *-*-pe *-*-wince *-*-*aout* *-*-netbsd + +.+: file .+ + +Contents of the .eh_frame section: + + +00000000 0000000000000010 00000000 CIE + Version: 1 + Augmentation: "zR" + Code alignment factor: 4 + Data alignment factor: -8 + Return address column: 30 + Augmentation data: 1b + DW_CFA_def_cfa: r31 \(sp\) ofs 0 + +00000014 000000000000001c 00000018 FDE cie=00000000 pc=0000000000000000..0000000000000014 + DW_CFA_advance_loc: 4 to 0000000000000004 + DW_CFA_AARCH64_negate_ra_state_with_pc + DW_CFA_advance_loc: 4 to 0000000000000008 + DW_CFA_def_cfa_offset: 16 + DW_CFA_offset: r29 \(x29\) at cfa-16 + DW_CFA_offset: r30 \(x30\) at cfa-8 + DW_CFA_advance_loc: 8 to 0000000000000010 + DW_CFA_restore: r30 \(x30\) + DW_CFA_restore: r29 \(x29\) + DW_CFA_advance_loc: 4 to 0000000000000014 + DW_CFA_AARCH64_negate_ra_state_with_pc + DW_CFA_nop + +00000034 0000000000000014 00000000 CIE + Version: 1 + Augmentation: "zRB" + Code alignment factor: 4 + Data alignment factor: -8 + Return address column: 30 + Augmentation data: 1b + DW_CFA_def_cfa: r31 \(sp\) ofs 0 + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop + +0000004c 0000000000000020 0000001c FDE cie=00000034 pc=0000000000000014..0000000000000038 + DW_CFA_advance_loc: 8 to 000000000000001c + DW_CFA_AARCH64_negate_ra_state_with_pc + DW_CFA_advance_loc: 4 to 0000000000000020 + DW_CFA_def_cfa_offset: 16 + DW_CFA_offset: r29 \(x29\) at cfa-16 + DW_CFA_offset: r30 \(x30\) at cfa-8 + DW_CFA_advance_loc: 8 to 0000000000000028 + DW_CFA_restore: r30 \(x30\) + DW_CFA_restore: r29 \(x29\) + DW_CFA_advance_loc: 12 to 0000000000000034 + DW_CFA_AARCH64_negate_ra_state_with_pc + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop + DW_CFA_nop + diff --git a/gas/testsuite/gas/aarch64/pac_negate_ra_state_with_pc.s b/gas/testsuite/gas/aarch64/pac_negate_ra_state_with_pc.s new file mode 100644 index 00000000000..e179b40ab1a --- /dev/null +++ b/gas/testsuite/gas/aarch64/pac_negate_ra_state_with_pc.s @@ -0,0 +1,53 @@ + .text + .align 2 + .global _Z5foo_pauth_lrv + .type _Z5foo_pauth_lrv, %function +_Z5foo_pauth_lrv: +.LFB0: + .cfi_startproc + paciasppc + .cfi_negate_ra_state_with_pc + stp x29, x30, [sp, -16]! + .cfi_def_cfa_offset 16 + .cfi_offset 29, -16 + .cfi_offset 30, -8 + mov x29, sp + // ... + ldp x29, x30, [sp], #16 + .cfi_restore 30 + .cfi_restore 29 + retaasppc .LFB0 + .cfi_negate_ra_state_with_pc + .cfi_endproc +.LFE0: + .size _Z5foo_pauth_lrv, .-_Z5foo_pauth_lrv + + + .align 2 + .global _Z5foo_pacmv + .type _Z5foo_pacmv, %function +_Z5foo_pac2_compatible_pauthv: +.LFB1: + .cfi_startproc + .cfi_b_key_frame + hint #0x27 // pacm +.Ltmp1: + hint #0x1b // pacibsp + .cfi_negate_ra_state_with_pc + stp x29, x30, [sp, -16]! + .cfi_def_cfa_offset 16 + .cfi_offset 29, -16 + .cfi_offset 30, -8 + mov x29, sp + // ... + ldp x29, x30, [sp], #16 + .cfi_restore 30 + .cfi_restore 29 + adr x16, .Ltmp1 + hint #0x27 // pacm + hint #0x1f // autibsp + .cfi_negate_ra_state_with_pc + ret + .cfi_endproc +.LFE1: + .size _Z5foo_pac2_compatible_pauthv, .-_Z5foo_pac2_compatible_pauthv diff --git a/include/dwarf2.def b/include/dwarf2.def index 66c7fa1220f..95601fc7018 100644 --- a/include/dwarf2.def +++ b/include/dwarf2.def @@ -788,9 +788,11 @@ DW_CFA (DW_CFA_MIPS_advance_loc8, 0x1d) /* GNU extensions. NOTE: DW_CFA_GNU_window_save is multiplexed on Sparc and AArch64. */ DW_CFA (DW_CFA_GNU_window_save, 0x2d) -DW_CFA_DUP (DW_CFA_AARCH64_negate_ra_state, 0x2d) DW_CFA (DW_CFA_GNU_args_size, 0x2e) DW_CFA (DW_CFA_GNU_negative_offset_extended, 0x2f) +/* AArch64 extensions. */ +DW_CFA (DW_CFA_AARCH64_negate_ra_state_with_pc, 0x2c) +DW_CFA_DUP (DW_CFA_AARCH64_negate_ra_state, 0x2d) DW_END_CFA diff --git a/include/sframe.h b/include/sframe.h index 53388aaaa91..f7a830a7275 100644 --- a/include/sframe.h +++ b/include/sframe.h @@ -265,7 +265,7 @@ typedef struct sframe_fre_info /* Set the mangled_ra_p bit as indicated. */ #define SFRAME_V1_FRE_INFO_UPDATE_RA_SIGNING_INFO(ra_signing_info, fre_info) \ - ((((ra_signing_info) & 0x1) << 7) | ((fre_info) & 0x7f)) + ((((ra_signing_info) & 0x3) << 7) | ((fre_info) & 0x7f)) #define SFRAME_V1_FRE_CFA_BASE_REG_ID(data) ((data) & 0x1) #define SFRAME_V1_FRE_OFFSET_COUNT(data) (((data) >> 1) & 0xf)