diff --git a/gcc/common/config/aarch64/aarch64-common.c b/gcc/common/config/aarch64/aarch64-common.c
index a0b7f48..05fe4e4 100644
--- a/gcc/common/config/aarch64/aarch64-common.c
+++ b/gcc/common/config/aarch64/aarch64-common.c
@@ -107,6 +107,36 @@ aarch64_handle_option (struct gcc_options *opts,
     }
 }
 
+/* -fsplit-stack uses an area allocated before thread pointer (which points
+   to TCB) and it is available on glibc-2.26.  GLIBC also exports a symbol
+   (__libc_tcb_private_ss) to signal it allocates the pre-TCB area.
+   This aims to prevent binaries linked against newer GLIBC to run on
+   non-supported ones.  */
+
+static bool
+aarch64_supports_split_stack (bool report ATTRIBUTE_UNUSED,
+			      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 >= 2026)
+    return true;
+
+  if (report)
+    error ("%<-fsplit-stack%> currently only supported on AArch64 GNU/Linux"
+	   " with glibc-2.26 or later");
+  return false;
+}
+
+#undef TARGET_SUPPORTS_SPLIT_STACK
+#define TARGET_SUPPORTS_SPLIT_STACK aarch64_supports_split_stack
+
 struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;
 
 /* An ISA extension in the co-processor and main instruction set space.  */
@@ -340,4 +370,3 @@ aarch64_rewrite_mcpu (int argc, const char **argv)
 }
 
 #undef AARCH64_CPU_NAME_LENGTH
-
diff --git a/gcc/config/aarch64/aarch64-linux.h b/gcc/config/aarch64/aarch64-linux.h
index c45fc1d..b8daba4 100644
--- a/gcc/config/aarch64/aarch64-linux.h
+++ b/gcc/config/aarch64/aarch64-linux.h
@@ -80,8 +80,6 @@
     }						\
   while (0)
 
-#define TARGET_ASM_FILE_END file_end_indicate_exec_stack
-
 /* Uninitialized common symbols in non-PIE executables, even with
    strong definitions in dependent shared libraries, will resolve
    to COPY relocated symbol in the executable.  See PR65780.  */
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index 9543f8c..5766afd 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -383,6 +383,8 @@ void aarch64_err_no_fpadvsimd (machine_mode, const char *);
 void aarch64_expand_epilogue (bool);
 void aarch64_expand_mov_immediate (rtx, rtx);
 void aarch64_expand_prologue (void);
+void aarch64_expand_split_stack_prologue (void);
+void aarch64_split_stack_space_check (rtx, rtx);
 void aarch64_expand_vector_init (rtx, rtx);
 void aarch64_init_cumulative_args (CUMULATIVE_ARGS *, const_tree, rtx,
 				   const_tree, unsigned);
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 4be3131..c21116a 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -913,7 +913,12 @@ aarch64_gen_far_branch (rtx * operands, int pos_label, const char * dest,
     snprintf (buffer, sizeof (buffer), "%s%s", branch_format, label_ptr);
     output_asm_insn (buffer, operands);
 
-    snprintf (buffer, sizeof (buffer), "b\t%%l%d\n%s:", pos_label, label_ptr);
+    if (GET_CODE (operands[pos_label]) == LABEL_REF)
+      snprintf (buffer, sizeof (buffer), "b\t%%l%d\n%s:", pos_label,
+		label_ptr);
+    else
+      snprintf (buffer, sizeof (buffer), "b\t%%%d\n%s:", pos_label,
+		label_ptr);
     operands[pos_label] = dest_label;
     output_asm_insn (buffer, operands);
     return "";
@@ -10139,7 +10144,7 @@ aarch64_expand_builtin_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
   /* Emit code to initialize STACK, which points to the next varargs stack
      argument.  CUM->AAPCS_STACK_SIZE gives the number of stack words used
      by named arguments.  STACK is 8-byte aligned.  */
-  t = make_tree (TREE_TYPE (stack), virtual_incoming_args_rtx);
+  t = make_tree (TREE_TYPE (stack), crtl->args.internal_arg_pointer);
   if (cum->aapcs_stack_size > 0)
     t = fold_build_pointer_plus_hwi (t, cum->aapcs_stack_size * UNITS_PER_WORD);
   t = build2 (MODIFY_EXPR, TREE_TYPE (stack), stack, t);
@@ -14682,6 +14687,167 @@ aarch64_excess_precision (enum excess_precision_type type)
   return FLT_EVAL_METHOD_UNPREDICTABLE;
 }
 
