rs6000-common.c (TARGET_SUPPORTS_SPLIT_STACK): Define.

gcc/
	* common/config/rs6000/rs6000-common.c (TARGET_SUPPORTS_SPLIT_STACK):
	Define.
	(rs6000_supports_split_stack): New function.
	* gcc/config/rs6000/rs6000.c (machine_function): Add
	split_stack_arg_pointer.
	(TARGET_EXTRA_LIVE_ON_ENTRY, TARGET_INTERNAL_ARG_POINTER): Define.
	(setup_incoming_varargs): Use crtl->args.internal_arg_pointer
	rather than virtual_incoming_args_rtx.
	(rs6000_va_start): Likewise.
	(split_stack_arg_pointer_used_p): New function.
	(rs6000_emit_prologue): Set up arg pointer for -fsplit-stack.
	(morestack_ref): New var.
	(gen_add3_const, rs6000_expand_split_stack_prologue,
	rs6000_internal_arg_pointer, rs6000_live_on_entry,
	rs6000_split_stack_space_check): New functions.
	(rs6000_elf_file_end): Call file_end_indicate_split_stack.
	* gcc/config/rs6000/rs6000.md (UNSPEC_STACK_CHECK): Define.
	(UNSPECV_SPLIT_STACK_RETURN): Define.
	(split_stack_prologue, load_split_stack_limit,
	load_split_stack_limit_di, load_split_stack_limit_si,
	split_stack_return, split_stack_space_check): New expands and insns.
	* gcc/config/rs6000/rs6000-protos.h
	(rs6000_expand_split_stack_prologue): Declare.
	(rs6000_split_stack_space_check): Declare.
libgcc/
	* config/rs6000/morestack.S: New.
	* config/rs6000/t-stack-rs6000: New.
	* config.host (powerpc*-*-linux*): Add t-stack and t-stack-rs6000
	to tmake_file.
	* generic-morestack.c: Don't build for powerpc 32-bit.

From-SVN: r223426
This commit is contained in:
Alan Modra 2015-05-20 10:56:28 +09:30 committed by Alan Modra
parent 8a03f86937
commit 0f0fd74525
10 changed files with 754 additions and 2 deletions

View file

@ -1,3 +1,30 @@
2015-05-20 Alan Modra <amodra@gmail.com>
* common/config/rs6000/rs6000-common.c (TARGET_SUPPORTS_SPLIT_STACK):
Define.
(rs6000_supports_split_stack): New function.
* gcc/config/rs6000/rs6000.c (machine_function): Add
split_stack_arg_pointer.
(TARGET_EXTRA_LIVE_ON_ENTRY, TARGET_INTERNAL_ARG_POINTER): Define.
(setup_incoming_varargs): Use crtl->args.internal_arg_pointer
rather than virtual_incoming_args_rtx.
(rs6000_va_start): Likewise.
(split_stack_arg_pointer_used_p): New function.
(rs6000_emit_prologue): Set up arg pointer for -fsplit-stack.
(morestack_ref): New var.
(gen_add3_const, rs6000_expand_split_stack_prologue,
rs6000_internal_arg_pointer, rs6000_live_on_entry,
rs6000_split_stack_space_check): New functions.
(rs6000_elf_file_end): Call file_end_indicate_split_stack.
* gcc/config/rs6000/rs6000.md (UNSPEC_STACK_CHECK): Define.
(UNSPECV_SPLIT_STACK_RETURN): Define.
(split_stack_prologue, load_split_stack_limit,
load_split_stack_limit_di, load_split_stack_limit_si,
split_stack_return, split_stack_space_check): New expands and insns.
* gcc/config/rs6000/rs6000-protos.h
(rs6000_expand_split_stack_prologue): Declare.
(rs6000_split_stack_space_check): Declare.
2015-05-20 Alan Modra <amodra@gmail.com>
* config/rs6000/rs6000.c (struct rs6000_stack): Correct comments.

View file

