Patchwork [07/13] Implement protection of global variables

login
register
mail settings
Submitter Dodji Seketeli
Date Nov. 1, 2012, 7:52 p.m.
Message ID <1351799566-31447-8-git-send-email-dodji@redhat.com>
Download mbox | patch
Permalink /patch/196369/
State New
Headers show

Comments

Dodji Seketeli - Nov. 1, 2012, 7:52 p.m.
From: jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>

This patch implements the protection of global variables.

The basic idea is to insert a red zone between two global variables
and install a constructor function that calls the asan runtime to do
the populating of the relevant shadow memory regions at load time.

So the patch lays out the global variables as to insert a red zone
between them. The size of the red zones is so that each variable
starts on a 32 bytes boundary.

Then it installs a constructor function that, for each global
variable, calls the runtime asan library function
__asan_register_globals_with an instance of this type:

    struct __asan_global
    {
      /* Address of the beginning of the global variable.  */
      const void *__beg;

      /* Initial size of the global variable.  */
      uptr __size;

      /* Size of the global variable + size of the red zone.  This
         size is 32 bytes aligned.  */
      uptr __size_with_redzone;

      /*  Name of the global variable.  */
      const void *__name;

      /* This is always set to NULL for now.  */
      uptr __has_dynamic_init;
    }

The patch also installs a destructor function that calls the
runtime asan library function _asan_unregister_globals.

	* varasm.c: Include asan.h.
	(assemble_noswitch_variable): Grow size by asan_red_zone_size
	if decl is asan protected.
	(place_block_symbol): Likewise.
	(assemble_variable): If decl is asan protected, increase
	DECL_ALIGN if needed, and for decls emitted using
	assemble_variable_contents append padding zeros after it.
	* Makefile.in (varasm.o): Depend on asan.h.
	* asan.c: Include output.h.
	(asan_pp, asan_pp_initialized): New variables.
	(asan_pp_initialize, asan_pp_string): New functions.
	(asan_emit_stack_protection): Use asan_pp{,_initialized}
	instead of local pp{,_initialized} vars, use asan_pp_initialize
	and asan_pp_string helpers.
	(asan_needs_local_alias, asan_protect_global,
	asan_global_struct, asan_add_global): New functions.
	(asan_finish_file): Protect global vars that can be protected.
	* asan.h (asan_protect_global): New prototype.
	(asan_red_zone_size): New inline function.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/asan@192541 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog.asan |  20 ++++
 gcc/Makefile.in    |   2 +-
 gcc/asan.c         | 299 +++++++++++++++++++++++++++++++++++++++++++++++------
 gcc/asan.h         |  11 ++
 gcc/varasm.c       |  22 ++++
 5 files changed, 319 insertions(+), 35 deletions(-)

Patch

diff --git a/gcc/ChangeLog.asan b/gcc/ChangeLog.asan
index 23454f3..971de42 100644
--- a/gcc/ChangeLog.asan
+++ b/gcc/ChangeLog.asan
@@ -1,5 +1,25 @@ 
 2012-10-17  Jakub Jelinek  <jakub@redhat.com>
 
