413 lines
12 KiB
ArmAsm
413 lines
12 KiB
ArmAsm
#ifdef __powerpc64__
|
|
# PowerPC64 support for -fsplit-stack.
|
|
# Copyright (C) 2009-2022 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/>.
|
|
|
|
#include <auto-host.h>
|
|
|
|
#if _CALL_ELF == 2
|
|
.abiversion 2
|
|
#define PARAMS 32
|
|
#else
|
|
#define PARAMS 48
|
|
#endif
|
|
#define MORESTACK_FRAMESIZE (PARAMS+96)
|
|
#define R2_SAVE -MORESTACK_FRAMESIZE+PARAMS-8
|
|
#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##:
|
|
|
|
#ifdef __PCREL__
|
|
#define ENTRY(name) \
|
|
ENTRY0(name); \
|
|
.localentry name, 1
|
|
#define JUMP_TARGET(name) name##@notoc
|
|
#else
|
|
#define ENTRY(name) \
|
|
ENTRY0(name); \
|
|
0: addis %r2,%r12,.TOC.-0b@ha; \
|
|
addi %r2,%r2,.TOC.-0b@l; \
|
|
.localentry name, .-name
|
|
#endif
|
|
|
|
#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)
|
|
|
|
#ifndef JUMP_TARGET
|
|
#define JUMP_TARGET(name) name
|
|
#endif
|
|
|
|
.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)
|
|
|
|
#if _CALL_ELF == 2
|
|
# Functions with localentry bits of zero cannot make calls if those
|
|
# calls might change r2. This is true generally, and also true for
|
|
# __morestack with its special calling convention. When __morestack's
|
|
# caller is non-pcrel but libgcc is pcrel, the functions called here
|
|
# might modify r2. r2 must be preserved on exit, and also restored
|
|
# for the call back to our caller.
|
|
std %r2,R2_SAVE(%r1)
|
|
#endif
|
|
|
|
# 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
|
|
#if _CALL_ELF == 2
|
|
.cfi_offset %r2,R2_SAVE
|
|
#endif
|
|
.cfi_offset %r29,R29_SAVE
|
|
.cfi_def_cfa_register %r29
|
|
stdu %r1,-MORESTACK_FRAMESIZE(%r1)
|
|
|
|
#if _CALL_ELF == 2 && !defined __PCREL__
|
|
# If this isn't a pcrel libgcc then the functions we call here will
|
|
# require r2 to be valid. If __morestack is called from pcrel code r2
|
|
# won't be valid. Set it up.
|
|
bcl 20,31,1f
|
|
1:
|
|
mflr %r12
|
|
addis %r2,%r12,.TOC.-1b@ha
|
|
addi %r2,%r2,.TOC.-1b@l
|
|
#endif
|
|
|
|
# void __morestack_block_signals (void)
|
|
bl JUMP_TARGET(__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 JUMP_TARGET(__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 JUMP_TARGET(__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)
|
|
#if _CALL_ELF == 2
|
|
ld %r2,R2_SAVE(%r29)
|
|
#endif
|
|
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
|
|
|
|
#if _CALL_ELF == 2 && !defined __PCREL__
|
|
# r2 was restored for calling back into our caller. Set it up again.
|
|
bcl 20,31,1f
|
|
1:
|
|
mflr %r12
|
|
addis %r2,%r12,.TOC.-1b@ha
|
|
addi %r2,%r2,.TOC.-1b@l
|
|
#endif
|
|
|
|
bl JUMP_TARGET(__morestack_block_signals)
|
|
|
|
# void *__generic_releasestack (size_t *pavailable)
|
|
addi %r3,%r29,NEWSTACKSIZE_SAVE
|
|
bl JUMP_TARGET(__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 JUMP_TARGET(__morestack_unblock_signals)
|
|
|
|
# Use old stack again.
|
|
mr %r1,%r29
|
|
|
|
# Restore return value regs, and return.
|
|
ld %r0,LINKREG_SAVE(%r29)
|
|
mtlr %r0
|
|
#if _CALL_ELF == 2
|
|
ld %r2,R2_SAVE(%r29)
|
|
#endif
|
|
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 JUMP_TARGET(__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 JUMP_TARGET(_Unwind_Resume)
|
|
#ifndef __PCREL__
|
|
nop
|
|
#endif
|
|
.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)
|
|
.cfi_startproc
|
|
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 JUMP_TARGET(__generic_morestack_set_initial_sp)
|
|
# The lack of .cfi_endproc here is deliberate. This function and the
|
|
# following ones can all use the default FDE.
|
|
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
|
|
.cfi_endproc
|
|
SIZE (__morestack_make_guard)
|
|
|
|
|
|
# Make __stack_split_initialize a high priority constructor.
|
|
#if HAVE_INITFINI_ARRAY_SUPPORT
|
|
.section .init_array.00000,"aw",@progbits
|
|
#else
|
|
.section .ctors.65535,"aw",@progbits
|
|
#endif
|
|
.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__ */
|