@ -288,6 +288,31 @@ rs6000_handle_option (struct gcc_options *opts, struct gcc_options *opts_set,
return true;
}
/* -fsplit-stack uses a field in the TCB, available with glibc-2.19.
We also allow 2.18 because alignment padding guarantees that the
space is available there too. */
static bool
rs6000_supports_split_stack (bool report,
struct gcc_options *opts ATTRIBUTE_UNUSED)
{
#ifndef TARGET_GLIBC_MAJOR
#define TARGET_GLIBC_MAJOR 0
#endif
#ifndef TARGET_GLIBC_MINOR
#define TARGET_GLIBC_MINOR 0
#endif
/* Note: Can't test DEFAULT_ABI here, it isn't set until later. */
if (TARGET_GLIBC_MAJOR * 1000 + TARGET_GLIBC_MINOR >= 2018
&& TARGET_64BIT
&& TARGET_ELF)
return true;
if (report)
error ("%<-fsplit-stack%> currently only supported on PowerPC64 GNU/Linux with glibc-2.18 or later");
return false;
}
#undef TARGET_HANDLE_OPTION
#define TARGET_HANDLE_OPTION rs6000_handle_option
@ -300,4 +325,7 @@ rs6000_handle_option (struct gcc_options *opts, struct gcc_options *opts_set,
#undef TARGET_OPTION_OPTIMIZATION_TABLE
#define TARGET_OPTION_OPTIMIZATION_TABLE rs6000_option_optimization_table
#undef TARGET_SUPPORTS_SPLIT_STACK
#define TARGET_SUPPORTS_SPLIT_STACK rs6000_supports_split_stack
struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;

View file

@ -191,6 +191,8 @@ extern void rs6000_emit_prologue (void);
extern void rs6000_emit_load_toc_table (int);
extern unsigned int rs6000_dbx_register_number (unsigned int, unsigned int);
extern void rs6000_emit_epilogue (int);
extern void rs6000_expand_split_stack_prologue (void);
extern void rs6000_split_stack_space_check (rtx, rtx);
extern void rs6000_emit_eh_reg_restore (rtx, rtx);
extern const char * output_isel (rtx *);
extern void rs6000_call_aix (rtx, rtx, rtx, rtx);

View file

@ -187,6 +187,8 @@ typedef struct GTY(()) machine_function
64-bits wide and is allocated early enough so that the offset
does not overflow the 16-bit load/store offset field. */
rtx sdmode_stack_slot;
/* Alternative internal arg pointer for -fsplit-stack. */
rtx split_stack_arg_pointer;
/* Flag if r2 setup is needed with ELFv2 ABI. */
bool r2_setup_needed;
} machine_function;
@ -1190,6 +1192,7 @@ static bool rs6000_debug_cannot_change_mode_class (machine_mode,
machine_mode,
enum reg_class);
static bool rs6000_save_toc_in_prologue_p (void);
static rtx rs6000_internal_arg_pointer (void);
rtx (*rs6000_legitimize_reload_address_ptr) (rtx, machine_mode, int, int,
int, int *)
@ -1411,6 +1414,12 @@ static const struct attribute_spec rs6000_attribute_table[] =
#undef TARGET_SET_UP_BY_PROLOGUE
#define TARGET_SET_UP_BY_PROLOGUE rs6000_set_up_by_prologue
#undef TARGET_EXTRA_LIVE_ON_ENTRY
#define TARGET_EXTRA_LIVE_ON_ENTRY rs6000_live_on_entry
#undef TARGET_INTERNAL_ARG_POINTER
#define TARGET_INTERNAL_ARG_POINTER rs6000_internal_arg_pointer
#undef TARGET_HAVE_TLS
#define TARGET_HAVE_TLS HAVE_AS_TLS
@ -11150,7 +11159,7 @@ setup_incoming_varargs (cumulative_args_t cum, machine_mode mode,
else
{
first_reg_offset = next_cum.words;
save_area = virtual_incoming_args_rtx;
save_area = crtl->args.internal_arg_pointer;
if (targetm.calls.must_pass_in_stack (mode, type))
first_reg_offset += rs6000_arg_size (TYPE_MODE (type), type);
@ -11344,7 +11353,7 @@ rs6000_va_start (tree valist, rtx nextarg)
}
/* Find the overflow area. */
t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
t = make_tree (TREE_TYPE (ovf), crtl->args.internal_arg_pointer);
if (words != 0)
t = fold_build_pointer_plus_hwi (t, words * MIN_UNITS_PER_WORD);
t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
@ -23424,6 +23433,48 @@ rs6000_reg_live_or_pic_offset_p (int reg)
|| (DEFAULT_ABI == ABI_DARWIN && flag_pic))));
}
/* Return whether the split-stack arg pointer (r12) is used. */
static bool
split_stack_arg_pointer_used_p (void)
{
/* If the pseudo holding the arg pointer is no longer a pseudo,
then the arg pointer is used. */
if (cfun->machine->split_stack_arg_pointer != NULL_RTX
&& (!REG_P (cfun->machine->split_stack_arg_pointer)
|| (REGNO (cfun->machine->split_stack_arg_pointer)
< FIRST_PSEUDO_REGISTER)))
return true;
/* Unfortunately we also need to do some code scanning, since
r12 may have been substituted for the pseudo. */
rtx_insn *insn;
basic_block bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
FOR_BB_INSNS (bb, insn)
if (NONDEBUG_INSN_P (insn))
{
/* A call destroys r12. */
if (CALL_P (insn))
return false;
df_ref use;
FOR_EACH_INSN_USE (use, insn)
{
rtx x = DF_REF_REG (use);
if (REG_P (x) && REGNO (x) == 12)
return true;
}
df_ref def;
FOR_EACH_INSN_DEF (def, insn)
{
rtx x = DF_REF_REG (def);
if (REG_P (x) && REGNO (x) == 12)
return false;
}
}
return bitmap_bit_p (DF_LR_OUT (bb), 12);
}
/* Emit function prologue as insns. */
void
@ -24375,6 +24426,40 @@ rs6000_emit_prologue (void)
rtx reg = gen_rtx_REG (reg_mode, TOC_REGNUM);
emit_insn (gen_frame_store (reg, sp_reg_rtx, RS6000_TOC_SAVE_SLOT));
}
if (flag_split_stack && split_stack_arg_pointer_used_p ())
{
/* Set up the arg pointer (r12) for -fsplit-stack code. If
__morestack was called, it left the arg pointer to the old
stack in r29. Otherwise, the arg pointer is the top of the
current frame. */
if (frame_off != 0 || REGNO (frame_reg_rtx) != 12)
{
rtx r12 = gen_rtx_REG (Pmode, 12);
if (frame_off == 0)
emit_move_insn (r12, frame_reg_rtx);
else
emit_insn (gen_add3_insn (r12, frame_reg_rtx, GEN_INT (frame_off)));
}
if (info->push_p)
{
rtx r12 = gen_rtx_REG (Pmode, 12);
rtx r29 = gen_rtx_REG (Pmode, 29);
rtx cr7 = gen_rtx_REG (CCUNSmode, CR7_REGNO);
rtx not_more = gen_label_rtx ();
rtx jump;
jump = gen_rtx_IF_THEN_ELSE (VOIDmode,
gen_rtx_GEU (VOIDmode, cr7, const0_rtx),
gen_rtx_LABEL_REF (VOIDmode, not_more),
pc_rtx);
jump = emit_jump_insn (gen_rtx_SET (pc_rtx, jump));
JUMP_LABEL (jump) = not_more;
LABEL_NUSES (not_more) += 1;
emit_move_insn (r12, r29);
emit_label (not_more);
}
}
}
/* Output .extern statements for the save/restore routines we use. */
@ -25802,6 +25887,178 @@ rs6000_output_function_epilogue (FILE *file,
fputs ("\t.align 2\n", file);
}
}
/* -fsplit-stack support. */
/* A SYMBOL_REF for __morestack. */
static GTY(()) rtx morestack_ref;
static rtx
gen_add3_const (rtx rt, rtx ra, long c)
{
if (TARGET_64BIT)
return gen_adddi3 (rt, ra, GEN_INT (c));
else
return gen_addsi3 (rt, ra, GEN_INT (c));
}
/* Emit -fsplit-stack prologue, which goes before the regular function
prologue (at local entry point in the case of ELFv2). */
void
rs6000_expand_split_stack_prologue (void)
{
rs6000_stack_t *info = rs6000_stack_info ();
unsigned HOST_WIDE_INT allocate;
long alloc_hi, alloc_lo;
rtx r0, r1, r12, lr, ok_label, compare, jump, call_fusage;
rtx_insn *insn;
gcc_assert (flag_split_stack && reload_completed);
if (!info->push_p)
return;
allocate = info->total_size;
if (allocate > (unsigned HOST_WIDE_INT) 1 << 31)
{
sorry ("Stack frame larger than 2G is not supported for -fsplit-stack");
return;
}
if (morestack_ref == NULL_RTX)
{
morestack_ref = gen_rtx_SYMBOL_REF (Pmode, "__morestack");
SYMBOL_REF_FLAGS (morestack_ref) |= (SYMBOL_FLAG_LOCAL
| SYMBOL_FLAG_FUNCTION);
}
r0 = gen_rtx_REG (Pmode, 0);
r1 = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
r12 = gen_rtx_REG (Pmode, 12);
emit_insn (gen_load_split_stack_limit (r0));
/* Always emit two insns here to calculate the requested stack,
so that the linker can edit them when adjusting size for calling
non-split-stack code. */
alloc_hi = (-allocate + 0x8000) & ~0xffffL;
alloc_lo = -allocate - alloc_hi;
if (alloc_hi != 0)
{
emit_insn (gen_add3_const (r12, r1, alloc_hi));
if (alloc_lo != 0)
emit_insn (gen_add3_const (r12, r12, alloc_lo));
else
emit_insn (gen_nop ());
}
else
{
emit_insn (gen_add3_const (r12, r1, alloc_lo));
emit_insn (gen_nop ());
}
compare = gen_rtx_REG (CCUNSmode, CR7_REGNO);
emit_insn (gen_rtx_SET (compare, gen_rtx_COMPARE (CCUNSmode, r12, r0)));
ok_label = gen_label_rtx ();
jump = gen_rtx_IF_THEN_ELSE (VOIDmode,
gen_rtx_GEU (VOIDmode, compare, const0_rtx),
gen_rtx_LABEL_REF (VOIDmode, ok_label),
pc_rtx);
jump = emit_jump_insn (gen_rtx_SET (pc_rtx, jump));
JUMP_LABEL (jump) = ok_label;
/* Mark the jump as very likely to be taken. */
add_int_reg_note (jump, REG_BR_PROB,
REG_BR_PROB_BASE - REG_BR_PROB_BASE / 100);
lr = gen_rtx_REG (Pmode, LR_REGNO);
insn = emit_move_insn (r0, lr);
RTX_FRAME_RELATED_P (insn) = 1;
insn = emit_insn (gen_frame_store (r0, r1, info->lr_save_offset));
RTX_FRAME_RELATED_P (insn) = 1;
insn = emit_call_insn (gen_call (gen_rtx_MEM (SImode, morestack_ref),
const0_rtx, const0_rtx));
call_fusage = NULL_RTX;
use_reg (&call_fusage, r12);
add_function_usage_to (insn, call_fusage);
emit_insn (gen_frame_load (r0, r1, info->lr_save_offset));
insn = emit_move_insn (lr, r0);
add_reg_note (insn, REG_CFA_RESTORE, lr);
RTX_FRAME_RELATED_P (insn) = 1;
emit_insn (gen_split_stack_return ());
emit_label (ok_label);
LABEL_NUSES (ok_label) = 1;
}
/* Return the internal arg pointer used for function incoming
arguments. When -fsplit-stack, the arg pointer is r12 so we need
to copy it to a pseudo in order for it to be preserved over calls
and suchlike. We'd really like to use a pseudo here for the
internal arg pointer but data-flow analysis is not prepared to
accept pseudos as live at the beginning of a function. */
static rtx
rs6000_internal_arg_pointer (void)
{
if (flag_split_stack)
{
if (cfun->machine->split_stack_arg_pointer == NULL_RTX)
{
rtx pat;
cfun->machine->split_stack_arg_pointer = gen_reg_rtx (Pmode);
REG_POINTER (cfun->machine->split_stack_arg_pointer) = 1;
/* Put the pseudo initialization right after the note at the
beginning of the function. */
pat = gen_rtx_SET (cfun->machine->split_stack_arg_pointer,
gen_rtx_REG (Pmode, 12));
push_topmost_sequence ();
emit_insn_after (pat, get_insns ());
pop_topmost_sequence ();
}
return plus_constant (Pmode, cfun->machine->split_stack_arg_pointer,
FIRST_PARM_OFFSET (current_function_decl));
}
return virtual_incoming_args_rtx;
}
/* We may have to tell the dataflow pass that the split stack prologue
is initializing a register. */
static void
rs6000_live_on_entry (bitmap regs)
{
if (flag_split_stack)
bitmap_set_bit (regs, 12);
}
/* Emit -fsplit-stack dynamic stack allocation space check. */
void
rs6000_split_stack_space_check (rtx size, rtx label)
{
rtx sp = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
rtx limit = gen_reg_rtx (Pmode);
rtx requested = gen_reg_rtx (Pmode);
rtx cmp = gen_reg_rtx (CCUNSmode);
rtx jump;
emit_insn (gen_load_split_stack_limit (limit));
if (CONST_INT_P (size))
emit_insn (gen_add3_insn (requested, sp, GEN_INT (-INTVAL (size))));
else
{
size = force_reg (Pmode, size);
emit_move_insn (requested, gen_rtx_MINUS (Pmode, sp, size));
}
emit_insn (gen_rtx_SET (cmp, gen_rtx_COMPARE (CCUNSmode, requested, limit)));
jump = gen_rtx_IF_THEN_ELSE (VOIDmode,
gen_rtx_GEU (VOIDmode, cmp, const0_rtx),
gen_rtx_LABEL_REF (VOIDmode, label),
pc_rtx);
jump = emit_jump_insn (gen_rtx_SET (pc_rtx, jump));
JUMP_LABEL (jump) = label;
}
/* A C compound statement that outputs the assembler code for a thunk
function, used to implement C++ virtual function calls with
@ -29810,6 +30067,9 @@ rs6000_elf_file_end (void)
if (TARGET_32BIT || DEFAULT_ABI == ABI_ELFv2)
file_end_indicate_exec_stack ();
#endif
if (flag_split_stack)
file_end_indicate_split_stack ();
}
#endif

View file

@ -140,6 +140,7 @@
UNSPEC_PACK_128BIT
UNSPEC_LSQ
UNSPEC_FUSION_GPR
UNSPEC_STACK_CHECK
])
;;
@ -157,6 +158,7 @@
UNSPECV_NLGR ; non-local goto receiver
UNSPECV_MFFS ; Move from FPSCR
UNSPECV_MTFSF ; Move to FPSCR Fields
UNSPECV_SPLIT_STACK_RETURN ; A camouflaged return
])
@ -12345,6 +12347,72 @@
}"
[(set_attr "type" "load")])
;; Handle -fsplit-stack.
(define_expand "split_stack_prologue"
[(const_int 0)]
""
{
rs6000_expand_split_stack_prologue ();
DONE;
})
(define_expand "load_split_stack_limit"
[(set (match_operand 0)
(unspec [(const_int 0)] UNSPEC_STACK_CHECK))]
""
{
emit_insn (gen_rtx_SET (operands[0],
gen_rtx_UNSPEC (Pmode,
gen_rtvec (1, const0_rtx),
UNSPEC_STACK_CHECK)));
DONE;
})
(define_insn "load_split_stack_limit_di"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
(unspec:DI [(const_int 0)] UNSPEC_STACK_CHECK))]
"TARGET_64BIT"
"ld %0,-0x7040(13)"
[(set_attr "type" "load")
(set_attr "update" "no")
(set_attr "indexed" "no")])
(define_insn "load_split_stack_limit_si"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(unspec:SI [(const_int 0)] UNSPEC_STACK_CHECK))]
"!TARGET_64BIT"
"lwz %0,-0x7020(2)"
[(set_attr "type" "load")
(set_attr "update" "no")
(set_attr "indexed" "no")])
;; A return instruction which the middle-end doesn't see.
(define_insn "split_stack_return"
[(unspec_volatile [(const_int 0)] UNSPECV_SPLIT_STACK_RETURN)]
""
"blr"
[(set_attr "type" "jmpreg")])
;; If there are operand 0 bytes available on the stack, jump to
;; operand 1.
(define_expand "split_stack_space_check"
[(set (match_dup 2)
(unspec [(const_int 0)] UNSPEC_STACK_CHECK))
(set (match_dup 3)
(minus (reg STACK_POINTER_REGNUM)
(match_operand 0)))
(set (match_dup 4) (compare:CCUNS (match_dup 3) (match_dup 2)))
(set (pc) (if_then_else
(geu (match_dup 4) (const_int 0))
(label_ref (match_operand 1))
(pc)))]
""
{
rs6000_split_stack_space_check (operands[0], operands[1]);
DONE;
})
(define_insn "bpermd_<mode>"
[(set (match_operand:P 0 "gpc_reg_operand" "=r")
(unspec:P [(match_operand:P 1 "gpc_reg_operand" "r")

View file

@ -1,3 +1,11 @@
2015-05-20 Alan Modra <amodra@gmail.com>
* config/rs6000/morestack.S: New.
* config/rs6000/t-stack-rs6000: New.
* config.host (powerpc*-*-linux*): Add t-stack and t-stack-rs6000
to tmake_file.
* generic-morestack.c: Don't build for powerpc 32-bit.
2015-05-19 Eric Botcazou <ebotcazou@adacore.com>
* Makefile.in (LIBUNWIND): Move dependency for shared libgcc.

View file

@ -1027,6 +1027,7 @@ powerpc-*-rtems*)
;;
powerpc*-*-linux*)
tmake_file="${tmake_file} rs6000/t-ppccomm rs6000/t-savresfgpr rs6000/t-crtstuff rs6000/t-linux t-dfprules rs6000/t-ppc64-fp t-slibgcc-libgcc"
tmake_file="${tmake_file} t-stack rs6000/t-stack-rs6000"
case $ppc_fp_type in
64)
;;

View file

@ -0,0 +1,351 @@
#ifdef __powerpc64__
# PowerPC64 support for -fsplit-stack.
# Copyright (C) 2009-2015 Free Software Foundation, Inc.
# Contributed by Alan Modra <amodra@gmail.com>.
# This file is part of GCC.
# GCC is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 3, or (at your option) any later
# version.
# GCC is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
# Under Section 7 of GPL version 3, you are granted additional
# permissions described in the GCC Runtime Library Exception, version
# 3.1, as published by the Free Software Foundation.
# You should have received a copy of the GNU General Public License and
# a copy of the GCC Runtime Library Exception along with this program;
# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
# <http://www.gnu.org/licenses/>.
#if _CALL_ELF == 2
.abiversion 2
#define PARAMS 32
#else
.abiversion 1
#define PARAMS 48
#endif
#define MORESTACK_FRAMESIZE (PARAMS+96)
#define PARAMREG_SAVE -MORESTACK_FRAMESIZE+PARAMS+0
#define STATIC_CHAIN_SAVE -MORESTACK_FRAMESIZE+PARAMS+64
#define R29_SAVE -MORESTACK_FRAMESIZE+PARAMS+72
#define LINKREG_SAVE -MORESTACK_FRAMESIZE+PARAMS+80
#define NEWSTACKSIZE_SAVE -MORESTACK_FRAMESIZE+PARAMS+88
# Excess space needed to call ld.so resolver for lazy plt
# resolution. Go uses sigaltstack so this doesn't need to
# also cover signal frame size.
#define BACKOFF 4096
# Large excess allocated when calling non-split-stack code.
#define NON_SPLIT_STACK 0x100000
#if _CALL_ELF == 2
#define BODY_LABEL(name) name
#define ENTRY0(name) \
.global name; \
.hidden name; \
.type name,@function; \
name##:
#define ENTRY(name) \
ENTRY0(name); \
0: addis %r2,%r12,.TOC.-0b@ha; \
addi %r2,%r2,.TOC.-0b@l; \
.localentry name, .-name
#else
#define BODY_LABEL(name) .L.##name
#define ENTRY0(name) \
.global name; \
.hidden name; \
.type name,@function; \
.pushsection ".opd","aw"; \
.p2align 3; \
name##: .quad BODY_LABEL (name), .TOC.@tocbase, 0; \
.popsection; \
BODY_LABEL(name)##:
#define ENTRY(name) ENTRY0(name)
#endif
#define SIZE(name) .size name, .-BODY_LABEL(name)
.text
# Just like __morestack, but with larger excess allocation
ENTRY0(__morestack_non_split)
.LFB1:
.cfi_startproc
# We use a cleanup to restore the tcbhead_t.__private_ss if
# an exception is thrown through this code.
#ifdef __PIC__
.cfi_personality 0x9b,DW.ref.__gcc_personality_v0
.cfi_lsda 0x1b,.LLSDA1
#else
.cfi_personality 0x3,__gcc_personality_v0
.cfi_lsda 0x3,.LLSDA1
#endif
# LR is already saved by the split-stack prologue code.
# We may as well have the unwinder skip over the call in the
# prologue too.
.cfi_offset %lr,16
addis %r12,%r12,-NON_SPLIT_STACK@h
SIZE (__morestack_non_split)
# Fall through into __morestack
# This function is called with non-standard calling conventions.
# On entry, r12 is the requested stack pointer. One version of the
# split-stack prologue that calls __morestack looks like
# ld %r0,-0x7000-64(%r13)
# addis %r12,%r1,-allocate@ha
# addi %r12,%r12,-allocate@l
# cmpld %r12,%r0
# bge+ enough
# mflr %r0
# std %r0,16(%r1)
# bl __morestack
# ld %r0,16(%r1)
# mtlr %r0
# blr
# enough:
# The normal function prologue follows here, with a small addition at
# the end to set up the arg pointer. The arg pointer is set up with:
# addi %r12,%r1,offset
# bge %cr7,.+8
# mr %r12,%r29
#
# Note that the lr save slot 16(%r1) has already been used.
# r3 thru r11 possibly contain arguments and a static chain
# pointer for the function we're calling, so must be preserved.
# cr7 must also be preserved.
ENTRY0(__morestack)
# Save parameter passing registers, our arguments, lr, r29
# and use r29 as a frame pointer.
std %r3,PARAMREG_SAVE+0(%r1)
sub %r3,%r1,%r12 # calculate requested stack size
mflr %r12
std %r4,PARAMREG_SAVE+8(%r1)
std %r5,PARAMREG_SAVE+16(%r1)
std %r6,PARAMREG_SAVE+24(%r1)
std %r7,PARAMREG_SAVE+32(%r1)
addi %r3,%r3,BACKOFF
std %r8,PARAMREG_SAVE+40(%r1)
std %r9,PARAMREG_SAVE+48(%r1)
std %r10,PARAMREG_SAVE+56(%r1)
std %r11,STATIC_CHAIN_SAVE(%r1)
std %r29,R29_SAVE(%r1)
std %r12,LINKREG_SAVE(%r1)
std %r3,NEWSTACKSIZE_SAVE(%r1) # new stack size
mr %r29,%r1
.cfi_offset %r29,R29_SAVE
.cfi_def_cfa_register %r29
stdu %r1,-MORESTACK_FRAMESIZE(%r1)
# void __morestack_block_signals (void)
bl __morestack_block_signals
# void *__generic_morestack (size_t *pframe_size,
# void *old_stack,
# size_t param_size)
addi %r3,%r29,NEWSTACKSIZE_SAVE
mr %r4,%r29
li %r5,0 # no copying from old stack
bl __generic_morestack
# Start using new stack
stdu %r29,-32(%r3) # back-chain
mr %r1,%r3
# Set __private_ss stack guard for the new stack.
ld %r12,NEWSTACKSIZE_SAVE(%r29) # modified size
addi %r3,%r3,BACKOFF-32
sub %r3,%r3,%r12
# Note that a signal frame has $pc pointing at the instruction
# where the signal occurred. For something like a timer
# interrupt this means the instruction has already executed,
# thus the region starts at the instruction modifying
# __private_ss, not one instruction after.
.LEHB0:
std %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss
# void __morestack_unblock_signals (void)
bl __morestack_unblock_signals
# Set up for a call to the target function, located 3
# instructions after __morestack's return address.
#
ld %r12,LINKREG_SAVE(%r29)
ld %r3,PARAMREG_SAVE+0(%r29) # restore arg regs
ld %r4,PARAMREG_SAVE+8(%r29)
ld %r5,PARAMREG_SAVE+16(%r29)
ld %r6,PARAMREG_SAVE+24(%r29)
ld %r7,PARAMREG_SAVE+32(%r29)
ld %r8,PARAMREG_SAVE+40(%r29)
ld %r9,PARAMREG_SAVE+48(%r29)
addi %r0,%r12,12 # add 3 instructions
ld %r10,PARAMREG_SAVE+56(%r29)
ld %r11,STATIC_CHAIN_SAVE(%r29)
cmpld %cr7,%r12,%r0 # indicate we were called
mtctr %r0
bctrl # call caller!
# On return, save regs possibly used to return a value, and
# possibly trashed by calls to __morestack_block_signals,
# __generic_releasestack and __morestack_unblock_signals.
# Assume those calls don't use vector or floating point regs.
std %r3,PARAMREG_SAVE+0(%r29)
std %r4,PARAMREG_SAVE+8(%r29)
std %r5,PARAMREG_SAVE+16(%r29)
std %r6,PARAMREG_SAVE+24(%r29)
#if _CALL_ELF == 2
std %r7,PARAMREG_SAVE+32(%r29)
std %r8,PARAMREG_SAVE+40(%r29)
std %r9,PARAMREG_SAVE+48(%r29)
std %r10,PARAMREG_SAVE+56(%r29)
#endif
bl __morestack_block_signals
# void *__generic_releasestack (size_t *pavailable)
addi %r3,%r29,NEWSTACKSIZE_SAVE
bl __generic_releasestack
# Reset __private_ss stack guard to value for old stack
ld %r12,NEWSTACKSIZE_SAVE(%r29)
addi %r3,%r3,BACKOFF
sub %r3,%r3,%r12
.LEHE0:
std %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss
bl __morestack_unblock_signals
# Use old stack again.
mr %r1,%r29
# Restore return value regs, and return.
ld %r0,LINKREG_SAVE(%r29)
mtlr %r0
ld %r3,PARAMREG_SAVE+0(%r29)
ld %r4,PARAMREG_SAVE+8(%r29)
ld %r5,PARAMREG_SAVE+16(%r29)
ld %r6,PARAMREG_SAVE+24(%r29)
#if _CALL_ELF == 2
ld %r7,PARAMREG_SAVE+32(%r29)
ld %r8,PARAMREG_SAVE+40(%r29)
ld %r9,PARAMREG_SAVE+48(%r29)
ld %r10,PARAMREG_SAVE+56(%r29)
#endif
ld %r29,R29_SAVE(%r29)
.cfi_def_cfa_register %r1
blr
# This is the cleanup code called by the stack unwinder when
# unwinding through code between .LEHB0 and .LEHE0 above.
cleanup:
.cfi_def_cfa_register %r29
std %r3,PARAMREG_SAVE(%r29) # Save exception header
# size_t __generic_findstack (void *stack)
mr %r3,%r29
bl __generic_findstack
sub %r3,%r29,%r3
addi %r3,%r3,BACKOFF
std %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss
ld %r3,PARAMREG_SAVE(%r29)
bl _Unwind_Resume
nop
.cfi_endproc
SIZE (__morestack)
.section .gcc_except_table,"a",@progbits
.p2align 2
.LLSDA1:
.byte 0xff # @LPStart format (omit)
.byte 0xff # @TType format (omit)
.byte 0x1 # call-site format (uleb128)
.uleb128 .LLSDACSE1-.LLSDACSB1 # Call-site table length
.LLSDACSB1:
.uleb128 .LEHB0-.LFB1 # region 0 start
.uleb128 .LEHE0-.LEHB0 # length
.uleb128 cleanup-.LFB1 # landing pad
.uleb128 0 # no action, ie. a cleanup
.LLSDACSE1:
#ifdef __PIC__
# Build a position independent reference to the personality function.
.hidden DW.ref.__gcc_personality_v0
.weak DW.ref.__gcc_personality_v0
.section .data.DW.ref.__gcc_personality_v0,"awG",@progbits,DW.ref.__gcc_personality_v0,comdat
.p2align 3
DW.ref.__gcc_personality_v0:
.quad __gcc_personality_v0
.type DW.ref.__gcc_personality_v0, @object
.size DW.ref.__gcc_personality_v0, 8
#endif
.text
# Initialize the stack guard when the program starts or when a
# new thread starts. This is called from a constructor.
# void __stack_split_initialize (void)
ENTRY(__stack_split_initialize)
addi %r3,%r1,-0x4000 # We should have at least 16K.
std %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss
# void __generic_morestack_set_initial_sp (void *sp, size_t len)
mr %r3,%r1
li %r4, 0x4000
b __generic_morestack_set_initial_sp
SIZE (__stack_split_initialize)
# Return current __private_ss
# void *__morestack_get_guard (void)
ENTRY0(__morestack_get_guard)
ld %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss
blr
SIZE (__morestack_get_guard)
# Set __private_ss
# void __morestack_set_guard (void *ptr)
ENTRY0(__morestack_set_guard)
std %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss
blr
SIZE (__morestack_set_guard)
# Return the stack guard value for given stack
# void *__morestack_make_guard (void *stack, size_t size)
ENTRY0(__morestack_make_guard)
sub %r3,%r3,%r4
addi %r3,%r3,BACKOFF
blr
SIZE (__morestack_make_guard)
# Make __stack_split_initialize a high priority constructor.
.section .ctors.65535,"aw",@progbits
.p2align 3
.quad __stack_split_initialize
.quad __morestack_load_mmap
.section .note.GNU-stack,"",@progbits
.section .note.GNU-split-stack,"",@progbits
.section .note.GNU-no-split-stack,"",@progbits
#endif /* __powerpc64__ */

View file

@ -0,0 +1,2 @@
# Makefile fragment to support -fsplit-stack for powerpc.
LIB2ADD_ST += $(srcdir)/config/rs6000/morestack.S

View file

@ -23,6 +23,9 @@ a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
/* powerpc 32-bit not supported. */
#if !defined __powerpc__ || defined __powerpc64__
#include "tconfig.h"
#include "tsystem.h"
#include "coretypes.h"
@ -935,6 +938,7 @@ __splitstack_find (void *segment_arg, void *sp, size_t *len,
nsp -= 12 * sizeof (void *);
#elif defined (__i386__)
nsp -= 6 * sizeof (void *);
#elif defined __powerpc64__
#else
#error "unrecognized target"
#endif
@ -1170,3 +1174,4 @@ __splitstack_find_context (void *context[NUMBER_OFFSETS], size_t *stack_size,
}
#endif /* !defined (inhibit_libc) */
#endif /* not powerpc 32-bit */