+	* varasm.c: Include asan.h.
+	(assemble_noswitch_variable): Grow size by asan_red_zone_size
+	if decl is asan protected.
+	(place_block_symbol): Likewise.
+	(assemble_variable): If decl is asan protected, increase
+	DECL_ALIGN if needed, and for decls emitted using
+	assemble_variable_contents append padding zeros after it.
+	* Makefile.in (varasm.o): Depend on asan.h.
+	* asan.c: Include output.h.
+	(asan_pp, asan_pp_initialized): New variables.
+	(asan_pp_initialize, asan_pp_string): New functions.
+	(asan_emit_stack_protection): Use asan_pp{,_initialized}
+	instead of local pp{,_initialized} vars, use asan_pp_initialize
+	and asan_pp_string helpers.
+	(asan_needs_local_alias, asan_protect_global,
+	asan_global_struct, asan_add_global): New functions.
+	(asan_finish_file): Protect global vars that can be protected.
+	* asan.h (asan_protect_global): New prototype.
+	(asan_red_zone_size): New inline function.
+
 	* Makefile.in (asan.o): Depend on $(EXPR_H) $(OPTABS_H).
 	(cfgexpand.o): Depend on asan.h.
 	* asan.c: Include expr.h and optabs.h.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 2743e24..c6a9825 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -2721,7 +2721,7 @@  varasm.o : varasm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
    output.h $(DIAGNOSTIC_CORE_H) xcoffout.h debug.h $(GGC_H) $(TM_P_H) \
    $(HASHTAB_H) $(TARGET_H) langhooks.h gt-varasm.h $(BASIC_BLOCK_H) \
    $(CGRAPH_H) $(TARGET_DEF_H) tree-mudflap.h \
-   pointer-set.h $(COMMON_TARGET_H)
+   pointer-set.h $(COMMON_TARGET_H) asan.h
 function.o : function.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_ERROR_H) \
    $(TREE_H) $(GIMPLE_H) $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) \
    $(OPTABS_H) $(LIBFUNCS_H) $(REGS_H) hard-reg-set.h insn-config.h $(RECOG_H) \
diff --git a/gcc/asan.c b/gcc/asan.c
index fe0e9a8..c435d35 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -45,6 +45,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "expr.h"
 #include "optabs.h"
+#include "output.h"
 
 /*
  AddressSanitizer finds out-of-bounds and use-after-free bugs 
@@ -87,6 +88,34 @@  alias_set_type asan_shadow_set = -1;
    alias set is used for all shadow memory accesses.  */
 static GTY(()) tree shadow_ptr_types[2];
 
+/* Asan pretty-printer, used for buidling of the description STRING_CSTs.  */
+static pretty_printer asan_pp;
+static bool asan_pp_initialized;
+
+/* Initialize asan_pp.  */
+
+static void
+asan_pp_initialize (void)
+{
+  pp_construct (&asan_pp, /* prefix */NULL, /* line-width */0);
+  asan_pp_initialized = true;
+}
+
+/* Create ADDR_EXPR of STRING_CST with asan_pp text.  */
+
+static tree
+asan_pp_string (void)
+{
+  const char *buf = pp_base_formatted_text (&asan_pp);
+  size_t len = strlen (buf);
+  tree ret = build_string (len + 1, buf);
+  TREE_TYPE (ret)
+    = build_array_type (char_type_node, build_index_type (size_int (len)));
+  TREE_READONLY (ret) = 1;
+  TREE_STATIC (ret) = 1;
+  return build1 (ADDR_EXPR, build_pointer_type (char_type_node), ret);
+}
+
 /* Return a CONST_INT representing 4 subsequent shadow memory bytes.  */
 
 static rtx