+/* -fsplit-stack support.  */
+
+/* A SYMBOL_REF for __morestack.  */
+static GTY(()) rtx morestack_ref;
+
+/* Load split-stack area from thread pointer position.  The split-stack is
+   allocate just before thread pointer.  */
+
+static rtx
+aarch64_load_split_stack_value (bool use_hard_reg)
+{
+  /* Offset from thread pointer to split-stack area.  */
+  const int psso = -8;
+
+  rtx ssvalue = use_hard_reg
+		? gen_rtx_REG (Pmode, R9_REGNUM) : gen_reg_rtx (Pmode);
+  ssvalue = aarch64_load_tp (ssvalue);
+  rtx mem = gen_rtx_MEM (Pmode, plus_constant (Pmode, ssvalue, psso));
+  emit_move_insn (ssvalue, mem);
+  return ssvalue;
+}
+
+/* Emit -fsplit-stack prologue, which goes before the regular function
+   prologue.  */
+
+void
+aarch64_expand_split_stack_prologue (void)
+{
+  rtx ssvalue, reg10, reg11, reg12, cc, cmp, jump;
+  HOST_WIDE_INT allocate;
+  rtx_code_label *ok_label = NULL;
+
+  gcc_assert (flag_split_stack && reload_completed);
+
+  /* It limits total maximum stack allocation on 4G so its value can be
+     materialized using two instructions at most (movn/movk).  It might be
+     used by the linker to add some extra space for split calling non split
+     stack functions.  */
+  allocate = cfun->machine->frame.frame_size;
+  if (allocate > ((int64_t)1 << 32))
+    {
+      sorry ("Stack frame larger than 4G 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);
+    }
+
+  ssvalue = aarch64_load_split_stack_value (true);
+
+  /* Always emit two insns to calculate the requested stack, so the linker
+     can edit them when adjusting size for calling non-split-stack code.  */
+  reg10 = gen_rtx_REG (Pmode, R10_REGNUM);
+  emit_insn (gen_rtx_SET (reg10, GEN_INT (allocate & 0xffff)));
+  emit_insn (gen_insv_immdi (reg10, GEN_INT (16),
+			     GEN_INT ((allocate & 0xffff0000) >> 16)));
+  emit_insn (gen_sub3_insn (reg10, stack_pointer_rtx, reg10));
+
+  ok_label = gen_label_rtx ();
+
+  /* If function uses stacked arguments save the old stack value so morestack
+     can return it.  */
+  reg11 = gen_rtx_REG (Pmode, R11_REGNUM);
+  if (crtl->args.size
+      || cfun->machine->frame.saved_varargs_size)
+    emit_move_insn (reg11, stack_pointer_rtx);
+
+  /* x12 holds the continuation address used to return to function.  */
+  reg12 = gen_rtx_REG (Pmode, R12_REGNUM);
+  aarch64_expand_mov_immediate (reg12, gen_rtx_LABEL_REF (VOIDmode, ok_label));
+
+  /* Jump to __morestack call if current ss guard is not suffice.  */
+  cc = aarch64_gen_compare_reg (GE, ssvalue, reg10);
+  cmp = gen_rtx_fmt_ee (GE, VOIDmode, cc, const0_rtx);
+  jump = gen_split_stack_cond_call (morestack_ref, cmp, ok_label, reg12);
+
+  aarch64_emit_unlikely_jump (jump);
+  JUMP_LABEL (jump) = ok_label;
+  LABEL_NUSES (ok_label)++;
+
+  /* __morestack will call us here.  */
+  emit_label (ok_label);
+}
+
+/* Implement TARGET_ASM_FILE_END.  */
+
+static void
+aarch64_file_end (void)
+{
+  file_end_indicate_exec_stack ();
+
+  if (flag_split_stack)
+    {
+      file_end_indicate_split_stack ();
+
+      /* Emit a reference to special symbol that LIBC uses to declare it
+	 supports the split-stack before TCB.  */
+      switch_to_section (data_section);
+      fprintf (asm_out_file, "\t.align 3\n");
+      fprintf (asm_out_file, "\t.quad __libc_tcb_private_ss\n");
+    }
+}
+
+/* Return the internal arg pointer used for function incoming arguments.  */
+
+static rtx
+aarch64_internal_arg_pointer (void)
+{
+  if (flag_split_stack
+     && (lookup_attribute ("no_split_stack", DECL_ATTRIBUTES (cfun->decl))
+         == NULL))
+    {
+      if (cfun->machine->frame.split_stack_arg_pointer == NULL_RTX)
+	{
+	  rtx pat;
+
+	  cfun->machine->frame.split_stack_arg_pointer = gen_reg_rtx (Pmode);
+	  REG_POINTER (cfun->machine->frame.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->frame.split_stack_arg_pointer,
+			     gen_rtx_REG (Pmode, R11_REGNUM));
+	  push_topmost_sequence ();
+	  emit_insn_after (pat, get_insns ());
+	  pop_topmost_sequence ();
+	}
+      return plus_constant (Pmode, cfun->machine->frame.split_stack_arg_pointer,
+			    FIRST_PARM_OFFSET (current_function_decl));
+    }
+  return virtual_incoming_args_rtx;
+}
+
+/* Emit -fsplit-stack dynamic stack allocation space check.  */
+
+void
+aarch64_split_stack_space_check (rtx size, rtx label)
+{
+  rtx ssvalue, cc, cmp, jump, temp;
+  rtx requested = gen_reg_rtx (Pmode);
+
+  /* Load __private_ss from TCB.  */
+  ssvalue = aarch64_load_split_stack_value (false);
+
+  temp = gen_reg_rtx (Pmode);
+
+  /* And compare it with frame pointer plus required stack.  */
+  size = force_reg (Pmode, size);
+  emit_move_insn (requested, gen_rtx_MINUS (Pmode, stack_pointer_rtx, size));
+
+  /* Jump to label call if current ss guard is not suffice.  */
+  cc = aarch64_gen_compare_reg (LT, temp, ssvalue);
+  cmp = gen_rtx_fmt_ee (GEU, VOIDmode, cc, const0_rtx);
+  jump = emit_jump_insn (gen_condjump (cmp, cc, label));
+  JUMP_LABEL (jump) = label;
+}
+
 /* Target-specific selftests.  */
 
 #if CHECKING_P
@@ -14754,6 +14920,9 @@ aarch64_run_selftests (void)
 #undef TARGET_ASM_FILE_START
 #define TARGET_ASM_FILE_START aarch64_start_file
 
+#undef TARGET_ASM_FILE_END
+#define TARGET_ASM_FILE_END aarch64_file_end
+
 #undef TARGET_ASM_OUTPUT_MI_THUNK
 #define TARGET_ASM_OUTPUT_MI_THUNK aarch64_output_mi_thunk
 
@@ -14839,6 +15008,9 @@ aarch64_run_selftests (void)
 #undef TARGET_FRAME_POINTER_REQUIRED
 #define TARGET_FRAME_POINTER_REQUIRED aarch64_frame_pointer_required
 
+#undef TARGET_INTERNAL_ARG_POINTER
+#define TARGET_INTERNAL_ARG_POINTER aarch64_internal_arg_pointer
+
 #undef TARGET_GIMPLE_FOLD_BUILTIN
 #define TARGET_GIMPLE_FOLD_BUILTIN aarch64_gimple_fold_builtin
 
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index e4fb96f..510f60a 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -594,6 +594,9 @@ struct GTY (()) aarch64_frame
   unsigned wb_candidate2;
 
   bool laid_out;
+
+  /* Alternative internal arg pointer for -fsplit-stack.  */
+  rtx split_stack_arg_pointer;
 };
 
 typedef struct GTY (()) machine_function
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 5adc5ed..b0141f9 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -150,6 +150,7 @@
     UNSPECV_SET_FPSR		; Represent assign of FPSR content.
     UNSPECV_BLOCKAGE		; Represent a blockage
     UNSPECV_PROBE_STACK_RANGE	; Represent stack range probing.
