diff --git a/gcc/config.gcc b/gcc/config.gcc
index 882e4134b4c883a5fe0f19996e54ac63769bada1..701082e82ee3da6c5bf00da799293c92af8624ff 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -321,7 +321,7 @@ arc*-*-*)
 arm*-*-*)
 	cpu_type=arm
 	extra_objs="arm-builtins.o aarch-common.o"
-	extra_headers="mmintrin.h arm_neon.h arm_acle.h"
+	extra_headers="mmintrin.h arm_neon.h arm_acle.h arm_cmse.h"
 	target_type_format_char='%'
 	c_target_objs="arm-c.o"
 	cxx_target_objs="arm-c.o"
diff --git a/gcc/config/arm/arm-arches.def b/gcc/config/arm/arm-arches.def
index 1d0301a3b9414127d387834584f3e42c225b6d3f..52518e64e07a1b085ae5ed1932b598e064258971 100644
--- a/gcc/config/arm/arm-arches.def
+++ b/gcc/config/arm/arm-arches.def
@@ -58,11 +58,11 @@ ARM_ARCH("armv7e-m", cortexm4,  7EM,	ARM_FSET_MAKE_CPU1 (FL_CO_PROC |	      FL_F
 ARM_ARCH("armv8-a", cortexa53,  8A,	ARM_FSET_MAKE_CPU1 (FL_CO_PROC |             FL_FOR_ARCH8A))
 ARM_ARCH("armv8-a+crc",cortexa53, 8A,   ARM_FSET_MAKE_CPU1 (FL_CO_PROC | FL_CRC32  | FL_FOR_ARCH8A))
 ARM_ARCH("armv8-m.base", cortexm0, 8M_BASE,
-	 ARM_FSET_MAKE_CPU1 (			      FL_FOR_ARCH8M_BASE))
+	 ARM_FSET_MAKE (			  FL_FOR_ARCH8M_BASE, FL2_CMSE))
 ARM_ARCH("armv8-m.main", cortexm7, 8M_MAIN,
-	 ARM_FSET_MAKE_CPU1(FL_CO_PROC |	      FL_FOR_ARCH8M_MAIN))
+	 ARM_FSET_MAKE (FL_CO_PROC |		  FL_FOR_ARCH8M_MAIN, FL2_CMSE))
 ARM_ARCH("armv8-m.main+dsp", cortexm7, 8M_MAIN,
-	 ARM_FSET_MAKE_CPU1(FL_CO_PROC | FL_ARCH7EM | FL_FOR_ARCH8M_MAIN))
+	 ARM_FSET_MAKE (FL_CO_PROC | FL_ARCH7EM | FL_FOR_ARCH8M_MAIN, FL2_CMSE))
 ARM_ARCH("iwmmxt",  iwmmxt,     5TE,	ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT))
 ARM_ARCH("iwmmxt2", iwmmxt2,    5TE,	ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT | FL_IWMMXT2))
 
diff --git a/gcc/config/arm/arm-c.c b/gcc/config/arm/arm-c.c
index 7dee28ec52df68f8c7a60fe66e1b049fed39c1c0..459ddbb1f41947cbeeb1a291ab7395843528e562 100644
--- a/gcc/config/arm/arm-c.c
+++ b/gcc/config/arm/arm-c.c
@@ -73,6 +73,14 @@ arm_cpu_builtins (struct cpp_reader* pfile)
 
   def_or_undef_macro (pfile, "__ARM_32BIT_STATE", TARGET_32BIT); 
 
+  if (arm_arch8 && !arm_arch_notm)
+    {
+      if (arm_arch_cmse && use_cmse)
+	builtin_define_with_int_value ("__ARM_FEATURE_CMSE", 3);
+      else
+	builtin_define ("__ARM_FEATURE_CMSE");
+    }
+
   if (TARGET_ARM_FEATURE_LDREX)
     builtin_define_with_int_value ("__ARM_FEATURE_LDREX", 
 				   TARGET_ARM_FEATURE_LDREX);
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 339b49ed22f95804b0f78a544ea6f739fb4fc7f0..85dca057d63544c672188db39b05a33b1be10915 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -387,6 +387,8 @@ extern bool arm_is_constant_pool_ref (rtx);
 #define FL_IWMMXT2    (1 << 30)       /* "Intel Wireless MMX2 technology".  */
 #define FL_ARCH6KZ    (1 << 31)       /* ARMv6KZ architecture.  */
 