@@ -121,51 +150,38 @@  asan_emit_stack_protection (rtx base, HOST_WIDE_INT *offsets, tree *decls,
   HOST_WIDE_INT last_offset, last_size;
   int l;
   unsigned char cur_shadow_byte = ASAN_STACK_MAGIC_LEFT;
-  static pretty_printer pp;
-  static bool pp_initialized;
-  const char *buf;
-  size_t len;
   tree str_cst;
 
   /* First of all, prepare the description string.  */
-  if (!pp_initialized)
-    {
-      pp_construct (&pp, /* prefix */NULL, /* line-width */0);
-      pp_initialized = true;
-    }
-  pp_clear_output_area (&pp);
+  if (!asan_pp_initialized)
+    asan_pp_initialize ();
+
+  pp_clear_output_area (&asan_pp);
   if (DECL_NAME (current_function_decl))
-    pp_base_tree_identifier (&pp, DECL_NAME (current_function_decl));
+    pp_base_tree_identifier (&asan_pp, DECL_NAME (current_function_decl));
   else
-    pp_string (&pp, "<unknown>");
-  pp_space (&pp);
-  pp_decimal_int (&pp, length / 2 - 1);
-  pp_space (&pp);
+    pp_string (&asan_pp, "<unknown>");
+  pp_space (&asan_pp);
+  pp_decimal_int (&asan_pp, length / 2 - 1);
+  pp_space (&asan_pp);
   for (l = length - 2; l; l -= 2)
     {
       tree decl = decls[l / 2 - 1];
-      pp_wide_integer (&pp, offsets[l] - base_offset);
-      pp_space (&pp);
-      pp_wide_integer (&pp, offsets[l - 1] - offsets[l]);
-      pp_space (&pp);
+      pp_wide_integer (&asan_pp, offsets[l] - base_offset);
+      pp_space (&asan_pp);
+      pp_wide_integer (&asan_pp, offsets[l - 1] - offsets[l]);
+      pp_space (&asan_pp);
       if (DECL_P (decl) && DECL_NAME (decl))
 	{
-	  pp_decimal_int (&pp, IDENTIFIER_LENGTH (DECL_NAME (decl)));
-	  pp_space (&pp);
-	  pp_base_tree_identifier (&pp, DECL_NAME (decl));
+	  pp_decimal_int (&asan_pp, IDENTIFIER_LENGTH (DECL_NAME (decl)));
+	  pp_space (&asan_pp);
+	  pp_base_tree_identifier (&asan_pp, DECL_NAME (decl));
 	}
       else
-	pp_string (&pp, "9 <unknown>");
-      pp_space (&pp);
+	pp_string (&asan_pp, "9 <unknown>");
+      pp_space (&asan_pp);
     }
-  buf = pp_base_formatted_text (&pp);
-  len = strlen (buf);
-  str_cst = build_string (len + 1, buf);
-  TREE_TYPE (str_cst)
-    = build_array_type (char_type_node, build_index_type (size_int (len)));
-  TREE_READONLY (str_cst) = 1;
-  TREE_STATIC (str_cst) = 1;
-  str_cst = build1 (ADDR_EXPR, build_pointer_type (char_type_node), str_cst);
+  str_cst = asan_pp_string ();
 
   /* Emit the prologue sequence.  */
   base = expand_binop (Pmode, add_optab, base, GEN_INT (base_offset),
@@ -270,6 +286,75 @@  asan_emit_stack_protection (rtx base, HOST_WIDE_INT *offsets, tree *decls,
   return ret;
 }
 
+/* Return true if DECL, a global var, might be overridden and needs
+   therefore a local alias.  */
+
+static bool
+asan_needs_local_alias (tree decl)
+{
+  return DECL_WEAK (decl) || !targetm.binds_local_p (decl);
+}
+
+/* Return true if DECL is a VAR_DECL that should be protected
+   by Address Sanitizer, by appending a red zone with protected
+   shadow memory after it and aligning it to at least
+   ASAN_RED_ZONE_SIZE bytes.  */
+
+bool
+asan_protect_global (tree decl)
+{
+  rtx rtl, symbol;
+  section *sect;
+
+  if (TREE_CODE (decl) != VAR_DECL
+      /* TLS vars aren't statically protectable.  */
+      || DECL_THREAD_LOCAL_P (decl)
+      /* Externs will be protected elsewhere.  */
+      || DECL_EXTERNAL (decl)
+      || !TREE_ASM_WRITTEN (decl)
+      || !DECL_RTL_SET_P (decl)
+      /* Comdat vars pose an ABI problem, we can't know if
+	 the var that is selected by the linker will have
+	 padding or not.  */
+      || DECL_ONE_ONLY (decl)
+      /* Similarly for common vars.  People can use -fno-common.  */
+      || DECL_COMMON (decl)
+      /* Don't protect if using user section, often vars placed
+	 into user section from multiple TUs are then assumed
+	 to be an array of such vars, putting padding in there
+	 breaks this assumption.  */
+      || (DECL_SECTION_NAME (decl) != NULL_TREE
+	  && !DECL_HAS_IMPLICIT_SECTION_NAME_P (decl))
+      || DECL_SIZE (decl) == 0
+      || ASAN_RED_ZONE_SIZE * BITS_PER_UNIT > MAX_OFILE_ALIGNMENT
+      || !valid_constant_size_p (DECL_SIZE_UNIT (decl))
+      || DECL_ALIGN_UNIT (decl) > 2 * ASAN_RED_ZONE_SIZE)
+    return false;
+
+  rtl = DECL_RTL (decl);
+  if (!MEM_P (rtl) || GET_CODE (XEXP (rtl, 0)) != SYMBOL_REF)
+    return false;
+  symbol = XEXP (rtl, 0);
+
+  if (CONSTANT_POOL_ADDRESS_P (symbol)
+      || TREE_CONSTANT_POOL_ADDRESS_P (symbol))
+    return false;
+
+  sect = get_variable_section (decl, false);
+  if (sect->common.flags & SECTION_COMMON)
+    return false;
+
+  if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
+    return false;
+
+#ifndef ASM_OUTPUT_DEF
+  if (asan_needs_local_alias (decl))
+    return false;
+#endif
+
+  return true;    
+}
+
 /* Construct a function tree for __asan_report_{load,store}{1,2,4,8,16}.
    IS_STORE is either 1 (for a store) or 0 (for a load).
    SIZE_IN_BYTES is one of 1, 2, 4, 8, 16.  */
@@ -568,6 +653,101 @@  transform_statements (void)
     }
 }
 
