aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKito Cheng <kito.cheng@sifive.com>2024-11-15 12:14:54 +0800
committerKito Cheng <kito.cheng@sifive.com>2024-11-25 06:34:33 +0000
commit63c68752768fd6d67c695e09c85e0e1ca59cd6d4 (patch)
treedb22e5ec77d788752b497e3f8246f8a66096a2ec
parente4f4b2dc08b6720acab563db48fd4b0427d2b0c6 (diff)
downloadgcc-63c68752768fd6d67c695e09c85e0e1ca59cd6d4.zip
gcc-63c68752768fd6d67c695e09c85e0e1ca59cd6d4.tar.gz
gcc-63c68752768fd6d67c695e09c85e0e1ca59cd6d4.tar.bz2
asan: Support dynamic shadow offset
AddressSanitizer has supported dynamic shadow offsets since 2016[1], but GCC hasn't implemented this yet because targets using dynamic shadow offsets, such as Fuchsia and iOS, are mostly unsupported in GCC. However, RISC-V 64 switched to dynamic shadow offsets this year[2] because virtual memory space support varies across different RISC-V cores, such as Sv39, Sv48, and Sv57. We realized that the best way to handle this situation is by using a dynamic shadow offset to obtain the offset at runtime. We introduce a new target hook, TARGET_ASAN_DYNAMIC_SHADOW_OFFSET_P, to determine if the target is using a dynamic shadow offset, so this change won't affect the static offset path. Additionally, TARGET_ASAN_SHADOW_OFFSET continues to work even if TARGET_ASAN_DYNAMIC_SHADOW_OFFSET_P is non-zero, ensuring that KASAN functions as expected. This patch set has been verified on the Banana Pi F3, currently one of the most popular RISC-V development boards. All AddressSanitizer-related tests passed without introducing new regressions. It was also verified on AArch64 and x86_64 with no regressions in AddressSanitizer. [1] https://github.com/llvm/llvm-project/commit/130a190bf08a3d955d9db24dac936159dc049e12 [2] https://github.com/llvm/llvm-project/commit/da0c8b275564f814a53a5c19497669ae2d99538d gcc/ChangeLog: * asan.cc (asan_dynamic_shadow_offset_p): New. (asan_shadow_memory_dynamic_address): New. (asan_local_shadow_memory_dynamic_address): New. (get_asan_shadow_memory_dynamic_address_decl): New. (asan_maybe_insert_dynamic_shadow_at_function_entry): New. (asan_emit_stack_protection): Support dynamic shadow offset. (build_shadow_mem_access): Ditto. * asan.h (asan_maybe_insert_dynamic_shadow_at_function_entry): New. * doc/tm.texi (TARGET_ASAN_DYNAMIC_SHADOW_OFFSET_P): New. * doc/tm.texi.in (TARGET_ASAN_DYNAMIC_SHADOW_OFFSET_P): Ditto. * sanopt.cc (pass_sanopt::execute): Handle dynamic shadow offset. * target.def (asan_dynamic_shadow_offset_p): New. * toplev.cc (process_options): Handle dynamic shadow offset.
-rw-r--r--gcc/asan.cc80
-rw-r--r--gcc/asan.h3
-rw-r--r--gcc/doc/tm.texi6
-rw-r--r--gcc/doc/tm.texi.in2
-rw-r--r--gcc/sanopt.cc4
-rw-r--r--gcc/target.def8
-rw-r--r--gcc/toplev.cc3
7 files changed, 98 insertions, 8 deletions
diff --git a/gcc/asan.cc b/gcc/asan.cc
index 087595b..a54ecf2 100644
--- a/gcc/asan.cc
+++ b/gcc/asan.cc
@@ -457,6 +457,13 @@ asan_shadow_offset ()
return asan_shadow_offset_value;
}
+static bool
+asan_dynamic_shadow_offset_p ()
+{
+ return (asan_shadow_offset_value == 0)
+ && targetm.asan_dynamic_shadow_offset_p ();
+}
+
/* Returns Asan shadow offset has been set. */
bool
asan_shadow_offset_set_p ()
@@ -473,6 +480,55 @@ static GTY(()) tree shadow_ptr_types[3];
/* Decl for __asan_option_detect_stack_use_after_return. */
static GTY(()) tree asan_detect_stack_use_after_return;
+static GTY (()) tree asan_shadow_memory_dynamic_address;
+
+/* Local copy for the asan_shadow_memory_dynamic_address within the
+ function. */
+static GTY (()) tree asan_local_shadow_memory_dynamic_address;
+
+static tree
+get_asan_shadow_memory_dynamic_address_decl ()
+{
+ if (asan_shadow_memory_dynamic_address == NULL_TREE)
+ {
+ tree id, decl;
+ id = get_identifier ("__asan_shadow_memory_dynamic_address");
+ decl
+ = build_decl (BUILTINS_LOCATION, VAR_DECL, id, pointer_sized_int_node);
+ SET_DECL_ASSEMBLER_NAME (decl, id);
+ TREE_ADDRESSABLE (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ DECL_EXTERNAL (decl) = 1;
+ TREE_STATIC (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+ TREE_USED (decl) = 1;
+ asan_shadow_memory_dynamic_address = decl;
+ }
+
+ return asan_shadow_memory_dynamic_address;
+}
+
+void
+asan_maybe_insert_dynamic_shadow_at_function_entry (function *fun)
+{
+ asan_local_shadow_memory_dynamic_address = NULL_TREE;
+ if (!asan_dynamic_shadow_offset_p ())
+ return;
+
+ gimple *g;
+
+ tree lhs = create_tmp_var (pointer_sized_int_node,
+ "__local_asan_shadow_memory_dynamic_address");
+
+ g = gimple_build_assign (lhs, get_asan_shadow_memory_dynamic_address_decl ());
+ gimple_set_location (g, fun->function_start_locus);
+ edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ gsi_insert_on_edge_immediate (e, g);
+
+ asan_local_shadow_memory_dynamic_address = lhs;
+}
+
/* Hashtable support for memory references used by gimple
statements. */
@@ -2033,10 +2089,21 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
shadow_base = expand_binop (Pmode, lshr_optab, base,
gen_int_shift_amount (Pmode, ASAN_SHADOW_SHIFT),
NULL_RTX, 1, OPTAB_DIRECT);
- shadow_base
- = plus_constant (Pmode, shadow_base,
- asan_shadow_offset ()
- + (base_align_bias >> ASAN_SHADOW_SHIFT));
+ if (asan_dynamic_shadow_offset_p ())
+ {
+ ret = expand_normal (get_asan_shadow_memory_dynamic_address_decl ());
+ shadow_base
+ = expand_simple_binop (Pmode, PLUS, shadow_base, ret, NULL_RTX,
+ /* unsignedp = */ 1, OPTAB_WIDEN);
+ shadow_base = plus_constant (Pmode, shadow_base,
+ (base_align_bias >> ASAN_SHADOW_SHIFT));
+ }
+ else
+ {
+ shadow_base = plus_constant (Pmode, shadow_base,
+ asan_shadow_offset ()
+ + (base_align_bias >> ASAN_SHADOW_SHIFT));
+ }
gcc_assert (asan_shadow_set != -1
&& (ASAN_RED_ZONE_SIZE >> ASAN_SHADOW_SHIFT) == 4);
shadow_mem = gen_rtx_MEM (SImode, shadow_base);
@@ -2558,7 +2625,10 @@ build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location,
gimple_set_location (g, location);
gsi_insert_after (gsi, g, GSI_NEW_STMT);
- t = build_int_cst (uintptr_type, asan_shadow_offset ());
+ if (asan_dynamic_shadow_offset_p ())
+ t = asan_local_shadow_memory_dynamic_address;
+ else
+ t = build_int_cst (uintptr_type, asan_shadow_offset ());
g = gimple_build_assign (make_ssa_name (uintptr_type), PLUS_EXPR,
gimple_assign_lhs (g), t);
gimple_set_location (g, location);
diff --git a/gcc/asan.h b/gcc/asan.h
index d1bf8b1..fd80a62 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -35,6 +35,9 @@ extern bool asan_expand_poison_ifn (gimple_stmt_iterator *, bool *,
hash_map<tree, tree> &);
extern rtx asan_memfn_rtl (tree);
+extern void
+asan_maybe_insert_dynamic_shadow_at_function_entry (function *);
+
extern void hwasan_record_frame_init ();
extern void hwasan_record_stack_var (rtx, rtx, poly_int64, poly_int64);
extern void hwasan_emit_prologue ();
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 7ff4537..31b8c29 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -12619,7 +12619,11 @@ is zero, which disables this optimization.
Return the offset bitwise ored into shifted address to get corresponding
Address Sanitizer shadow memory address. NULL if Address Sanitizer is not
supported by the target. May return 0 if Address Sanitizer is not supported
-by a subtarget.
+or using dynamic shadow offset by a subtarget.
+@end deftypefn
+
+@deftypefn {Target Hook} bool TARGET_ASAN_DYNAMIC_SHADOW_OFFSET_P (void)
+Return true if asan should use dynamic shadow offset.
@end deftypefn
@deftypefn {Target Hook} {unsigned HOST_WIDE_INT} TARGET_MEMMODEL_CHECK (unsigned HOST_WIDE_INT @var{val})
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 73643c2..8813975 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -8046,6 +8046,8 @@ and the associated definitions of those functions.
@hook TARGET_ASAN_SHADOW_OFFSET
+@hook TARGET_ASAN_DYNAMIC_SHADOW_OFFSET_P
+
@hook TARGET_MEMMODEL_CHECK
@hook TARGET_ATOMIC_TEST_AND_SET_TRUEVAL
diff --git a/gcc/sanopt.cc b/gcc/sanopt.cc
index 604db6b..581bb5a 100644
--- a/gcc/sanopt.cc
+++ b/gcc/sanopt.cc
@@ -1320,6 +1320,10 @@ pass_sanopt::execute (function *fun)
}
}
+ if (asan_num_accesses || contains_asan_mark || asan_sanitize_stack_p ()
+ || hwasan_sanitize_stack_p ())
+ asan_maybe_insert_dynamic_shadow_at_function_entry (fun);
+
if (contains_asan_mark)
{
sanitize_asan_mark_unpoison ();
diff --git a/gcc/target.def b/gcc/target.def
index 000dd11..2697870 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4700,10 +4700,16 @@ DEFHOOK
"Return the offset bitwise ored into shifted address to get corresponding\n\
Address Sanitizer shadow memory address. NULL if Address Sanitizer is not\n\
supported by the target. May return 0 if Address Sanitizer is not supported\n\
-by a subtarget.",
+or using dynamic shadow offset by a subtarget.",
unsigned HOST_WIDE_INT, (void),
NULL)
+DEFHOOK
+(asan_dynamic_shadow_offset_p,
+ "Return true if asan should use dynamic shadow offset.",
+ bool, (void),
+ hook_bool_void_false)
+
/* Functions relating to calls - argument passing, returns, etc. */
/* Members of struct call have no special macro prefix. */
HOOK_VECTOR (TARGET_CALLS, calls)
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
index 1bb94db..7eb7733 100644
--- a/gcc/toplev.cc
+++ b/gcc/toplev.cc
@@ -1693,7 +1693,8 @@ process_options ()
if ((flag_sanitize & SANITIZE_USER_ADDRESS)
&& ((targetm.asan_shadow_offset == NULL)
- || (targetm.asan_shadow_offset () == 0)))
+ || ((targetm.asan_shadow_offset () == 0)
+ && !targetm.asan_dynamic_shadow_offset_p ())))
{
warning_at (UNKNOWN_LOCATION, 0,
"%<-fsanitize=address%> not supported for this target");