+#define FL2_CMSE      (1 << 0)	      /* ARMv8-M Security Extensions.  */
+
 /* Flags that only effect tuning, not available instructions.  */
 #define FL_TUNE		(FL_WBUF | FL_VFPV2 | FL_STRONG | FL_LDSCHED \
 			 | FL_CO_PROC)
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 999f824f7f98230a4b1cd7431ab011f18796aca3..cf6d9466fb79e4f8a2dbfe725c52d5be8ea24fd2 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -505,6 +505,9 @@ extern bool arm_disable_literal_pool;
 /* Nonzero if chip supports the ARMv8 CRC instructions.  */
 extern int arm_arch_crc;
 
+/* Nonzero if chip support the ARMv8-M Security Extensions.  */
+extern int arm_arch_cmse;
+
 #ifndef TARGET_DEFAULT
 #define TARGET_DEFAULT  (MASK_APCS_FRAME)
 #endif
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 3028cd6cf5bff07e27947cc365f8952f24515440..06a6184ee0c4ed1a7cec1de4c1786e297cc57872 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -889,6 +889,9 @@ int arm_condexec_masklen = 0;
 /* Nonzero if chip supports the ARMv8 CRC instructions.  */
 int arm_arch_crc = 0;
 
+/* Nonzero if chip support the ARMv8-M security extensions.  */
+int arm_arch_cmse = 0;
+
 /* Nonzero if the core has a very small, high-latency, multiply unit.  */
 int arm_m_profile_small_mul = 0;
 
@@ -3171,6 +3174,7 @@ arm_option_override (void)
   arm_arch_no_volatile_ce = ARM_FSET_HAS_CPU1 (insn_flags, FL_NO_VOLATILE_CE);
   arm_tune_cortex_a9 = (arm_tune == cortexa9) != 0;
   arm_arch_crc = ARM_FSET_HAS_CPU1 (insn_flags, FL_CRC32);