+/* Build
+   struct __asan_global
+   {
+     const void *__beg;
+     uptr __size;
+     uptr __size_with_redzone;
+     const void *__name;
+     uptr __has_dynamic_init;
+   } type.  */
+
+static tree
+asan_global_struct (void)
+{
+  static const char *field_names[5]
+    = { "__beg", "__size", "__size_with_redzone",
+	"__name", "__has_dynamic_init" };
+  tree fields[5], ret;
+  int i;
+
+  ret = make_node (RECORD_TYPE);
+  for (i = 0; i < 5; i++)
+    {
+      fields[i]
+	= build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+		      get_identifier (field_names[i]),
+		      (i == 0 || i == 3) ? const_ptr_type_node
+		      : build_nonstandard_integer_type (POINTER_SIZE, 1));
+      DECL_CONTEXT (fields[i]) = ret;
+      if (i)
+	DECL_CHAIN (fields[i - 1]) = fields[i];
+    }
+  TYPE_FIELDS (ret) = fields[0];
+  TYPE_NAME (ret) = get_identifier ("__asan_global");
+  layout_type (ret);
+  return ret;
+}
+
+/* Append description of a single global DECL into vector V.
+   TYPE is __asan_global struct type as returned by asan_global_struct.  */
+
+static void
+asan_add_global (tree decl, tree type, VEC(constructor_elt, gc) *v)
+{
+  tree init, uptr = TREE_TYPE (DECL_CHAIN (TYPE_FIELDS (type)));
+  unsigned HOST_WIDE_INT size;
+  tree str_cst, refdecl = decl;
+  VEC(constructor_elt, gc) *vinner = NULL;
+
+  if (!asan_pp_initialized)
+    asan_pp_initialize ();
+
+  pp_clear_output_area (&asan_pp);
+  if (DECL_NAME (decl))
+    pp_base_tree_identifier (&asan_pp, DECL_NAME (decl));
+  else
+    pp_string (&asan_pp, "<unknown>");
+  pp_space (&asan_pp);
+  pp_left_paren (&asan_pp);
+  pp_string (&asan_pp, main_input_filename);
+  pp_right_paren (&asan_pp);
+  str_cst = asan_pp_string ();
+
+  if (asan_needs_local_alias (decl))
+    {
+      char buf[20];
+      ASM_GENERATE_INTERNAL_LABEL (buf, "LASAN",
+				   VEC_length (constructor_elt, v) + 1);
+      refdecl = build_decl (DECL_SOURCE_LOCATION (decl),
+			    VAR_DECL, get_identifier (buf), TREE_TYPE (decl));
+      TREE_ADDRESSABLE (refdecl) = TREE_ADDRESSABLE (decl);
+      TREE_READONLY (refdecl) = TREE_READONLY (decl);
+      TREE_THIS_VOLATILE (refdecl) = TREE_THIS_VOLATILE (decl);
+      DECL_GIMPLE_REG_P (refdecl) = DECL_GIMPLE_REG_P (decl);
+      DECL_ARTIFICIAL (refdecl) = DECL_ARTIFICIAL (decl);
+      DECL_IGNORED_P (refdecl) = DECL_IGNORED_P (decl);
+      TREE_STATIC (refdecl) = 1;
+      TREE_PUBLIC (refdecl) = 0;
+      TREE_USED (refdecl) = 1;
+      assemble_alias (refdecl, DECL_ASSEMBLER_NAME (decl));
+    }
+
+  CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
+			  fold_convert (const_ptr_type_node,
+					build_fold_addr_expr (refdecl)));
+  size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+  CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, size));
+  size += asan_red_zone_size (size);
+  CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, size));
+  CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
+			  fold_convert (const_ptr_type_node, str_cst));
+  CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, 0));
+  init = build_constructor (type, vinner);
+  CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init);
+}
+
 /* Module-level instrumentation.
    - Insert __asan_init() into the list of CTORs.
    - TODO: insert redzones around globals.
@@ -577,10 +757,61 @@  void
 asan_finish_file (void)
 {
   tree ctor_statements = NULL_TREE;
+  struct varpool_node *vnode;
+  unsigned HOST_WIDE_INT gcount = 0;
+
   append_to_statement_list (build_call_expr (asan_init_func (), 0),
-                            &ctor_statements);
+			    &ctor_statements);
+  FOR_EACH_DEFINED_VARIABLE (vnode)
+    if (asan_protect_global (vnode->symbol.decl))
+      ++gcount;
+  if (gcount)
+    {
+      tree type = asan_global_struct (), var, ctor, decl;
+      tree uptr = build_nonstandard_integer_type (POINTER_SIZE, 1);
+      tree dtor_statements = NULL_TREE;
+      VEC(constructor_elt, gc) *v;
+      char buf[20];
+
+      type = build_array_type_nelts (type, gcount);
+      ASM_GENERATE_INTERNAL_LABEL (buf, "LASAN", 0);
+      var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (buf),
+			type);
+      TREE_STATIC (var) = 1;
+      TREE_PUBLIC (var) = 0;
+      DECL_ARTIFICIAL (var) = 1;
+      DECL_IGNORED_P (var) = 1;
+      v = VEC_alloc (constructor_elt, gc, gcount);
+      FOR_EACH_DEFINED_VARIABLE (vnode)
+	if (asan_protect_global (vnode->symbol.decl))
+	  asan_add_global (vnode->symbol.decl, TREE_TYPE (type), v);
+      ctor = build_constructor (type, v);
+      TREE_CONSTANT (ctor) = 1;
+      TREE_STATIC (ctor) = 1;
+      DECL_INITIAL (var) = ctor;
+      varpool_assemble_decl (varpool_node (var));
+
+      type = build_function_type_list (void_type_node,
+				       build_pointer_type (TREE_TYPE (type)),
+				       uptr, NULL_TREE);
+      decl = build_fn_decl ("__asan_register_globals", type);
+      TREE_NOTHROW (decl) = 1;
+      append_to_statement_list (build_call_expr (decl, 2,
+						 build_fold_addr_expr (var),
+						 build_int_cst (uptr, gcount)),
+				&ctor_statements);
+
+      decl = build_fn_decl ("__asan_unregister_globals", type);
+      TREE_NOTHROW (decl) = 1;
+      append_to_statement_list (build_call_expr (decl, 2,
+						 build_fold_addr_expr (var),
+						 build_int_cst (uptr, gcount)),
+				&dtor_statements);
+      cgraph_build_static_cdtor ('D', dtor_statements,
+				 MAX_RESERVED_INIT_PRIORITY - 1);
+    }
   cgraph_build_static_cdtor ('I', ctor_statements,
-                             MAX_RESERVED_INIT_PRIORITY - 1);
+			     MAX_RESERVED_INIT_PRIORITY - 1);
 }
 
 /* Initialize shadow_ptr_types array.  */
