PR 47656 points out that Go programs are often marked as having an
executable stack.  This is incorrect.  Go does use trampolines, but they
are never built on the stack.  They are built on the heap, using
mprotect.  This is necessary because Go closures may be returned from
functions and as such must be heap allocated, not stack allocated.

Currently gcc decides that a program requires an executable stack if it
calls __builtin_init_trampoline.  This turns out to be non-trivial to
change, because that function serves as a marked for LTO as well.  That
is, there is currently no way for the frontend to signal that is
creating a trampoline but that it does not need an executable stack.

This patch fixes the problem by introducing a new builtin function
__builtin_init_heap_trampoline.  This is a middle-end change so it is
covered under my maintainership.  I also believe it is quite safe.
However, given that we are in stage 4 I would like to ask the release
managers if this is OK to put in.  It fixes a user-reported bug, but the
bug is technically not a regression because it has never actually worked
correctly.

Bootstrapped and ran full testsuite on x86_64-unknown-linux-gnu.  OK to
commit?

Ian


2012-01-27  Ian Lance Taylor  <i...@google.com>

        PR go/47656
        * builtins.def (BUILT_IN_INIT_HEAP_TRAMPOLINE): Define.
        * builtins.c (expand_builtin_init_trampoline): Add onstack
        parameter.  Change caller.
        (expand_builtin): Handle BUILT_IN_INIT_HEAP_TRAMPOLINE.
        * tree.c (build_common_builtin_nodes): Declare
        __builtin_init_heap_trampoline.


Index: tree.c
===================================================================
--- tree.c	(revision 183603)
+++ tree.c	(working copy)
@@ -1,7 +1,7 @@
 /* Language-independent node constructors for parse phase of GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-   2011 Free Software Foundation, Inc.
+   2011, 2012 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -9527,6 +9527,10 @@ build_common_builtin_nodes (void)
   local_define_builtin ("__builtin_init_trampoline", ftype,
 			BUILT_IN_INIT_TRAMPOLINE,
 			"__builtin_init_trampoline", ECF_NOTHROW | ECF_LEAF);
+  local_define_builtin ("__builtin_init_heap_trampoline", ftype,
+			BUILT_IN_INIT_HEAP_TRAMPOLINE,
+			"__builtin_init_heap_trampoline",
+			ECF_NOTHROW | ECF_LEAF);
 
   ftype = build_function_type_list (ptr_type_node, ptr_type_node, NULL_TREE);
   local_define_builtin ("__builtin_adjust_trampoline", ftype,
Index: builtins.c
===================================================================
--- builtins.c	(revision 183603)
+++ builtins.c	(working copy)
@@ -1,7 +1,7 @@
 /* Expand builtin functions.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
-   Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
+   2012 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -4854,7 +4854,7 @@ round_trampoline_addr (rtx tramp)
 }
 
 static rtx
-expand_builtin_init_trampoline (tree exp)
+expand_builtin_init_trampoline (tree exp, bool onstack)
 {
   tree t_tramp, t_func, t_chain;
   rtx m_tramp, r_tramp, r_chain, tmp;
@@ -4871,13 +4871,16 @@ expand_builtin_init_trampoline (tree exp
   m_tramp = gen_rtx_MEM (BLKmode, r_tramp);
   MEM_NOTRAP_P (m_tramp) = 1;
 
-  /* The TRAMP argument should be the address of a field within the
-     local function's FRAME decl.  Let's see if we can fill in the
-     to fill in the MEM_ATTRs for this memory.  */
+  /* If ONSTACK, the TRAMP argument should be the address of a field
+     within the local function's FRAME decl.  Either way, let's see if
+     we can fill in the MEM_ATTRs for this memory.  */
   if (TREE_CODE (t_tramp) == ADDR_EXPR)
     set_mem_attributes_minus_bitpos (m_tramp, TREE_OPERAND (t_tramp, 0),
 				     true, 0);
 
+  /* Creator of a heap trampoline is responsible for making sure the
+     address is aligned to at least STACK_BOUNDARY.  Normally malloc
+     will ensure this anyhow.  */
   tmp = round_trampoline_addr (r_tramp);
   if (tmp != r_tramp)
     {
@@ -4897,10 +4900,13 @@ expand_builtin_init_trampoline (tree exp
   /* Generate insns to initialize the trampoline.  */
   targetm.calls.trampoline_init (m_tramp, t_func, r_chain);
 
-  trampolines_created = 1;
+  if (onstack)
+    {
+      trampolines_created = 1;
 
-  warning_at (DECL_SOURCE_LOCATION (t_func), OPT_Wtrampolines,
-              "trampoline generated for nested function %qD", t_func);
+      warning_at (DECL_SOURCE_LOCATION (t_func), OPT_Wtrampolines,
+		  "trampoline generated for nested function %qD", t_func);
+    }
 
   return const0_rtx;
 }
@@ -6325,7 +6331,9 @@ expand_builtin (tree exp, rtx target, rt
       return const0_rtx;
 
     case BUILT_IN_INIT_TRAMPOLINE:
-      return expand_builtin_init_trampoline (exp);
+      return expand_builtin_init_trampoline (exp, true);
+    case BUILT_IN_INIT_HEAP_TRAMPOLINE:
+      return expand_builtin_init_trampoline (exp, false);
     case BUILT_IN_ADJUST_TRAMPOLINE:
       return expand_builtin_adjust_trampoline (exp);
 
Index: builtins.def
===================================================================
--- builtins.def	(revision 183603)
+++ builtins.def	(working copy)
@@ -1,7 +1,7 @@
 /* This file contains the definitions and documentation for the
    builtins used in the GNU compiler.
    Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-   2010, 2011 Free Software Foundation, Inc.
+   2010, 2011, 2012 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -740,6 +740,7 @@ DEF_C99_BUILTIN        (BUILT_IN__EXIT2,
 
 /* Implementing nested functions.  */
 DEF_BUILTIN_STUB (BUILT_IN_INIT_TRAMPOLINE, "__builtin_init_trampoline")
+DEF_BUILTIN_STUB (BUILT_IN_INIT_HEAP_TRAMPOLINE, "__builtin_init_heap_trampoline")
 DEF_BUILTIN_STUB (BUILT_IN_ADJUST_TRAMPOLINE, "__builtin_adjust_trampoline")
 DEF_BUILTIN_STUB (BUILT_IN_NONLOCAL_GOTO, "__builtin_nonlocal_goto")
 
Index: go/gofrontend/gogo-tree.cc
===================================================================
--- go/gofrontend/gogo-tree.cc	(revision 183603)
+++ go/gofrontend/gogo-tree.cc	(working copy)
@@ -2422,8 +2422,8 @@ Gogo::make_trampoline(tree fnaddr, tree 
   x = save_expr(x);
 
   // Initialize the trampoline.
-  tree ini = build_call_expr(builtin_decl_implicit(BUILT_IN_INIT_TRAMPOLINE),
-			     3, x, fnaddr, closure);
+  tree calldecl = builtin_decl_implicit(BUILT_IN_INIT_HEAP_TRAMPOLINE);
+  tree ini = build_call_expr(calldecl, 3, x, fnaddr, closure);
 
   // On some targets the trampoline address needs to be adjusted.  For
   // example, when compiling in Thumb mode on the ARM, the address

Reply via email to