i386: Add indirect_return function attribute
authorH.J. Lu <hongjiu.lu@intel.com>
Wed, 4 Jul 2018 03:01:33 +0000 (03:01 +0000)
committerH.J. Lu <hjl@gcc.gnu.org>
Wed, 4 Jul 2018 03:01:33 +0000 (20:01 -0700)
On x86, swapcontext may return via indirect branch when shadow stack
is enabled.  To support code instrumentation of control-flow transfers
with -fcf-protection, add indirect_return function attribute to inform
compiler that a function may return via indirect branch.

Note: Unlike setjmp, swapcontext only returns once.  Mark it return
twice will unnecessarily disable compiler optimization as shown in
the testcase here.

gcc/

PR target/85620
* config/i386/i386.c (rest_of_insert_endbranch): Also generate
ENDBRANCH for non-tail call which may return via indirect branch.
* doc/extend.texi: Document indirect_return attribute.

gcc/testsuite/

PR target/85620
* gcc.target/i386/pr85620-1.c: New test.
* gcc.target/i386/pr85620-2.c: Likewise.
* gcc.target/i386/pr85620-3.c: Likewise.
* gcc.target/i386/pr85620-4.c: Likewise.

From-SVN: r262370

gcc/ChangeLog
gcc/config/i386/i386.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/pr85620-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr85620-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr85620-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr85620-4.c [new file with mode: 0644]

index cd8f6ab5cbc91fc306776a49f58e9d33f1d7cc41..05d1e05e9909df22986c4ea9ccc60bce2b2c36be 100644 (file)
@@ -1,3 +1,10 @@
+2018-07-03  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR target/85620
+       * config/i386/i386.c (rest_of_insert_endbranch): Also generate
+       ENDBRANCH for non-tail call which may return via indirect branch.
+       * doc/extend.texi: Document indirect_return attribute.
+
 2018-07-03  Martin Sebor  <msebor@redhat.com>
 
        PR tree-optimization/86274
index e6d17632142fb4d07d56700e2283ab23f224fa7e..41461d582a4ea16119d1cbdb41fac9610e612374 100644 (file)
@@ -2621,7 +2621,26 @@ rest_of_insert_endbranch (void)
        {
          if (CALL_P (insn))
            {
-             if (find_reg_note (insn, REG_SETJMP, NULL) == NULL)
+             bool need_endbr;
+             need_endbr = find_reg_note (insn, REG_SETJMP, NULL) != NULL;
+             if (!need_endbr && !SIBLING_CALL_P (insn))
+               {
+                 rtx call = get_call_rtx_from (insn);
+                 rtx fnaddr = XEXP (call, 0);
+
+                 /* Also generate ENDBRANCH for non-tail call which
+                    may return via indirect branch.  */
+                 if (MEM_P (fnaddr)
+                     && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF)
+                   {
+                     tree fndecl = SYMBOL_REF_DECL (XEXP (fnaddr, 0));
+                     if (fndecl
+                         && lookup_attribute ("indirect_return",
+                                              DECL_ATTRIBUTES (fndecl)))
+                       need_endbr = true;
+                   }
+               }
+             if (!need_endbr)
                continue;
              /* Generate ENDBRANCH after CALL, which can return more than
                 twice, setjmp-like functions.  */
@@ -45897,6 +45916,8 @@ static const struct attribute_spec ix86_attribute_table[] =
     ix86_handle_fndecl_attribute, NULL },
   { "function_return", 1, 1, true, false, false, false,
     ix86_handle_fndecl_attribute, NULL },
+  { "indirect_return", 0, 0, true, false, false, false,
+    ix86_handle_fndecl_attribute, NULL },
 
   /* End element.  */
   { NULL, 0, 0, false, false, false, false, NULL, NULL }
index 19c2da2e5dbd4ea2bbdafecfb5a3f912a06ea6e0..071d0ffc4143652bd330a8b67f9e2c36eb45cfcb 100644 (file)
@@ -5886,6 +5886,12 @@ foo (void)
 @}
 @end smallexample
 
+@item indirect_return
+@cindex @code{indirect_return} function attribute, x86
+
+The @code{indirect_return} attribute on a function is used to inform
+the compiler that the function may return via indirect branch.
+
 @end table
 
 On the x86, the inliner does not inline a
index 020bed84961194796097fbfdd0a6610595c44c8a..a0e6ec2d77600dca18e32f81e98b7abf158995c8 100644 (file)
@@ -1,3 +1,11 @@
+2018-07-03  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR target/85620
+       * gcc.target/i386/pr85620-1.c: New test.
+       * gcc.target/i386/pr85620-2.c: Likewise.
+       * gcc.target/i386/pr85620-3.c: Likewise.
+       * gcc.target/i386/pr85620-4.c: Likewise.
+
 2018-07-03  Martin Sebor  <msebor@redhat.com>
 
        PR tree-optimization/86274
diff --git a/gcc/testsuite/gcc.target/i386/pr85620-1.c b/gcc/testsuite/gcc.target/i386/pr85620-1.c
new file mode 100644 (file)
index 0000000..32efb08
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection" } */
+/* { dg-final { scan-assembler-times {\mendbr} 2 } } */
+
+struct ucontext;
+
+extern int bar (struct ucontext *) __attribute__((__indirect_return__));
+
+extern int res;
+
+void
+foo (struct ucontext *oucp)
+{
+  res = bar (oucp);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr85620-2.c b/gcc/testsuite/gcc.target/i386/pr85620-2.c
new file mode 100644 (file)
index 0000000..b2e680f
--- /dev/null
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection" } */
+/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
+
+struct ucontext;
+
+extern int bar (struct ucontext *) __attribute__((__indirect_return__));
+
+int
+foo (struct ucontext *oucp)
+{
+  return bar (oucp);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr85620-3.c b/gcc/testsuite/gcc.target/i386/pr85620-3.c
new file mode 100644 (file)
index 0000000..c70a5ca
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wno-attributes" } */
+
+struct ucontext;
+
+extern int bar (struct ucontext *) __attribute__((__indirect_return__));
+
+static int __attribute__ ((__always_inline__))
+foo (struct ucontext *oucp)
+{
+  return bar (oucp);
+}
+
+int
+test (struct ucontext *oucp)
+{
+  return foo (oucp);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr85620-4.c b/gcc/testsuite/gcc.target/i386/pr85620-4.c
new file mode 100644 (file)
index 0000000..13056c4
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wno-attributes" } */
+
+struct ucontext;
+
+extern int bar (struct ucontext *) __attribute__((__returns_twice__));
+
+static int __attribute__ ((__always_inline__))
+foo (struct ucontext *oucp) /* { dg-error "setjmp" } */
+{
+  return bar (oucp);
+}
+
+int
+test (struct ucontext *oucp)
+{
+  return foo (oucp);
+}