diff --git a/gcc/asan.h b/gcc/asan.h
index 6f0edbf..d9368a8 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -23,6 +23,7 @@  along with GCC; see the file COPYING3.  If not see
 
 extern void asan_finish_file (void);
 extern rtx asan_emit_stack_protection (rtx, HOST_WIDE_INT *, tree *, int);
+extern bool asan_protect_global (tree);
 
 /* Alias set for accessing the shadow memory.  */
 extern alias_set_type asan_shadow_set;
@@ -56,4 +57,14 @@  asan_protect_stack_decl (tree decl)
   return DECL_P (decl) && !DECL_ARTIFICIAL (decl);
 }
 
+/* Return the size of padding needed to insert after a protected
+   decl of SIZE.  */
+
+static inline unsigned int
+asan_red_zone_size (unsigned int size)
+{
+  unsigned int c = size & (ASAN_RED_ZONE_SIZE - 1);
+  return c ? 2 * ASAN_RED_ZONE_SIZE - c : ASAN_RED_ZONE_SIZE;
+}
+
 #endif /* TREE_ASAN */
diff --git a/gcc/varasm.c b/gcc/varasm.c
index b300348..8a533ed 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -51,6 +51,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "tree-mudflap.h"
 #include "cgraph.h"
 #include "pointer-set.h"
