https://gcc.gnu.org/g:63c68752768fd6d67c695e09c85e0e1ca59cd6d4

commit r15-5644-g63c68752768fd6d67c695e09c85e0e1ca59cd6d4
Author: Kito Cheng <kito.ch...@sifive.com>
Date:   Fri Nov 15 12:14:54 2024 +0800

    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.

Diff:
---
 gcc/asan.cc        | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 gcc/asan.h         |  3 ++
 gcc/doc/tm.texi    |  6 +++-
 gcc/doc/tm.texi.in |  2 ++
 gcc/sanopt.cc      |  4 +++
 gcc/target.def     |  8 +++++-
 gcc/toplev.cc      |  3 +-
 7 files changed, 98 insertions(+), 8 deletions(-)

diff --git a/gcc/asan.cc b/gcc/asan.cc
index 087595bd9c70..a54ecf2b1ed5 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 d1bf8b1e701b..fd80a62ed240 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 7ff45373d590..31b8c29dd446 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 73643c239ca6..88139757191e 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 604db6b3912a..581bb5af709e 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 000dd1167989..269787023e45 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 1bb94db3916f..7eb7733c2761 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");

Reply via email to