+    UNSPECV_SPLIT_STACK_CALL    ; Represent a morestack call
   ]
 )
 
@@ -5572,3 +5573,58 @@
 
 ;; ldp/stp peephole patterns
 (include "aarch64-ldpstp.md")
+
+;; Handle -fsplit-stack
+(define_expand "split_stack_prologue"
+  [(const_int 0)]
+  ""
+{
+  aarch64_expand_split_stack_prologue ();
+  DONE;
+})
+
+;; If there are operand 0 bytes available on the stack, jump to
+;; operand 1.
+(define_expand "split_stack_space_check"
+  [(set (match_dup 2) (compare:CC (match_dup 3) (match_dup 2)))
+   (set (pc) (if_then_else
+	      (geu (match_dup 4) (const_int 0))
+	      (label_ref (match_operand 1))
+	      (pc)))]
+  ""
+{
+  aarch64_split_stack_space_check (operands[0], operands[1]);
+  DONE;
+})
+
+;; A __morestack call using branch
+
+(define_expand "split_stack_cond_call"
+  [(match_operand 0 "aarch64_call_insn_operand" "")
+   (match_operand 1 "" "")
+   (match_operand 2 "" "")
+   (match_operand 3 "" "")]
+  ""
+{
+  emit_jump_insn (gen_split_stack_cond_call_di (operands[0], operands[1],
+						operands[2], operands[3]));
+  DONE;
+})
+
+
+(define_insn "split_stack_cond_call_<mode>"
+  [(set (pc)
+        (if_then_else
+          (match_operand 1 "aarch64_comparison_operator" "")
+          (label_ref (match_operand 2 "" ""))
+          (pc)))
+   (set (reg:P 1) (unspec_volatile:P [(match_operand:P 0 "aarch64_call_insn_operand" "")
+                                    (reg:P 1)]
+                                   UNSPECV_SPLIT_STACK_CALL))
+   (use (match_operand:P 3 "register_operand" ""))]
+  ""
+  {
+    return aarch64_gen_far_branch (operands, 0, "Lbcond", "b%M1\\t");
+  }
+  [(set_attr "type" "branch")]
+)
diff --git a/libgcc/config.host b/libgcc/config.host
index 9472a60..d6f4312 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -347,6 +347,7 @@ aarch64*-*-linux*)
 	md_unwind_header=aarch64/linux-unwind.h
 	tmake_file="${tmake_file} ${cpu_type}/t-aarch64"
 	tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm"
