[gcc(refs/users/aoliva/heads/testme)] strub: sparc64: unbias the stack address [PR112917]

Alexandre Oliva aoliva@gcc.gnu.org
Thu Dec 14 13:45:33 GMT 2023


https://gcc.gnu.org/g:d5eaad6f06d5b8903a2e2e530add56c9fb6117a5

commit d5eaad6f06d5b8903a2e2e530add56c9fb6117a5
Author: Alexandre Oliva <oliva@adacore.com>
Date:   Thu Dec 14 04:50:45 2023 -0300

    strub: sparc64: unbias the stack address [PR112917]
    
    The stack pointer is biased by 2047 bytes on sparc64, so the range it
    delimits is way off.  Unbias the addresses returned by
    __builtin_stack_address (), so that the strub builtins, inlined or
    not, can function correctly.  I've considered introducing a new target
    macro, but using STACK_POINTER_OFFSET seems safe.
    
    Because of the large fixed-size outgoing args area next to the
    register save area on sparc, we still need __strub_leave to not
    allocate its own frame, otherwise it won't be able to clear part of
    the frame it should.
    
    
    for  gcc/ChangeLog
    
            PR middle-end/112917
            * builtins.cc (expand_bultin_stack_address): Add
            STACK_POINTER_OFFSET.

Diff:
---
 gcc/builtins.cc | 34 ++++++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index 7c2732ab79e..71116c6ab45 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -5443,8 +5443,38 @@ expand_builtin_frame_address (tree fndecl, tree exp)
 static rtx
 expand_builtin_stack_address ()
 {
-  return convert_to_mode (ptr_mode, copy_to_reg (stack_pointer_rtx),
-			  STACK_UNSIGNED);
+  rtx ret = convert_to_mode (ptr_mode, copy_to_reg (stack_pointer_rtx),
+			     STACK_UNSIGNED);
+
+  /* Unbias the stack pointer, bringing it to the boundary between the
+     stack area claimed by the active function calling this builtin,
+     and stack ranges that could get clobbered if it called another
+     function.  It should NOT encompass any stack red zone, that is
+     used in leaf functions.
+
+     On SPARC, the register save area is *not* considered active or
+     used by the active function, but rather as akin to the area in
+     which call-preserved registers are saved by callees.  This
+     enables __strub_leave to clear what would otherwise overlap with
+     its own register save area.
+
+     If the address is computed too high or too low, parts of a stack
+     range that should be scrubbed may be left unscrubbed, scrubbing
+     may corrupt active portions of the stack frame, and stack ranges
+     may be doubly-scrubbed by caller and callee.
+
+     In order for it to be just right, the area delimited by
+     @code{__builtin_stack_address} and @code{__builtin_frame_address
+     (0)} should encompass caller's registers saved by the function,
+     local on-stack variables and @code{alloca} stack areas.
+     Accumulated outgoing on-stack arguments, preallocated as part of
+     a function's own prologue, are to be regarded as part of the
+     (caller) function's active area as well, whereas those pushed or
+     allocated temporarily for a call are regarded as part of the
+     callee's stack range, rather than the caller's.  */
+  ret = plus_constant (ptr_mode, ret, STACK_POINTER_OFFSET);
+
+  return force_operand (ptr_mode, ret);
 }
 
 /* Expand a call to builtin function __builtin_strub_enter.  */


More information about the Gcc-cvs mailing list