In

struct ucontext;
typedef struct ucontext ucontext_t;

extern int (*bar) (ucontext_t *__restrict __oucp,
                   const ucontext_t *__restrict __ucp)
  __attribute__((__indirect_return__));

extern int res;

void
foo (ucontext_t *oucp, ucontext_t *ucp)
{
  res = bar (oucp, ucp);
}

bar() may return via indirect branch.  This patch changes indirect_return
to type attribute to allow indirect_return attribute on variable or type
of function pointer so that ENDBR can be inserted after call to bar().

Tested on i386 and x86-64.  OK for trunk?

Thanks.


H.J.
---
gcc/

        PR target/86560
        * config/i386/i386.c (rest_of_insert_endbranch): Lookup
        indirect_return as function type attribute.
        (ix86_attribute_table): Change indirect_return to function
        type attribute.
        * doc/extend.texi: Update indirect_return attribute.

gcc/testsuite/

        PR target/86560
        * gcc.target/i386/pr86560-1.c: New test.
        * gcc.target/i386/pr86560-2.c: Likewise.
        * gcc.target/i386/pr86560-3.c: Likewise.
---
 gcc/config/i386/i386.c                    | 23 +++++++++++++++--------
 gcc/doc/extend.texi                       |  5 +++--
 gcc/testsuite/gcc.target/i386/pr86560-1.c | 16 ++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr86560-2.c | 16 ++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr86560-3.c | 17 +++++++++++++++++
 5 files changed, 67 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr86560-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr86560-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr86560-3.c

diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index aec739c3974..ac27248370b 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -2627,16 +2627,23 @@ rest_of_insert_endbranch (void)
                {
                  rtx call = get_call_rtx_from (insn);
                  rtx fnaddr = XEXP (call, 0);
+                 tree fndecl = NULL_TREE;
 
                  /* Also generate ENDBRANCH for non-tail call which
                     may return via indirect branch.  */
-                 if (MEM_P (fnaddr)
-                     && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF)
+                 if (GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF)
+                   fndecl = SYMBOL_REF_DECL (XEXP (fnaddr, 0));
+                 if (fndecl == NULL_TREE)
+                   fndecl = MEM_EXPR (fnaddr);
+                 if (fndecl
+                     && TREE_CODE (TREE_TYPE (fndecl)) != FUNCTION_TYPE
+                     && TREE_CODE (TREE_TYPE (fndecl)) != METHOD_TYPE)
+                   fndecl = NULL_TREE;
+                 if (fndecl && TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
                    {
-                     tree fndecl = SYMBOL_REF_DECL (XEXP (fnaddr, 0));
-                     if (fndecl
-                         && lookup_attribute ("indirect_return",
-                                              DECL_ATTRIBUTES (fndecl)))
+                     tree fntype = TREE_TYPE (fndecl);
+                     if (lookup_attribute ("indirect_return",
+                                           TYPE_ATTRIBUTES (fntype)))
                        need_endbr = true;
                    }
                }
@@ -46101,8 +46108,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 },
+  { "indirect_return", 0, 0, false, true, true, false,
+    NULL, NULL },
 
   /* End element.  */
   { NULL, 0, 0, false, false, false, false, NULL, NULL }
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 8b4d3fd9de3..edeaec6d872 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -5861,8 +5861,9 @@ foo (void)
 @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.
+The @code{indirect_return} attribute can be applied to a function,
+as well as variable or type of function pointer to inform the
+compiler that the function may return via indirect branch.
 
 @end table
 
diff --git a/gcc/testsuite/gcc.target/i386/pr86560-1.c 
b/gcc/testsuite/gcc.target/i386/pr86560-1.c
new file mode 100644
index 00000000000..a2b702695c5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr86560-1.c
@@ -0,0 +1,16 @@
+/* { 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/pr86560-2.c 
b/gcc/testsuite/gcc.target/i386/pr86560-2.c
new file mode 100644
index 00000000000..6f01b385afd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr86560-2.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection" } */
+/* { dg-final { scan-assembler-times {\mendbr} 2 } } */
+
+struct ucontext;
+
+typedef int (*bar_p) (struct ucontext *)
+  __attribute__((__indirect_return__));
+
+extern int res;
+
+void
+foo (bar_p bar, struct ucontext *oucp)
+{
+  res = bar (oucp);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr86560-3.c 
b/gcc/testsuite/gcc.target/i386/pr86560-3.c
new file mode 100644
index 00000000000..05328e24509
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr86560-3.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection" } */
+/* { dg-final { scan-assembler-times {\mendbr} 2 } } */
+
+struct ucontext;
+
+extern int (*bar) (struct ucontext *);
+
+extern int res;
+
+void
+foo (struct ucontext *oucp)
+{
+  int (*f) (struct ucontext *) __attribute__((__indirect_return__))
+    = bar;
+  res = f (oucp);
+}
-- 
2.17.1

Reply via email to