+  arm_arch_cmse = ARM_FSET_HAS_CPU2 (insn_flags, FL2_CMSE);
   arm_m_profile_small_mul = ARM_FSET_HAS_CPU1 (insn_flags, FL_SMALLMUL);
 
   /* V5 code we generate is completely interworking capable, so we turn off
@@ -3423,6 +3427,9 @@ arm_option_override (void)
   if (target_slow_flash_data)
     arm_disable_literal_pool = true;
 
+  if (use_cmse && !arm_arch_cmse)
+    error ("target CPU does not support ARMv8-M Security Extensions");
+
   /* Disable scheduling fusion by default if it's not armv7 processor
      or doesn't prefer ldrd/strd.  */
   if (flag_schedule_fusion == 2
diff --git a/gcc/config/arm/arm.opt b/gcc/config/arm/arm.opt
index 1e438a9c092f3f4994527729bcb5e29a367e727a..cecff4574f97d30080538521e1fdfca0f0be296e 100644
--- a/gcc/config/arm/arm.opt
+++ b/gcc/config/arm/arm.opt
@@ -109,6 +109,10 @@ mfloat-abi=
 Target RejectNegative Joined Enum(float_abi_type) Var(arm_float_abi) Init(TARGET_DEFAULT_FLOAT_ABI)
 Specify if floating point hardware should be used.
 
+mcmse
+Target RejectNegative Var(use_cmse)
+Specify that the compiler should target secure code as per ARMv8-M Security Extensions.
+
 Enum
 Name(float_abi_type) Type(enum float_abi_type)
 Known floating-point ABIs (for use with the -mfloat-abi= option):
diff --git a/gcc/config/arm/arm_cmse.h b/gcc/config/arm/arm_cmse.h
new file mode 100644
index 0000000000000000000000000000000000000000..ab20a3ec46025f268a1e9bed895d27da9af7aab6
--- /dev/null
+++ b/gcc/config/arm/arm_cmse.h
@@ -0,0 +1,192 @@
+/* ARMV8-M Secure Extensions intrinsics include file.
+
+   Copyright (C) 2015 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   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/>.  */
+
+
+#ifndef _GCC_ARM_CMSE_H
+#define _GCC_ARM_CMSE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if __ARM_FEATURE_CMSE & 1
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __ARM_BIG_ENDIAN
+
+typedef union {
+  struct cmse_address_info {
+#if __ARM_FEATURE_CMSE & 2
+    unsigned idau_region:8;
+    unsigned idau_region_valid:1;
+    unsigned secure:1;
+    unsigned nonsecure_readwrite_ok:1;
+    unsigned nonsecure_read_ok:1;
+#else
+    unsigned :12;
+#endif
+    unsigned readwrite_ok:1;
+    unsigned read_ok:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region_valid:1;
+#else
+    unsigned :1;
+#endif
+    unsigned mpu_region_valid:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region:8;
+#else
+    unsigned :8;
+#endif
+    unsigned mpu_region:8;
+  } flags;
+  unsigned value;
+} cmse_address_info_t;
+
+#else
+
+typedef union {
+  struct cmse_address_info {
+    unsigned mpu_region:8;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region:8;
+#else
+    unsigned :8;
+#endif
+    unsigned mpu_region_valid:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned sau_region_valid:1;
+#else
+    unsigned :1;
+#endif
+    unsigned read_ok:1;
+    unsigned readwrite_ok:1;
+#if __ARM_FEATURE_CMSE & 2
+    unsigned nonsecure_read_ok:1;
+    unsigned nonsecure_readwrite_ok:1;
+    unsigned secure:1;
+    unsigned idau_region_valid:1;
+    unsigned idau_region:8;
+#else
+    unsigned :12;
+#endif
+  } flags;
+  unsigned value;
+} cmse_address_info_t;
+
+#endif
+
+#define cmse_TT_fptr(p) (cmse_TT_fptr_generic ((cmse_fptr)p))
+
+typedef void (*cmse_fptr)(void);
+
+#define CMSE_TT_ASM(flags) \
+{ \
+  cmse_address_info_t result; \
+   __asm__ ("tt" # flags " %0,%1" \
+	   : "=r"(result) \
+	   : "r"(p) \
+	   : "memory"); \
+  return result; \
+}
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TT_fptr_generic (cmse_fptr p)
+CMSE_TT_ASM ()
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TT (void *p)
+CMSE_TT_ASM ()
+
+#define cmse_TTT_fptr(p) (cmse_TTT_fptr_generic ((cmse_fptr)p))
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTT_fptr_generic (cmse_fptr p)
+CMSE_TT_ASM (t)
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTT (void *p)
+CMSE_TT_ASM (t)
+
+#if __ARM_FEATURE_CMSE & 2
+
+#define cmse_TTA_fptr(p) (cmse_TTA_fptr_generic ((cmse_fptr)p))
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTA_fptr_generic (cmse_fptr p)
+CMSE_TT_ASM (a)
+
+__extension__ static __inline __attribute__ ((__always_inline__))
+cmse_address_info_t
+cmse_TTA (void *p)
+CMSE_TT_ASM (a)
+
+#define cmse_TTAT_fptr(p) (cmse_TTAT_fptr_generic ((cmse_fptr)p))
+
+__extension__ static __inline cmse_address_info_t
+__attribute__ ((__always_inline__))
+cmse_TTAT_fptr_generic (cmse_fptr p)
+CMSE_TT_ASM (at)
+
+__extension__ static __inline cmse_address_info_t
+__attribute__ ((__always_inline__))
+cmse_TTAT (void *p)
+CMSE_TT_ASM (at)
+
+#define CMSE_AU_NONSECURE	2
+#define CMSE_MPU_NONSECURE	16
+#define CMSE_NONSECURE		18
+
+#endif
+
+#define CMSE_MPU_UNPRIV		4
+#define CMSE_MPU_READWRITE	1
+#define CMSE_MPU_READ		8
+
+__extension__ void *
+cmse_check_address_range (void *p, size_t size, int flags);
+
+#define cmse_check_pointed_object(p, f) \
+  ((typeof (p)) cmse_check_address_range (p, sizeof (*p), f))
+
+#define cmse_nsfptr_create(p) ((typeof (p)) ((intptr_t) p & ~1))
+
+#define cmse_is_nsfptr(p) (!((intptr_t) p & 1))
+
+#endif /* ifdef __ARM_FEATURE_CMSE.  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ifndef _GCC_ARM_CMSE_H.  */
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 190112be9e550f62953982202d968aaed2ac7be2..c07de944f9b0aa30be72f2e3c410be0f0366e19a 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -583,7 +583,8 @@ Objective-C and Objective-C++ Dialects}.
 -mneon-for-64bits @gol
 -mslow-flash-data @gol
 -masm-syntax-unified @gol
