Implement protection of global variables
This patch implements the protection of global variables. See the comments appended to the beginning of the asan.c file. * 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, asan_ctor_statements): 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. Use asan_ctor_statements instead of ctor_statements * asan.h (asan_protect_global): New prototype. (asan_red_zone_size): New inline function. Co-Authored-By: Wei Mi <wmi@google.com> From-SVN: r193437
This commit is contained in:
parent
f3ddd6929a
commit
8240018b0c
5 changed files with 365 additions and 38 deletions
|
@ -1,3 +1,27 @@
|
|||
2012-11-12 Jakub Jelinek <jakub@redhat.com>
|
||||
Wei Mi <wmi@google.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, asan_ctor_statements): 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. Use
|
||||
asan_ctor_statements instead of ctor_statements
|
||||
* asan.h (asan_protect_global): New prototype.
|
||||
(asan_red_zone_size): New inline function.
|
||||
|
||||
2012-11-12 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* Makefile.in (asan.o): Depend on $(EXPR_H) $(OPTABS_H).
|
||||
|
|
|
@ -2719,7 +2719,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) \
|
||||
|
|
344
gcc/asan.c
344
gcc/asan.c
|
@ -31,6 +31,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
|
||||
|
@ -166,7 +167,43 @@ along with GCC; see the file COPYING3. If not see
|
|||
non-accessible) the regions of the red zones and mark the regions of
|
||||
stack variables as accessible, and emit some epilogue code to
|
||||
un-poison (mark as accessible) the regions of red zones right before
|
||||
the function exits. */
|
||||
the function exits.
|
||||
|
||||
[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 global variables are laid out 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 a constructor function is installed so that, for each global
|
||||
variable, it 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;
|
||||
}
|
||||
|
||||
A destructor function that calls the runtime asan library function
|
||||
_asan_unregister_globals is also installed. */
|
||||
|
||||
alias_set_type asan_shadow_set = -1;
|
||||
|
||||
|
@ -174,6 +211,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
|
||||
|
@ -208,51 +273,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),
|
||||
|
@ -357,6 +409,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. */
|
||||
|
@ -657,6 +778,105 @@ 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);
|
||||
}
|
||||
|
||||
/* Needs to be GTY(()), because cgraph_build_static_cdtor may
|
||||
invoke ggc_collect. */
|
||||
static GTY(()) tree asan_ctor_statements;
|
||||
|
||||
/* Module-level instrumentation.
|
||||
- Insert __asan_init() into the list of CTORs.
|
||||
- TODO: insert redzones around globals.
|
||||
|
@ -665,11 +885,61 @@ transform_statements (void)
|
|||
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);
|
||||
cgraph_build_static_cdtor ('I', ctor_statements,
|
||||
MAX_RESERVED_INIT_PRIORITY - 1);
|
||||
&asan_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_for_decl (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)),
|
||||
&asan_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', asan_ctor_statements,
|
||||
MAX_RESERVED_INIT_PRIORITY - 1);
|
||||
}
|
||||
|
||||
/* Initialize shadow_ptr_types array. */
|
||||
|
|
11
gcc/asan.h
11
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 */
|
||||
|
|
22
gcc/varasm.c
22
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))
|
||||
{
|
||||
asan_protected = true;
|
||||
DECL_ALIGN (decl) = MAX (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. */
|
||||
|
|
Loading…
Add table
Reference in a new issue