From patchwork Fri Nov 11 18:35:03 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiong Wang X-Patchwork-Id: 81887 Delivered-To: patch@linaro.org Received: by 10.140.97.165 with SMTP id m34csp1405258qge; Fri, 11 Nov 2016 10:35:35 -0800 (PST) X-Received: by 10.98.64.195 with SMTP id f64mr9438590pfd.16.1478889335152; Fri, 11 Nov 2016 10:35:35 -0800 (PST) Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id u89si11489632pfg.283.2016.11.11.10.35.34 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 11 Nov 2016 10:35:35 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-return-441178-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org; spf=pass (google.com: domain of gcc-patches-return-441178-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom=gcc-patches-return-441178-patch=linaro.org@gcc.gnu.org DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :subject:to:references:cc:message-id:date:mime-version :in-reply-to:content-type; q=dns; s=default; b=naj/VAxs16u3M3263 OIGYd5ZQso+kYPP3/pkOL5fS19XQbsPnMF/V035aWd+gMwkfZ/8ryLGMQSK9SYcf P7BSjq1AsUkHaqDJlJjlwpvHehqNHH+0/pbPvWWgIFWmYYnQBPj+a/YONAdu2VXj ClbiJUmtv4t8ZGxX5y3d6iMEaw= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :subject:to:references:cc:message-id:date:mime-version :in-reply-to:content-type; s=default; bh=WEwIyHDjrNVdeN9QOva012Q 1e5c=; b=w9So1HgKc9745aZlQZOKlRxT3ga8rVjexjFE1e7QyK9bblHvS1kOIgr FPyii0ayrWfjkIPtHnqWo+k8xXPEm2aaVU1DaZRojMlhw0wXLeJRlDMQ7ADZ8Wa5 VVJks5BHyaRdA8uS0ywbrDZBVoPRReCp8+eenrV7fhgyTzHJgi9E= Received: (qmail 126239 invoked by alias); 11 Nov 2016 18:35:17 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 124939 invoked by uid 89); 11 Nov 2016 18:35:16 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.8 required=5.0 tests=BAYES_00, KAM_LAZY_DOMAIN_SECURITY, RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=9704, reserved, letter X-HELO: foss.arm.com Received: from foss.arm.com (HELO foss.arm.com) (217.140.101.70) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 11 Nov 2016 18:35:06 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id E9B5A16; Fri, 11 Nov 2016 10:35:04 -0800 (PST) Received: from [10.2.206.198] (e104437-lin.cambridge.arm.com [10.2.206.198]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 5560D3F24D; Fri, 11 Nov 2016 10:35:04 -0800 (PST) From: Jiong Wang Subject: [5/9][AArch64] Generate dwarf information for -msign-return-address To: gcc-patches References: <72418e98-a400-c503-e8ce-c3fbe1ecc4a7@foss.arm.com> <64dd1b38-ff0a-5df0-1d3c-2fbf083e2697@foss.arm.com> <532363d6-0b33-491f-264d-9cd627713bf6@foss.arm.com> Cc: "Richard Earnshaw (lists)" , James Greenhalgh Message-ID: <304d5b3e-59a3-5a31-653a-6f8f99896264@foss.arm.com> Date: Fri, 11 Nov 2016 18:35:03 +0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.4.0 MIME-Version: 1.0 In-Reply-To: <532363d6-0b33-491f-264d-9cd627713bf6@foss.arm.com> X-IsSubscribed: yes This patch generate DWARF description for pointer authentication. DWARF value expression is used to describe the authentication action. Please see the cover letter and AArch64 DWARF specification for the semantics of AArch64 DWARF operations. When authentication key index is A key, we use compact DWARF description which can largely save DWARF frame size, otherwise we fallback to general operator. Example === int cal (int a, int b, int c) { return a + dec (b) + c; } Compact DWARF description (-march=armv8.3-a -msign-return-address) === DW_CFA_advance_loc: 4 to 0000000000000004 DW_CFA_val_expression: r30 (x30) (DW_OP_AARCH64_paciasp) DW_CFA_advance_loc: 4 to 0000000000000008 DW_CFA_val_expression: r30 (x30) (DW_OP_AARCH64_paciasp_deref: -24) General DWARF description === (-march=armv8.3-a -msign-return-address -mpauth-key=b_key) DW_CFA_advance_loc: 4 to 0000000000000004 DW_CFA_val_expression: r30 (x30) (DW_OP_breg30 (x30): 0; DW_OP_AARCH64_pauth: 18) DW_CFA_advance_loc: 4 to 0000000000000008 DW_CFA_val_expression: r30 (x30) (DW_OP_dup; DW_OP_const1s: -24; DW_OP_plus; DW_OP_deref; DW_OP_AARCH64_pauth: 18) From Linux kernel testing, -msign-return-address will introduce +24% .debug_frame size increase when signing all functions and using compact description, and about +45% .debug_frame size increase if using general description. gcc/ 2016-11-11 Jiong Wang * config/aarch64/aarch64.h (aarch64_pauth_action_type): New enum. * config/aarch64/aarch64.c (aarch64_attach_ra_auth_dwarf_note): New function. (aarch64_attach_ra_auth_dwarf_general): New function. (aarch64_attach_ra_auth_dwarf_shortcut): New function. (aarch64_save_callee_saves): Generate dwarf information if LR is signed. (aarch64_expand_prologue): Likewise. (aarch64_expand_epilogue): Likewise. 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)