+	tmake_file="${tmake_file} t-stack aarch64/t-stack-aarch64"
 	;;
 alpha*-*-linux*)
 	tmake_file="${tmake_file} alpha/t-alpha alpha/t-ieee t-crtfm alpha/t-linux"
diff --git a/libgcc/config/aarch64/morestack-c.c b/libgcc/config/aarch64/morestack-c.c
new file mode 100644
index 0000000..607ef05
--- /dev/null
+++ b/libgcc/config/aarch64/morestack-c.c
@@ -0,0 +1,85 @@
+/* AArch64 support for -fsplit-stack.
+ * Copyright (C) 2016 Free Software Foundation, Inc.
+ *
+ * This file 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.
+ *
+ * This file 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/>.
+ */
+
+#ifndef inhibit_libc
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include "generic-morestack.h"
+
+#define INITIAL_STACK_SIZE  0x4000
+#define BACKOFF             0x1000
+
+void __generic_morestack_set_initial_sp (void *sp, size_t len);
+void *__morestack_get_guard (void);
+void __morestack_set_guard (void *);
+void *__morestack_make_guard (void *stack, size_t size);
+void __morestack_load_mmap (void);
+
+/* split-stack area position from thread pointer.  */
+#define SPLITSTACK_PTR_TP	(-8)
+
+/* Initialize the stack guard when the program starts or when a new
+   thread.  This is called from a constructor using ctors section.  */
+void
+__stack_split_initialize (void)
+{
+  register uintptr_t* sp __asm__ ("sp");
+  uintptr_t *ss = (uintptr_t*)((char*)__builtin_thread_pointer ()
+                                + SPLITSTACK_PTR_TP);
+  *ss = (uintptr_t)sp - INITIAL_STACK_SIZE;
+  __generic_morestack_set_initial_sp (sp, INITIAL_STACK_SIZE);
+}
+
+/* Return current __private_ss.  */
+void *
+__morestack_get_guard (void)
+{
+  void **ss = (void**)((char*)__builtin_thread_pointer ()
+                       + SPLITSTACK_PTR_TP);
+  return *ss;
+}
+
+/* Set __private_ss to ptr.  */
+void
+__morestack_set_guard (void *ptr)
+{
+  void **ss = (void**)((char*)__builtin_thread_pointer ()
+                       + SPLITSTACK_PTR_TP);
+  *ss = ptr;
+}
+
+/* Return the stack guard value for given stack.  */
+void *
+__morestack_make_guard (void *stack, size_t size)
+{
+  return (void*)((uintptr_t)stack - size + BACKOFF);
+}
+
+/* Make __stack_split_initialize a high priority constructor.  */
+static void (*const ctors []) 
+  __attribute__ ((used, section (".ctors.65535"), aligned (sizeof (void *))))
+  = { __stack_split_initialize, __morestack_load_mmap };
+
+#endif /* !defined (inhibit_libc) */
diff --git a/libgcc/config/aarch64/morestack.S b/libgcc/config/aarch64/morestack.S
new file mode 100644
index 0000000..c8a3d82
--- /dev/null
+++ b/libgcc/config/aarch64/morestack.S
@@ -0,0 +1,246 @@
+# AArch64 support for -fsplit-stack.
+# Copyright (C) 2016 Free Software Foundation, Inc.
+
+# 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/>.
+
+/* Define an entry point visible from C.  */
+#define ENTRY(name)						\
+  .globl name;							\
+  .type name,%function;						\
+  .align 4;							\
+  name##:
+
+#define END(name)						\
+  .size name,.-name
+
+/* __morestack frame size.  */
+#define MORESTACK_FRAMESIZE	112
+/* Offset from __morestack frame where the new stack size is saved and
+   passed to __generic_morestack.  */
+#define NEWSTACK_SAVE		96
+
+#define BACKOFF			0x1000
+# Large excess allocated when calling non-split-stack code.
+#define NON_SPLIT_STACK		0x100000
+
+/* split-stack area position from thread pointer.  */
+#define SPLITSTACK_PTR_TP	-8
+
+	.text
+ENTRY(__morestack_non_split)
+	.cfi_startproc
+# We use a cleanup to restore the tcbhead_t.__private_ss if
+# an exception is thrown through this code.
+	add	x10, x10, NON_SPLIT_STACK
+	.cfi_endproc
+END(__morestack_non_split)
+# Fall through into __morestack
+
+# This function is called with non-standard calling conventions, on entry
+# x10 is the requested stack pointer.  The split-stack prologue is in the
+# form:
+#
+# function:
+#	mrs    x9, tpidr_el0
+#	mov    x10, <required stack allocation>
+#	movk   x10, #0x0, lsl #16
+#	sub    x10, sp, x10
+#	mov    x11, sp   	# if function has stacked arguments
+#	adrp   x12, main_fn_entry
+#	add    x12, x12, :lo12:.L2
+#	cmp    x9, x10
+#	b.lt   <main_fn_entry>
+#	b      __morestack
+# main_fn_entry:
+#	[function prologue]
+#
+# The N bit is also restored to indicate that the function is called
+# (so the prologue addition can set up the argument pointer correctly).
+
+ENTRY(__morestack)
+.LFB1:
+	.cfi_startproc
+
+#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
+
+	# Calculate requested stack size.
+	sub	x10, sp, x10
+	# Save parameters
+	stp	x29, x30, [sp, -MORESTACK_FRAMESIZE]!
+	.cfi_def_cfa_offset MORESTACK_FRAMESIZE
+	.cfi_offset 29, -MORESTACK_FRAMESIZE
+	.cfi_offset 30, -MORESTACK_FRAMESIZE+8
+	add	x29, sp, 0
+	.cfi_def_cfa_register 29
+	# Adjust the requested stack size for the frame pointer save.
+	stp	x0, x1, [sp, 16]
+	stp	x2, x3, [sp, 32]
+	add	x10, x10, BACKOFF
+	stp	x4, x5, [sp, 48]
+	stp	x6, x7, [sp, 64]
+	stp 	x8, x12, [sp, 80]
+	str	x10, [sp, 96]
+
+	# void __morestack_block_signals (void)
+	bl	__morestack_block_signals
+
+	# void *__generic_morestack (size_t *pframe_size,
+	#			     void *old_stack,
+	#			     size_t param_size)
+	# pframe_size: is the size of the required stack frame (the function
+	#	       amount of space remaining on the allocated stack).
+	# old_stack: points at the parameters the old stack
+	# param_size: size in bytes of parameters to copy to the new stack.
+	add	x0, x29, NEWSTACK_SAVE
+	add	x1, x29, MORESTACK_FRAMESIZE
+	mov	x2, 0
+	bl	__generic_morestack
+
+	# Start using new stack
+	mov	sp, x0
+
+	# Set __private_ss stack guard for the new stack.
+	ldr	x9, [x29, NEWSTACK_SAVE]
+	add	x0, x0, BACKOFF
+	sub	x0, x0, x9
+.LEHB0:
+	mrs	x1, tpidr_el0
+	str	x0, [x1, SPLITSTACK_PTR_TP]
+
+	# void __morestack_unblock_signals (void)
+	bl	__morestack_unblock_signals
+
+	# Set up for a call to the target function.
+	ldp	x0, x1, [x29, 16]
+	ldp	x2, x3, [x29, 32]
+	ldp	x4, x5, [x29, 48]
+	ldp	x6, x7, [x29, 64]
+	ldp	x8, x12, [x29, 80]
+	add	x11, x29, MORESTACK_FRAMESIZE
+	# Indicate __morestack was called.
+	cmp	x12, 0
+	blr	x12
+
+	stp	x0, x1, [x29, 16]
+	stp	x2, x3, [x29, 32]
+	stp	x4, x5, [x29, 48]
+	stp	x6, x7, [x29, 64]
+
+	bl	__morestack_block_signals
+
+	# void *__generic_releasestack (size_t *pavailable)
+	add	x0, x29, NEWSTACK_SAVE
+	bl	__generic_releasestack
+
+	# Reset __private_ss stack guard to value for old stack
+	ldr	x9, [x29, NEWSTACK_SAVE]
+	add	x0, x0, BACKOFF
+	sub	x0, x0, x9
+
+	# Update TCB split stack field
+.LEHE0:
+	mrs	x1, tpidr_el0
+	str	x0, [x1, SPLITSTACK_PTR_TP]
+
+	bl __morestack_unblock_signals
+
+	# Use old stack again.
+	add	sp, x29, MORESTACK_FRAMESIZE
+
+	ldp	x0, x1, [x29, 16]
+	ldp	x2, x3, [x29, 32]
+	ldp	x4, x5, [x29, 48]
+	ldp	x6, x7, [x29, 64]
+	ldp	x29, x30, [x29]
+
+	.cfi_remember_state
+	.cfi_restore 30
+	.cfi_restore 29
+	.cfi_def_cfa 31, 0
+
+	ret
+
+# This is the cleanup code called by the stack unwinder when
+# unwinding through code between .LEHB0 and .LEHE0 above.
+cleanup:
+	.cfi_restore_state
+	# Reuse the new stack allocation to save/restore the
+	# exception header
+	str	x0, [x29, NEWSTACK_SAVE]
+	# size_t __generic_findstack (void *stack)
+	add	x0, x29, MORESTACK_FRAMESIZE
+	bl	__generic_findstack
+	sub	x0, x29, x0
+	add	x0, x0, BACKOFF
+	# Restore split-stack guard value
+	mrs	x1, tpidr_el0
+	str	x0, [x1, SPLITSTACK_PTR_TP]
+	ldr	x0, [x29, NEWSTACK_SAVE]
+	b	_Unwind_Resume
+        .cfi_endproc
+END(__morestack)
+
+	.section .gcc_except_table,"a",@progbits
+	.align 4
+.LLSDA1:
+	# @LPStart format (omit)
+        .byte   0xff
+	# @TType format (omit)
+        .byte   0xff
+	# Call-site format (uleb128)
+        .byte   0x1
+	# Call-site table length
+        .uleb128 .LLSDACSE1-.LLSDACSB1
+.LLSDACSB1:
+	# region 0 start
+        .uleb128 .LEHB0-.LFB1
+	# length
+        .uleb128 .LEHE0-.LEHB0
+	# landing pad
+        .uleb128 cleanup-.LFB1
+	# no action (ie a cleanup)
+        .uleb128 0
+.LLSDACSE1:
+
+
+	.global __gcc_personality_v0
+#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
+	.type   DW.ref.__gcc_personality_v0, @object
+	.align 3
+DW.ref.__gcc_personality_v0:
+	.size   DW.ref.__gcc_personality_v0, 8
+	.quad   __gcc_personality_v0
+#endif
+
+	.section .note.GNU-stack,"",@progbits
+	.section .note.GNU-split-stack,"",@progbits
+	.section .note.GNU-no-split-stack,"",@progbits
diff --git a/libgcc/config/aarch64/t-stack-aarch64 b/libgcc/config/aarch64/t-stack-aarch64
new file mode 100644
index 0000000..4babb4e
--- /dev/null
+++ b/libgcc/config/aarch64/t-stack-aarch64
@@ -0,0 +1,3 @@
+# Makefile fragment to support -fsplit-stack for aarch64.
+LIB2ADD_ST += $(srcdir)/config/aarch64/morestack.S \
+	      $(srcdir)/config/aarch64/morestack-c.c
diff --git a/libgcc/generic-morestack.c b/libgcc/generic-morestack.c
index adbe436..e91ceb4 100644
--- a/libgcc/generic-morestack.c
+++ b/libgcc/generic-morestack.c
@@ -943,6 +943,7 @@ __splitstack_find (void *segment_arg, void *sp, size_t *len,
       nsp -= 2 * 160;
 #elif defined __s390__
       nsp -= 2 * 96;
+#elif defined __aarch64__
 #else
 #error "unrecognized target"
 #endif