+#include "asan.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"		/* Needed for external data
@@ -1831,6 +1832,9 @@  assemble_noswitch_variable (tree decl, const char *name, section *sect)
   size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
   rounded = size;
 
+  if (flag_asan && asan_protect_global (decl))
+    size += asan_red_zone_size (size);
+
   /* Don't allocate zero bytes of common,
      since that means "undefined external" in the linker.  */
   if (size == 0)
@@ -1897,6 +1901,7 @@  assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   const char *name;
   rtx decl_rtl, symbol;
   section *sect;
+  bool asan_protected = false;
 
   /* This function is supposed to handle VARIABLES.  Ensure we have one.  */
   gcc_assert (TREE_CODE (decl) == VAR_DECL);
@@ -1984,6 +1989,15 @@  assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
   /* Compute the alignment of this data.  */
 
   align_variable (decl, dont_output_data);
+
+  if (flag_asan
+      && asan_protect_global (decl)
+      && DECL_ALIGN (decl) < ASAN_RED_ZONE_SIZE * BITS_PER_UNIT)
+    {
+      asan_protected = true;
+      DECL_ALIGN (decl) = ASAN_RED_ZONE_SIZE * BITS_PER_UNIT;
+    }
+
   set_mem_align (decl_rtl, DECL_ALIGN (decl));
 
   if (TREE_PUBLIC (decl))
@@ -2022,6 +2036,12 @@  assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
       if (DECL_ALIGN (decl) > BITS_PER_UNIT)
 	ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
       assemble_variable_contents (decl, name, dont_output_data);
+      if (asan_protected)
+	{
+	  unsigned HOST_WIDE_INT int size
+	    = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+	  assemble_zeros (asan_red_zone_size (size));
+	}
     }
 }
 
@@ -6926,6 +6946,8 @@  place_block_symbol (rtx symbol)
       decl = SYMBOL_REF_DECL (symbol);
       alignment = DECL_ALIGN (decl);
       size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+      if (flag_asan && asan_protect_global (decl))
+	size += asan_red_zone_size (size);
     }
 
   /* Calculate the object's offset from the start of the block.  */