diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index 4bfadb512915d5dc606f7fc06f027868d6be7613..907e8bdf5b4961b3107dcd5a481de28335e4be89 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -970,4 +970,16 @@ extern tree aarch64_fp16_ptr_type_node;
 	     || (aarch64_ra_sign_scope == AARCH64_FUNCTION_NON_LEAF \
 		 && cfun->machine->frame.reg_offset[LR_REGNUM] >= 0))
 
+/* AArch64 pointer authentication action types.  See AArch64 DWARF ABI for
+   details.  */
+enum aarch64_pauth_action_type
+{
+  /* Drop the authentication signature for instruction pointer.  */
+  AARCH64_PAUTH_DROP_I,
+  /* Likewise for data pointer.  */
+  AARCH64_PAUTH_DROP_D,
+  /* Do authentication.  */
+  AARCH64_PAUTH_AUTH
+};
+
 #endif /* GCC_AARCH64_H */
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index b3d9a2a3f51ee240d00beb4cc65f99b089a3215e..cae177dca511fdb909ef82c972d3bbdebab215e2 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -2717,6 +2717,104 @@ aarch64_output_probe_stack_range (rtx reg1, rtx reg2)
   return "";
 }
 
+/* Generate return address signing DWARF annotation using general DWARF
+   operator.  DWARF frame size will be bigger than using shortcut DWARF
+   operator.  See aarch64_attach_ra_auth_dwarf for parameter meanings.  */
+
+static rtx
+aarch64_attach_ra_auth_dwarf_general (rtx notes, HOST_WIDE_INT offset)
+{
+  /* The authentication descriptor.  */
+  HOST_WIDE_INT desc_const = (AARCH64_PAUTH_AUTH | (aarch64_pauth_key << 4));
+
+  /* DW_OP_AARCH64_pauth takes one uleb128 operand which is the authentication
+     descriptor.  The low 4 bits of the descriptor is the authentication action
+     code, all other bits are reserved and initialized into zero except when the
+     action code is AARCH64_PAUTH_AUTH then bits[7:4] is the authentication key
+     index.  */
+  rtx auth_op
+    = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, GEN_INT (desc_const), const0_rtx),
+		      DW_OP_AARCH64_pauth);
+
+  rtx par;
+  if (offset == 0)
+    {
+      /* Step 1: Push LR onto stack.
+		 NOTE: the bottom of DWARF expression stack is always CFA.
+	 Step 2: Issue AArch64 authentication operation.  */
+    par = gen_rtx_PARALLEL (DImode,
+			    gen_rtvec (2, gen_rtx_REG (Pmode, LR_REGNUM),
+				       auth_op));
+    }
+  else
+    {
+      rtx dup_cfa
+	= gen_rtx_UNSPEC (Pmode, gen_rtvec (2, const0_rtx, const0_rtx),
+			  DW_OP_dup);
+
+      rtx deref_op
+	= gen_rtx_UNSPEC (Pmode, gen_rtvec (2, const0_rtx, const0_rtx),
+			  DW_OP_deref);
+
+      rtx raw_plus
+	= gen_rtx_UNSPEC (Pmode, gen_rtvec (2, const0_rtx, const0_rtx),
+			  DW_OP_plus);
+      /* Step 1: Push the authentication key on to dwarf expression stack.
+	 Step 2: Push the stack address of where return address saved, followed
+	 by a memory de-reference operation.
+	 Step 3: Push the authentication descriptor.
+	 Step 4: Issue AArch64 authentication operation.  */
+      par = gen_rtx_PARALLEL (DImode,
+			      gen_rtvec (5, dup_cfa, GEN_INT (offset), raw_plus,
+					 deref_op, auth_op));
+    }
+
+  /* Generate the final dwarf value expression.  */
+  return alloc_reg_note (REG_CFA_VAL_EXPRESSION,
+			 gen_rtx_SET (gen_rtx_REG (DImode, LR_REGNUM), par),
+			 notes);
+}
+
+/* Generate return address signing DWARF annotation using shortcut DWARF
+   operators.  See aarch64_attach_ra_auth_dwarf for parameter meanings.  */
+
+static rtx
+aarch64_attach_ra_auth_dwarf_shortcut (rtx notes, HOST_WIDE_INT offset)
+{
+  rtx auth_op, par;
+
+  /* See GCC/include/dwarf2.def for the semantics of DW_OP_AARCH64_paciasp
+     and DW_OP_AARCH64_paciasp_deref.  */
+  if (offset == 0)
+    auth_op
+      = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, const0_rtx, const0_rtx),
+			DW_OP_AARCH64_paciasp);
+  else
+    auth_op
+      = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, GEN_INT (offset), const0_rtx),
+			DW_OP_AARCH64_paciasp_deref);
+
+  par = gen_rtx_PARALLEL (DImode, gen_rtvec (1, auth_op));
+
+  /* Generate the final dwarf value expression.  */
+  return alloc_reg_note (REG_CFA_VAL_EXPRESSION,
+			 gen_rtx_SET (gen_rtx_REG (DImode, LR_REGNUM), par),
+			 notes);
+}
+
+/* Generate AArch64 specific dwarf expression annotation.  NOTES is any existed
+   annotation that we want this new one to append.  BASE is a valid base
+   register if the value should be fetch from BASE + OFFSET.  */
+
+static rtx
+aarch64_attach_ra_auth_dwarf_note (rtx notes, HOST_WIDE_INT offset)
+{
+  if (aarch64_pauth_key != AARCH64_PAUTH_IKEY_A)
+    return aarch64_attach_ra_auth_dwarf_general (notes, offset);
+  else
+    return aarch64_attach_ra_auth_dwarf_shortcut (notes, offset);
+}
+
 static bool
 aarch64_frame_pointer_required (void)
 {
@@ -3058,6 +3156,7 @@ aarch64_save_callee_saves (machine_mode mode, HOST_WIDE_INT start_offset,
     {
       rtx reg, mem;
       HOST_WIDE_INT offset;
+      unsigned lr_pair_reg = INVALID_REGNUM;
 
       if (skip_wb
 	  && (regno == cfun->machine->frame.wb_candidate1
@@ -3069,6 +3168,9 @@ aarch64_save_callee_saves (machine_mode mode, HOST_WIDE_INT start_offset,
       mem = gen_mem_ref (mode, plus_constant (Pmode, stack_pointer_rtx,
 					      offset));
 
+      if (regno == LR_REGNUM)
+	lr_pair_reg = LR_REGNUM;
+
       regno2 = aarch64_next_callee_save (regno + 1, limit);
 
       if (regno2 <= limit
@@ -3090,12 +3192,39 @@ aarch64_save_callee_saves (machine_mode mode, HOST_WIDE_INT start_offset,
 	     calculations; subsequent parts, are only
 	     frame-related if explicitly marked.  */
 	  RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, 1)) = 1;
+
+	  if (regno2 == LR_REGNUM)
+	    lr_pair_reg = regno;
+
 	  regno = regno2;
 	}
       else
 	insn = emit_move_insn (mem, reg);
 
       RTX_FRAME_RELATED_P (insn) = 1;
+
+      if (AARCH64_ENABLE_RETURN_ADDRESS_SIGN && lr_pair_reg != INVALID_REGNUM)
+	{
+	  rtx cfi_ops = NULL_RTX;
+
+	  if (lr_pair_reg != LR_REGNUM)
+	    {
+	      /* Another register is saved together with LR to make a STP.  We
+		 need to generate .cfi_offset for that register.  */
+	      cfi_ops =
+		alloc_reg_note (REG_CFA_OFFSET,
+				gen_rtx_SET (mem,
+					     gen_rtx_REG (Pmode, lr_pair_reg)),
+				NULL_RTX);
+	    }
+
+	  HOST_WIDE_INT lr_cfa_adj
+	    = (-cfun->machine->frame.hard_fp_offset
+	       + cfun->machine->frame.reg_offset[LR_REGNUM]);
+
+	  REG_NOTES (insn)
+	    = aarch64_attach_ra_auth_dwarf_note (cfi_ops, lr_cfa_adj);
+	}
     }
 }
 
@@ -3204,12 +3333,18 @@ aarch64_expand_prologue (void)
   unsigned reg2 = cfun->machine->frame.wb_candidate2;
   rtx_insn *insn;
 
+  /* Do return address signing for all functions, even those for which LR is not
+     pushed onto stack.  */
   if (AARCH64_ENABLE_RETURN_ADDRESS_SIGN)
-    emit_insn (gen_sign_reg (gen_rtx_REG (Pmode, LR_REGNUM),
-			     gen_rtx_REG (Pmode, LR_REGNUM),
-			     stack_pointer_rtx,
-			     GEN_INT (aarch64_pauth_key),
-			     const0_rtx));
+    {
+      insn = emit_insn (gen_sign_reg (gen_rtx_REG (Pmode, LR_REGNUM),
+				      gen_rtx_REG (Pmode, LR_REGNUM),
+				      stack_pointer_rtx,
+				      GEN_INT (aarch64_pauth_key),
+				      const0_rtx));
+      RTX_FRAME_RELATED_P (insn) = 1;
+      REG_NOTES (insn) = aarch64_attach_ra_auth_dwarf_note (NULL_RTX, 0);
+    }
 
   if (flag_stack_usage_info)
     current_function_static_stack_size = frame_size;
@@ -3229,7 +3364,42 @@ aarch64_expand_prologue (void)
   aarch64_add_constant (Pmode, SP_REGNUM, IP0_REGNUM, -initial_adjust, true);
 
   if (callee_adjust != 0)
-    aarch64_push_regs (reg1, reg2, callee_adjust);
+    {
+      aarch64_push_regs (reg1, reg2, callee_adjust);
+      /* Generate return address signing dwarf annotation when
+	 omit-frame-pointer.  */
+      if (AARCH64_ENABLE_RETURN_ADDRESS_SIGN
+	  && (reg1 == LR_REGNUM || reg2 == LR_REGNUM))
+	{
+	  rtx cfi_ops = NULL_RTX;
+
+	  if (reg2 == LR_REGNUM)
+	    {
+	      rtx mem_loc
+		= gen_rtx_MEM (Pmode,
+			       plus_constant (Pmode, stack_pointer_rtx, 0));
+	      cfi_ops
+		= alloc_reg_note (REG_CFA_OFFSET,
+				  gen_rtx_SET (mem_loc,
+					       gen_rtx_REG (Pmode, reg1)),
+				  cfi_ops);
+	    }
+
+	  rtx sp_adj
+	    = plus_constant (Pmode, stack_pointer_rtx, -callee_adjust);
+	  cfi_ops
+	    = alloc_reg_note (REG_CFA_ADJUST_CFA,
+			      gen_rtx_SET (stack_pointer_rtx, sp_adj),
+			      cfi_ops);
+
+	  HOST_WIDE_INT lr_cfa_adj
+	    = (-cfun->machine->frame.hard_fp_offset
+	       + cfun->machine->frame.reg_offset[LR_REGNUM]);
+	  rtx insn = get_last_insn ();
+	  REG_NOTES (insn) = aarch64_attach_ra_auth_dwarf_note (cfi_ops,
+								lr_cfa_adj);
+	}
+    }
 
   if (frame_pointer_needed)
     {
@@ -3331,7 +3501,12 @@ aarch64_expand_epilogue (bool for_sibcall)
       /* Emit delayed restores and set the CFA to be SP + initial_adjust.  */
       insn = get_last_insn ();
       rtx new_cfa = plus_constant (Pmode, stack_pointer_rtx, initial_adjust);
-      REG_NOTES (insn) = alloc_reg_note (REG_CFA_DEF_CFA, new_cfa, cfi_ops);
+      cfi_ops = alloc_reg_note (REG_CFA_DEF_CFA, new_cfa, cfi_ops);
+
+      if (AARCH64_ENABLE_RETURN_ADDRESS_SIGN)
+	REG_NOTES (insn) = aarch64_attach_ra_auth_dwarf_note (cfi_ops, 0);
+      else
+	REG_NOTES (insn) = cfi_ops;
       RTX_FRAME_RELATED_P (insn) = 1;
       cfi_ops = NULL;
     }
@@ -3355,11 +3530,14 @@ aarch64_expand_epilogue (bool for_sibcall)
      __builtin_eh_return.  */
   if (AARCH64_ENABLE_RETURN_ADDRESS_SIGN
       && (for_sibcall || !TARGET_PAUTH || crtl->calls_eh_return))
-    emit_insn (gen_auth_reg (gen_rtx_REG (Pmode, LR_REGNUM),
-			     gen_rtx_REG (Pmode, LR_REGNUM),
-			     stack_pointer_rtx,
-			     GEN_INT (aarch64_pauth_key),
-			     const0_rtx));
+    {
+      insn = emit_insn (gen_auth_reg (gen_rtx_REG (Pmode, LR_REGNUM),
+				      gen_rtx_REG (Pmode, LR_REGNUM),
+				      stack_pointer_rtx,
+				      GEN_INT (aarch64_pauth_key), const0_rtx));
+      add_reg_note (insn, REG_CFA_RESTORE, gen_rtx_REG (Pmode, LR_REGNUM));
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
 
   /* Stack adjustment for exception handler.  */
   if (crtl->calls_eh_return)

