From patchwork Sun Jan 14 04:53:57 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bill Schmidt X-Patchwork-Id: 860408 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-471134-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="nhMtPRjb"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zK3zy4FN1z9s83 for ; Sun, 14 Jan 2018 15:54:21 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to:cc :from:subject:date:mime-version:content-type :content-transfer-encoding:message-id; q=dns; s=default; b=RKeNj icUBpGo6Bl6OkXzQnNZ/DyfZl5hR1/v6rc+i9ImMN4usUlO62iJk+0maGVvJFNjr SPugmMOwSINn7rquHWm+XKJ281gnAhMQQyFghfFnMJgSNA3rutxW7Ea6ZhP2f2kJ dTNYT1fvH8TqVQEalLK0l6mplWxb0Io3HxUSCw= 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:to:cc :from:subject:date:mime-version:content-type :content-transfer-encoding:message-id; s=default; bh=VqEIWM2i1V0 Ir9zd1CKw5BUQzVM=; b=nhMtPRjbTUzN7CQue7cUpDcpx/UDi5tsLpJ+WOZ7b9I 0ri7lJU59hoTEs2sUvHJTORuJtL95zYnpmdSWjxi4YfeBUahqM+dtYYZiQoqk02F xcp2qN3f/AenBkmGk5SSR2KFD4bY7xazWI1rKviL1wUyAuDHVXw+7jAdd1uaeNB4 = Received: (qmail 79712 invoked by alias); 14 Jan 2018 04:54:11 -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 79690 invoked by uid 89); 14 Jan 2018 04:54:09 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-9.8 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, KAM_LAZY_DOMAIN_SECURITY, KAM_SHORT, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 spammy=yy X-HELO: mx0a-001b2d01.pphosted.com Received: from mx0a-001b2d01.pphosted.com (HELO mx0a-001b2d01.pphosted.com) (148.163.156.1) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 14 Jan 2018 04:54:06 +0000 Received: from pps.filterd (m0098410.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w0E4s4hf057233 for ; Sat, 13 Jan 2018 23:54:04 -0500 Received: from e18.ny.us.ibm.com (e18.ny.us.ibm.com [129.33.205.208]) by mx0a-001b2d01.pphosted.com with ESMTP id 2ffytw94ej-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Sat, 13 Jan 2018 23:54:03 -0500 Received: from localhost by e18.ny.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Sat, 13 Jan 2018 23:54:01 -0500 Received: from b01cxnp22035.gho.pok.ibm.com (9.57.198.25) by e18.ny.us.ibm.com (146.89.104.205) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Sat, 13 Jan 2018 23:53:58 -0500 Received: from b01ledav004.gho.pok.ibm.com (b01ledav004.gho.pok.ibm.com [9.57.199.109]) by b01cxnp22035.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id w0E4rwxS48300082; Sun, 14 Jan 2018 04:53:58 GMT Received: from b01ledav004.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id AF0F2112051; Sat, 13 Jan 2018 23:52:07 -0500 (EST) Received: from BigMac.local (unknown [9.80.219.102]) by b01ledav004.gho.pok.ibm.com (Postfix) with ESMTP id 33CA3112047; Sat, 13 Jan 2018 23:52:07 -0500 (EST) To: GCC Patches Cc: Segher Boessenkool , amodra@gmail.com, David Edelsohn From: Bill Schmidt Subject: [PATCH v2, rs6000] Add -msafe-indirect-jumps option and implement safe bctr / bctrl Date: Sat, 13 Jan 2018 22:53:57 -0600 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:52.0) Gecko/20100101 Thunderbird/52.5.2 MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 18011404-0044-0000-0000-000003CE933D X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00008373; HX=3.00000241; KW=3.00000007; PH=3.00000004; SC=3.00000245; SDB=6.00974724; UDB=6.00493957; IPR=6.00754650; BA=6.00005775; NDR=6.00000001; ZLA=6.00000005; ZF=6.00000009; ZB=6.00000000; ZP=6.00000000; ZH=6.00000000; ZU=6.00000002; MB=3.00019027; XFM=3.00000015; UTC=2018-01-14 04:54:00 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18011404-0045-0000-0000-000007FDEF1A Message-Id: X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2018-01-14_01:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=0 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 impostorscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1709140000 definitions=main-1801140069 X-IsSubscribed: yes Hi, [This patch supercedes and extends https://gcc.gnu.org/ml/gcc-patches/2018-01/msg01135.html. There was a small error in the assembly code produced by that patch (bad memory on my account of how to spell "crset eq"). I've also increased the function provided; see below.] This patch adds a new option for the compiler to produce only "safe" indirect jumps, in the sense that these jumps are deliberately mispredicted to inhibit speculative execution. For now, this option is undocumented; this may change at some future date. It is intended eventually for the linker to also honor this flag when creating PLT stubs, for example. In addition to the new option, I've included changes to indirect calls for the ELFv2 ABI when the option is specified. In place of bctrl, we generate a "crset eq" followed by a beqctrl-. Using the CR0.eq bit is safe since CR0 is volatile over the call. I've also added code to replace uses of bctr when the new option is specified, with the sequence crset 4x[CRb]+2 beqctr- CRb b . where CRb is an available condition register field. This applies to all subtargets, and in particular is not restricted to ELFv2. The use cases covered here are computed gotos and switch statements. NOT yet covered by this patch: indirect calls for ELFv1. That will come later. Please let me know if there is a better way to represent the crset without an unspec. For the indirect jump, I don't see a way around it due to the expected form of indirect jumps in cfganal.c. Bootstrapped and tested on powerpc64-linux-gnu and powerpc64le-linux-gnu with no regressions. Is this okay for trunk? Thanks, Bill [gcc] 2018-01-13 Bill Schmidt * config/rs6000/rs6000.c (rs6000_opt_vars): Add entry for -msafe-indirect-jumps. * config/rs6000/rs6000.md (UNSPEC_CRSET_EQ): New UNSPEC enum. (UNSPEC_COMP_GOTO_CR): Likewise. (*call_indirect_elfv2): Disable for -msafe-indirect-jumps. (*call_indirect_elfv2_safe): New define_insn. (*call_value_indirect_elfv2): Disable for -msafe-indirect-jumps. (*call_value_indirect_elfv2_safe): New define_insn. (indirect_jump): Emit different RTL for -msafe-indirect-jumps. (*indirect_jump): Disable for -msafe-indirect-jumps. (*indirect_jump_safe): New define_insn. (*set_cr_eq): New define_insn. (tablejump): Emit different RTL for -msafe-indirect-jumps. (tablejumpsi): Disable for -msafe-indirect-jumps. (tablejumpsi_safe): New define_expand. (tablejumpdi): Disable for -msafe-indirect-jumps. (tablejumpdi_safe): New define_expand. (*tablejump_internal1): Disable for -msafe-indirect-jumps. (*tablejump_internal1_safe): New define_insn. * config/rs6000/rs6000.opt (msafe-indirect-jumps): New option. [gcc/testsuite] 2018-01-13 Bill Schmidt * gcc.target/powerpc/safe-indirect-jump-1.c: New file. * gcc.target/powerpc/safe-indirect-jump-2.c: New file. * gcc.target/powerpc/safe-indirect-jump-3.c: New file. Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 256364) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -36726,6 +36726,9 @@ static struct rs6000_opt_var const rs6000_opt_vars { "sched-epilog", offsetof (struct gcc_options, x_TARGET_SCHED_PROLOG), offsetof (struct cl_target_option, x_TARGET_SCHED_PROLOG), }, + { "safe-indirect-jumps", + offsetof (struct gcc_options, x_rs6000_safe_indirect_jumps), + offsetof (struct cl_target_option, x_rs6000_safe_indirect_jumps), }, }; /* Inner function to handle attribute((target("..."))) and #pragma GCC target Index: gcc/config/rs6000/rs6000.md =================================================================== --- gcc/config/rs6000/rs6000.md (revision 256364) +++ gcc/config/rs6000/rs6000.md (working copy) @@ -150,6 +150,8 @@ UNSPEC_SIGNBIT UNSPEC_SF_FROM_SI UNSPEC_SI_FROM_SF + UNSPEC_CRSET_EQ + UNSPEC_COMP_GOTO_CR ]) ;; @@ -11222,11 +11224,22 @@ (match_operand 1 "" "g,g")) (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT)) (clobber (reg:P LR_REGNO))] - "DEFAULT_ABI == ABI_ELFv2" + "DEFAULT_ABI == ABI_ELFv2 && !rs6000_safe_indirect_jumps" "b%T0l\; 2,%2(1)" [(set_attr "type" "jmpreg") (set_attr "length" "8")]) +;; Variant with deliberate misprediction. +(define_insn "*call_indirect_elfv2_safe" + [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l")) + (match_operand 1 "" "g,g")) + (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT)) + (clobber (reg:P LR_REGNO))] + "DEFAULT_ABI == ABI_ELFv2 && rs6000_safe_indirect_jumps" + "crset eq\;beq%T0l-\; 2,%2(1)" + [(set_attr "type" "jmpreg") + (set_attr "length" "12")]) + (define_insn "*call_value_indirect_elfv2" [(set (match_operand 0 "" "") (call (mem:SI (match_operand:P 1 "register_operand" "c,*l")) @@ -11233,11 +11246,22 @@ (match_operand 2 "" "g,g"))) (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT)) (clobber (reg:P LR_REGNO))] - "DEFAULT_ABI == ABI_ELFv2" + "DEFAULT_ABI == ABI_ELFv2 && !rs6000_safe_indirect_jumps" "b%T1l\; 2,%3(1)" [(set_attr "type" "jmpreg") (set_attr "length" "8")]) +; Variant with deliberate misprediction. +(define_insn "*call_value_indirect_elfv2_safe" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:P 1 "register_operand" "c,*l")) + (match_operand 2 "" "g,g"))) + (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT)) + (clobber (reg:P LR_REGNO))] + "DEFAULT_ABI == ABI_ELFv2 && rs6000_safe_indirect_jumps" + "crset eq\;beq%T1l-\; 2,%3(1)" + [(set_attr "type" "jmpreg") + (set_attr "length" "12")]) ;; Call subroutine returning any type. (define_expand "untyped_call" @@ -12917,15 +12941,50 @@ [(set_attr "type" "jmpreg")]) (define_expand "indirect_jump" - [(set (pc) (match_operand 0 "register_operand"))]) + [(set (pc) (match_operand 0 "register_operand"))] + "" +{ + /* We need to reserve a CR when forcing a mispredicted jump. */ + if (rs6000_safe_indirect_jumps) { + rtx ccreg = gen_reg_rtx (CCmode); + emit_insn (gen_rtx_SET (ccreg, + gen_rtx_UNSPEC (CCmode, + gen_rtvec (1, const0_rtx), + UNSPEC_CRSET_EQ))); + rtvec v = rtvec_alloc (2); + RTVEC_ELT (v, 0) = operands[0]; + RTVEC_ELT (v, 1) = ccreg; + emit_jump_insn (gen_rtx_SET (pc_rtx, + gen_rtx_UNSPEC (Pmode, v, + UNSPEC_COMP_GOTO_CR))); + DONE; + } +}) (define_insn "*indirect_jump" [(set (pc) (match_operand:P 0 "register_operand" "c,*l"))] - "" + "!rs6000_safe_indirect_jumps" "b%T0" [(set_attr "type" "jmpreg")]) +(define_insn "*indirect_jump_safe" + [(set (pc) + (unspec:P [(match_operand:P 0 "register_operand" "c,*l") + (match_operand:CC 1 "cc_reg_operand" "y,y")] + UNSPEC_COMP_GOTO_CR))] + "rs6000_safe_indirect_jumps" + "beq%T0- %1\;b ." + [(set_attr "type" "jmpreg") + (set_attr "length" "8")]) + +(define_insn "*set_cr_eq" + [(set (match_operand:CC 0 "cc_reg_operand" "=y") + (unspec:CC [(const_int 0)] UNSPEC_CRSET_EQ))] + "rs6000_safe_indirect_jumps" + "crset %E0" + [(set_attr "type" "cr_logical")]) + ;; Table jump for switch statements: (define_expand "tablejump" [(use (match_operand 0)) @@ -12933,9 +12992,19 @@ "" { if (TARGET_32BIT) - emit_jump_insn (gen_tablejumpsi (operands[0], operands[1])); + { + if (rs6000_safe_indirect_jumps) + emit_jump_insn (gen_tablejumpsi_safe (operands[0], operands[1])); + else + emit_jump_insn (gen_tablejumpsi (operands[0], operands[1])); + } else - emit_jump_insn (gen_tablejumpdi (operands[0], operands[1])); + { + if (rs6000_safe_indirect_jumps) + emit_jump_insn (gen_tablejumpdi_safe (operands[0], operands[1])); + else + emit_jump_insn (gen_tablejumpdi (operands[0], operands[1])); + } DONE; }) @@ -12946,7 +13015,7 @@ (parallel [(set (pc) (match_dup 3)) (use (label_ref (match_operand 1)))])] - "TARGET_32BIT" + "TARGET_32BIT && !rs6000_safe_indirect_jumps" { operands[0] = force_reg (SImode, operands[0]); operands[2] = force_reg (SImode, gen_rtx_LABEL_REF (SImode, operands[1])); @@ -12953,6 +13022,23 @@ operands[3] = gen_reg_rtx (SImode); }) +(define_expand "tablejumpsi_safe" + [(set (match_dup 3) + (plus:SI (match_operand:SI 0) + (match_dup 2))) + (set (match_dup 4) (unspec:CC [(const_int 0)] UNSPEC_CRSET_EQ)) + (parallel [(set (pc) + (match_dup 3)) + (use (label_ref (match_operand 1))) + (use (match_dup 4))])] + "TARGET_32BIT && rs6000_safe_indirect_jumps" +{ + operands[0] = force_reg (SImode, operands[0]); + operands[2] = force_reg (SImode, gen_rtx_LABEL_REF (SImode, operands[1])); + operands[3] = gen_reg_rtx (SImode); + operands[4] = gen_reg_rtx (CCmode); +}) + (define_expand "tablejumpdi" [(set (match_dup 4) (sign_extend:DI (match_operand:SI 0 "lwa_operand"))) @@ -12962,7 +13048,7 @@ (parallel [(set (pc) (match_dup 3)) (use (label_ref (match_operand 1)))])] - "TARGET_64BIT" + "TARGET_64BIT && !rs6000_safe_indirect_jumps" { operands[2] = force_reg (DImode, gen_rtx_LABEL_REF (DImode, operands[1])); operands[3] = gen_reg_rtx (DImode); @@ -12969,14 +13055,43 @@ operands[4] = gen_reg_rtx (DImode); }) +(define_expand "tablejumpdi_safe" + [(set (match_dup 4) + (sign_extend:DI (match_operand:SI 0 "lwa_operand"))) + (set (match_dup 5) (unspec:CC [(const_int 0)] UNSPEC_CRSET_EQ)) + (set (match_dup 3) + (plus:DI (match_dup 4) + (match_dup 2))) + (parallel [(set (pc) + (match_dup 3)) + (use (label_ref (match_operand 1))) + (use (match_dup 5))])] + "TARGET_64BIT && rs6000_safe_indirect_jumps" +{ + operands[2] = force_reg (DImode, gen_rtx_LABEL_REF (DImode, operands[1])); + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_reg_rtx (DImode); + operands[5] = gen_reg_rtx (CCmode); +}) + (define_insn "*tablejump_internal1" [(set (pc) (match_operand:P 0 "register_operand" "c,*l")) (use (label_ref (match_operand 1)))] - "" + "!rs6000_safe_indirect_jumps" "b%T0" [(set_attr "type" "jmpreg")]) +(define_insn "*tablejump_internal1_safe" + [(set (pc) + (match_operand:P 0 "register_operand" "c,*l")) + (use (label_ref (match_operand 1))) + (use (match_operand:CC 2 "cc_reg_operand" "y,y"))] + "rs6000_safe_indirect_jumps" + "beq%T0- %2\;b ." + [(set_attr "type" "jmpreg") + (set_attr "length" "8")]) + (define_insn "nop" [(unspec [(const_int 0)] UNSPEC_NOP)] "" Index: gcc/config/rs6000/rs6000.opt =================================================================== --- gcc/config/rs6000/rs6000.opt (revision 256364) +++ gcc/config/rs6000/rs6000.opt (working copy) @@ -617,3 +617,8 @@ Use the given offset for addressing the stack-prot TargetVariable long rs6000_stack_protector_guard_offset = 0 + +;; -msafe-indirect-jumps adds deliberate misprediction to indirect +;; branches via the CTR. +msafe-indirect-jumps +Target Undocumented Var(rs6000_safe_indirect_jumps) Init(0) Save Index: gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-1.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-1.c (nonexistent) +++ gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-1.c (working copy) @@ -0,0 +1,14 @@ +/* { dg-do compile { target { powerpc64le-*-* } } } */ +/* { dg-options "-msafe-indirect-jumps" } */ + +/* Test for deliberate misprediction of indirect calls for ELFv2. */ + +extern int (*f)(); + +int bar () +{ + return (*f) (); +} + +/* { dg-final { scan-assembler "crset eq" } } */ +/* { dg-final { scan-assembler "beqctrl-" } } */ Index: gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-2.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-2.c (nonexistent) +++ gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-2.c (working copy) @@ -0,0 +1,33 @@ +/* { dg-do compile { target { powerpc*-*-* } } } */ +/* { dg-options "-msafe-indirect-jumps" } */ + +/* Test for deliberate misprediction of computed goto. */ + +int bar (int); +int baz (int); +int spaz (int); + +int foo (int x) +{ + static void *labptr[] = { &&lab0, &&lab1, &&lab2 }; + + if (x < 0 || x > 2) + return -1; + + goto *labptr[x]; + + lab0: + return bar (x); + + lab1: + return baz (x) + 1; + + lab2: + return spaz (x) / 2; +} + +/* The following assumes CR7 as the first chosen volatile. */ + +/* { dg-final { scan-assembler "crset 30" } } */ +/* { dg-final { scan-assembler "beqctr- 7" } } */ +/* { dg-final { scan-assembler "b ." } } */ Index: gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-3.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-3.c (nonexistent) +++ gcc/testsuite/gcc.target/powerpc/safe-indirect-jump-3.c (working copy) @@ -0,0 +1,52 @@ +/* { dg-do compile { target { powerpc*-*-* } } } */ +/* { dg-options "-msafe-indirect-jumps" } */ + +/* Test for deliberate misprediction of jump tables. */ + +void bar (void); + +int foo (int x) +{ + int a; + + switch (x) + { + default: + a = -1; + break; + case 0: + a = x * x; + break; + case 1: + a = x + 1; + break; + case 2: + a = x + x; + break; + case 3: + a = x << 3; + break; + case 4: + a = x >> 1; + break; + case 5: + a = x; + break; + case 6: + a = 0; + break; + case 7: + a = x * x + x; + break; + } + + bar(); + + return a; +} + +/* The following assumes CR7 as the first chosen volatile. */ + +/* { dg-final { scan-assembler "crset 30" } } */ +/* { dg-final { scan-assembler "beqctr- 7" } } */ +/* { dg-final { scan-assembler "b ." } } */