--mrestrict-it}
+-mrestrict-it
+-mcmse}
 
 @emph{AVR Options}
 @gccoptlist{-mmcu=@var{mcu} -maccumulate-args -mbranch-cost=@var{cost} @gol
@@ -13892,6 +13893,10 @@ Print CPU tuning information as comment in assembler file.  This is
 an option used only for regression testing of the compiler and not
 intended for ordinary use in compiling code.  This option is disabled
 by default.
+
+@item -mcmse
+@opindex mcmse
+Generate secure code as per ARMv8-M Security Extensions.
 @end table
 
 @node AVR Options
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..1c3d4e9e934f4b1166d4d98383cf4ae8c3515117
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-1.c
@@ -0,0 +1,68 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_cmse_ok } */
+/* { dg-options "-Os -mcmse -fdump-rtl-expand" }  */
+
+#include <arm_cmse.h>
+
+extern int a;
+extern int bar (void);
+
+int foo (char * p)
+{
+  cmse_address_info_t cait;
+
+  cait = cmse_TT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTA (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTA_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  cait = cmse_TTAT (&a);
+  if (cait.flags.mpu_region)
+    a++;
+
+  cait = cmse_TTAT_fptr (&bar);
+  if (cait.flags.mpu_region)
+    a+= bar ();
+
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char), 0);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_UNPRIV);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_READWRITE);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_MPU_UNPRIV | CMSE_MPU_READ);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_AU_NONSECURE
+					 | CMSE_MPU_NONSECURE);
+  p = (char *) cmse_check_address_range ((void *) p, sizeof (char),
+					 CMSE_NONSECURE | CMSE_MPU_UNPRIV);
+
+  p = (char *) cmse_check_pointed_object (p, CMSE_NONSECURE | CMSE_MPU_UNPRIV);
+
+  return a;
+}
+/* { dg-final { scan-assembler-times "\ttt " 2 } } */
+/* { dg-final { scan-assembler-times "ttt " 2 } } */
+/* { dg-final { scan-assembler-times "tta " 2 } } */
+/* { dg-final { scan-assembler-times "ttat " 2 } } */
+/* { dg-final { scan-assembler-times "bl.cmse_check_address_range" 7 } } */
+/* { dg-final { scan-assembler-not "cmse_check_pointed_object" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c b/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c
new file mode 100644
index 0000000000000000000000000000000000000000..b0cdc3cc82a61877572e3ba694c3d20f764d9a96
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse-12.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_cmse_ok } */
+/* { dg-options "-mcmse" }  */
+#include <arm_cmse.h>
+
+char *
+foo (char * p)
+{
+  if (!cmse_is_nsfptr (p))
+    return cmse_nsfptr_create (p);
+}
+
+/* Checks for saving and clearing prior to function call.  */
+/* { dg-final { scan-assembler-not "cmse_is_nsfptr" } } */
+/* { dg-final { scan-assembler-not "cmse_nsfptr_create" } } */
diff --git a/gcc/testsuite/gcc.target/arm/cmse/cmse.exp b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
new file mode 100644
index 0000000000000000000000000000000000000000..6d4bfec1d12bc575218e0b8c33559d0a4da9ec70
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmse/cmse.exp
@@ -0,0 +1,45 @@
+#   Copyright (C) 1997-2015 Free Software Foundation, Inc.
+
+# This program 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite for ARMv8-M Security Extensions using the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+set saved-dg-do-what-default ${dg-do-what-default}
+set dg-do-what-default "assemble"
+
+set saved-lto_torture_options ${LTO_TORTURE_OPTIONS}
+set LTO_TORTURE_OPTIONS ""
+
+# These are for both baseline and mainline.
+gcc-dg-runtest [lsort [glob $srcdir/$subdir/*.c]] \
+	"" $DEFAULT_CFLAGS
+
+set LTO_TORTURE_OPTIONS ${saved-lto_torture_options}
+set dg-do-what-default ${saved-dg-do-what-default}
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 75af7a561848912d52366368756056c84b9c7757..1da38aef7fa27e9931ec777bdfceac03c01bd727 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -3261,6 +3261,19 @@ proc check_effective_target_arm_thumb1_movt_ko {} {
     }
 }
 
+# Return 1 if this is an ARM target where ARMv8-M security extension is
+# available.
+
+proc check_effective_target_arm_cmse_ok {} {
+    return [check_no_compiler_messages arm_cmse object {
+	int
+	foo (void)
+	{
+	  asm ("movt r0, #42");
+	}
+    } "-mcmse"];
+}
+
 # Return 1 if this compilation turns on string_ops_prefer_neon on.
 
 proc check_effective_target_arm_tune_string_ops_prefer_neon { } {
diff --git a/libgcc/config/arm/cmse.c b/libgcc/config/arm/cmse.c
new file mode 100644
index 0000000000000000000000000000000000000000..798ebd898d417d0bb6c8cdb0a2599938e2e24e60
--- /dev/null
+++ b/libgcc/config/arm/cmse.c
@@ -0,0 +1,110 @@
+/* ARMv8-M Security Extensions routines.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   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/>.  */
+
+
+#if __ARM_FEATURE_CMSE & 1
+
+#include <arm_cmse.h>
+#include <stdint.h>
+
+
+/* ARM intrinsic function to perform a permission check on a given
+   address range.  See ACLE changes for ARMv8-M.  */
+
+void *
+cmse_check_address_range (void *p, size_t size, int flags)
+{
+  cmse_address_info_t permb, perme;
+  char *pb = (char *) p, *pe;
+
+  /* Check if the range wraps around.  */
+  if (UINTPTR_MAX - (uintptr_t) p < size)
+    return NULL;
+
+  /* Check if an unknown flag is present.  */
+  int known = CMSE_MPU_UNPRIV | CMSE_MPU_READWRITE | CMSE_MPU_READ;
+  int known_secure_level = CMSE_MPU_UNPRIV;
+#if __ARM_FEATURE_CMSE & 2
+  known |= CMSE_AU_NONSECURE | CMSE_MPU_NONSECURE;
+  known_secure_level |= CMSE_MPU_NONSECURE;
+#endif
+  if (flags & (~known))
+    return NULL;
+
+  /* Execute the right variant of the TT instructions.  */
+  pe = pb + size - 1;
+  const int singleCheck = (((uintptr_t) pb ^ (uintptr_t) pe) < 32);
+  switch (flags & known_secure_level)
+    {
+    case 0:
+      permb = cmse_TT (pb);
+      perme = singleCheck ? permb : cmse_TT (pe);
+      break;
+    case CMSE_MPU_UNPRIV:
+      permb = cmse_TTT (pb);
+      perme = singleCheck ? permb : cmse_TTT (pe);
+      break;
+#if __ARM_FEATURE_CMSE & 2
+    case CMSE_MPU_NONSECURE:
+      permb = cmse_TTA (pb);
+      perme = singleCheck ? permb : cmse_TTA (pe);
+      break;
+    case CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE:
+      permb = cmse_TTAT (pb);
+      perme = singleCheck ? permb : cmse_TTAT (pe);
+      break;
+#endif
+    default:
+      /* Invalid flag, eg.  CMSE_MPU_NONSECURE specified but
+	 __ARM_FEATURE_CMSE & 2 == 0.  */
+      return NULL;
+    }
+
+  /* Check that the range does not cross MPU, SAU, or IDAU boundaries.  */
+  if (permb.value != perme.value)
+    return NULL;
+
+  /* Check the permissions on the range.  */
+  switch (flags & (~known_secure_level))
+    {
+#if __ARM_FEATURE_CMSE & 2
+    case CMSE_MPU_READ | CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+    case		 CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+      return permb.flags.nonsecure_readwrite_ok	? p : NULL;
+    case CMSE_MPU_READ | CMSE_AU_NONSECURE:
+      return permb.flags.nonsecure_read_ok	? p : NULL;
+    case CMSE_AU_NONSECURE:
+      return permb.flags.secure			? NULL : p;
+#endif
+    case CMSE_MPU_READ | CMSE_MPU_READWRITE:
+    case		 CMSE_MPU_READWRITE:
+      return permb.flags.readwrite_ok		? p : NULL;
+    case CMSE_MPU_READ:
+      return permb.flags.read_ok		? p : NULL;
+    default:
+      return NULL;
+    }
+}
+
+
+#endif /* __ARM_FEATURE_CMSE & 1.  */
diff --git a/libgcc/config/arm/t-arm b/libgcc/config/arm/t-arm
index 4e17e99b4a53bbafc0f1f8dddd02000f0e8f4f48..e6024f38b0b01ab2d2921d6f8da5b522422d0581 100644
--- a/libgcc/config/arm/t-arm
+++ b/libgcc/config/arm/t-arm
@@ -1,3 +1,15 @@
 LIB1ASMSRC = arm/lib1funcs.S
 LIB1ASMFUNCS = _thumb1_case_sqi _thumb1_case_uqi _thumb1_case_shi \
 	_thumb1_case_uhi _thumb1_case_si
+
+HAVE_CMSE:=$(findstring __ARM_FEATURE_CMSE,$(shell $(gcc_compile_bare) -dM -E - </dev/null))
+ifneq ($(shell $(gcc_compile_bare) -E -mcmse - </dev/null 2>/dev/null),)
+CMSE_OPTS:=-mcmse
+endif
+
+ifdef HAVE_CMSE
+libgcc-objects += cmse.o
+
+cmse.o: $(srcdir)/config/arm/cmse.c
+	$(gcc_compile) -c $(CMSE_OPTS) $<
+endif
