public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [RFC PATCH, binutils, ARM 6/9] Add support for ARMv8-M Secure Gateway veneer generation
@ 2015-12-23  7:59 Thomas Preud'homme
  2016-03-29 14:42 ` [RFC PATCH, binutils, ARM 8/11] " Thomas Preudhomme
  0 siblings, 1 reply; 10+ messages in thread
From: Thomas Preud'homme @ 2015-12-23  7:59 UTC (permalink / raw)
  To: binutils

Hi,

[Posting patch series as RFC]

This patch is part of a patch series to add support for ARMv8-M security extension[1] to GNU ld. This specific patch adds support for creating ARMv8-M Secure Gateway veneers.

ARM v8-M security extensions require [3] secure gateway veneers to be generated for (secure) entry function in order for code to transition from non-secure state to secure state when calling these entry function. Unlike other veneers, these veneers are generated independently of relocations, ie a veneer can be generated in the absence of relocation. The condition for the generation is that the normal symbol (the one whose name is the same as in C) of an entry function has the same value as the special symbol (normal symbol prefixed with "__acle_se_"). When that happens, the normal symbol is rebound to the veneer generated. When the two symbols have different value it indicates that the entry function already contains an sg instruction to do the secure state transition and the normal symbol points to the sg instruction while the special symbol points after that.

It is also required [4] that such veneers must be able to keep their address when the secure code is relinked in order to avoid relinking the non secure code with the secure code. This patch adds support for generating these veneers in a dedicated output section and expect the user to specify the address of that section (either via --section-start parameter or in the linker script). This ensure that they are placed in a memory area with sufficient space for more veneers to be added. Ensuring that existing veneers keep their addresses when the secure executable is relinked is handled by a subsequent patch of this patch serie.

Note: this patch needs the Cortex-A8 errata workaround refactoring patch applied to work (patch 1/9 in the patch serie).

RFC Note: This patch contains some Secure Gateway specific elements that could potentially be made into more generic and independent suitable for separate patch. Namely, these are the padding of stub section and setting a specific output section for a given stub section.


[1] Software requirements for ARMv8-M security extension are described in document ARM-ECM-0359818 [2]
[2] Available on http://infocenter.arm.com in Developer guides and articles > Software development > ARM®v8-M Security Extensions: Requirements on Development Tools
[3] See section 3.4.3 and requirement 44 of ARM-ECM-0359818 [2]
[4] requirement 14 and following comment of ARM-ECM-0359818 [2]


ChangeLog entries are as follows:

*** bfd/ChangeLog ***

2015-12-16  Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * elf32-arm.c (CMSE_PREFIX): Define macro.
        (CMSE_STUB_OUT_SEC_NAME): Likewise.
        (CMSE_STUB_SEC_PADDING): Likewise.
        (elf32_arm_stub_cmse_branch_thumb_only): Define stub sequence.
        (cmse_branch_thumb_only): Declare stub.
        (struct elf32_arm_link_hash_table): Define cmse_stub_sec field.
        (arm_stub_is_thumb): Add case for arm_stub_cmse_branch_thumb_only.
        (arm_stub_required_alignment): Likewise.
        (arm_stub_sym_claimed): Likewise.
        (elf32_arm_create_or_find_stub_sec): Add a stub type parameter and
        add support for arm_stub_cmse_branch_thumb_only input and output stub
        sections.
        (elf32_arm_add_stub): Add a stub type parameter and pass it down to
        elf32_arm_create_or_find_stub_sec.
        (elf32_arm_create_stub): Pass stub type down to elf32_arm_add_stub.
        (cmse_scan): New function.
        (elf32_arm_size_stubs): Call cmse_scan for ARM M profile targets to
        generate veneers for entry point functions to ARMv8-M secure code.
        Set stub_changed to TRUE if such veneers were created.  Account for
        32byte padding of secure gateway veneer section when computing its
        size. Pass stub type when calling elf32_arm_create_or_find_stub_sec for
        Cortex-A8 erratum veneers.
        (elf32_arm_build_stubs): Pad the aforementionned stub section to
        32byte boundary.
        (elf32_arm_final_link_relocate): Don't consider a symbol as having a
        PLT if dynobj is NULL.
        (elf32_arm_swap_symbol_in): Add detection code for CMSE special
        symbols.


*** include/elf/ChangeLog ***

2015-12-16  Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * arm.h (ARM_GET_SYM_CMSE_SPCL): Define macro.
        (ARM_SET_SYM_CMSE_SPCL): Likewise.


*** ld/ChangeLog ***

2015-12-16  Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * emultempl/armelf.em (arm_elf_before_allocation): Add SEC_KEEP flag
        to .sgstubs output section if it exists.


*** ld/testsuite/ChangeLog ***

2015-12-16  Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * ld-arm/arm-elf.exp (Secure gateway veneers: no .sgstubs section): New
        test.
        (Secure gateway veneers: wrong entry functions): Likewise.
        (Secure gateway veneers (ARMv8-M Baseline)): Likewise.
        (Secure gateway veneers (ARMv8-M Mainline)): Likewise.
        * ld-arm/cmse-veneers.s: New file.
        * ld-arm/cmse-veneers.d: Likewise.
        * ld-arm/cmse-veneers.rd: Likewise.
        * ld-arm/cmse-veneers.sd: Likewise.
        * ld-arm/cmse-veneers-no-sgstubs.out: Likewise.
        * ld-arm/cmse-veneers-wrong-entryfct.out: Likewise.


diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index b69981ab1259a3415a9974ed2770bf96edfd7eb9..1d9b0135022a6a6a2d9f97564cdd63e267a22e2b 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -2080,6 +2080,8 @@ typedef unsigned short int insn16;
 
 #define STUB_ENTRY_NAME   "__%s_veneer"
 
+#define CMSE_PREFIX "__acle_se_"
+
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
 #define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
@@ -2485,6 +2487,13 @@ static const insn_sequence elf32_arm_stub_long_branch_arm_nacl_pic[] =
   DATA_WORD (0, R_ARM_NONE, 0),         /* .word 0 */
 };
 
+/* Stub used for transition to secure state (aka SG veneer).  */
+static const insn_sequence elf32_arm_stub_cmse_branch_thumb_only[] =
+{
+  THUMB32_INSN (0xe97fe97f),		/* sg.  */
+  THUMB32_B_INSN (0xf000b800, -4),	/* b.w original_branch_dest.  */
+};
+
 
 /* Cortex-A8 erratum-workaround stubs.  */
 
@@ -2546,6 +2555,14 @@ static const insn_sequence elf32_arm_stub_a8_veneer_blx[] =
    C identifier.  */
 #define STUB_SUFFIX ".__stub"
 
+/* Name of the output section holding secure gateway veneers.  This definition
+   must be kept in sync with name used in ld/emultempl/armelf.em.  */
+#define CMSE_STUB_OUT_SEC_NAME ".sgstubs"
+
+/* Section for secure gateway veneers must be zero padded to a 32 byte
+   boundary.  */
+#define CMSE_STUB_SEC_PADDING 32
+
 /* One entry per long/short branch stub defined above.  */
 #define DEF_STUBS \
   DEF_STUB(long_branch_any_any)	\
@@ -2564,6 +2581,7 @@ static const insn_sequence elf32_arm_stub_a8_veneer_blx[] =
   DEF_STUB(long_branch_v4t_thumb_tls_pic) \
   DEF_STUB(long_branch_arm_nacl) \
   DEF_STUB(long_branch_arm_nacl_pic) \
+  DEF_STUB(cmse_branch_thumb_only) \
   DEF_STUB(a8_veneer_b_cond) \
   DEF_STUB(a8_veneer_b) \
   DEF_STUB(a8_veneer_bl) \
@@ -3111,6 +3129,9 @@ struct elf32_arm_link_hash_table
      information on stub grouping.  */
   struct map_stub *stub_group;
 
+  /* Input stub section holding secure gateway veneers.  */
+  asection *cmse_stub_sec;
+
   /* Number of elements in stub_group.  */
   unsigned int top_id;
 
@@ -3691,6 +3712,7 @@ arm_stub_is_thumb (enum elf32_arm_stub_type stub_type)
     case arm_stub_long_branch_v4t_thumb_arm_pic:
     case arm_stub_long_branch_v4t_thumb_tls_pic:
     case arm_stub_long_branch_thumb_only_pic:
+    case arm_stub_cmse_branch_thumb_only:
       return TRUE;
     case arm_stub_none:
       BFD_FAIL ();
@@ -4059,68 +4081,94 @@ elf32_arm_get_stub_entry (const asection *input_section,
   return stub_entry;
 }
 
-/* Find or create a stub section.  Returns a pointer to the stub section, and
-   the section to which the stub section will be attached (in *LINK_SEC_P).
-   LINK_SEC_P may be NULL.  */
+/* Find or create a stub section to contain a stub of type STUB_TYPE.  Returns
+   a pointer to the stub section, and the section to which the stub section
+   will be attached (in *LINK_SEC_P).  LINK_SEC_P may be NULL.  */
 
 static asection *
 elf32_arm_create_or_find_stub_sec (asection **link_sec_p, asection *section,
-				   struct elf32_arm_link_hash_table *htab)
+				   struct elf32_arm_link_hash_table *htab,
+				   enum elf32_arm_stub_type stub_type)
 {
-  asection *link_sec;
-  asection *stub_sec;
-  asection *out_sec;
+  asection *link_sec, *out_sec, **stub_sec_p;
+  const char *stub_sec_prefix;
+  int align;
 
-  link_sec = htab->stub_group[section->id].link_sec;
-  BFD_ASSERT (link_sec != NULL);
-  stub_sec = htab->stub_group[section->id].stub_sec;
-
-  if (stub_sec == NULL)
+  if (stub_type == arm_stub_cmse_branch_thumb_only)
     {
-      stub_sec = htab->stub_group[link_sec->id].stub_sec;
-      if (stub_sec == NULL)
+      bfd *output_bfd = htab->obfd;
+      link_sec = NULL;
+      stub_sec_p = &htab->cmse_stub_sec;
+      stub_sec_prefix = CMSE_PREFIX;
+      align = 5;
+      out_sec = bfd_get_section_by_name (output_bfd, CMSE_STUB_OUT_SEC_NAME);
+      if (out_sec == NULL)
 	{
-	  size_t namelen;
-	  bfd_size_type len;
-	  char *s_name;
-
-	  namelen = strlen (link_sec->name);
-	  len = namelen + sizeof (STUB_SUFFIX);
-	  s_name = (char *) bfd_alloc (htab->stub_bfd, len);
-	  if (s_name == NULL)
-	    return NULL;
-
-	  memcpy (s_name, link_sec->name, namelen);
-	  memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
-	  out_sec = link_sec->output_section;
-	  stub_sec = (*htab->add_stub_section) (s_name, out_sec, link_sec,
-						htab->nacl_p ? 4 : 3);
-	  if (stub_sec == NULL)
-	    return NULL;
-	  htab->stub_group[link_sec->id].stub_sec = stub_sec;
+	  (*_bfd_error_handler) (_("No address assigned to the secure gateway "
+				   "veneers output section %s"),
+				 CMSE_STUB_OUT_SEC_NAME);
+	  return NULL;
 	}
-      htab->stub_group[section->id].stub_sec = stub_sec;
+    }
+  else
+    {
+      link_sec = htab->stub_group[section->id].link_sec;
+      BFD_ASSERT (link_sec != NULL);
+      stub_sec_p = &htab->stub_group[section->id].stub_sec;
+      if (*stub_sec_p == NULL)
+	stub_sec_p = &htab->stub_group[link_sec->id].stub_sec;
+      stub_sec_prefix = link_sec->name;
+      out_sec = link_sec->output_section;
+      align = htab->nacl_p ? 4 : 3;
     }
 
+  if (*stub_sec_p == NULL)
+    {
+      size_t namelen;
+      bfd_size_type len;
+      char *s_name;
+
+      namelen = strlen (stub_sec_prefix);
+      len = namelen + sizeof (STUB_SUFFIX);
+      s_name = (char *) bfd_alloc (htab->stub_bfd, len);
+      if (s_name == NULL)
+	return NULL;
+
+      memcpy (s_name, stub_sec_prefix, namelen);
+      memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
+      *stub_sec_p = (*htab->add_stub_section) (s_name, out_sec, link_sec,
+					       align);
+      if (*stub_sec_p == NULL)
+	return NULL;
+
+      out_sec->flags |= SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
+			| SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY
+			| SEC_KEEP;
+    }
+
+  if (stub_type != arm_stub_cmse_branch_thumb_only)
+    htab->stub_group[section->id].stub_sec = *stub_sec_p;
+
   if (link_sec_p)
     *link_sec_p = link_sec;
 
-  return stub_sec;
+  return *stub_sec_p;
 }
 
 /* Add a new stub entry to the stub hash.  Not all fields of the new
    stub entry are initialised.  */
 
 static struct elf32_arm_stub_hash_entry *
-elf32_arm_add_stub (const char *stub_name,
-		    asection *section,
-		    struct elf32_arm_link_hash_table *htab)
+elf32_arm_add_stub (const char *stub_name, asection *section,
+		    struct elf32_arm_link_hash_table *htab,
+		    enum elf32_arm_stub_type stub_type)
 {
   asection *link_sec;
   asection *stub_sec;
   struct elf32_arm_stub_hash_entry *stub_entry;
 
-  stub_sec = elf32_arm_create_or_find_stub_sec (&link_sec, section, htab);
+  stub_sec = elf32_arm_create_or_find_stub_sec (&link_sec, section, htab,
+						stub_type);
   if (stub_sec == NULL)
     return NULL;
 
@@ -4247,6 +4295,7 @@ arm_stub_required_alignment (enum elf32_arm_stub_type stub_type)
     case arm_stub_long_branch_thumb_only_pic:
     case arm_stub_long_branch_any_tls_pic:
     case arm_stub_long_branch_v4t_thumb_tls_pic:
+    case arm_stub_cmse_branch_thumb_only:
     case arm_stub_a8_veneer_blx:
       return 4;
 
@@ -4289,6 +4338,9 @@ arm_stub_sym_claimed (enum elf32_arm_stub_type stub_type)
     case arm_stub_long_branch_arm_nacl_pic:
       return FALSE;
 
+    case arm_stub_cmse_branch_thumb_only:
+      return TRUE;
+
     default:
       abort ();  /* Should be unreachable.  */
     }
@@ -5132,7 +5184,7 @@ elf32_arm_create_stub (struct elf32_arm_link_hash_table *htab,
       return TRUE;
     }
 
-  stub_entry = elf32_arm_add_stub (stub_name, section, htab);
+  stub_entry = elf32_arm_add_stub (stub_name, section, htab, stub_type);
   if (stub_entry == NULL)
     {
       if (!arm_stub_sym_claimed (stub_type))
@@ -5181,6 +5233,184 @@ elf32_arm_create_stub (struct elf32_arm_link_hash_table *htab,
   return TRUE;
 }
 
+/* Scan symbols in INPUT_BFD for secure gateway veneers to create.  OUT_ATTR
+   gives the output attributes, SYM_HASHES the symbol index to hash entry
+   mapping while HTAB gives the name to hash entry mapping.
+
+   If any secure gateway veneer is created, *STUB_CHANGED is set to TRUE.  The
+   return value gives whether a stub failed to be allocated.  */
+
+static bfd_boolean
+cmse_scan (bfd *input_bfd, struct elf32_arm_link_hash_table *htab,
+	   obj_attribute *out_attr, struct elf_link_hash_entry **sym_hashes,
+	   bfd_boolean *stub_changed)
+{
+  const struct elf_backend_data *bed;
+  Elf_Internal_Shdr *symtab_hdr;
+  unsigned i, j, sym_count, ext_start;
+  Elf_Internal_Sym *cmse_sym, *local_syms;
+  struct elf32_arm_link_hash_entry *hash, *cmse_hash = NULL;
+  enum arm_st_branch_type branch_type;
+  char *sym_name, *lsym_name;
+  bfd_vma sym_value;
+  asection *section;
+  bfd_boolean is_v8m, new_stub, created_stub, cmse_invalid, ret = TRUE;
+
+  bed = get_elf_backend_data (input_bfd);
+  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym;
+  ext_start = symtab_hdr->sh_info;
+  is_v8m = (out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE
+	    && out_attr[Tag_CPU_arch_profile].i == 'M');
+
+  local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+  if (local_syms == NULL)
+    local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
+				       symtab_hdr->sh_info, 0, NULL, NULL,
+				       NULL);
+  if (symtab_hdr->sh_info && local_syms == NULL)
+    return FALSE;
+
+  /* Scan symbols.  */
+  for (i = 0; i < sym_count; i++)
+    {
+      cmse_invalid = FALSE;
+
+      if (i < ext_start)
+	{
+	  cmse_sym = &local_syms[i];
+	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_sym->st_target_internal))
+	    continue;
+	  sym_name = bfd_elf_string_from_elf_section (input_bfd,
+						      symtab_hdr->sh_link,
+						      cmse_sym->st_name);
+	  cmse_invalid = TRUE;
+	}
+      else
+	{
+	  cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]);
+	  sym_name = (char *) cmse_hash->root.root.root.string;
+
+	  /* Not a special symbol.  */
+	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal))
+	    continue;
+
+	  if ((cmse_hash->root.root.type != bfd_link_hash_defined
+	       && cmse_hash->root.root.type != bfd_link_hash_defweak)
+	      || cmse_hash->root.type != STT_FUNC)
+	    cmse_invalid = TRUE;
+	}
+
+      if (!is_v8m)
+	{
+	  (*_bfd_error_handler) (_("%B: Special symbol `%s' only allowed for "
+				   "ARMv8-M architecture or later."),
+				 input_bfd, sym_name);
+	  is_v8m = TRUE; /* Avoid multiple warning.  */
+	  ret = FALSE;
+	}
+
+      if (cmse_invalid)
+	{
+	  (*_bfd_error_handler) (_("%B: invalid special symbol `%s'."),
+				 input_bfd, sym_name);
+	  (*_bfd_error_handler) (_("It must be a global or weak function "
+				   "symbol."));
+	  ret = FALSE;
+	  if (i < ext_start)
+	    continue;
+	}
+
+      sym_name += strlen (CMSE_PREFIX);
+      hash = (struct elf32_arm_link_hash_entry *)
+	elf_link_hash_lookup (&(htab)->root, sym_name, FALSE, FALSE, TRUE);
+
+      /* No associated normal symbol or it is neither global nor weak.  */
+      if (!hash
+	  || (hash->root.root.type != bfd_link_hash_defined
+	      && hash->root.root.type != bfd_link_hash_defweak)
+	  || hash->root.type != STT_FUNC)
+	{
+	  if (!hash)
+	    {
+	      for (j = 0; j < ext_start; j++)
+		{
+		  lsym_name =
+		    bfd_elf_string_from_elf_section (input_bfd,
+						     symtab_hdr->sh_link,
+						     local_syms[j].st_name);
+		  if (!strcmp (sym_name, lsym_name))
+		    break;
+		}
+	    }
+
+	  if (hash || j < ext_start)
+	    {
+	      (*_bfd_error_handler)
+		(_("%B: invalid standard symbol `%s'."), input_bfd, sym_name);
+	      (*_bfd_error_handler)
+		(_("It must be a global or weak function symbol."));
+	    }
+	  else
+	    (*_bfd_error_handler)
+	      (_("%B: absent standard symbol `%s'."), input_bfd, sym_name);
+	  ret = FALSE;
+	  if (!hash)
+	    continue;
+	}
+
+      sym_value = hash->root.root.u.def.value;
+      section = hash->root.root.u.def.section;
+
+      /* Value or input section different.  */
+      if (cmse_hash->root.root.u.def.section != section)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: `%s' and its special symbol are in different sections."),
+	     input_bfd, sym_name);
+	  ret = FALSE;
+	}
+      if (cmse_hash->root.root.u.def.value != sym_value)
+	continue; /* Ignore: could be an entry function starting with SG.  */
+
+	/* If this section is a link-once section that will be discarded, then
+	   don't create any stubs.  */
+      if (section->output_section == NULL)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: entry function `%s' not output."), input_bfd, sym_name);
+	  continue;
+	}
+
+      if (hash->root.size == 0)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: entry function `%s' is empty."), input_bfd, sym_name);
+	  ret = FALSE;
+	}
+
+      if (!ret)
+	continue;
+      branch_type = ARM_GET_SYM_BRANCH_TYPE (hash->root.target_internal);
+      created_stub
+	= elf32_arm_create_stub (htab, arm_stub_cmse_branch_thumb_only,
+				 NULL, NULL, section, hash, sym_name,
+				 sym_value, branch_type, &new_stub);
+
+      if (!created_stub)
+	 ret = FALSE;
+      else
+	{
+	  BFD_ASSERT (new_stub);
+	  *stub_changed = TRUE;
+	}
+    }
+
+  if (!symtab_hdr->contents)
+    free (local_syms);
+  return ret;
+}
+
 /* Determine and set the size of the stub section for a final link.
 
    The basic idea here is to examine all the relocations looking for
@@ -5197,8 +5427,9 @@ elf32_arm_size_stubs (bfd *output_bfd,
 						      unsigned int),
 		      void (*layout_sections_again) (void))
 {
+  obj_attribute *out_attr;
   bfd_size_type stub_group_size;
-  bfd_boolean stubs_always_after_branch;
+  bfd_boolean stubs_always_after_branch, cmse_stub_changed = FALSE;
   struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
   struct a8_erratum_fix *a8_fixes = NULL;
   unsigned int num_a8_fixes = 0, a8_fix_table_size = 10;
@@ -5227,6 +5458,24 @@ elf32_arm_size_stubs (bfd *output_bfd,
   htab->layout_sections_again = layout_sections_again;
   stubs_always_after_branch = group_size < 0;
 
+  out_attr = elf_known_obj_attributes_proc (output_bfd);
+  /* Limit scan of symbols to object file whose profile is Microcontroller to
+     not hinder performance in the general case.  */
+  if (out_attr[Tag_CPU_arch_profile].i == 'M')
+    {
+      bfd *input_bfd;
+
+      for (input_bfd = info->input_bfds; input_bfd != NULL;
+	   input_bfd = input_bfd->link.next)
+	{
+	  struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd);
+
+	  if (!cmse_scan (input_bfd, htab, out_attr, sym_hashes,
+			  &cmse_stub_changed))
+	    goto error_ret_free_local;
+	}
+    }
+
   /* The Cortex-A8 erratum fix depends on stubs not being in the same 4K page
      as the first half of a 32-bit branch straddling two 4K pages.  This is a
      crude way of enforcing that.  */
@@ -5269,10 +5518,11 @@ elf32_arm_size_stubs (bfd *output_bfd,
       bfd *input_bfd;
       unsigned int bfd_indx;
       asection *stub_sec;
-      bfd_boolean stub_changed = FALSE;
+      bfd_boolean stub_changed = cmse_stub_changed;
       unsigned prev_num_a8_fixes = num_a8_fixes;
 
       num_a8_fixes = 0;
+      cmse_stub_changed = FALSE;
       for (input_bfd = info->input_bfds, bfd_indx = 0;
 	   input_bfd != NULL;
 	   input_bfd = input_bfd->link.next, bfd_indx++)
@@ -5280,6 +5530,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
 	  Elf_Internal_Shdr *symtab_hdr;
 	  asection *section;
 	  Elf_Internal_Sym *local_syms = NULL;
+	  struct elf_link_hash_entry **sym_hashes;
 
 	  if (!is_arm_elf (input_bfd))
 	    continue;
@@ -5291,6 +5542,8 @@ elf32_arm_size_stubs (bfd *output_bfd,
 	  if (symtab_hdr->sh_info == 0)
 	    continue;
 
+	  sym_hashes = elf_sym_hashes (input_bfd);
+
 	  /* Walk over each section attached to the input bfd.  */
 	  for (section = input_bfd->sections;
 	       section != NULL;
@@ -5349,8 +5602,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
 		  hash = NULL;
 		  if (r_indx >= symtab_hdr->sh_info)
 		    hash = elf32_arm_hash_entry
-		      (elf_sym_hashes (input_bfd)
-		       [r_indx - symtab_hdr->sh_info]);
+		      (sym_hashes[r_indx - symtab_hdr->sh_info]);
 
 		  /* Only look for stubs on branch instructions, or
 		     non-relaxed TLSCALL  */
@@ -5625,13 +5877,20 @@ elf32_arm_size_stubs (bfd *output_bfd,
 	}
 
       bfd_hash_traverse (&htab->stub_hash_table, arm_size_one_stub, htab);
+      if (htab->cmse_stub_sec)
+	{
+	  int size = htab->cmse_stub_sec->size;
+	  size = (size + CMSE_STUB_SEC_PADDING - 1)
+		 & ~(CMSE_STUB_SEC_PADDING - 1);
+	  htab->cmse_stub_sec->size = size;
+	}
 
       /* Add Cortex-A8 erratum veneers to stub section sizes too.  */
       if (htab->fix_cortex_a8)
 	for (i = 0; i < num_a8_fixes; i++)
 	  {
 	    stub_sec = elf32_arm_create_or_find_stub_sec (NULL,
-			 a8_fixes[i].section, htab);
+			 a8_fixes[i].section, htab, a8_fixes[i].stub_type);
 
 	    if (stub_sec == NULL)
 	      goto error_ret_free_local;
@@ -5743,6 +6002,18 @@ elf32_arm_build_stubs (struct bfd_link_info *info)
   /* Build the stubs as directed by the stub hash table.  */
   table = &htab->stub_hash_table;
   bfd_hash_traverse (table, arm_build_one_stub, info);
+  if (htab->cmse_stub_sec)
+    {
+      bfd_byte *loc;
+      int size, padded_size;
+
+      loc = htab->cmse_stub_sec->contents + htab->cmse_stub_sec->size;
+      size = htab->cmse_stub_sec->size;
+      padded_size = (size + CMSE_STUB_SEC_PADDING - 1)
+		    & ~(CMSE_STUB_SEC_PADDING - 1);
+      memset (loc, 0, padded_size - size);
+      htab->cmse_stub_sec->size = padded_size;
+    }
   if (htab->fix_cortex_a8)
     {
       /* Place the cortex a8 stubs last.  */
@@ -8954,6 +9225,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
      VALUE appropriately for relocations that we resolve at link time.  */
   has_iplt_entry = FALSE;
   if (elf32_arm_get_plt_info (input_bfd, eh, r_symndx, &root_plt, &arm_plt)
+      && globals->root.dynobj != NULL
       && root_plt->offset != (bfd_vma) -1)
     {
       plt_offset = root_plt->offset;
@@ -17402,6 +17674,9 @@ elf32_arm_swap_symbol_in (bfd * abfd,
 			  const void *pshn,
 			  Elf_Internal_Sym *dst)
 {
+  Elf_Internal_Shdr *symtab_hdr;
+  const char *name = NULL;
+
   if (!bfd_elf32_swap_symbol_in (abfd, psrc, pshn, dst))
     return FALSE;
   dst->st_target_internal = 0;
@@ -17430,6 +17705,13 @@ elf32_arm_swap_symbol_in (bfd * abfd,
   else
     ARM_SET_SYM_BRANCH_TYPE (dst->st_target_internal, ST_BRANCH_UNKNOWN);
 
+  /* Mark CMSE special symbols.  */
+  symtab_hdr = & elf_symtab_hdr (abfd);
+  if (symtab_hdr->sh_size)
+    name = bfd_elf_sym_name (abfd, symtab_hdr, dst, NULL);
+  if (name && CONST_STRNEQ (name, CMSE_PREFIX))
+    ARM_SET_SYM_CMSE_SPCL (dst->st_target_internal);
+
   return TRUE;
 }
 
diff --git a/include/elf/arm.h b/include/elf/arm.h
index 1a7fe1cf947bfb890884f77b3b30c035046b3fd5..c7e4c478dd8168c7cb9cd83eb3d9dfbf77730d39 100644
--- a/include/elf/arm.h
+++ b/include/elf/arm.h
@@ -361,4 +361,11 @@ enum arm_st_branch_type {
 #define ARM_SET_SYM_BRANCH_TYPE(SYM_TARGET_INTERNAL,TYPE) \
   ((SYM_TARGET_INTERNAL) = ((SYM_TARGET_INTERNAL) & ~3) | ((TYPE) & 3))
 
+/* Get or set whether a symbol is a special symbol of an entry function of CMSE
+   secure code.  */
+#define ARM_GET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
+  (((SYM_TARGET_INTERNAL) >> 2) & 1)
+#define ARM_SET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
+  (SYM_TARGET_INTERNAL) |= 4
+
 #endif /* _ELF_ARM_H */
diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em
index f20820733e37b78e45eb6c5f466f6ad2ccea9a14..f297f4574348c0c3705f53638cc9225dfb1978bb 100644
--- a/ld/emultempl/armelf.em
+++ b/ld/emultempl/armelf.em
@@ -70,6 +70,8 @@ gld${EMULATION_NAME}_set_symbols (void)
 static void
 arm_elf_before_allocation (void)
 {
+  asection *cmse_stub_out_sec;
+
   bfd_elf32_arm_set_byteswap_code (&link_info, byteswap_code);
 
   /* Choose type of VFP11 erratum fix, or warn if specified fix is unnecessary
@@ -83,6 +85,15 @@ arm_elf_before_allocation (void)
   /* Auto-select Cortex-A8 erratum fix if it wasn't explicitly specified.  */
   bfd_elf32_arm_set_cortex_a8_fix (link_info.output_bfd, &link_info);
 
+  /* Mark output section for SG veneers with SEC_KEEP to ensure it's not marked
+     for deletion by strip_excluded_output_sections () when veneers are going
+     to be created later.  Not doing so would trigger assert on empty section
+     size in lang_size_sections_1 ().  */
+  cmse_stub_out_sec = bfd_get_section_by_name (link_info.output_bfd,
+					       ".sgstubs");
+  if (cmse_stub_out_sec != NULL)
+    cmse_stub_out_sec->flags |= SEC_KEEP;
+
   /* We should be able to set the size of the interworking stub section.  We
      can't do it until later if we have dynamic sections, though.  */
   if (elf_hash_table (&link_info)->dynobj == NULL)
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index a991c39717791837691f5b01e6a642aec9941e5e..037198fe0f17eef66c10f755ee56ad4dac2d5c8e 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -597,6 +597,33 @@ set armeabitests_nonacl {
      {{objdump -d jump-reloc-veneers-long.d}}
      "jump-reloc-veneers-long"}
 
+    {"Secure gateway veneers: no .sgstubs section" "" ""
+     "-march=armv8-m.base -mthumb"
+     {cmse-veneers.s}
+     {{ld cmse-veneers-no-sgstubs.out}}
+     "cmse-veneers-no-sgstubs"}
+    {"Secure gateway veneers: wrong entry functions" "" ""
+     "-march=armv7-m -mthumb --defsym CHECK_ERRORS=1"
+     {cmse-veneers.s}
+     {{ld cmse-veneers-wrong-entryfct.out}}
+     "cmse-veneers-wrong-entryfct"}
+    {"Secure gateway veneers (ARMv8-M Baseline)"
+     "-Ttext=0x8000 --section-start .sgstubs=0x20000" ""
+     "-march=armv8-m.base -mthumb"
+     {cmse-veneers.s}
+     {{objdump {-d -j .sgstubs} cmse-veneers.d}
+      {objdump {-h -j .sgstubs} cmse-veneers.sd}
+      {nm {} cmse-veneers.rd}}
+     "cmse-veneers-baseline"}
+    {"Secure gateway veneers (ARMv8-M Mainline)"
+     "-Ttext=0x8000 --section-start .sgstubs=0x20000" ""
+     "-march=armv8-m.main -mthumb"
+     {cmse-veneers.s}
+     {{objdump {-d -j .sgstubs} cmse-veneers.d}
+      {objdump {-h -j .sgstubs} cmse-veneers.sd}
+      {nm {} cmse-veneers.rd}}
+     "cmse-veneers-mainline"}
+
     {"R_ARM_THM_JUMP19 Relocation veneers: Short"
      "--section-start destsect=0x000108002 --section-start .text=0x8000" ""
      "-march=armv7-m -mthumb"
diff --git a/ld/testsuite/ld-arm/cmse-veneers-no-sgstubs.out b/ld/testsuite/ld-arm/cmse-veneers-no-sgstubs.out
new file mode 100644
index 0000000000000000000000000000000000000000..6a29a6cc1cb3822d397e5812937ffc659b7b47a7
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers-no-sgstubs.out
@@ -0,0 +1,3 @@
+.*: No address assigned to the secure gateway veneers output section .sgstubs
+.*: cannot size stub section: Invalid operation
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
new file mode 100644
index 0000000000000000000000000000000000000000..fd4766ab877a4abbeb8b2c4c053ab11d3f86773c
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
@@ -0,0 +1,19 @@
+.*: .*: Special symbol `__acle_se_loc_entry_veneer1' only allowed for ARMv8-M architecture or later.
+.*: .*: invalid .* symbol `.*loc_entry_veneer1'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_loc_entry_veneer2'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_loc_entry_veneer4'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid standard symbol `loc_entry_veneer3'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid standard symbol `loc_entry_veneer5'.
+.*: It must be a global or weak function symbol.
+.*: .*: absent standard symbol `fake_entry_veneer1'.
+.*: .*: invalid standard symbol `obj_entry_veneer1'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_obj_entry_veneer2'.
+.*: It must be a global or weak function symbol.
+.*: .*: `fake_entry_veneer2' and its special symbol are in different sections.
+.*: cannot size stub section: Invalid operation
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers.d b/ld/testsuite/ld-arm/cmse-veneers.d
new file mode 100644
index 0000000000000000000000000000000000000000..868e5605e9cfc72fef567f896af1e0aff6875296
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.d
@@ -0,0 +1,21 @@
+
+.*
+
+
+Disassembly of section \.sgstubs:
+
+00020000 <glob_entry_veneer2>:
+   20000:	e97f e97f 	sg
+   20004:	f7e8 b800 	b\.w	8008 <__acle_se_glob_entry_veneer2>
+
+00020008 <weak_entry_veneer2>:
+   20008:	e97f e97f 	sg
+   2000c:	f7e7 bffe 	b\.w	800c <__acle_se_weak_entry_veneer2>
+
+00020010 <glob_entry_veneer1>:
+   20010:	e97f e97f 	sg
+   20014:	f7e7 bff4 	b\.w	8000 <__acle_se_glob_entry_veneer1>
+
+00020018 <weak_entry_veneer1>:
+   20018:	e97f e97f 	sg
+   2001c:	f7e7 bff2 	b\.w	8004 <__acle_se_weak_entry_veneer1>
diff --git a/ld/testsuite/ld-arm/cmse-veneers.rd b/ld/testsuite/ld-arm/cmse-veneers.rd
new file mode 100644
index 0000000000000000000000000000000000000000..20fad961bd8803109c3cf57ef22e3b36da5b1500
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.rd
@@ -0,0 +1,9 @@
+#...
+[0-9a-f]+ T glob_entry_fct
+#...
+[0-9a-f]+ T glob_entry_veneer1
+[0-9a-f]+ T glob_entry_veneer2
+#...
+[0-9a-f]+ W weak_entry_veneer1
+[0-9a-f]+ W weak_entry_veneer2
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers.s b/ld/testsuite/ld-arm/cmse-veneers.s
new file mode 100644
index 0000000000000000000000000000000000000000..d5c57f646a78c4736e4f084d8ad6aff7efea554f
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.s
@@ -0,0 +1,97 @@
+	.syntax unified
+	.thumb
+	.file	"foo.c"
+	.text
+
+.macro	decltype	name, type
+.ifc \type,object
+	.data
+.else
+	.thumb
+	.thumb_func
+.endif
+	.type	\name, %\type
+.endm
+
+
+.macro	entry	name, type, vis, typespc, visspc, entry_fct
+	.align	2
+.ifb \visspc
+	.\vis	__acle_se_\name
+.else
+	.\visspc	__acle_se_\name
+.endif
+	.\vis	\name
+	.thumb
+	.thumb_func
+.ifb \typespc
+	decltype	__acle_se_\name, \type
+.else
+	decltype	__acle_se_\name, \typespc
+.endif
+	decltype	\name, \type
+__acle_se_\name:
+	\entry_fct
+\name:
+.ifc \type,object
+	.word 42
+.else
+	nop
+.endif
+	.size	\name, .-\name
+	.size	__acle_se_\name, .-__acle_se_\name
+.endm
+
+
+.ifndef CHECK_ERRORS
+	@ Valid setups for veneer generation
+	entry glob_entry_veneer1, function, global
+	entry weak_entry_veneer1, function, weak
+	entry glob_entry_veneer2, function, global, visspc=weak
+	entry weak_entry_veneer2, function, weak, visspc=global
+
+	@ Valid setup for entry function without SG veneer
+	entry glob_entry_fct, function, global, entry_fct=nop
+
+.else
+	@ Invalid setups for veneer generation (visibility)
+	entry loc_entry_veneer1, function, local
+	entry loc_entry_veneer2, function, global, visspc=local
+	entry loc_entry_veneer3, function, local, visspc=global
+	entry loc_entry_veneer4, function, weak, visspc=local
+	entry loc_entry_veneer5, function, local, visspc=weak
+
+	@ Invalid setups for veneer generation (absent standard symbol)
+	.align	2
+	.global	__acle_se_fake_entry_veneer1
+	.thumb
+	.thumb_func
+	.type	__acle_se_fake_entry_veneer1, %function
+__acle_se_fake_entry_veneer1:
+	nop
+	.size	__acle_se_fake_entry_veneer1, .-__acle_se_fake_entry_veneer1
+
+	@ Invalid setups for veneer generation (type)
+	entry obj_entry_veneer1, object, global, typespc=function
+	entry obj_entry_veneer2, function, global, typespc=object
+
+	@ Invalid setup for veneer generation (sections)
+	.section .text.sub1
+	.align	2
+	.thumb
+	.thumb_func
+	.global	__acle_se_fake_entry_veneer2
+	.type	__acle_se_fake_entry_veneer2, %function
+__acle_se_fake_entry_veneer2:
+	nop
+	.size	__acle_se_fake_entry_veneer2, .-__acle_se_fake_entry_veneer2
+	.section .text.sub2
+	.align	2
+	.thumb
+	.thumb_func
+	.global	fake_entry_veneer2
+	.type	fake_entry_veneer2, %function
+fake_entry_veneer2:
+	nop
+	.size	fake_entry_veneer2, .-fake_entry_veneer2
+.endif
diff --git a/ld/testsuite/ld-arm/cmse-veneers.sd b/ld/testsuite/ld-arm/cmse-veneers.sd
new file mode 100644
index 0000000000000000000000000000000000000000..a31f284dd125d900e37e5c517edc2487a0964b76
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.sd
@@ -0,0 +1,7 @@
+
+.*
+
+Sections:
+Idx Name          Size      VMA       LMA       File off  Algn
+  1 \.sgstubs      00000020  00020000  00020000  00010000  2\*\*5
+                  CONTENTS, ALLOC, LOAD, READONLY, CODE


The patch doesn't show any regression when running the binutils-gdb testsuite for the arm-none-eabi target.

Any comments?

Best regards,

Thomas

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH, binutils, ARM 8/11] Add support for ARMv8-M Secure Gateway veneer generation
  2015-12-23  7:59 [RFC PATCH, binutils, ARM 6/9] Add support for ARMv8-M Secure Gateway veneer generation Thomas Preud'homme
@ 2016-03-29 14:42 ` Thomas Preudhomme
  2016-05-18 16:30   ` Thomas Preudhomme
  0 siblings, 1 reply; 10+ messages in thread
From: Thomas Preudhomme @ 2016-03-29 14:42 UTC (permalink / raw)
  To: binutils

On Wednesday 23 December 2015 15:59:44 Thomas Preud'homme wrote:
> Hi,
> 
> [Posting patch series as RFC]
> 
> This patch is part of a patch series to add support for ARMv8-M security
> extension[1] to GNU ld. This specific patch adds support for creating
> ARMv8-M Secure Gateway veneers.
> 
> ARM v8-M security extensions require [3] secure gateway veneers to be
> generated for (secure) entry function in order for code to transition from
> non-secure state to secure state when calling these entry function. Unlike
> other veneers, these veneers are generated independently of relocations, ie
> a veneer can be generated in the absence of relocation. The condition for
> the generation is that the normal symbol (the one whose name is the same as
> in C) of an entry function has the same value as the special symbol (normal
> symbol prefixed with "__acle_se_"). When that happens, the normal symbol is
> rebound to the veneer generated. When the two symbols have different value
> it indicates that the entry function already contains an sg instruction to
> do the secure state transition and the normal symbol points to the sg
> instruction while the special symbol points after that.
> 
> It is also required [4] that such veneers must be able to keep their address
> when the secure code is relinked in order to avoid relinking the non secure
> code with the secure code. This patch adds support for generating these
> veneers in a dedicated output section and expect the user to specify the
> address of that section (either via --section-start parameter or in the
> linker script). This ensure that they are placed in a memory area with
> sufficient space for more veneers to be added. Ensuring that existing
> veneers keep their addresses when the secure executable is relinked is
> handled by a subsequent patch of this patch serie.
> 
> Note: this patch needs the Cortex-A8 errata workaround refactoring patch
> applied to work (patch 1/9 in the patch serie).
> 
> RFC Note: This patch contains some Secure Gateway specific elements that
> could potentially be made into more generic and independent suitable for
> separate patch. Namely, these are the padding of stub section and setting a
> specific output section for a given stub section.
> 
> 
> [1] Software requirements for ARMv8-M security extension are described in
> document ARM-ECM-0359818 [2] [2] Available on http://infocenter.arm.com in
> Developer guides and articles > Software development > ARM®v8-M Security
> Extensions: Requirements on Development Tools [3] See section 3.4.3 and
> requirement 44 of ARM-ECM-0359818 [2]
> [4] requirement 14 and following comment of ARM-ECM-0359818 [2]

Please find an updated patch below, following the split of most of its content 
in 6/11 and 7/11.

*** bfd/ChangeLog ***

2016-02-17  Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * elf32-arm.c (CMSE_PREFIX): Define macro.
        (elf32_arm_stub_cmse_branch_thumb_only): Define stub sequence.
        (cmse_branch_thumb_only): Declare stub.
        (struct elf32_arm_link_hash_table): Define cmse_stub_sec field.
        (elf32_arm_get_plt_info): Add globals parameter.  Use it to return
        FALSE if there is no PLT.
        (arm_type_of_stub): Adapt to new elf32_arm_get_plt_info signature.
        (elf32_arm_final_link_relocate): Likewise.
        (elf32_arm_gc_sweep_hook): Likewise.
        (arm_stub_is_thumb): Add case for arm_stub_cmse_branch_thumb_only.
        (arm_dedicated_stub_output_section_required): Likewise.
        (arm_dedicated_stub_output_section_required_alignment): Likewise.
        (arm_stub_dedicated_output_section_name): Likewise.
        (arm_stub_dedicated_input_section_ptr): Likewise and remove
        ATTRIBUTE_UNUSED for htab parameter.
        (arm_stub_required_alignment): Likewise.
        (arm_stub_sym_claimed): Likewise.
        (arm_dedicated_stub_section_padding): Likewise.
        (cmse_scan): New function.
        (elf32_arm_size_stubs): Call cmse_scan for ARM M profile targets.
        Set stub_changed to TRUE if such veneers were created.
        (elf32_arm_swap_symbol_in): Add detection code for CMSE special
        symbols.


*** include/elf/ChangeLog ***

2015-12-16  Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * arm.h (ARM_GET_SYM_CMSE_SPCL): Define macro.
        (ARM_SET_SYM_CMSE_SPCL): Likewise.


*** ld/ChangeLog ***

2016-02-17  Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * ld.texinfo (Placement of SG veneers): New concept entry.
        * testsuite/ld-arm/arm-elf.exp
        (Secure gateway veneers: no .gnu.sgstubs section): New test.
        (Secure gateway veneers: wrong entry functions): Likewise.
        (Secure gateway veneers (ARMv8-M Baseline)): Likewise.
        (Secure gateway veneers (ARMv8-M Mainline)): Likewise.
        * testsuite/ld-arm/cmse-veneers.s: New file.
        * testsuite/ld-arm/cmse-veneers.d: Likewise.
        * testsuite/ld-arm/cmse-veneers.rd: Likewise.
        * testsuite/ld-arm/cmse-veneers.sd: Likewise.
        * testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out: Likewise.
        * testsuite/ld-arm/cmse-veneers-wrong-entryfct.out: Likewise.


diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 
8b3dc8fc2dce2a4dbb1b5dbea6e94ee287111286..126c30df9fbf5ee11020b9fa4efb59c61bc1c352 
100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -2138,6 +2138,8 @@ typedef unsigned short int insn16;
 
 #define STUB_ENTRY_NAME   "__%s_veneer"
 
+#define CMSE_PREFIX "__acle_se_"
+
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
 #define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
@@ -2543,6 +2545,13 @@ static const insn_sequence 
elf32_arm_stub_long_branch_arm_nacl_pic[] =
   DATA_WORD (0, R_ARM_NONE, 0),         /* .word 0 */
 };
 
+/* Stub used for transition to secure state (aka SG veneer).  */
+static const insn_sequence elf32_arm_stub_cmse_branch_thumb_only[] =
+{
+  THUMB32_INSN (0xe97fe97f),		/* sg.  */
+  THUMB32_B_INSN (0xf000b800, -4),	/* b.w original_branch_dest.  */
+};
+
 
 /* Cortex-A8 erratum-workaround stubs.  */
 
@@ -2622,6 +2631,7 @@ static const insn_sequence 
elf32_arm_stub_a8_veneer_blx[] =
   DEF_STUB(long_branch_v4t_thumb_tls_pic) \
   DEF_STUB(long_branch_arm_nacl) \
   DEF_STUB(long_branch_arm_nacl_pic) \
+  DEF_STUB(cmse_branch_thumb_only) \
   DEF_STUB(a8_veneer_b_cond) \
   DEF_STUB(a8_veneer_b) \
   DEF_STUB(a8_veneer_bl) \
@@ -3171,6 +3181,9 @@ struct elf32_arm_link_hash_table
      information on stub grouping.  */
   struct map_stub *stub_group;
 
+  /* Input stub section holding secure gateway veneers.  */
+  asection *cmse_stub_sec;
+
   /* Number of elements in stub_group.  */
   unsigned int top_id;
 
@@ -3319,12 +3332,16 @@ elf32_arm_create_local_iplt (bfd *abfd, unsigned long 
r_symndx)
    union and *ARM_PLT at the ARM-specific information.  */
 
 static bfd_boolean
-elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_entry *h,
+elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_table *globals,
+			struct elf32_arm_link_hash_entry *h,
 			unsigned long r_symndx, union gotplt_union **root_plt,
 			struct arm_plt_info **arm_plt)
 {
   struct arm_local_iplt_info *local_iplt;
 
+  if (globals->root.splt == NULL && globals->root.iplt == NULL)
+    return FALSE;
+
   if (h != NULL)
     {
       *root_plt = &h->root.plt;
@@ -3767,6 +3784,7 @@ arm_stub_is_thumb (enum elf32_arm_stub_type stub_type)
     case arm_stub_long_branch_v4t_thumb_arm_pic:
     case arm_stub_long_branch_v4t_thumb_tls_pic:
     case arm_stub_long_branch_thumb_only_pic:
+    case arm_stub_cmse_branch_thumb_only:
       return TRUE;
     case arm_stub_none:
       BFD_FAIL ();
@@ -3832,8 +3850,9 @@ arm_type_of_stub (struct bfd_link_info *info,
      the address of the appropriate trampoline.  */
   if (r_type != R_ARM_TLS_CALL
       && r_type != R_ARM_THM_TLS_CALL
-      && elf32_arm_get_plt_info (input_bfd, hash, ELF32_R_SYM (rel->r_info),
-				 &root_plt, &arm_plt)
+      && elf32_arm_get_plt_info (input_bfd, globals, hash,
+				 ELF32_R_SYM (rel->r_info), &root_plt,
+				 &arm_plt)
       && root_plt->offset != (bfd_vma) -1)
     {
       asection *splt;
@@ -4146,6 +4165,9 @@ arm_dedicated_stub_output_section_required (enum 
elf32_arm_stub_type stub_type)
 
   switch (stub_type)
     {
+    case arm_stub_cmse_branch_thumb_only:
+      return TRUE;
+
     default:
       return FALSE;
     }
@@ -4166,6 +4188,11 @@ arm_dedicated_stub_output_section_required_alignment
 
   switch (stub_type)
     {
+    /* Vectors of Secure Gateway veneers must be aligned on 32byte
+       boundary.  */
+    case arm_stub_cmse_branch_thumb_only:
+      return 5;
+
     default:
       BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
       return 0;
@@ -4185,6 +4212,9 @@ arm_dedicated_stub_output_section_name (enum 
elf32_arm_stub_type stub_type)
 
   switch (stub_type)
     {
+    case arm_stub_cmse_branch_thumb_only:
+      return ".gnu.sgstubs";
+
     default:
       BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
       return NULL;
@@ -4198,15 +4228,17 @@ arm_dedicated_stub_output_section_name (enum 
elf32_arm_stub_type stub_type)
    corresponding input section.  Otherwise, returns NULL.  */
 
 static asection **
-arm_dedicated_stub_input_section_ptr
-  (struct elf32_arm_link_hash_table *htab ATTRIBUTE_UNUSED,
-   enum elf32_arm_stub_type stub_type)
+arm_dedicated_stub_input_section_ptr (struct elf32_arm_link_hash_table *htab,
+				      enum elf32_arm_stub_type stub_type)
 {
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
   switch (stub_type)
     {
+    case arm_stub_cmse_branch_thumb_only:
+      return &htab->cmse_stub_sec;
+
     default:
       BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
       return NULL;
@@ -4434,6 +4466,7 @@ arm_stub_required_alignment (enum elf32_arm_stub_type 
stub_type)
     case arm_stub_long_branch_thumb_only_pic:
     case arm_stub_long_branch_any_tls_pic:
     case arm_stub_long_branch_v4t_thumb_tls_pic:
+    case arm_stub_cmse_branch_thumb_only:
     case arm_stub_a8_veneer_blx:
       return 4;
 
@@ -4457,6 +4490,9 @@ arm_stub_sym_claimed (enum elf32_arm_stub_type 
stub_type)
 
   switch (stub_type)
     {
+    case arm_stub_cmse_branch_thumb_only:
+      return TRUE;
+
     default:
       return FALSE;
     }
@@ -4475,6 +4511,9 @@ arm_dedicated_stub_section_padding (enum 
elf32_arm_stub_type stub_type)
 
   switch (stub_type)
     {
+    case arm_stub_cmse_branch_thumb_only:
+      return 32;
+
     default:
       return 0;
     }
@@ -5370,6 +5409,198 @@ elf32_arm_create_stub (struct 
elf32_arm_link_hash_table *htab,
   return TRUE;
 }
 
+/* Scan symbols in INPUT_BFD to identify secure entry functions needing a
+   gateway veneer to transition from non secure to secure state and create 
them
+   accordingly.
+
+   As per "ARMv8-M Security Extensions: Requirements on Development Tools"
+   document, a secure gateway veneer is needed when there exists a non-local
+   function symbol called "normal" symbol (eg. foo) with the same value as a
+   symbol with the same type, binding a name save for a __acle_se_ prefix,
+   called a "special" symbol (eg. __acle_se_foo).  Entry functions handling
+   with secure state transition by themselves have these symbols with 
different
+   values.
+
+   OUT_ATTR gives the output attributes, SYM_HASHES the symbol index to hash
+   entry mapping while HTAB gives the name to hash entry mapping.
+
+   If any secure gateway veneer is created, *STUB_CHANGED is set to TRUE.  
The
+   return value gives whether a stub failed to be allocated.  */
+
+static bfd_boolean
+cmse_scan (bfd *input_bfd, struct elf32_arm_link_hash_table *htab,
+	   obj_attribute *out_attr, struct elf_link_hash_entry **sym_hashes,
+	   bfd_boolean *stub_changed)
+{
+  const struct elf_backend_data *bed;
+  Elf_Internal_Shdr *symtab_hdr;
+  unsigned i, j, sym_count, ext_start;
+  Elf_Internal_Sym *cmse_sym, *local_syms;
+  struct elf32_arm_link_hash_entry *hash, *cmse_hash = NULL;
+  enum arm_st_branch_type branch_type;
+  char *sym_name, *lsym_name;
+  bfd_vma sym_value;
+  asection *section;
+  bfd_boolean is_v8m, new_stub, created_stub, cmse_invalid, ret = TRUE;
+
+  bed = get_elf_backend_data (input_bfd);
+  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym;
+  ext_start = symtab_hdr->sh_info;
+  is_v8m = (out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE
+	    && out_attr[Tag_CPU_arch_profile].i == 'M');
+
+  local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+  if (local_syms == NULL)
+    local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
+				       symtab_hdr->sh_info, 0, NULL, NULL,
+				       NULL);
+  if (symtab_hdr->sh_info && local_syms == NULL)
+    return FALSE;
+
+  /* Scan symbols.  */
+  for (i = 0; i < sym_count; i++)
+    {
+      cmse_invalid = FALSE;
+
+      if (i < ext_start)
+	{
+	  cmse_sym = &local_syms[i];
+	  /* Not a special symbol.  */
+	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_sym->st_target_internal))
+	    continue;
+	  sym_name = bfd_elf_string_from_elf_section (input_bfd,
+						      symtab_hdr->sh_link,
+						      cmse_sym->st_name);
+	  /* Special symbol with local binding.  */
+	  cmse_invalid = TRUE;
+	}
+      else
+	{
+	  cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]);
+	  sym_name = (char *) cmse_hash->root.root.root.string;
+
+	  /* Not a special symbol.  */
+	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal))
+	    continue;
+
+	  /* Special symbol has incorrect binding or type.  */
+	  if ((cmse_hash->root.root.type != bfd_link_hash_defined
+	       && cmse_hash->root.root.type != bfd_link_hash_defweak)
+	      || cmse_hash->root.type != STT_FUNC)
+	    cmse_invalid = TRUE;
+	}
+
+      if (!is_v8m)
+	{
+	  (*_bfd_error_handler) (_("%B: Special symbol `%s' only allowed for "
+				   "ARMv8-M architecture or later."),
+				 input_bfd, sym_name);
+	  is_v8m = TRUE; /* Avoid multiple warning.  */
+	  ret = FALSE;
+	}
+
+      if (cmse_invalid)
+	{
+	  (*_bfd_error_handler) (_("%B: invalid special symbol `%s'."),
+				 input_bfd, sym_name);
+	  (*_bfd_error_handler) (_("It must be a global or weak function "
+				   "symbol."));
+	  ret = FALSE;
+	  if (i < ext_start)
+	    continue;
+	}
+
+      sym_name += strlen (CMSE_PREFIX);
+      hash = (struct elf32_arm_link_hash_entry *)
+	elf_link_hash_lookup (&(htab)->root, sym_name, FALSE, FALSE, TRUE);
+
+      /* No associated normal symbol or it is neither global nor weak.  */
+      if (!hash
+	  || (hash->root.root.type != bfd_link_hash_defined
+	      && hash->root.root.type != bfd_link_hash_defweak)
+	  || hash->root.type != STT_FUNC)
+	{
+	  if (!hash)
+	    {
+	      /* Searching for a normal symbol with local binding.  */
+	      for (j = 0; j < ext_start; j++)
+		{
+		  lsym_name =
+		    bfd_elf_string_from_elf_section (input_bfd,
+						     symtab_hdr->sh_link,
+						     local_syms[j].st_name);
+		  if (!strcmp (sym_name, lsym_name))
+		    break;
+		}
+	    }
+
+	  if (hash || j < ext_start)
+	    {
+	      (*_bfd_error_handler)
+		(_("%B: invalid standard symbol `%s'."), input_bfd, sym_name);
+	      (*_bfd_error_handler)
+		(_("It must be a global or weak function symbol."));
+	    }
+	  else
+	    (*_bfd_error_handler)
+	      (_("%B: absent standard symbol `%s'."), input_bfd, sym_name);
+	  ret = FALSE;
+	  if (!hash)
+	    continue;
+	}
+
+      sym_value = hash->root.root.u.def.value;
+      section = hash->root.root.u.def.section;
+
+      if (cmse_hash->root.root.u.def.section != section)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: `%s' and its special symbol are in different sections."),
+	     input_bfd, sym_name);
+	  ret = FALSE;
+	}
+      if (cmse_hash->root.root.u.def.value != sym_value)
+	continue; /* Ignore: could be an entry function starting with SG.  */
+
+	/* If this section is a link-once section that will be discarded, then
+	   don't create any stubs.  */
+      if (section->output_section == NULL)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: entry function `%s' not output."), input_bfd, sym_name);
+	  continue;
+	}
+
+      if (hash->root.size == 0)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: entry function `%s' is empty."), input_bfd, sym_name);
+	  ret = FALSE;
+	}
+
+      if (!ret)
+	continue;
+      branch_type = ARM_GET_SYM_BRANCH_TYPE (hash->root.target_internal);
+      created_stub
+	= elf32_arm_create_stub (htab, arm_stub_cmse_branch_thumb_only,
+				 NULL, NULL, section, hash, sym_name,
+				 sym_value, branch_type, &new_stub);
+
+      if (!created_stub)
+	 ret = FALSE;
+      else
+	{
+	  BFD_ASSERT (new_stub);
+	  *stub_changed = TRUE;
+	}
+    }
+
+  if (!symtab_hdr->contents)
+    free (local_syms);
+  return ret;
+}
+
 /* Determine and set the size of the stub section for a final link.
 
    The basic idea here is to examine all the relocations looking for
@@ -5386,8 +5617,9 @@ elf32_arm_size_stubs (bfd *output_bfd,
 						      unsigned int),
 		      void (*layout_sections_again) (void))
 {
+  obj_attribute *out_attr;
   bfd_size_type stub_group_size;
-  bfd_boolean stubs_always_after_branch;
+  bfd_boolean m_profile, stubs_always_after_branch, first_veneer_scan = TRUE;
   struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
   struct a8_erratum_fix *a8_fixes = NULL;
   unsigned int num_a8_fixes = 0, a8_fix_table_size = 10;
@@ -5416,6 +5648,8 @@ elf32_arm_size_stubs (bfd *output_bfd,
   htab->layout_sections_again = layout_sections_again;
   stubs_always_after_branch = group_size < 0;
 
+  out_attr = elf_known_obj_attributes_proc (output_bfd);
+  m_profile = out_attr[Tag_CPU_arch_profile].i == 'M';
   /* The Cortex-A8 erratum fix depends on stubs not being in the same 4K page
      as the first half of a 32-bit branch straddling two 4K pages.  This is a
      crude way of enforcing that.  */
@@ -5481,6 +5715,18 @@ elf32_arm_size_stubs (bfd *output_bfd,
 	  if (symtab_hdr->sh_info == 0)
 	    continue;
 
+	  /* Limit scan of symbols to object file whose profile is
+	     Microcontroller to not hinder performance in the general case.  */
+	  if (m_profile && first_veneer_scan)
+	    {
+	      struct elf_link_hash_entry **sym_hashes;
+
+	      sym_hashes = elf_sym_hashes (input_bfd);
+	      if (!cmse_scan (input_bfd, htab, out_attr, sym_hashes,
+			      &stub_changed))
+		goto error_ret_free_local;
+	    }
+
 	  /* Walk over each section attached to the input bfd.  */
 	  for (section = input_bfd->sections;
 	       section != NULL;
@@ -5853,6 +6099,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
 
       /* Ask the linker to do its stuff.  */
       (*htab->layout_sections_again) ();
+      first_veneer_scan = FALSE;
     }
 
   /* Add stubs for Cortex-A8 erratum fixes now.  */
@@ -9194,7 +9441,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           
howto,
   /* Find out whether the symbol has a PLT.  Set ST_VALUE, BRANCH_TYPE and
      VALUE appropriately for relocations that we resolve at link time.  */
   has_iplt_entry = FALSE;
-  if (elf32_arm_get_plt_info (input_bfd, eh, r_symndx, &root_plt, &arm_plt)
+  if (elf32_arm_get_plt_info (input_bfd, globals, eh, r_symndx, &root_plt,
+			      &arm_plt)
       && root_plt->offset != (bfd_vma) -1)
     {
       plt_offset = root_plt->offset;
@@ -13616,7 +13864,8 @@ elf32_arm_gc_sweep_hook (bfd *                     
abfd,
 	}
 
       if (may_need_local_target_p
-	  && elf32_arm_get_plt_info (abfd, eh, r_symndx, &root_plt, &arm_plt))
+	  && elf32_arm_get_plt_info (abfd, globals, eh, r_symndx, &root_plt,
+				     &arm_plt))
 	{
 	  /* If PLT refcount book-keeping is wrong and too low, we'll
 	     see a zero value (going to -1) for the root PLT reference
@@ -17769,6 +18018,9 @@ elf32_arm_swap_symbol_in (bfd * abfd,
 			  const void *pshn,
 			  Elf_Internal_Sym *dst)
 {
+  Elf_Internal_Shdr *symtab_hdr;
+  const char *name = NULL;
+
   if (!bfd_elf32_swap_symbol_in (abfd, psrc, pshn, dst))
     return FALSE;
   dst->st_target_internal = 0;
@@ -17797,6 +18049,13 @@ elf32_arm_swap_symbol_in (bfd * abfd,
   else
     ARM_SET_SYM_BRANCH_TYPE (dst->st_target_internal, ST_BRANCH_UNKNOWN);
 
+  /* Mark CMSE special symbols.  */
+  symtab_hdr = & elf_symtab_hdr (abfd);
+  if (symtab_hdr->sh_size)
+    name = bfd_elf_sym_name (abfd, symtab_hdr, dst, NULL);
+  if (name && CONST_STRNEQ (name, CMSE_PREFIX))
+    ARM_SET_SYM_CMSE_SPCL (dst->st_target_internal);
+
   return TRUE;
 }
 
diff --git a/include/elf/arm.h b/include/elf/arm.h
index 
d98fef3c605deda3d01e4644870c8e7fa783814c..28a437205f09714901e4266f9a46f359acde25a2 
100644
--- a/include/elf/arm.h
+++ b/include/elf/arm.h
@@ -367,4 +367,11 @@ enum arm_st_branch_type {
 #define ARM_SET_SYM_BRANCH_TYPE(SYM_TARGET_INTERNAL,TYPE) \
   ((SYM_TARGET_INTERNAL) = ((SYM_TARGET_INTERNAL) & ~3) | ((TYPE) & 3))
 
+/* Get or set whether a symbol is a special symbol of an entry function of 
CMSE
+   secure code.  */
+#define ARM_GET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
+  (((SYM_TARGET_INTERNAL) >> 2) & 1)
+#define ARM_SET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
+  (SYM_TARGET_INTERNAL) |= 4
+
 #endif /* _ELF_ARM_H */
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 
8507c3fe677921c0c8fbd5fcb5b5a5799d8cfae0..f339e30a3c4b8a5c4e44cc6cf1bca8fe2e2ef3d8 
100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -6804,6 +6804,12 @@ The @samp{--long-plt} option enables the use of 16 byte 
PLT entries
 which support up to 4Gb of code.  The default is to use 12 byte PLT
 entries which only support 512Mb of code.
 
+@cindex Placement of SG veneers
+All SG veneers are placed in the special output section @code{.gnu.sgstubs}.
+Its start address must be set, either with the command line option
+@samp{--section-start} or in a linker script, to indicate where to place 
these
+veneers in memory.
+
 @ifclear GENERIC
 @lowersections
 @end ifclear
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index 
e2fa3b054cfe8ccbb3b93c21b7de9fd89bfb241f..d6e20504e45f4210a1af6a814fe48d30ff91f6fc 
100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -635,6 +635,33 @@ set armeabitests_nonacl {
      {{objdump -d jump-reloc-veneers-long.d}}
      "jump-reloc-veneers-long"}
 
+    {"Secure gateway veneers: no .gnu.sgstubs section" "" ""
+     "-march=armv8-m.base -mthumb"
+     {cmse-veneers.s}
+     {{ld cmse-veneers-no-gnu_sgstubs.out}}
+     "cmse-veneers-no-gnu_sgstubs"}
+    {"Secure gateway veneers: wrong entry functions" "" ""
+     "-march=armv7-m -mthumb --defsym CHECK_ERRORS=1"
+     {cmse-veneers.s}
+     {{ld cmse-veneers-wrong-entryfct.out}}
+     "cmse-veneers-wrong-entryfct"}
+    {"Secure gateway veneers (ARMv8-M Baseline)"
+     "-Ttext=0x8000 --section-start .gnu.sgstubs=0x20000" ""
+     "-march=armv8-m.base -mthumb"
+     {cmse-veneers.s}
+     {{objdump {-d -j .gnu.sgstubs} cmse-veneers.d}
+      {objdump {-h -j .gnu.sgstubs} cmse-veneers.sd}
+      {nm {} cmse-veneers.rd}}
+     "cmse-veneers-baseline"}
+    {"Secure gateway veneers (ARMv8-M Mainline)"
+     "-Ttext=0x8000 --section-start .gnu.sgstubs=0x20000" ""
+     "-march=armv8-m.main -mthumb"
+     {cmse-veneers.s}
+     {{objdump {-d -j .gnu.sgstubs} cmse-veneers.d}
+      {objdump {-h -j .gnu.sgstubs} cmse-veneers.sd}
+      {nm {} cmse-veneers.rd}}
+     "cmse-veneers-mainline"}
+
     {"R_ARM_THM_JUMP19 Relocation veneers: Short"
      "--section-start destsect=0x000108002 --section-start .text=0x8000" ""
      "-march=armv7-m -mthumb"
diff --git a/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out 
b/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out
new file mode 100644
index 
0000000000000000000000000000000000000000..9d1e5ba3215ae8a29585fcf04ec1f94314670a29
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out
@@ -0,0 +1,3 @@
+.*: No address assigned to the veneers output section .gnu.sgstubs
+.*: cannot size stub section: Invalid operation
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out 
b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
new file mode 100644
index 
0000000000000000000000000000000000000000..fd4766ab877a4abbeb8b2c4c053ab11d3f86773c
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
@@ -0,0 +1,19 @@
+.*: .*: Special symbol `__acle_se_loc_entry_veneer1' only allowed for ARMv8-M 
architecture or later.
+.*: .*: invalid .* symbol `.*loc_entry_veneer1'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_loc_entry_veneer2'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_loc_entry_veneer4'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid standard symbol `loc_entry_veneer3'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid standard symbol `loc_entry_veneer5'.
+.*: It must be a global or weak function symbol.
+.*: .*: absent standard symbol `fake_entry_veneer1'.
+.*: .*: invalid standard symbol `obj_entry_veneer1'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_obj_entry_veneer2'.
+.*: It must be a global or weak function symbol.
+.*: .*: `fake_entry_veneer2' and its special symbol are in different sections.
+.*: cannot size stub section: Invalid operation
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers.d b/ld/testsuite/ld-arm/cmse-
veneers.d
new file mode 100644
index 
0000000000000000000000000000000000000000..6a44a2b5dce9de4f5d64fe644e41f5ab9840806e
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.d
@@ -0,0 +1,21 @@
+
+.*
+
+
+Disassembly of section \.gnu.sgstubs:
+
+00020000 <glob_entry_veneer2>:
+   20000:	e97f e97f 	sg
+   20004:	f7e8 b800 	b\.w	8008 <__acle_se_glob_entry_veneer2>
+
+00020008 <weak_entry_veneer2>:
+   20008:	e97f e97f 	sg
+   2000c:	f7e7 bffe 	b\.w	800c <__acle_se_weak_entry_veneer2>
+
+00020010 <glob_entry_veneer1>:
+   20010:	e97f e97f 	sg
+   20014:	f7e7 bff4 	b\.w	8000 <__acle_se_glob_entry_veneer1>
+
+00020018 <weak_entry_veneer1>:
+   20018:	e97f e97f 	sg
+   2001c:	f7e7 bff2 	b\.w	8004 <__acle_se_weak_entry_veneer1>
diff --git a/ld/testsuite/ld-arm/cmse-veneers.rd b/ld/testsuite/ld-arm/cmse-
veneers.rd
new file mode 100644
index 
0000000000000000000000000000000000000000..20fad961bd8803109c3cf57ef22e3b36da5b1500
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.rd
@@ -0,0 +1,9 @@
+#...
+[0-9a-f]+ T glob_entry_fct
+#...
+[0-9a-f]+ T glob_entry_veneer1
+[0-9a-f]+ T glob_entry_veneer2
+#...
+[0-9a-f]+ W weak_entry_veneer1
+[0-9a-f]+ W weak_entry_veneer2
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers.s b/ld/testsuite/ld-arm/cmse-
veneers.s
new file mode 100644
index 
0000000000000000000000000000000000000000..d5c57f646a78c4736e4f084d8ad6aff7efea554f
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.s
@@ -0,0 +1,97 @@
+	.syntax unified
+	.thumb
+	.file	"foo.c"
+	.text
+
+.macro	decltype	name, type
+.ifc \type,object
+	.data
+.else
+	.thumb
+	.thumb_func
+.endif
+	.type	\name, %\type
+.endm
+
+
+.macro	entry	name, type, vis, typespc, visspc, entry_fct
+	.align	2
+.ifb \visspc
+	.\vis	__acle_se_\name
+.else
+	.\visspc	__acle_se_\name
+.endif
+	.\vis	\name
+	.thumb
+	.thumb_func
+.ifb \typespc
+	decltype	__acle_se_\name, \type
+.else
+	decltype	__acle_se_\name, \typespc
+.endif
+	decltype	\name, \type
+__acle_se_\name:
+	\entry_fct
+\name:
+.ifc \type,object
+	.word 42
+.else
+	nop
+.endif
+	.size	\name, .-\name
+	.size	__acle_se_\name, .-__acle_se_\name
+.endm
+
+
+.ifndef CHECK_ERRORS
+	@ Valid setups for veneer generation
+	entry glob_entry_veneer1, function, global
+	entry weak_entry_veneer1, function, weak
+	entry glob_entry_veneer2, function, global, visspc=weak
+	entry weak_entry_veneer2, function, weak, visspc=global
+
+	@ Valid setup for entry function without SG veneer
+	entry glob_entry_fct, function, global, entry_fct=nop
+
+.else
+	@ Invalid setups for veneer generation (visibility)
+	entry loc_entry_veneer1, function, local
+	entry loc_entry_veneer2, function, global, visspc=local
+	entry loc_entry_veneer3, function, local, visspc=global
+	entry loc_entry_veneer4, function, weak, visspc=local
+	entry loc_entry_veneer5, function, local, visspc=weak
+
+	@ Invalid setups for veneer generation (absent standard symbol)
+	.align	2
+	.global	__acle_se_fake_entry_veneer1
+	.thumb
+	.thumb_func
+	.type	__acle_se_fake_entry_veneer1, %function
+__acle_se_fake_entry_veneer1:
+	nop
+	.size	__acle_se_fake_entry_veneer1, .-__acle_se_fake_entry_veneer1
+
+	@ Invalid setups for veneer generation (type)
+	entry obj_entry_veneer1, object, global, typespc=function
+	entry obj_entry_veneer2, function, global, typespc=object
+
+	@ Invalid setup for veneer generation (sections)
+	.section .text.sub1
+	.align	2
+	.thumb
+	.thumb_func
+	.global	__acle_se_fake_entry_veneer2
+	.type	__acle_se_fake_entry_veneer2, %function
+__acle_se_fake_entry_veneer2:
+	nop
+	.size	__acle_se_fake_entry_veneer2, .-__acle_se_fake_entry_veneer2
+	.section .text.sub2
+	.align	2
+	.thumb
+	.thumb_func
+	.global	fake_entry_veneer2
+	.type	fake_entry_veneer2, %function
+fake_entry_veneer2:
+	nop
+	.size	fake_entry_veneer2, .-fake_entry_veneer2
+.endif
diff --git a/ld/testsuite/ld-arm/cmse-veneers.sd b/ld/testsuite/ld-arm/cmse-
veneers.sd
new file mode 100644
index 
0000000000000000000000000000000000000000..99bfc8f37c25b7a57122b330b1145e27a9b087fd
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.sd
@@ -0,0 +1,7 @@
+
+.*
+
+Sections:
+Idx Name          Size      VMA       LMA       File off  Algn
+  \d+ \.gnu\.sgstubs  00000020  00020000  00020000  00010000  2\*\*5
+                  CONTENTS, ALLOC, LOAD, READONLY, CODE


Is this ok for master branch?

Best regards,

Thomas

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH, binutils, ARM 8/11] Add support for ARMv8-M Secure Gateway veneer generation
  2016-03-29 14:42 ` [RFC PATCH, binutils, ARM 8/11] " Thomas Preudhomme
@ 2016-05-18 16:30   ` Thomas Preudhomme
  2016-07-07 10:53     ` Richard Earnshaw (lists)
  0 siblings, 1 reply; 10+ messages in thread
From: Thomas Preudhomme @ 2016-05-18 16:30 UTC (permalink / raw)
  To: binutils

On Tuesday 29 March 2016 15:42:39 Thomas Preudhomme wrote:
> On Wednesday 23 December 2015 15:59:44 Thomas Preud'homme wrote:
> > Hi,
> > 
> > [Posting patch series as RFC]
> > 
> > This patch is part of a patch series to add support for ARMv8-M Security
> > Extensions[1] to GNU ld. This specific patch adds support for creating
> > ARMv8-M Secure Gateway veneers.
> > 
> > ARM v8-M Security Extensions require [3] secure gateway veneers to be
> > generated for (secure) entry function in order for code to transition from
> > non-secure state to secure state when calling these entry function. Unlike
> > other veneers, these veneers are generated independently of relocations,
> > ie
> > a veneer can be generated in the absence of relocation. The condition for
> > the generation is that the normal symbol (the one whose name is the same
> > as
> > in C) of an entry function has the same value as the special symbol
> > (normal
> > symbol prefixed with "__acle_se_"). When that happens, the normal symbol
> > is
> > rebound to the veneer generated. When the two symbols have different value
> > it indicates that the entry function already contains an sg instruction to
> > do the secure state transition and the normal symbol points to the sg
> > instruction while the special symbol points after that.
> > 
> > It is also required [4] that such veneers must be able to keep their
> > address when the secure code is relinked in order to avoid relinking the
> > non secure code with the secure code. This patch adds support for
> > generating these veneers in a dedicated output section and expect the
> > user to specify the address of that section (either via --section-start
> > parameter or in the linker script). This ensure that they are placed in a
> > memory area with sufficient space for more veneers to be added. Ensuring
> > that existing veneers keep their addresses when the secure executable is
> > relinked is handled by a subsequent patch of this patch serie.
> > 
> > Note: this patch needs the Cortex-A8 errata workaround refactoring patch
> > applied to work (patch 1/9 in the patch serie).
> > 
> > RFC Note: This patch contains some Secure Gateway specific elements that
> > could potentially be made into more generic and independent suitable for
> > separate patch. Namely, these are the padding of stub section and setting
> > a
> > specific output section for a given stub section.
> > 
> > 
> > [1] Software requirements for ARMv8-M Security Extensions are described in
> > document ARM-ECM-0359818 [2] [2] Available on http://infocenter.arm.com in
> > Developer guides and articles > Software development > ARM®v8-M Security
> > Extensions: Requirements on Development Tools [3] See section 3.4.3 and
> > requirement 44 of ARM-ECM-0359818 [2]
> > [4] requirement 14 and following comment of ARM-ECM-0359818 [2]
> 
> Please find an updated patch below, following the split of most of its
> content in 6/11 and 7/11.

Please find a rebased patch that now deal with the new 
elf32_arm_stub_cmse_branch_thumb_only by changing boolean returning function 
into switch cases in addition to add the case statement for the stub itself. 
It also makes sure SG veneers are kept when calling the linker with --gc-
sections.

ChangeLog entries are now:

*** bfd/ChangeLog ***

2016-05-04  Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * elf32-arm.c (CMSE_PREFIX): Define macro.
        (elf32_arm_stub_cmse_branch_thumb_only): Define stub sequence.
        (cmse_branch_thumb_only): Declare stub.
        (struct elf32_arm_link_hash_table): Define cmse_stub_sec field.
        (elf32_arm_get_plt_info): Add globals parameter.  Use it to return
        FALSE if there is no PLT.
        (arm_type_of_stub): Adapt to new elf32_arm_get_plt_info signature.
        (elf32_arm_final_link_relocate): Likewise.
        (elf32_arm_gc_sweep_hook): Likewise.
        (elf32_arm_gc_mark_extra_sections): Mark sections holding ARMv8-M
        secure entry functions.
        (arm_stub_is_thumb): Add case for arm_stub_cmse_branch_thumb_only.
        (arm_dedicated_stub_output_section_required): Change to a switch case
        and add a case for arm_stub_cmse_branch_thumb_only.
        (arm_dedicated_stub_output_section_required_alignment): Likewise.
        (arm_stub_dedicated_output_section_name): Likewise.
        (arm_stub_dedicated_input_section_ptr): Likewise and remove
        ATTRIBUTE_UNUSED for htab parameter.
        (arm_stub_required_alignment): Likewise.
        (arm_stub_sym_claimed): Likewise.
        (arm_dedicated_stub_section_padding): Likewise.
        (cmse_scan): New function.
        (elf32_arm_size_stubs): Call cmse_scan for ARM M profile targets.
        Set stub_changed to TRUE if such veneers were created.
        (elf32_arm_swap_symbol_in): Add detection code for CMSE special
        symbols.


*** include/elf/ChangeLog ***

2015-12-16  Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * arm.h (ARM_GET_SYM_CMSE_SPCL): Define macro.
        (ARM_SET_SYM_CMSE_SPCL): Likewise.


*** ld/ChangeLog ***

2016-02-17  Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * ld.texinfo (Placement of SG veneers): New concept entry.
        * testsuite/ld-arm/arm-elf.exp
        (Secure gateway veneers: no .gnu.sgstubs section): New test.
        (Secure gateway veneers: wrong entry functions): Likewise.
        (Secure gateway veneers (ARMv8-M Baseline)): Likewise.
        (Secure gateway veneers (ARMv8-M Mainline)): Likewise.
        * testsuite/ld-arm/cmse-veneers.s: New file.
        * testsuite/ld-arm/cmse-veneers.d: Likewise.
        * testsuite/ld-arm/cmse-veneers.rd: Likewise.
        * testsuite/ld-arm/cmse-veneers.sd: Likewise.
        * testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out: Likewise.
        * testsuite/ld-arm/cmse-veneers-wrong-entryfct.out: Likewise.


diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 
3a93fd057e02d9ee1231208af4fe2ae5fa718a21..a73c6c3d755420225cae89b1b5beaa5def7aaca0 
100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -2138,6 +2138,8 @@ typedef unsigned short int insn16;
 
 #define STUB_ENTRY_NAME   "__%s_veneer"
 
+#define CMSE_PREFIX "__acle_se_"
+
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
 #define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
@@ -2543,6 +2545,13 @@ static const insn_sequence 
elf32_arm_stub_long_branch_arm_nacl_pic[] =
   DATA_WORD (0, R_ARM_NONE, 0),         /* .word 0 */
 };
 
+/* Stub used for transition to secure state (aka SG veneer).  */
+static const insn_sequence elf32_arm_stub_cmse_branch_thumb_only[] =
+{
+  THUMB32_INSN (0xe97fe97f),		/* sg.  */
+  THUMB32_B_INSN (0xf000b800, -4),	/* b.w original_branch_dest.  */
+};
+
 
 /* Cortex-A8 erratum-workaround stubs.  */
 
@@ -2622,6 +2631,7 @@ static const insn_sequence 
elf32_arm_stub_a8_veneer_blx[] =
   DEF_STUB(long_branch_v4t_thumb_tls_pic) \
   DEF_STUB(long_branch_arm_nacl) \
   DEF_STUB(long_branch_arm_nacl_pic) \
+  DEF_STUB(cmse_branch_thumb_only) \
   DEF_STUB(a8_veneer_b_cond) \
   DEF_STUB(a8_veneer_b) \
   DEF_STUB(a8_veneer_bl) \
@@ -3172,6 +3182,9 @@ struct elf32_arm_link_hash_table
      information on stub grouping.  */
   struct map_stub *stub_group;
 
+  /* Input stub section holding secure gateway veneers.  */
+  asection *cmse_stub_sec;
+
   /* Number of elements in stub_group.  */
   unsigned int top_id;
 
@@ -3320,12 +3333,16 @@ elf32_arm_create_local_iplt (bfd *abfd, unsigned long 
r_symndx)
    union and *ARM_PLT at the ARM-specific information.  */
 
 static bfd_boolean
-elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_entry *h,
+elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_table *globals,
+			struct elf32_arm_link_hash_entry *h,
 			unsigned long r_symndx, union gotplt_union **root_plt,
 			struct arm_plt_info **arm_plt)
 {
   struct arm_local_iplt_info *local_iplt;
 
+  if (globals->root.splt == NULL && globals->root.iplt == NULL)
+    return FALSE;
+
   if (h != NULL)
     {
       *root_plt = &h->root.plt;
@@ -3768,6 +3785,7 @@ arm_stub_is_thumb (enum elf32_arm_stub_type stub_type)
     case arm_stub_long_branch_v4t_thumb_arm_pic:
     case arm_stub_long_branch_v4t_thumb_tls_pic:
     case arm_stub_long_branch_thumb_only_pic:
+    case arm_stub_cmse_branch_thumb_only:
       return TRUE;
     case arm_stub_none:
       BFD_FAIL ();
@@ -3833,8 +3851,9 @@ arm_type_of_stub (struct bfd_link_info *info,
      the address of the appropriate trampoline.  */
   if (r_type != R_ARM_TLS_CALL
       && r_type != R_ARM_THM_TLS_CALL
-      && elf32_arm_get_plt_info (input_bfd, hash, ELF32_R_SYM (rel->r_info),
-				 &root_plt, &arm_plt)
+      && elf32_arm_get_plt_info (input_bfd, globals, hash,
+				 ELF32_R_SYM (rel->r_info), &root_plt,
+				 &arm_plt)
       && root_plt->offset != (bfd_vma) -1)
     {
       asection *splt;
@@ -4145,7 +4164,16 @@ arm_dedicated_stub_output_section_required (enum 
elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  return FALSE;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Required alignment (as a power of 2) for the dedicated section holding
@@ -4159,8 +4187,19 @@ arm_dedicated_stub_output_section_required_alignment
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
-  return 0;
+  switch (stub_type)
+    {
+    /* Vectors of Secure Gateway veneers must be aligned on 32byte
+       boundary.  */
+    case arm_stub_cmse_branch_thumb_only:
+      return 5;
+
+    default:
+      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
+      return 0;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Name of the dedicated output section to put veneers of type STUB_TYPE, or
@@ -4172,8 +4211,17 @@ arm_dedicated_stub_output_section_name (enum 
elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
-  return NULL;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return ".gnu.sgstubs";
+
+    default:
+      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
+      return NULL;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* If veneers of type STUB_TYPE should go in a dedicated output section,
@@ -4181,15 +4229,23 @@ arm_dedicated_stub_output_section_name (enum 
elf32_arm_stub_type stub_type)
    corresponding input section.  Otherwise, returns NULL.  */
 
 static asection **
-arm_dedicated_stub_input_section_ptr
-  (struct elf32_arm_link_hash_table *htab ATTRIBUTE_UNUSED,
-   enum elf32_arm_stub_type stub_type)
+arm_dedicated_stub_input_section_ptr (struct elf32_arm_link_hash_table *htab,
+				      enum elf32_arm_stub_type stub_type)
 {
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
-  return NULL;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return &htab->cmse_stub_sec;
+
+    default:
+      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
+      return NULL;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Find or create a stub section to contain a stub of type STUB_TYPE.  
SECTION
@@ -4411,6 +4467,7 @@ arm_stub_required_alignment (enum elf32_arm_stub_type 
stub_type)
     case arm_stub_long_branch_thumb_only_pic:
     case arm_stub_long_branch_any_tls_pic:
     case arm_stub_long_branch_v4t_thumb_tls_pic:
+    case arm_stub_cmse_branch_thumb_only:
     case arm_stub_a8_veneer_blx:
       return 4;
 
@@ -4432,7 +4489,16 @@ arm_stub_sym_claimed (enum elf32_arm_stub_type 
stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  return FALSE;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Returns the padding needed for the dedicated section used stubs of type
@@ -4444,7 +4510,16 @@ arm_dedicated_stub_section_padding (enum 
elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  return 0;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return 32;
+
+    default:
+      return 0;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 static bfd_boolean
@@ -5335,6 +5410,198 @@ elf32_arm_create_stub (struct 
elf32_arm_link_hash_table *htab,
   return TRUE;
 }
 
+/* Scan symbols in INPUT_BFD to identify secure entry functions needing a
+   gateway veneer to transition from non secure to secure state and create 
them
+   accordingly.
+
+   As per "ARMv8-M Security Extensions: Requirements on Development Tools"
+   document, a secure gateway veneer is needed when there exists a non-local
+   function symbol called "normal" symbol (eg. foo) with the same value as a
+   symbol with the same type, binding a name save for a __acle_se_ prefix,
+   called a "special" symbol (eg. __acle_se_foo).  Entry functions handling
+   with secure state transition by themselves have these symbols with 
different
+   values.
+
+   OUT_ATTR gives the output attributes, SYM_HASHES the symbol index to hash
+   entry mapping while HTAB gives the name to hash entry mapping.
+
+   If any secure gateway veneer is created, *STUB_CHANGED is set to TRUE.  
The
+   return value gives whether a stub failed to be allocated.  */
+
+static bfd_boolean
+cmse_scan (bfd *input_bfd, struct elf32_arm_link_hash_table *htab,
+	   obj_attribute *out_attr, struct elf_link_hash_entry **sym_hashes,
+	   bfd_boolean *stub_changed)
+{
+  const struct elf_backend_data *bed;
+  Elf_Internal_Shdr *symtab_hdr;
+  unsigned i, j, sym_count, ext_start;
+  Elf_Internal_Sym *cmse_sym, *local_syms;
+  struct elf32_arm_link_hash_entry *hash, *cmse_hash = NULL;
+  enum arm_st_branch_type branch_type;
+  char *sym_name, *lsym_name;
+  bfd_vma sym_value;
+  asection *section;
+  bfd_boolean is_v8m, new_stub, created_stub, cmse_invalid, ret = TRUE;
+
+  bed = get_elf_backend_data (input_bfd);
+  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym;
+  ext_start = symtab_hdr->sh_info;
+  is_v8m = (out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE
+	    && out_attr[Tag_CPU_arch_profile].i == 'M');
+
+  local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+  if (local_syms == NULL)
+    local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
+				       symtab_hdr->sh_info, 0, NULL, NULL,
+				       NULL);
+  if (symtab_hdr->sh_info && local_syms == NULL)
+    return FALSE;
+
+  /* Scan symbols.  */
+  for (i = 0; i < sym_count; i++)
+    {
+      cmse_invalid = FALSE;
+
+      if (i < ext_start)
+	{
+	  cmse_sym = &local_syms[i];
+	  /* Not a special symbol.  */
+	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_sym->st_target_internal))
+	    continue;
+	  sym_name = bfd_elf_string_from_elf_section (input_bfd,
+						      symtab_hdr->sh_link,
+						      cmse_sym->st_name);
+	  /* Special symbol with local binding.  */
+	  cmse_invalid = TRUE;
+	}
+      else
+	{
+	  cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]);
+	  sym_name = (char *) cmse_hash->root.root.root.string;
+
+	  /* Not a special symbol.  */
+	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal))
+	    continue;
+
+	  /* Special symbol has incorrect binding or type.  */
+	  if ((cmse_hash->root.root.type != bfd_link_hash_defined
+	       && cmse_hash->root.root.type != bfd_link_hash_defweak)
+	      || cmse_hash->root.type != STT_FUNC)
+	    cmse_invalid = TRUE;
+	}
+
+      if (!is_v8m)
+	{
+	  (*_bfd_error_handler) (_("%B: Special symbol `%s' only allowed for "
+				   "ARMv8-M architecture or later."),
+				 input_bfd, sym_name);
+	  is_v8m = TRUE; /* Avoid multiple warning.  */
+	  ret = FALSE;
+	}
+
+      if (cmse_invalid)
+	{
+	  (*_bfd_error_handler) (_("%B: invalid special symbol `%s'."),
+				 input_bfd, sym_name);
+	  (*_bfd_error_handler) (_("It must be a global or weak function "
+				   "symbol."));
+	  ret = FALSE;
+	  if (i < ext_start)
+	    continue;
+	}
+
+      sym_name += strlen (CMSE_PREFIX);
+      hash = (struct elf32_arm_link_hash_entry *)
+	elf_link_hash_lookup (&(htab)->root, sym_name, FALSE, FALSE, TRUE);
+
+      /* No associated normal symbol or it is neither global nor weak.  */
+      if (!hash
+	  || (hash->root.root.type != bfd_link_hash_defined
+	      && hash->root.root.type != bfd_link_hash_defweak)
+	  || hash->root.type != STT_FUNC)
+	{
+	  if (!hash)
+	    {
+	      /* Searching for a normal symbol with local binding.  */
+	      for (j = 0; j < ext_start; j++)
+		{
+		  lsym_name =
+		    bfd_elf_string_from_elf_section (input_bfd,
+						     symtab_hdr->sh_link,
+						     local_syms[j].st_name);
+		  if (!strcmp (sym_name, lsym_name))
+		    break;
+		}
+	    }
+
+	  if (hash || j < ext_start)
+	    {
+	      (*_bfd_error_handler)
+		(_("%B: invalid standard symbol `%s'."), input_bfd, sym_name);
+	      (*_bfd_error_handler)
+		(_("It must be a global or weak function symbol."));
+	    }
+	  else
+	    (*_bfd_error_handler)
+	      (_("%B: absent standard symbol `%s'."), input_bfd, sym_name);
+	  ret = FALSE;
+	  if (!hash)
+	    continue;
+	}
+
+      sym_value = hash->root.root.u.def.value;
+      section = hash->root.root.u.def.section;
+
+      if (cmse_hash->root.root.u.def.section != section)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: `%s' and its special symbol are in different sections."),
+	     input_bfd, sym_name);
+	  ret = FALSE;
+	}
+      if (cmse_hash->root.root.u.def.value != sym_value)
+	continue; /* Ignore: could be an entry function starting with SG.  */
+
+	/* If this section is a link-once section that will be discarded, then
+	   don't create any stubs.  */
+      if (section->output_section == NULL)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: entry function `%s' not output."), input_bfd, sym_name);
+	  continue;
+	}
+
+      if (hash->root.size == 0)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: entry function `%s' is empty."), input_bfd, sym_name);
+	  ret = FALSE;
+	}
+
+      if (!ret)
+	continue;
+      branch_type = ARM_GET_SYM_BRANCH_TYPE (hash->root.target_internal);
+      created_stub
+	= elf32_arm_create_stub (htab, arm_stub_cmse_branch_thumb_only,
+				 NULL, NULL, section, hash, sym_name,
+				 sym_value, branch_type, &new_stub);
+
+      if (!created_stub)
+	 ret = FALSE;
+      else
+	{
+	  BFD_ASSERT (new_stub);
+	  *stub_changed = TRUE;
+	}
+    }
+
+  if (!symtab_hdr->contents)
+    free (local_syms);
+  return ret;
+}
+
 /* Determine and set the size of the stub section for a final link.
 
    The basic idea here is to examine all the relocations looking for
@@ -5351,8 +5618,9 @@ elf32_arm_size_stubs (bfd *output_bfd,
 						      unsigned int),
 		      void (*layout_sections_again) (void))
 {
+  obj_attribute *out_attr;
   bfd_size_type stub_group_size;
-  bfd_boolean stubs_always_after_branch;
+  bfd_boolean m_profile, stubs_always_after_branch, first_veneer_scan = TRUE;
   struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
   struct a8_erratum_fix *a8_fixes = NULL;
   unsigned int num_a8_fixes = 0, a8_fix_table_size = 10;
@@ -5381,6 +5649,8 @@ elf32_arm_size_stubs (bfd *output_bfd,
   htab->layout_sections_again = layout_sections_again;
   stubs_always_after_branch = group_size < 0;
 
+  out_attr = elf_known_obj_attributes_proc (output_bfd);
+  m_profile = out_attr[Tag_CPU_arch_profile].i == 'M';
   /* The Cortex-A8 erratum fix depends on stubs not being in the same 4K page
      as the first half of a 32-bit branch straddling two 4K pages.  This is a
      crude way of enforcing that.  */
@@ -5446,6 +5716,18 @@ elf32_arm_size_stubs (bfd *output_bfd,
 	  if (symtab_hdr->sh_info == 0)
 	    continue;
 
+	  /* Limit scan of symbols to object file whose profile is
+	     Microcontroller to not hinder performance in the general case.  */
+	  if (m_profile && first_veneer_scan)
+	    {
+	      struct elf_link_hash_entry **sym_hashes;
+
+	      sym_hashes = elf_sym_hashes (input_bfd);
+	      if (!cmse_scan (input_bfd, htab, out_attr, sym_hashes,
+			      &stub_changed))
+		goto error_ret_free_local;
+	    }
+
 	  /* Walk over each section attached to the input bfd.  */
 	  for (section = input_bfd->sections;
 	       section != NULL;
@@ -5823,6 +6105,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
 
       /* Ask the linker to do its stuff.  */
       (*htab->layout_sections_again) ();
+      first_veneer_scan = FALSE;
     }
 
   /* Add stubs for Cortex-A8 erratum fixes now.  */
@@ -9164,7 +9447,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           
howto,
   /* Find out whether the symbol has a PLT.  Set ST_VALUE, BRANCH_TYPE and
      VALUE appropriately for relocations that we resolve at link time.  */
   has_iplt_entry = FALSE;
-  if (elf32_arm_get_plt_info (input_bfd, eh, r_symndx, &root_plt, &arm_plt)
+  if (elf32_arm_get_plt_info (input_bfd, globals, eh, r_symndx, &root_plt,
+			      &arm_plt)
       && root_plt->offset != (bfd_vma) -1)
     {
       plt_offset = root_plt->offset;
@@ -13586,7 +13870,8 @@ elf32_arm_gc_sweep_hook (bfd *                     
abfd,
 	}
 
       if (may_need_local_target_p
-	  && elf32_arm_get_plt_info (abfd, eh, r_symndx, &root_plt, &arm_plt))
+	  && elf32_arm_get_plt_info (abfd, globals, eh, r_symndx, &root_plt,
+				     &arm_plt))
 	{
 	  /* If PLT refcount book-keeping is wrong and too low, we'll
 	     see a zero value (going to -1) for the root PLT reference
@@ -14054,7 +14339,11 @@ elf32_arm_check_relocs (bfd *abfd, struct 
bfd_link_info *info,
 }
 
 /* Unwinding tables are not referenced directly.  This pass marks them as
-   required if the corresponding code section is marked.  */
+   required if the corresponding code section is marked.  Similarly, ARMv8-M
+   secure entry functions can only be referenced by SG veneers which are
+   created after the GC process. They need to be marked in case they reside 
in
+   their own section (as would be the case if code was compiled with
+   -ffunction-sections).  */
 
 static bfd_boolean
 elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
@@ -14062,10 +14351,21 @@ elf32_arm_gc_mark_extra_sections (struct 
bfd_link_info *info,
 {
   bfd *sub;
   Elf_Internal_Shdr **elf_shdrp;
-  bfd_boolean again;
+  asection *cmse_sec;
+  obj_attribute *out_attr;
+  Elf_Internal_Shdr *symtab_hdr;
+  unsigned i, sym_count, ext_start;
+  const struct elf_backend_data *bed;
+  struct elf_link_hash_entry **sym_hashes;
+  struct elf32_arm_link_hash_entry *cmse_hash;
+  bfd_boolean again, is_v8m, first_bfd_browse = TRUE;
 
   _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
 
+  out_attr = elf_known_obj_attributes_proc (info->output_bfd);
+  is_v8m = out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE
+	   && out_attr[Tag_CPU_arch_profile].i == 'M';
+
   /* Marking EH data may cause additional code sections to be marked,
      requiring multiple passes.  */
   again = TRUE;
@@ -14096,7 +14396,34 @@ elf32_arm_gc_mark_extra_sections (struct 
bfd_link_info *info,
 		    return FALSE;
 		}
 	    }
+
+	  /* Mark section holding ARMv8-M secure entry functions.  We mark all
+	     of them so no need for a second browsing.  */
+	  if (is_v8m && first_bfd_browse)
+	    {
+	      sym_hashes = elf_sym_hashes (sub);
+	      bed = get_elf_backend_data (sub);
+	      symtab_hdr = &elf_tdata (sub)->symtab_hdr;
+	      sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym;
+	      ext_start = symtab_hdr->sh_info;
+
+	      /* Scan symbols.  */
+	      for (i = ext_start; i < sym_count; i++)
+		{
+		  cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]);
+
+		  /* Assume it is a special symbol.  If not, cmse_scan will
+		     warn about it and user can do something about it.  */
+		  if (ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal))
+		    {
+		      cmse_sec = cmse_hash->root.root.u.def.section;
+		      if (!_bfd_elf_gc_mark (info, cmse_sec, gc_mark_hook))
+			return FALSE;
+		    }
+		}
+	    }
 	}
+      first_bfd_browse = FALSE;
     }
 
   return TRUE;
@@ -17749,6 +18076,9 @@ elf32_arm_swap_symbol_in (bfd * abfd,
 			  const void *pshn,
 			  Elf_Internal_Sym *dst)
 {
+  Elf_Internal_Shdr *symtab_hdr;
+  const char *name = NULL;
+
   if (!bfd_elf32_swap_symbol_in (abfd, psrc, pshn, dst))
     return FALSE;
   dst->st_target_internal = 0;
@@ -17777,6 +18107,13 @@ elf32_arm_swap_symbol_in (bfd * abfd,
   else
     ARM_SET_SYM_BRANCH_TYPE (dst->st_target_internal, ST_BRANCH_UNKNOWN);
 
+  /* Mark CMSE special symbols.  */
+  symtab_hdr = & elf_symtab_hdr (abfd);
+  if (symtab_hdr->sh_size)
+    name = bfd_elf_sym_name (abfd, symtab_hdr, dst, NULL);
+  if (name && CONST_STRNEQ (name, CMSE_PREFIX))
+    ARM_SET_SYM_CMSE_SPCL (dst->st_target_internal);
+
   return TRUE;
 }
 
diff --git a/include/elf/arm.h b/include/elf/arm.h
index 
bafc03c52ee686671e847eff272ab5cc8a79398c..abad4731b335485f34a06b45d7edea475cfb321b 
100644
--- a/include/elf/arm.h
+++ b/include/elf/arm.h
@@ -384,4 +384,11 @@ enum arm_st_branch_type {
 	   | ((TYPE) & ENUM_ARM_ST_BRANCH_TYPE_BITMASK))
 #endif
 
+/* Get or set whether a symbol is a special symbol of an entry function of 
CMSE
+   secure code.  */
+#define ARM_GET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
+  (((SYM_TARGET_INTERNAL) >> 2) & 1)
+#define ARM_SET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
+  (SYM_TARGET_INTERNAL) |= 4
+
 #endif /* _ELF_ARM_H */
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 
bc16764b0554851217316c438ada863843915307..171ae6e55bc2bf2708a23e822218b8d4e53f8ee6 
100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -6853,6 +6853,12 @@ entries which only support 512Mb of code.
 The @samp{--no-apply-dynamic-relocs} option makes AArch64 linker do not apply
 link-time values for dynamic relocations.
 
+@cindex Placement of SG veneers
+All SG veneers are placed in the special output section @code{.gnu.sgstubs}.
+Its start address must be set, either with the command line option
+@samp{--section-start} or in a linker script, to indicate where to place 
these
+veneers in memory.
+
 @ifclear GENERIC
 @lowersections
 @end ifclear
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index 
f34ce5ff2e4c45f01800df116d8f407f2dd75862..3bd8deb5239adbb38d07caaad0c5ba305d8b05e3 
100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -633,6 +633,33 @@ set armeabitests_nonacl {
      {{objdump -d jump-reloc-veneers-long.d}}
      "jump-reloc-veneers-long"}
 
+    {"Secure gateway veneers: no .gnu.sgstubs section" "" ""
+     "-march=armv8-m.base -mthumb"
+     {cmse-veneers.s}
+     {{ld cmse-veneers-no-gnu_sgstubs.out}}
+     "cmse-veneers-no-gnu_sgstubs"}
+    {"Secure gateway veneers: wrong entry functions" "" ""
+     "-march=armv7-m -mthumb --defsym CHECK_ERRORS=1"
+     {cmse-veneers.s}
+     {{ld cmse-veneers-wrong-entryfct.out}}
+     "cmse-veneers-wrong-entryfct"}
+    {"Secure gateway veneers (ARMv8-M Baseline)"
+     "-Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --gc-sections" ""
+     "-march=armv8-m.base -mthumb"
+     {cmse-veneers.s}
+     {{objdump {-d -j .gnu.sgstubs} cmse-veneers.d}
+      {objdump {-h -j .gnu.sgstubs} cmse-veneers.sd}
+      {nm {} cmse-veneers.rd}}
+     "cmse-veneers-baseline"}
+    {"Secure gateway veneers (ARMv8-M Mainline)"
+     "-Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --gc-sections" ""
+     "-march=armv8-m.main -mthumb"
+     {cmse-veneers.s}
+     {{objdump {-d -j .gnu.sgstubs} cmse-veneers.d}
+      {objdump {-h -j .gnu.sgstubs} cmse-veneers.sd}
+      {nm {} cmse-veneers.rd}}
+     "cmse-veneers-mainline"}
+
     {"R_ARM_THM_JUMP19 Relocation veneers: Short"
      "--section-start destsect=0x000108002 --section-start .text=0x8000" ""
      "-march=armv7-m -mthumb"
diff --git a/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out 
b/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out
new file mode 100644
index 
0000000000000000000000000000000000000000..9d1e5ba3215ae8a29585fcf04ec1f94314670a29
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out
@@ -0,0 +1,3 @@
+.*: No address assigned to the veneers output section .gnu.sgstubs
+.*: cannot size stub section: Invalid operation
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out 
b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
new file mode 100644
index 
0000000000000000000000000000000000000000..fd4766ab877a4abbeb8b2c4c053ab11d3f86773c
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
@@ -0,0 +1,19 @@
+.*: .*: Special symbol `__acle_se_loc_entry_veneer1' only allowed for ARMv8-M 
architecture or later.
+.*: .*: invalid .* symbol `.*loc_entry_veneer1'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_loc_entry_veneer2'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_loc_entry_veneer4'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid standard symbol `loc_entry_veneer3'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid standard symbol `loc_entry_veneer5'.
+.*: It must be a global or weak function symbol.
+.*: .*: absent standard symbol `fake_entry_veneer1'.
+.*: .*: invalid standard symbol `obj_entry_veneer1'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_obj_entry_veneer2'.
+.*: It must be a global or weak function symbol.
+.*: .*: `fake_entry_veneer2' and its special symbol are in different sections.
+.*: cannot size stub section: Invalid operation
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers.d b/ld/testsuite/ld-arm/cmse-
veneers.d
new file mode 100644
index 
0000000000000000000000000000000000000000..6a44a2b5dce9de4f5d64fe644e41f5ab9840806e
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.d
@@ -0,0 +1,21 @@
+
+.*
+
+
+Disassembly of section \.gnu.sgstubs:
+
+00020000 <glob_entry_veneer2>:
+   20000:	e97f e97f 	sg
+   20004:	f7e8 b800 	b\.w	8008 <__acle_se_glob_entry_veneer2>
+
+00020008 <weak_entry_veneer2>:
+   20008:	e97f e97f 	sg
+   2000c:	f7e7 bffe 	b\.w	800c <__acle_se_weak_entry_veneer2>
+
+00020010 <glob_entry_veneer1>:
+   20010:	e97f e97f 	sg
+   20014:	f7e7 bff4 	b\.w	8000 <__acle_se_glob_entry_veneer1>
+
+00020018 <weak_entry_veneer1>:
+   20018:	e97f e97f 	sg
+   2001c:	f7e7 bff2 	b\.w	8004 <__acle_se_weak_entry_veneer1>
diff --git a/ld/testsuite/ld-arm/cmse-veneers.rd b/ld/testsuite/ld-arm/cmse-
veneers.rd
new file mode 100644
index 
0000000000000000000000000000000000000000..20fad961bd8803109c3cf57ef22e3b36da5b1500
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.rd
@@ -0,0 +1,9 @@
+#...
+[0-9a-f]+ T glob_entry_fct
+#...
+[0-9a-f]+ T glob_entry_veneer1
+[0-9a-f]+ T glob_entry_veneer2
+#...
+[0-9a-f]+ W weak_entry_veneer1
+[0-9a-f]+ W weak_entry_veneer2
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers.s b/ld/testsuite/ld-arm/cmse-
veneers.s
new file mode 100644
index 
0000000000000000000000000000000000000000..3f68135a2038f2f95a5595e257db0785db4e3997
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.s
@@ -0,0 +1,98 @@
+	.syntax unified
+	.thumb
+	.file	"foo.c"
+	.section .text.entryfcts, "ax", %progbits
+	.text
+
+.macro	decltype	name, type
+.ifc \type,object
+	.data
+.else
+	.thumb
+	.thumb_func
+.endif
+	.type	\name, %\type
+.endm
+
+
+.macro	entry	name, type, vis, typespc, visspc, entry_fct
+	.align	2
+.ifb \visspc
+	.\vis	__acle_se_\name
+.else
+	.\visspc	__acle_se_\name
+.endif
+	.\vis	\name
+	.thumb
+	.thumb_func
+.ifb \typespc
+	decltype	__acle_se_\name, \type
+.else
+	decltype	__acle_se_\name, \typespc
+.endif
+	decltype	\name, \type
+__acle_se_\name:
+	\entry_fct
+\name:
+.ifc \type,object
+	.word 42
+.else
+	nop
+.endif
+	.size	\name, .-\name
+	.size	__acle_se_\name, .-__acle_se_\name
+.endm
+
+
+.ifndef CHECK_ERRORS
+	@ Valid setups for veneer generation
+	entry glob_entry_veneer1, function, global
+	entry weak_entry_veneer1, function, weak
+	entry glob_entry_veneer2, function, global, visspc=weak
+	entry weak_entry_veneer2, function, weak, visspc=global
+
+	@ Valid setup for entry function without SG veneer
+	entry glob_entry_fct, function, global, entry_fct=nop
+
+.else
+	@ Invalid setups for veneer generation (visibility)
+	entry loc_entry_veneer1, function, local
+	entry loc_entry_veneer2, function, global, visspc=local
+	entry loc_entry_veneer3, function, local, visspc=global
+	entry loc_entry_veneer4, function, weak, visspc=local
+	entry loc_entry_veneer5, function, local, visspc=weak
+
+	@ Invalid setups for veneer generation (absent standard symbol)
+	.align	2
+	.global	__acle_se_fake_entry_veneer1
+	.thumb
+	.thumb_func
+	.type	__acle_se_fake_entry_veneer1, %function
+__acle_se_fake_entry_veneer1:
+	nop
+	.size	__acle_se_fake_entry_veneer1, .-__acle_se_fake_entry_veneer1
+
+	@ Invalid setups for veneer generation (type)
+	entry obj_entry_veneer1, object, global, typespc=function
+	entry obj_entry_veneer2, function, global, typespc=object
+
+	@ Invalid setup for veneer generation (sections)
+	.section .text.sub1
+	.align	2
+	.thumb
+	.thumb_func
+	.global	__acle_se_fake_entry_veneer2
+	.type	__acle_se_fake_entry_veneer2, %function
+__acle_se_fake_entry_veneer2:
+	nop
+	.size	__acle_se_fake_entry_veneer2, .-__acle_se_fake_entry_veneer2
+	.section .text.sub2
+	.align	2
+	.thumb
+	.thumb_func
+	.global	fake_entry_veneer2
+	.type	fake_entry_veneer2, %function
+fake_entry_veneer2:
+	nop
+	.size	fake_entry_veneer2, .-fake_entry_veneer2
+.endif
diff --git a/ld/testsuite/ld-arm/cmse-veneers.sd b/ld/testsuite/ld-arm/cmse-
veneers.sd
new file mode 100644
index 
0000000000000000000000000000000000000000..99bfc8f37c25b7a57122b330b1145e27a9b087fd
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.sd
@@ -0,0 +1,7 @@
+
+.*
+
+Sections:
+Idx Name          Size      VMA       LMA       File off  Algn
+  \d+ \.gnu\.sgstubs  00000020  00020000  00020000  00010000  2\*\*5
+                  CONTENTS, ALLOC, LOAD, READONLY, CODE


Best regards,

Thomas

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH, binutils, ARM 8/11] Add support for ARMv8-M Secure Gateway veneer generation
  2016-05-18 16:30   ` Thomas Preudhomme
@ 2016-07-07 10:53     ` Richard Earnshaw (lists)
  2016-07-07 15:27       ` Thomas Preudhomme
  0 siblings, 1 reply; 10+ messages in thread
From: Richard Earnshaw (lists) @ 2016-07-07 10:53 UTC (permalink / raw)
  To: Thomas Preudhomme, binutils

+   As per "ARMv8-M Security Extensions: Requirements on Development Tools"
+   document, a secure gateway veneer is needed when there exists a
non-local
+   function symbol called "normal" symbol (eg. foo) with the same value
as a
+   symbol with the same type, binding a name save for a __acle_se_ prefix,
+   called a "special" symbol (eg. __acle_se_foo).  Entry functions handling
+   with secure state transition by themselves have these symbols with
different
+   values.


This is very unclear as to what is being/needs to be done.  Can you try
redrafting it?

Otherwise I think the patch is OK.

R.

On 18/05/16 17:30, Thomas Preudhomme wrote:
> On Tuesday 29 March 2016 15:42:39 Thomas Preudhomme wrote:
>> On Wednesday 23 December 2015 15:59:44 Thomas Preud'homme wrote:
>>> Hi,
>>>
>>> [Posting patch series as RFC]
>>>
>>> This patch is part of a patch series to add support for ARMv8-M Security
>>> Extensions[1] to GNU ld. This specific patch adds support for creating
>>> ARMv8-M Secure Gateway veneers.
>>>
>>> ARM v8-M Security Extensions require [3] secure gateway veneers to be
>>> generated for (secure) entry function in order for code to transition from
>>> non-secure state to secure state when calling these entry function. Unlike
>>> other veneers, these veneers are generated independently of relocations,
>>> ie
>>> a veneer can be generated in the absence of relocation. The condition for
>>> the generation is that the normal symbol (the one whose name is the same
>>> as
>>> in C) of an entry function has the same value as the special symbol
>>> (normal
>>> symbol prefixed with "__acle_se_"). When that happens, the normal symbol
>>> is
>>> rebound to the veneer generated. When the two symbols have different value
>>> it indicates that the entry function already contains an sg instruction to
>>> do the secure state transition and the normal symbol points to the sg
>>> instruction while the special symbol points after that.
>>>
>>> It is also required [4] that such veneers must be able to keep their
>>> address when the secure code is relinked in order to avoid relinking the
>>> non secure code with the secure code. This patch adds support for
>>> generating these veneers in a dedicated output section and expect the
>>> user to specify the address of that section (either via --section-start
>>> parameter or in the linker script). This ensure that they are placed in a
>>> memory area with sufficient space for more veneers to be added. Ensuring
>>> that existing veneers keep their addresses when the secure executable is
>>> relinked is handled by a subsequent patch of this patch serie.
>>>
>>> Note: this patch needs the Cortex-A8 errata workaround refactoring patch
>>> applied to work (patch 1/9 in the patch serie).
>>>
>>> RFC Note: This patch contains some Secure Gateway specific elements that
>>> could potentially be made into more generic and independent suitable for
>>> separate patch. Namely, these are the padding of stub section and setting
>>> a
>>> specific output section for a given stub section.
>>>
>>>
>>> [1] Software requirements for ARMv8-M Security Extensions are described in
>>> document ARM-ECM-0359818 [2] [2] Available on http://infocenter.arm.com in
>>> Developer guides and articles > Software development > ARM®v8-M Security
>>> Extensions: Requirements on Development Tools [3] See section 3.4.3 and
>>> requirement 44 of ARM-ECM-0359818 [2]
>>> [4] requirement 14 and following comment of ARM-ECM-0359818 [2]
>>
>> Please find an updated patch below, following the split of most of its
>> content in 6/11 and 7/11.
> 
> Please find a rebased patch that now deal with the new 
> elf32_arm_stub_cmse_branch_thumb_only by changing boolean returning function 
> into switch cases in addition to add the case statement for the stub itself. 
> It also makes sure SG veneers are kept when calling the linker with --gc-
> sections.
> 
> ChangeLog entries are now:
> 
> *** bfd/ChangeLog ***
> 
> 2016-05-04  Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * elf32-arm.c (CMSE_PREFIX): Define macro.
>         (elf32_arm_stub_cmse_branch_thumb_only): Define stub sequence.
>         (cmse_branch_thumb_only): Declare stub.
>         (struct elf32_arm_link_hash_table): Define cmse_stub_sec field.
>         (elf32_arm_get_plt_info): Add globals parameter.  Use it to return
>         FALSE if there is no PLT.
>         (arm_type_of_stub): Adapt to new elf32_arm_get_plt_info signature.
>         (elf32_arm_final_link_relocate): Likewise.
>         (elf32_arm_gc_sweep_hook): Likewise.
>         (elf32_arm_gc_mark_extra_sections): Mark sections holding ARMv8-M
>         secure entry functions.
>         (arm_stub_is_thumb): Add case for arm_stub_cmse_branch_thumb_only.
>         (arm_dedicated_stub_output_section_required): Change to a switch case
>         and add a case for arm_stub_cmse_branch_thumb_only.
>         (arm_dedicated_stub_output_section_required_alignment): Likewise.
>         (arm_stub_dedicated_output_section_name): Likewise.
>         (arm_stub_dedicated_input_section_ptr): Likewise and remove
>         ATTRIBUTE_UNUSED for htab parameter.
>         (arm_stub_required_alignment): Likewise.
>         (arm_stub_sym_claimed): Likewise.
>         (arm_dedicated_stub_section_padding): Likewise.
>         (cmse_scan): New function.
>         (elf32_arm_size_stubs): Call cmse_scan for ARM M profile targets.
>         Set stub_changed to TRUE if such veneers were created.
>         (elf32_arm_swap_symbol_in): Add detection code for CMSE special
>         symbols.
> 
> 
> *** include/elf/ChangeLog ***
> 
> 2015-12-16  Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * arm.h (ARM_GET_SYM_CMSE_SPCL): Define macro.
>         (ARM_SET_SYM_CMSE_SPCL): Likewise.
> 
> 
> *** ld/ChangeLog ***
> 
> 2016-02-17  Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * ld.texinfo (Placement of SG veneers): New concept entry.
>         * testsuite/ld-arm/arm-elf.exp
>         (Secure gateway veneers: no .gnu.sgstubs section): New test.
>         (Secure gateway veneers: wrong entry functions): Likewise.
>         (Secure gateway veneers (ARMv8-M Baseline)): Likewise.
>         (Secure gateway veneers (ARMv8-M Mainline)): Likewise.
>         * testsuite/ld-arm/cmse-veneers.s: New file.
>         * testsuite/ld-arm/cmse-veneers.d: Likewise.
>         * testsuite/ld-arm/cmse-veneers.rd: Likewise.
>         * testsuite/ld-arm/cmse-veneers.sd: Likewise.
>         * testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out: Likewise.
>         * testsuite/ld-arm/cmse-veneers-wrong-entryfct.out: Likewise.
> 
> 
> diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
> index 
> 3a93fd057e02d9ee1231208af4fe2ae5fa718a21..a73c6c3d755420225cae89b1b5beaa5def7aaca0 
> 100644
> --- a/bfd/elf32-arm.c
> +++ b/bfd/elf32-arm.c
> @@ -2138,6 +2138,8 @@ typedef unsigned short int insn16;
>  
>  #define STUB_ENTRY_NAME   "__%s_veneer"
>  
> +#define CMSE_PREFIX "__acle_se_"
> +
>  /* The name of the dynamic interpreter.  This is put in the .interp
>     section.  */
>  #define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
> @@ -2543,6 +2545,13 @@ static const insn_sequence 
> elf32_arm_stub_long_branch_arm_nacl_pic[] =
>    DATA_WORD (0, R_ARM_NONE, 0),         /* .word 0 */
>  };
>  
> +/* Stub used for transition to secure state (aka SG veneer).  */
> +static const insn_sequence elf32_arm_stub_cmse_branch_thumb_only[] =
> +{
> +  THUMB32_INSN (0xe97fe97f),		/* sg.  */
> +  THUMB32_B_INSN (0xf000b800, -4),	/* b.w original_branch_dest.  */
> +};
> +
>  
>  /* Cortex-A8 erratum-workaround stubs.  */
>  
> @@ -2622,6 +2631,7 @@ static const insn_sequence 
> elf32_arm_stub_a8_veneer_blx[] =
>    DEF_STUB(long_branch_v4t_thumb_tls_pic) \
>    DEF_STUB(long_branch_arm_nacl) \
>    DEF_STUB(long_branch_arm_nacl_pic) \
> +  DEF_STUB(cmse_branch_thumb_only) \
>    DEF_STUB(a8_veneer_b_cond) \
>    DEF_STUB(a8_veneer_b) \
>    DEF_STUB(a8_veneer_bl) \
> @@ -3172,6 +3182,9 @@ struct elf32_arm_link_hash_table
>       information on stub grouping.  */
>    struct map_stub *stub_group;
>  
> +  /* Input stub section holding secure gateway veneers.  */
> +  asection *cmse_stub_sec;
> +
>    /* Number of elements in stub_group.  */
>    unsigned int top_id;
>  
> @@ -3320,12 +3333,16 @@ elf32_arm_create_local_iplt (bfd *abfd, unsigned long 
> r_symndx)
>     union and *ARM_PLT at the ARM-specific information.  */
>  
>  static bfd_boolean
> -elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_entry *h,
> +elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_table *globals,
> +			struct elf32_arm_link_hash_entry *h,
>  			unsigned long r_symndx, union gotplt_union **root_plt,
>  			struct arm_plt_info **arm_plt)
>  {
>    struct arm_local_iplt_info *local_iplt;
>  
> +  if (globals->root.splt == NULL && globals->root.iplt == NULL)
> +    return FALSE;
> +
>    if (h != NULL)
>      {
>        *root_plt = &h->root.plt;
> @@ -3768,6 +3785,7 @@ arm_stub_is_thumb (enum elf32_arm_stub_type stub_type)
>      case arm_stub_long_branch_v4t_thumb_arm_pic:
>      case arm_stub_long_branch_v4t_thumb_tls_pic:
>      case arm_stub_long_branch_thumb_only_pic:
> +    case arm_stub_cmse_branch_thumb_only:
>        return TRUE;
>      case arm_stub_none:
>        BFD_FAIL ();
> @@ -3833,8 +3851,9 @@ arm_type_of_stub (struct bfd_link_info *info,
>       the address of the appropriate trampoline.  */
>    if (r_type != R_ARM_TLS_CALL
>        && r_type != R_ARM_THM_TLS_CALL
> -      && elf32_arm_get_plt_info (input_bfd, hash, ELF32_R_SYM (rel->r_info),
> -				 &root_plt, &arm_plt)
> +      && elf32_arm_get_plt_info (input_bfd, globals, hash,
> +				 ELF32_R_SYM (rel->r_info), &root_plt,
> +				 &arm_plt)
>        && root_plt->offset != (bfd_vma) -1)
>      {
>        asection *splt;
> @@ -4145,7 +4164,16 @@ arm_dedicated_stub_output_section_required (enum 
> elf32_arm_stub_type stub_type)
>    if (stub_type >= max_stub_type)
>      abort ();  /* Should be unreachable.  */
>  
> -  return FALSE;
> +  switch (stub_type)
> +    {
> +    case arm_stub_cmse_branch_thumb_only:
> +      return TRUE;
> +
> +    default:
> +      return FALSE;
> +    }
> +
> +  abort ();  /* Should be unreachable.  */
>  }
>  
>  /* Required alignment (as a power of 2) for the dedicated section holding
> @@ -4159,8 +4187,19 @@ arm_dedicated_stub_output_section_required_alignment
>    if (stub_type >= max_stub_type)
>      abort ();  /* Should be unreachable.  */
>  
> -  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
> -  return 0;
> +  switch (stub_type)
> +    {
> +    /* Vectors of Secure Gateway veneers must be aligned on 32byte
> +       boundary.  */
> +    case arm_stub_cmse_branch_thumb_only:
> +      return 5;
> +
> +    default:
> +      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
> +      return 0;
> +    }
> +
> +  abort ();  /* Should be unreachable.  */
>  }
>  
>  /* Name of the dedicated output section to put veneers of type STUB_TYPE, or
> @@ -4172,8 +4211,17 @@ arm_dedicated_stub_output_section_name (enum 
> elf32_arm_stub_type stub_type)
>    if (stub_type >= max_stub_type)
>      abort ();  /* Should be unreachable.  */
>  
> -  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
> -  return NULL;
> +  switch (stub_type)
> +    {
> +    case arm_stub_cmse_branch_thumb_only:
> +      return ".gnu.sgstubs";
> +
> +    default:
> +      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
> +      return NULL;
> +    }
> +
> +  abort ();  /* Should be unreachable.  */
>  }
>  
>  /* If veneers of type STUB_TYPE should go in a dedicated output section,
> @@ -4181,15 +4229,23 @@ arm_dedicated_stub_output_section_name (enum 
> elf32_arm_stub_type stub_type)
>     corresponding input section.  Otherwise, returns NULL.  */
>  
>  static asection **
> -arm_dedicated_stub_input_section_ptr
> -  (struct elf32_arm_link_hash_table *htab ATTRIBUTE_UNUSED,
> -   enum elf32_arm_stub_type stub_type)
> +arm_dedicated_stub_input_section_ptr (struct elf32_arm_link_hash_table *htab,
> +				      enum elf32_arm_stub_type stub_type)
>  {
>    if (stub_type >= max_stub_type)
>      abort ();  /* Should be unreachable.  */
>  
> -  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
> -  return NULL;
> +  switch (stub_type)
> +    {
> +    case arm_stub_cmse_branch_thumb_only:
> +      return &htab->cmse_stub_sec;
> +
> +    default:
> +      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
> +      return NULL;
> +    }
> +
> +  abort ();  /* Should be unreachable.  */
>  }
>  
>  /* Find or create a stub section to contain a stub of type STUB_TYPE.  
> SECTION
> @@ -4411,6 +4467,7 @@ arm_stub_required_alignment (enum elf32_arm_stub_type 
> stub_type)
>      case arm_stub_long_branch_thumb_only_pic:
>      case arm_stub_long_branch_any_tls_pic:
>      case arm_stub_long_branch_v4t_thumb_tls_pic:
> +    case arm_stub_cmse_branch_thumb_only:
>      case arm_stub_a8_veneer_blx:
>        return 4;
>  
> @@ -4432,7 +4489,16 @@ arm_stub_sym_claimed (enum elf32_arm_stub_type 
> stub_type)
>    if (stub_type >= max_stub_type)
>      abort ();  /* Should be unreachable.  */
>  
> -  return FALSE;
> +  switch (stub_type)
> +    {
> +    case arm_stub_cmse_branch_thumb_only:
> +      return TRUE;
> +
> +    default:
> +      return FALSE;
> +    }
> +
> +  abort ();  /* Should be unreachable.  */
>  }
>  
>  /* Returns the padding needed for the dedicated section used stubs of type
> @@ -4444,7 +4510,16 @@ arm_dedicated_stub_section_padding (enum 
> elf32_arm_stub_type stub_type)
>    if (stub_type >= max_stub_type)
>      abort ();  /* Should be unreachable.  */
>  
> -  return 0;
> +  switch (stub_type)
> +    {
> +    case arm_stub_cmse_branch_thumb_only:
> +      return 32;
> +
> +    default:
> +      return 0;
> +    }
> +
> +  abort ();  /* Should be unreachable.  */
>  }
>  
>  static bfd_boolean
> @@ -5335,6 +5410,198 @@ elf32_arm_create_stub (struct 
> elf32_arm_link_hash_table *htab,
>    return TRUE;
>  }
>  
> +/* Scan symbols in INPUT_BFD to identify secure entry functions needing a
> +   gateway veneer to transition from non secure to secure state and create 
> them
> +   accordingly.
> +
> +   As per "ARMv8-M Security Extensions: Requirements on Development Tools"
> +   document, a secure gateway veneer is needed when there exists a non-local
> +   function symbol called "normal" symbol (eg. foo) with the same value as a
> +   symbol with the same type, binding a name save for a __acle_se_ prefix,
> +   called a "special" symbol (eg. __acle_se_foo).  Entry functions handling
> +   with secure state transition by themselves have these symbols with 
> different
> +   values.
> +
> +   OUT_ATTR gives the output attributes, SYM_HASHES the symbol index to hash
> +   entry mapping while HTAB gives the name to hash entry mapping.
> +
> +   If any secure gateway veneer is created, *STUB_CHANGED is set to TRUE.  
> The
> +   return value gives whether a stub failed to be allocated.  */
> +
> +static bfd_boolean
> +cmse_scan (bfd *input_bfd, struct elf32_arm_link_hash_table *htab,
> +	   obj_attribute *out_attr, struct elf_link_hash_entry **sym_hashes,
> +	   bfd_boolean *stub_changed)
> +{
> +  const struct elf_backend_data *bed;
> +  Elf_Internal_Shdr *symtab_hdr;
> +  unsigned i, j, sym_count, ext_start;
> +  Elf_Internal_Sym *cmse_sym, *local_syms;
> +  struct elf32_arm_link_hash_entry *hash, *cmse_hash = NULL;
> +  enum arm_st_branch_type branch_type;
> +  char *sym_name, *lsym_name;
> +  bfd_vma sym_value;
> +  asection *section;
> +  bfd_boolean is_v8m, new_stub, created_stub, cmse_invalid, ret = TRUE;
> +
> +  bed = get_elf_backend_data (input_bfd);
> +  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
> +  sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym;
> +  ext_start = symtab_hdr->sh_info;
> +  is_v8m = (out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE
> +	    && out_attr[Tag_CPU_arch_profile].i == 'M');
> +
> +  local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
> +  if (local_syms == NULL)
> +    local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
> +				       symtab_hdr->sh_info, 0, NULL, NULL,
> +				       NULL);
> +  if (symtab_hdr->sh_info && local_syms == NULL)
> +    return FALSE;
> +
> +  /* Scan symbols.  */
> +  for (i = 0; i < sym_count; i++)
> +    {
> +      cmse_invalid = FALSE;
> +
> +      if (i < ext_start)
> +	{
> +	  cmse_sym = &local_syms[i];
> +	  /* Not a special symbol.  */
> +	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_sym->st_target_internal))
> +	    continue;
> +	  sym_name = bfd_elf_string_from_elf_section (input_bfd,
> +						      symtab_hdr->sh_link,
> +						      cmse_sym->st_name);
> +	  /* Special symbol with local binding.  */
> +	  cmse_invalid = TRUE;
> +	}
> +      else
> +	{
> +	  cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]);
> +	  sym_name = (char *) cmse_hash->root.root.root.string;
> +
> +	  /* Not a special symbol.  */
> +	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal))
> +	    continue;
> +
> +	  /* Special symbol has incorrect binding or type.  */
> +	  if ((cmse_hash->root.root.type != bfd_link_hash_defined
> +	       && cmse_hash->root.root.type != bfd_link_hash_defweak)
> +	      || cmse_hash->root.type != STT_FUNC)
> +	    cmse_invalid = TRUE;
> +	}
> +
> +      if (!is_v8m)
> +	{
> +	  (*_bfd_error_handler) (_("%B: Special symbol `%s' only allowed for "
> +				   "ARMv8-M architecture or later."),
> +				 input_bfd, sym_name);
> +	  is_v8m = TRUE; /* Avoid multiple warning.  */
> +	  ret = FALSE;
> +	}
> +
> +      if (cmse_invalid)
> +	{
> +	  (*_bfd_error_handler) (_("%B: invalid special symbol `%s'."),
> +				 input_bfd, sym_name);
> +	  (*_bfd_error_handler) (_("It must be a global or weak function "
> +				   "symbol."));
> +	  ret = FALSE;
> +	  if (i < ext_start)
> +	    continue;
> +	}
> +
> +      sym_name += strlen (CMSE_PREFIX);
> +      hash = (struct elf32_arm_link_hash_entry *)
> +	elf_link_hash_lookup (&(htab)->root, sym_name, FALSE, FALSE, TRUE);
> +
> +      /* No associated normal symbol or it is neither global nor weak.  */
> +      if (!hash
> +	  || (hash->root.root.type != bfd_link_hash_defined
> +	      && hash->root.root.type != bfd_link_hash_defweak)
> +	  || hash->root.type != STT_FUNC)
> +	{
> +	  if (!hash)
> +	    {
> +	      /* Searching for a normal symbol with local binding.  */
> +	      for (j = 0; j < ext_start; j++)
> +		{
> +		  lsym_name =
> +		    bfd_elf_string_from_elf_section (input_bfd,
> +						     symtab_hdr->sh_link,
> +						     local_syms[j].st_name);
> +		  if (!strcmp (sym_name, lsym_name))
> +		    break;
> +		}
> +	    }
> +
> +	  if (hash || j < ext_start)
> +	    {
> +	      (*_bfd_error_handler)
> +		(_("%B: invalid standard symbol `%s'."), input_bfd, sym_name);
> +	      (*_bfd_error_handler)
> +		(_("It must be a global or weak function symbol."));
> +	    }
> +	  else
> +	    (*_bfd_error_handler)
> +	      (_("%B: absent standard symbol `%s'."), input_bfd, sym_name);
> +	  ret = FALSE;
> +	  if (!hash)
> +	    continue;
> +	}
> +
> +      sym_value = hash->root.root.u.def.value;
> +      section = hash->root.root.u.def.section;
> +
> +      if (cmse_hash->root.root.u.def.section != section)
> +	{
> +	  (*_bfd_error_handler)
> +	    (_("%B: `%s' and its special symbol are in different sections."),
> +	     input_bfd, sym_name);
> +	  ret = FALSE;
> +	}
> +      if (cmse_hash->root.root.u.def.value != sym_value)
> +	continue; /* Ignore: could be an entry function starting with SG.  */
> +
> +	/* If this section is a link-once section that will be discarded, then
> +	   don't create any stubs.  */
> +      if (section->output_section == NULL)
> +	{
> +	  (*_bfd_error_handler)
> +	    (_("%B: entry function `%s' not output."), input_bfd, sym_name);
> +	  continue;
> +	}
> +
> +      if (hash->root.size == 0)
> +	{
> +	  (*_bfd_error_handler)
> +	    (_("%B: entry function `%s' is empty."), input_bfd, sym_name);
> +	  ret = FALSE;
> +	}
> +
> +      if (!ret)
> +	continue;
> +      branch_type = ARM_GET_SYM_BRANCH_TYPE (hash->root.target_internal);
> +      created_stub
> +	= elf32_arm_create_stub (htab, arm_stub_cmse_branch_thumb_only,
> +				 NULL, NULL, section, hash, sym_name,
> +				 sym_value, branch_type, &new_stub);
> +
> +      if (!created_stub)
> +	 ret = FALSE;
> +      else
> +	{
> +	  BFD_ASSERT (new_stub);
> +	  *stub_changed = TRUE;
> +	}
> +    }
> +
> +  if (!symtab_hdr->contents)
> +    free (local_syms);
> +  return ret;
> +}
> +
>  /* Determine and set the size of the stub section for a final link.
>  
>     The basic idea here is to examine all the relocations looking for
> @@ -5351,8 +5618,9 @@ elf32_arm_size_stubs (bfd *output_bfd,
>  						      unsigned int),
>  		      void (*layout_sections_again) (void))
>  {
> +  obj_attribute *out_attr;
>    bfd_size_type stub_group_size;
> -  bfd_boolean stubs_always_after_branch;
> +  bfd_boolean m_profile, stubs_always_after_branch, first_veneer_scan = TRUE;
>    struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
>    struct a8_erratum_fix *a8_fixes = NULL;
>    unsigned int num_a8_fixes = 0, a8_fix_table_size = 10;
> @@ -5381,6 +5649,8 @@ elf32_arm_size_stubs (bfd *output_bfd,
>    htab->layout_sections_again = layout_sections_again;
>    stubs_always_after_branch = group_size < 0;
>  
> +  out_attr = elf_known_obj_attributes_proc (output_bfd);
> +  m_profile = out_attr[Tag_CPU_arch_profile].i == 'M';
>    /* The Cortex-A8 erratum fix depends on stubs not being in the same 4K page
>       as the first half of a 32-bit branch straddling two 4K pages.  This is a
>       crude way of enforcing that.  */
> @@ -5446,6 +5716,18 @@ elf32_arm_size_stubs (bfd *output_bfd,
>  	  if (symtab_hdr->sh_info == 0)
>  	    continue;
>  
> +	  /* Limit scan of symbols to object file whose profile is
> +	     Microcontroller to not hinder performance in the general case.  */
> +	  if (m_profile && first_veneer_scan)
> +	    {
> +	      struct elf_link_hash_entry **sym_hashes;
> +
> +	      sym_hashes = elf_sym_hashes (input_bfd);
> +	      if (!cmse_scan (input_bfd, htab, out_attr, sym_hashes,
> +			      &stub_changed))
> +		goto error_ret_free_local;
> +	    }
> +
>  	  /* Walk over each section attached to the input bfd.  */
>  	  for (section = input_bfd->sections;
>  	       section != NULL;
> @@ -5823,6 +6105,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
>  
>        /* Ask the linker to do its stuff.  */
>        (*htab->layout_sections_again) ();
> +      first_veneer_scan = FALSE;
>      }
>  
>    /* Add stubs for Cortex-A8 erratum fixes now.  */
> @@ -9164,7 +9447,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           
> howto,
>    /* Find out whether the symbol has a PLT.  Set ST_VALUE, BRANCH_TYPE and
>       VALUE appropriately for relocations that we resolve at link time.  */
>    has_iplt_entry = FALSE;
> -  if (elf32_arm_get_plt_info (input_bfd, eh, r_symndx, &root_plt, &arm_plt)
> +  if (elf32_arm_get_plt_info (input_bfd, globals, eh, r_symndx, &root_plt,
> +			      &arm_plt)
>        && root_plt->offset != (bfd_vma) -1)
>      {
>        plt_offset = root_plt->offset;
> @@ -13586,7 +13870,8 @@ elf32_arm_gc_sweep_hook (bfd *                     
> abfd,
>  	}
>  
>        if (may_need_local_target_p
> -	  && elf32_arm_get_plt_info (abfd, eh, r_symndx, &root_plt, &arm_plt))
> +	  && elf32_arm_get_plt_info (abfd, globals, eh, r_symndx, &root_plt,
> +				     &arm_plt))
>  	{
>  	  /* If PLT refcount book-keeping is wrong and too low, we'll
>  	     see a zero value (going to -1) for the root PLT reference
> @@ -14054,7 +14339,11 @@ elf32_arm_check_relocs (bfd *abfd, struct 
> bfd_link_info *info,
>  }
>  
>  /* Unwinding tables are not referenced directly.  This pass marks them as
> -   required if the corresponding code section is marked.  */
> +   required if the corresponding code section is marked.  Similarly, ARMv8-M
> +   secure entry functions can only be referenced by SG veneers which are
> +   created after the GC process. They need to be marked in case they reside 
> in
> +   their own section (as would be the case if code was compiled with
> +   -ffunction-sections).  */
>  
>  static bfd_boolean
>  elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
> @@ -14062,10 +14351,21 @@ elf32_arm_gc_mark_extra_sections (struct 
> bfd_link_info *info,
>  {
>    bfd *sub;
>    Elf_Internal_Shdr **elf_shdrp;
> -  bfd_boolean again;
> +  asection *cmse_sec;
> +  obj_attribute *out_attr;
> +  Elf_Internal_Shdr *symtab_hdr;
> +  unsigned i, sym_count, ext_start;
> +  const struct elf_backend_data *bed;
> +  struct elf_link_hash_entry **sym_hashes;
> +  struct elf32_arm_link_hash_entry *cmse_hash;
> +  bfd_boolean again, is_v8m, first_bfd_browse = TRUE;
>  
>    _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
>  
> +  out_attr = elf_known_obj_attributes_proc (info->output_bfd);
> +  is_v8m = out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE
> +	   && out_attr[Tag_CPU_arch_profile].i == 'M';
> +
>    /* Marking EH data may cause additional code sections to be marked,
>       requiring multiple passes.  */
>    again = TRUE;
> @@ -14096,7 +14396,34 @@ elf32_arm_gc_mark_extra_sections (struct 
> bfd_link_info *info,
>  		    return FALSE;
>  		}
>  	    }
> +
> +	  /* Mark section holding ARMv8-M secure entry functions.  We mark all
> +	     of them so no need for a second browsing.  */
> +	  if (is_v8m && first_bfd_browse)
> +	    {
> +	      sym_hashes = elf_sym_hashes (sub);
> +	      bed = get_elf_backend_data (sub);
> +	      symtab_hdr = &elf_tdata (sub)->symtab_hdr;
> +	      sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym;
> +	      ext_start = symtab_hdr->sh_info;
> +
> +	      /* Scan symbols.  */
> +	      for (i = ext_start; i < sym_count; i++)
> +		{
> +		  cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]);
> +
> +		  /* Assume it is a special symbol.  If not, cmse_scan will
> +		     warn about it and user can do something about it.  */
> +		  if (ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal))
> +		    {
> +		      cmse_sec = cmse_hash->root.root.u.def.section;
> +		      if (!_bfd_elf_gc_mark (info, cmse_sec, gc_mark_hook))
> +			return FALSE;
> +		    }
> +		}
> +	    }
>  	}
> +      first_bfd_browse = FALSE;
>      }
>  
>    return TRUE;
> @@ -17749,6 +18076,9 @@ elf32_arm_swap_symbol_in (bfd * abfd,
>  			  const void *pshn,
>  			  Elf_Internal_Sym *dst)
>  {
> +  Elf_Internal_Shdr *symtab_hdr;
> +  const char *name = NULL;
> +
>    if (!bfd_elf32_swap_symbol_in (abfd, psrc, pshn, dst))
>      return FALSE;
>    dst->st_target_internal = 0;
> @@ -17777,6 +18107,13 @@ elf32_arm_swap_symbol_in (bfd * abfd,
>    else
>      ARM_SET_SYM_BRANCH_TYPE (dst->st_target_internal, ST_BRANCH_UNKNOWN);
>  
> +  /* Mark CMSE special symbols.  */
> +  symtab_hdr = & elf_symtab_hdr (abfd);
> +  if (symtab_hdr->sh_size)
> +    name = bfd_elf_sym_name (abfd, symtab_hdr, dst, NULL);
> +  if (name && CONST_STRNEQ (name, CMSE_PREFIX))
> +    ARM_SET_SYM_CMSE_SPCL (dst->st_target_internal);
> +
>    return TRUE;
>  }
>  
> diff --git a/include/elf/arm.h b/include/elf/arm.h
> index 
> bafc03c52ee686671e847eff272ab5cc8a79398c..abad4731b335485f34a06b45d7edea475cfb321b 
> 100644
> --- a/include/elf/arm.h
> +++ b/include/elf/arm.h
> @@ -384,4 +384,11 @@ enum arm_st_branch_type {
>  	   | ((TYPE) & ENUM_ARM_ST_BRANCH_TYPE_BITMASK))
>  #endif
>  
> +/* Get or set whether a symbol is a special symbol of an entry function of 
> CMSE
> +   secure code.  */
> +#define ARM_GET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
> +  (((SYM_TARGET_INTERNAL) >> 2) & 1)
> +#define ARM_SET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
> +  (SYM_TARGET_INTERNAL) |= 4
> +
>  #endif /* _ELF_ARM_H */
> diff --git a/ld/ld.texinfo b/ld/ld.texinfo
> index 
> bc16764b0554851217316c438ada863843915307..171ae6e55bc2bf2708a23e822218b8d4e53f8ee6 
> 100644
> --- a/ld/ld.texinfo
> +++ b/ld/ld.texinfo
> @@ -6853,6 +6853,12 @@ entries which only support 512Mb of code.
>  The @samp{--no-apply-dynamic-relocs} option makes AArch64 linker do not apply
>  link-time values for dynamic relocations.
>  
> +@cindex Placement of SG veneers
> +All SG veneers are placed in the special output section @code{.gnu.sgstubs}.
> +Its start address must be set, either with the command line option
> +@samp{--section-start} or in a linker script, to indicate where to place 
> these
> +veneers in memory.
> +
>  @ifclear GENERIC
>  @lowersections
>  @end ifclear
> diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
> index 
> f34ce5ff2e4c45f01800df116d8f407f2dd75862..3bd8deb5239adbb38d07caaad0c5ba305d8b05e3 
> 100644
> --- a/ld/testsuite/ld-arm/arm-elf.exp
> +++ b/ld/testsuite/ld-arm/arm-elf.exp
> @@ -633,6 +633,33 @@ set armeabitests_nonacl {
>       {{objdump -d jump-reloc-veneers-long.d}}
>       "jump-reloc-veneers-long"}
>  
> +    {"Secure gateway veneers: no .gnu.sgstubs section" "" ""
> +     "-march=armv8-m.base -mthumb"
> +     {cmse-veneers.s}
> +     {{ld cmse-veneers-no-gnu_sgstubs.out}}
> +     "cmse-veneers-no-gnu_sgstubs"}
> +    {"Secure gateway veneers: wrong entry functions" "" ""
> +     "-march=armv7-m -mthumb --defsym CHECK_ERRORS=1"
> +     {cmse-veneers.s}
> +     {{ld cmse-veneers-wrong-entryfct.out}}
> +     "cmse-veneers-wrong-entryfct"}
> +    {"Secure gateway veneers (ARMv8-M Baseline)"
> +     "-Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --gc-sections" ""
> +     "-march=armv8-m.base -mthumb"
> +     {cmse-veneers.s}
> +     {{objdump {-d -j .gnu.sgstubs} cmse-veneers.d}
> +      {objdump {-h -j .gnu.sgstubs} cmse-veneers.sd}
> +      {nm {} cmse-veneers.rd}}
> +     "cmse-veneers-baseline"}
> +    {"Secure gateway veneers (ARMv8-M Mainline)"
> +     "-Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --gc-sections" ""
> +     "-march=armv8-m.main -mthumb"
> +     {cmse-veneers.s}
> +     {{objdump {-d -j .gnu.sgstubs} cmse-veneers.d}
> +      {objdump {-h -j .gnu.sgstubs} cmse-veneers.sd}
> +      {nm {} cmse-veneers.rd}}
> +     "cmse-veneers-mainline"}
> +
>      {"R_ARM_THM_JUMP19 Relocation veneers: Short"
>       "--section-start destsect=0x000108002 --section-start .text=0x8000" ""
>       "-march=armv7-m -mthumb"
> diff --git a/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out 
> b/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out
> new file mode 100644
> index 
> 0000000000000000000000000000000000000000..9d1e5ba3215ae8a29585fcf04ec1f94314670a29
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out
> @@ -0,0 +1,3 @@
> +.*: No address assigned to the veneers output section .gnu.sgstubs
> +.*: cannot size stub section: Invalid operation
> +#...
> diff --git a/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out 
> b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
> new file mode 100644
> index 
> 0000000000000000000000000000000000000000..fd4766ab877a4abbeb8b2c4c053ab11d3f86773c
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
> @@ -0,0 +1,19 @@
> +.*: .*: Special symbol `__acle_se_loc_entry_veneer1' only allowed for ARMv8-M 
> architecture or later.
> +.*: .*: invalid .* symbol `.*loc_entry_veneer1'.
> +.*: It must be a global or weak function symbol.
> +.*: .*: invalid special symbol `__acle_se_loc_entry_veneer2'.
> +.*: It must be a global or weak function symbol.
> +.*: .*: invalid special symbol `__acle_se_loc_entry_veneer4'.
> +.*: It must be a global or weak function symbol.
> +.*: .*: invalid standard symbol `loc_entry_veneer3'.
> +.*: It must be a global or weak function symbol.
> +.*: .*: invalid standard symbol `loc_entry_veneer5'.
> +.*: It must be a global or weak function symbol.
> +.*: .*: absent standard symbol `fake_entry_veneer1'.
> +.*: .*: invalid standard symbol `obj_entry_veneer1'.
> +.*: It must be a global or weak function symbol.
> +.*: .*: invalid special symbol `__acle_se_obj_entry_veneer2'.
> +.*: It must be a global or weak function symbol.
> +.*: .*: `fake_entry_veneer2' and its special symbol are in different sections.
> +.*: cannot size stub section: Invalid operation
> +#...
> diff --git a/ld/testsuite/ld-arm/cmse-veneers.d b/ld/testsuite/ld-arm/cmse-
> veneers.d
> new file mode 100644
> index 
> 0000000000000000000000000000000000000000..6a44a2b5dce9de4f5d64fe644e41f5ab9840806e
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/cmse-veneers.d
> @@ -0,0 +1,21 @@
> +
> +.*
> +
> +
> +Disassembly of section \.gnu.sgstubs:
> +
> +00020000 <glob_entry_veneer2>:
> +   20000:	e97f e97f 	sg
> +   20004:	f7e8 b800 	b\.w	8008 <__acle_se_glob_entry_veneer2>
> +
> +00020008 <weak_entry_veneer2>:
> +   20008:	e97f e97f 	sg
> +   2000c:	f7e7 bffe 	b\.w	800c <__acle_se_weak_entry_veneer2>
> +
> +00020010 <glob_entry_veneer1>:
> +   20010:	e97f e97f 	sg
> +   20014:	f7e7 bff4 	b\.w	8000 <__acle_se_glob_entry_veneer1>
> +
> +00020018 <weak_entry_veneer1>:
> +   20018:	e97f e97f 	sg
> +   2001c:	f7e7 bff2 	b\.w	8004 <__acle_se_weak_entry_veneer1>
> diff --git a/ld/testsuite/ld-arm/cmse-veneers.rd b/ld/testsuite/ld-arm/cmse-
> veneers.rd
> new file mode 100644
> index 
> 0000000000000000000000000000000000000000..20fad961bd8803109c3cf57ef22e3b36da5b1500
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/cmse-veneers.rd
> @@ -0,0 +1,9 @@
> +#...
> +[0-9a-f]+ T glob_entry_fct
> +#...
> +[0-9a-f]+ T glob_entry_veneer1
> +[0-9a-f]+ T glob_entry_veneer2
> +#...
> +[0-9a-f]+ W weak_entry_veneer1
> +[0-9a-f]+ W weak_entry_veneer2
> +#...
> diff --git a/ld/testsuite/ld-arm/cmse-veneers.s b/ld/testsuite/ld-arm/cmse-
> veneers.s
> new file mode 100644
> index 
> 0000000000000000000000000000000000000000..3f68135a2038f2f95a5595e257db0785db4e3997
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/cmse-veneers.s
> @@ -0,0 +1,98 @@
> +	.syntax unified
> +	.thumb
> +	.file	"foo.c"
> +	.section .text.entryfcts, "ax", %progbits
> +	.text
> +
> +.macro	decltype	name, type
> +.ifc \type,object
> +	.data
> +.else
> +	.thumb
> +	.thumb_func
> +.endif
> +	.type	\name, %\type
> +.endm
> +
> +
> +.macro	entry	name, type, vis, typespc, visspc, entry_fct
> +	.align	2
> +.ifb \visspc
> +	.\vis	__acle_se_\name
> +.else
> +	.\visspc	__acle_se_\name
> +.endif
> +	.\vis	\name
> +	.thumb
> +	.thumb_func
> +.ifb \typespc
> +	decltype	__acle_se_\name, \type
> +.else
> +	decltype	__acle_se_\name, \typespc
> +.endif
> +	decltype	\name, \type
> +__acle_se_\name:
> +	\entry_fct
> +\name:
> +.ifc \type,object
> +	.word 42
> +.else
> +	nop
> +.endif
> +	.size	\name, .-\name
> +	.size	__acle_se_\name, .-__acle_se_\name
> +.endm
> +
> +
> +.ifndef CHECK_ERRORS
> +	@ Valid setups for veneer generation
> +	entry glob_entry_veneer1, function, global
> +	entry weak_entry_veneer1, function, weak
> +	entry glob_entry_veneer2, function, global, visspc=weak
> +	entry weak_entry_veneer2, function, weak, visspc=global
> +
> +	@ Valid setup for entry function without SG veneer
> +	entry glob_entry_fct, function, global, entry_fct=nop
> +
> +.else
> +	@ Invalid setups for veneer generation (visibility)
> +	entry loc_entry_veneer1, function, local
> +	entry loc_entry_veneer2, function, global, visspc=local
> +	entry loc_entry_veneer3, function, local, visspc=global
> +	entry loc_entry_veneer4, function, weak, visspc=local
> +	entry loc_entry_veneer5, function, local, visspc=weak
> +
> +	@ Invalid setups for veneer generation (absent standard symbol)
> +	.align	2
> +	.global	__acle_se_fake_entry_veneer1
> +	.thumb
> +	.thumb_func
> +	.type	__acle_se_fake_entry_veneer1, %function
> +__acle_se_fake_entry_veneer1:
> +	nop
> +	.size	__acle_se_fake_entry_veneer1, .-__acle_se_fake_entry_veneer1
> +
> +	@ Invalid setups for veneer generation (type)
> +	entry obj_entry_veneer1, object, global, typespc=function
> +	entry obj_entry_veneer2, function, global, typespc=object
> +
> +	@ Invalid setup for veneer generation (sections)
> +	.section .text.sub1
> +	.align	2
> +	.thumb
> +	.thumb_func
> +	.global	__acle_se_fake_entry_veneer2
> +	.type	__acle_se_fake_entry_veneer2, %function
> +__acle_se_fake_entry_veneer2:
> +	nop
> +	.size	__acle_se_fake_entry_veneer2, .-__acle_se_fake_entry_veneer2
> +	.section .text.sub2
> +	.align	2
> +	.thumb
> +	.thumb_func
> +	.global	fake_entry_veneer2
> +	.type	fake_entry_veneer2, %function
> +fake_entry_veneer2:
> +	nop
> +	.size	fake_entry_veneer2, .-fake_entry_veneer2
> +.endif
> diff --git a/ld/testsuite/ld-arm/cmse-veneers.sd b/ld/testsuite/ld-arm/cmse-
> veneers.sd
> new file mode 100644
> index 
> 0000000000000000000000000000000000000000..99bfc8f37c25b7a57122b330b1145e27a9b087fd
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/cmse-veneers.sd
> @@ -0,0 +1,7 @@
> +
> +.*
> +
> +Sections:
> +Idx Name          Size      VMA       LMA       File off  Algn
> +  \d+ \.gnu\.sgstubs  00000020  00020000  00020000  00010000  2\*\*5
> +                  CONTENTS, ALLOC, LOAD, READONLY, CODE
> 
> 
> Best regards,
> 
> Thomas
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH, binutils, ARM 8/11] Add support for ARMv8-M Secure Gateway veneer generation
  2016-07-07 10:53     ` Richard Earnshaw (lists)
@ 2016-07-07 15:27       ` Thomas Preudhomme
  2016-07-14  9:15         ` [RFC PATCH, binutils, ARM 8/11, ping] " Thomas Preudhomme
  0 siblings, 1 reply; 10+ messages in thread
From: Thomas Preudhomme @ 2016-07-07 15:27 UTC (permalink / raw)
  To: Richard Earnshaw (lists); +Cc: binutils

[-- Attachment #1: Type: text/plain, Size: 6262 bytes --]

Hi Richard,

On Thursday 07 July 2016 11:52:56 Richard Earnshaw wrote:
> +   As per "ARMv8-M Security Extensions: Requirements on Development Tools"
> +   document, a secure gateway veneer is needed when there exists a
> non-local
> +   function symbol called "normal" symbol (eg. foo) with the same value
> as a
> +   symbol with the same type, binding a name save for a __acle_se_ prefix,
> +   called a "special" symbol (eg. __acle_se_foo).  Entry functions handling
> +   with secure state transition by themselves have these symbols with
> different
> +   values.
> 
> 
> This is very unclear as to what is being/needs to be done.  Can you try
> redrafting it?

What do you think of the attached updated patch?

By the way, I realized I did not copy over the explanation for the changes to 
elf32_arm_get_plt_info from the original patch submission. I'm adding the full 
cover letter again here to have all the information in one email in the 
archive.



This patch is part of a patch series to add support for ARMv8-M security 
extension[1] to GNU ld. This specific patch adds support for creating ARMv8-M 
Secure Gateway veneers.

ARM v8-M security extensions require [3] secure gateway veneers to be 
generated for (secure) entry function in order for code to transition from 
non-secure state to secure state when calling these entry function. Unlike 
other veneers, these veneers are generated independently of relocations, ie a 
veneer can be generated in the absence of relocation. The condition for the 
generation is that the normal symbol (the one whose name is the same as in C) 
of an entry function has the same value as the special symbol (normal symbol 
prefixed with "__acle_se_"). When that happens, the normal symbol is rebound to 
the veneer generated. When the two symbols have different value it indicates 
that the entry function already contains an sg instruction to do the secure 
state transition and the normal symbol points to the sg instruction while the 
special symbol points after that.

This patch also makes use of the infrastructure laid out in previous patches 
to control the address of these veneers and to avoid the presence of the bit 
pattern of the SG instruction in non secure callable memory, as required [4]
[5].

Finally, the patch also contains a small change to elf32_arm_get_plt_info () 
to return FALSE when there is no PLT, ensuring that a NULL splt is not 
dereferenced in the block starting with "If the call goes through" in 
elf32_arm_final_relocate (). This was not necessary before because root_plt-
>offset is set to -1 in elf32_arm_adjust_dynamic_symbol called by 
_bfd_elf_adjust_dynamic_symbol from bfd_elf_size_dynamic_sections when dynobj 
is not NULL. However, dynobj is set in elf32_arm_check_relocs which is not 
called when there is no relocation in the input section. Such a situation is 
possible while still invoking elf32_arm_final_relocate () due to SG veneers 
being created in the absence of relocation but needing themselves relocation.

[1] Software requirements for ARMv8-M security extension are described in 
document ARM-ECM-0359818 [2]
[2] Available on http://infocenter.arm.com in Developer guides and articles > 
Software development > ARM®v8-M Security Extensions: Requirements on 
Development Tools
[3] See section 3.4.3 and requirement 44 of ARM-ECM-0359818 [2]
[4] requirement 14 and following comment of ARM-ECM-0359818 [2]
[5] requirement 12 and 13 and following comment of ARM-ECM-0359818 [2]


ChangeLog entries remain unchanged:

*** bfd/ChangeLog ***

2016-05-04  Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * elf32-arm.c (CMSE_PREFIX): Define macro.
        (elf32_arm_stub_cmse_branch_thumb_only): Define stub sequence.
        (cmse_branch_thumb_only): Declare stub.
        (struct elf32_arm_link_hash_table): Define cmse_stub_sec field.
        (elf32_arm_get_plt_info): Add globals parameter.  Use it to return
        FALSE if there is no PLT.
        (arm_type_of_stub): Adapt to new elf32_arm_get_plt_info signature.
        (elf32_arm_final_link_relocate): Likewise.
        (elf32_arm_gc_sweep_hook): Likewise.
        (elf32_arm_gc_mark_extra_sections): Mark sections holding ARMv8-M
        secure entry functions.
        (arm_stub_is_thumb): Add case for arm_stub_cmse_branch_thumb_only.
        (arm_dedicated_stub_output_section_required): Change to a switch case
        and add a case for arm_stub_cmse_branch_thumb_only.
        (arm_dedicated_stub_output_section_required_alignment): Likewise.
        (arm_stub_dedicated_output_section_name): Likewise.
        (arm_stub_dedicated_input_section_ptr): Likewise and remove
        ATTRIBUTE_UNUSED for htab parameter.
        (arm_stub_required_alignment): Likewise.
        (arm_stub_sym_claimed): Likewise.
        (arm_dedicated_stub_section_padding): Likewise.
        (cmse_scan): New function.
        (elf32_arm_size_stubs): Call cmse_scan for ARM M profile targets.
        Set stub_changed to TRUE if such veneers were created.
        (elf32_arm_swap_symbol_in): Add detection code for CMSE special
        symbols.


*** include/elf/ChangeLog ***

2015-12-16  Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * arm.h (ARM_GET_SYM_CMSE_SPCL): Define macro.
        (ARM_SET_SYM_CMSE_SPCL): Likewise.


*** ld/ChangeLog ***

2016-02-17  Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * ld.texinfo (Placement of SG veneers): New concept entry.
        * testsuite/ld-arm/arm-elf.exp
        (Secure gateway veneers: no .gnu.sgstubs section): New test.
        (Secure gateway veneers: wrong entry functions): Likewise.
        (Secure gateway veneers (ARMv8-M Baseline)): Likewise.
        (Secure gateway veneers (ARMv8-M Mainline)): Likewise.
        * testsuite/ld-arm/cmse-veneers.s: New file.
        * testsuite/ld-arm/cmse-veneers.d: Likewise.
        * testsuite/ld-arm/cmse-veneers.rd: Likewise.
        * testsuite/ld-arm/cmse-veneers.sd: Likewise.
        * testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out: Likewise.
        * testsuite/ld-arm/cmse-veneers-wrong-entryfct.out: Likewise.


Best regards,

Thomas

[-- Attachment #2: sg_veneers_support.patch --]
[-- Type: text/x-patch, Size: 28720 bytes --]

diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 8de01b46671cd2ac1cbd94ef4373db439a62a9c4..b5da179d266845c6bf2aa1c9359507a2c1f0e1d1 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -2138,6 +2138,8 @@ typedef unsigned short int insn16;
 
 #define STUB_ENTRY_NAME   "__%s_veneer"
 
+#define CMSE_PREFIX "__acle_se_"
+
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
 #define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
@@ -2543,6 +2545,13 @@ static const insn_sequence elf32_arm_stub_long_branch_arm_nacl_pic[] =
   DATA_WORD (0, R_ARM_NONE, 0),         /* .word 0 */
 };
 
+/* Stub used for transition to secure state (aka SG veneer).  */
+static const insn_sequence elf32_arm_stub_cmse_branch_thumb_only[] =
+{
+  THUMB32_INSN (0xe97fe97f),		/* sg.  */
+  THUMB32_B_INSN (0xf000b800, -4),	/* b.w original_branch_dest.  */
+};
+
 
 /* Cortex-A8 erratum-workaround stubs.  */
 
@@ -2622,6 +2631,7 @@ static const insn_sequence elf32_arm_stub_a8_veneer_blx[] =
   DEF_STUB(long_branch_v4t_thumb_tls_pic) \
   DEF_STUB(long_branch_arm_nacl) \
   DEF_STUB(long_branch_arm_nacl_pic) \
+  DEF_STUB(cmse_branch_thumb_only) \
   DEF_STUB(a8_veneer_b_cond) \
   DEF_STUB(a8_veneer_b) \
   DEF_STUB(a8_veneer_bl) \
@@ -3172,6 +3182,9 @@ struct elf32_arm_link_hash_table
      information on stub grouping.  */
   struct map_stub *stub_group;
 
+  /* Input stub section holding secure gateway veneers.  */
+  asection *cmse_stub_sec;
+
   /* Number of elements in stub_group.  */
   unsigned int top_id;
 
@@ -3320,12 +3333,16 @@ elf32_arm_create_local_iplt (bfd *abfd, unsigned long r_symndx)
    union and *ARM_PLT at the ARM-specific information.  */
 
 static bfd_boolean
-elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_entry *h,
+elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_table *globals,
+			struct elf32_arm_link_hash_entry *h,
 			unsigned long r_symndx, union gotplt_union **root_plt,
 			struct arm_plt_info **arm_plt)
 {
   struct arm_local_iplt_info *local_iplt;
 
+  if (globals->root.splt == NULL && globals->root.iplt == NULL)
+    return FALSE;
+
   if (h != NULL)
     {
       *root_plt = &h->root.plt;
@@ -3786,6 +3803,7 @@ arm_stub_is_thumb (enum elf32_arm_stub_type stub_type)
     case arm_stub_long_branch_v4t_thumb_arm_pic:
     case arm_stub_long_branch_v4t_thumb_tls_pic:
     case arm_stub_long_branch_thumb_only_pic:
+    case arm_stub_cmse_branch_thumb_only:
       return TRUE;
     case arm_stub_none:
       BFD_FAIL ();
@@ -3851,8 +3869,9 @@ arm_type_of_stub (struct bfd_link_info *info,
      the address of the appropriate trampoline.  */
   if (r_type != R_ARM_TLS_CALL
       && r_type != R_ARM_THM_TLS_CALL
-      && elf32_arm_get_plt_info (input_bfd, hash, ELF32_R_SYM (rel->r_info),
-				 &root_plt, &arm_plt)
+      && elf32_arm_get_plt_info (input_bfd, globals, hash,
+				 ELF32_R_SYM (rel->r_info), &root_plt,
+				 &arm_plt)
       && root_plt->offset != (bfd_vma) -1)
     {
       asection *splt;
@@ -4163,7 +4182,16 @@ arm_dedicated_stub_output_section_required (enum elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  return FALSE;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Required alignment (as a power of 2) for the dedicated section holding
@@ -4177,8 +4205,19 @@ arm_dedicated_stub_output_section_required_alignment
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
-  return 0;
+  switch (stub_type)
+    {
+    /* Vectors of Secure Gateway veneers must be aligned on 32byte
+       boundary.  */
+    case arm_stub_cmse_branch_thumb_only:
+      return 5;
+
+    default:
+      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
+      return 0;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Name of the dedicated output section to put veneers of type STUB_TYPE, or
@@ -4190,8 +4229,17 @@ arm_dedicated_stub_output_section_name (enum elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
-  return NULL;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return ".gnu.sgstubs";
+
+    default:
+      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
+      return NULL;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* If veneers of type STUB_TYPE should go in a dedicated output section,
@@ -4199,15 +4247,23 @@ arm_dedicated_stub_output_section_name (enum elf32_arm_stub_type stub_type)
    corresponding input section.  Otherwise, returns NULL.  */
 
 static asection **
-arm_dedicated_stub_input_section_ptr
-  (struct elf32_arm_link_hash_table *htab ATTRIBUTE_UNUSED,
-   enum elf32_arm_stub_type stub_type)
+arm_dedicated_stub_input_section_ptr (struct elf32_arm_link_hash_table *htab,
+				      enum elf32_arm_stub_type stub_type)
 {
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
-  return NULL;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return &htab->cmse_stub_sec;
+
+    default:
+      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
+      return NULL;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Find or create a stub section to contain a stub of type STUB_TYPE.  SECTION
@@ -4429,6 +4485,7 @@ arm_stub_required_alignment (enum elf32_arm_stub_type stub_type)
     case arm_stub_long_branch_thumb_only_pic:
     case arm_stub_long_branch_any_tls_pic:
     case arm_stub_long_branch_v4t_thumb_tls_pic:
+    case arm_stub_cmse_branch_thumb_only:
     case arm_stub_a8_veneer_blx:
       return 4;
 
@@ -4450,7 +4507,16 @@ arm_stub_sym_claimed (enum elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  return FALSE;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Returns the padding needed for the dedicated section used stubs of type
@@ -4462,7 +4528,16 @@ arm_dedicated_stub_section_padding (enum elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  return 0;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return 32;
+
+    default:
+      return 0;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 static bfd_boolean
@@ -5353,6 +5428,204 @@ elf32_arm_create_stub (struct elf32_arm_link_hash_table *htab,
   return TRUE;
 }
 
+/* Scan symbols in INPUT_BFD to identify secure entry functions needing a
+   gateway veneer to transition from non secure to secure state and create them
+   accordingly.
+
+   "ARMv8-M Security Extensions: Requirements on Development Tools" document
+   defines the conditions that govern Secure Gateway veneer creation for a
+   given symbol <SYM> as follows:
+   - it has function type
+   - it has non local binding
+   - a symbol named __acle_se_<SYM> (called special symbol) exists with the
+     same type, binding and value as <SYM> (called normal symbol).
+   An entry function can handle secure state transition itself in which case
+   its special symbol would have a different value from the normal symbol.
+
+   OUT_ATTR gives the output attributes, SYM_HASHES the symbol index to hash
+   entry mapping while HTAB gives the name to hash entry mapping.
+
+   If any secure gateway veneer is created, *STUB_CHANGED is set to TRUE.  The
+   return value gives whether a stub failed to be allocated.  */
+
+static bfd_boolean
+cmse_scan (bfd *input_bfd, struct elf32_arm_link_hash_table *htab,
+	   obj_attribute *out_attr, struct elf_link_hash_entry **sym_hashes,
+	   bfd_boolean *stub_changed)
+{
+  const struct elf_backend_data *bed;
+  Elf_Internal_Shdr *symtab_hdr;
+  unsigned i, j, sym_count, ext_start;
+  Elf_Internal_Sym *cmse_sym, *local_syms;
+  struct elf32_arm_link_hash_entry *hash, *cmse_hash = NULL;
+  enum arm_st_branch_type branch_type;
+  char *sym_name, *lsym_name;
+  bfd_vma sym_value;
+  asection *section;
+  bfd_boolean is_v8m, new_stub, created_stub, cmse_invalid, ret = TRUE;
+
+  bed = get_elf_backend_data (input_bfd);
+  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym;
+  ext_start = symtab_hdr->sh_info;
+  is_v8m = (out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE
+	    && out_attr[Tag_CPU_arch_profile].i == 'M');
+
+  local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+  if (local_syms == NULL)
+    local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
+				       symtab_hdr->sh_info, 0, NULL, NULL,
+				       NULL);
+  if (symtab_hdr->sh_info && local_syms == NULL)
+    return FALSE;
+
+  /* Scan symbols.  */
+  for (i = 0; i < sym_count; i++)
+    {
+      cmse_invalid = FALSE;
+
+      if (i < ext_start)
+	{
+	  cmse_sym = &local_syms[i];
+	  /* Not a special symbol.  */
+	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_sym->st_target_internal))
+	    continue;
+	  sym_name = bfd_elf_string_from_elf_section (input_bfd,
+						      symtab_hdr->sh_link,
+						      cmse_sym->st_name);
+	  /* Special symbol with local binding.  */
+	  cmse_invalid = TRUE;
+	}
+      else
+	{
+	  cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]);
+	  sym_name = (char *) cmse_hash->root.root.root.string;
+
+	  /* Not a special symbol.  */
+	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal))
+	    continue;
+
+	  /* Special symbol has incorrect binding or type.  */
+	  if ((cmse_hash->root.root.type != bfd_link_hash_defined
+	       && cmse_hash->root.root.type != bfd_link_hash_defweak)
+	      || cmse_hash->root.type != STT_FUNC)
+	    cmse_invalid = TRUE;
+	}
+
+      if (!is_v8m)
+	{
+	  (*_bfd_error_handler) (_("%B: Special symbol `%s' only allowed for "
+				   "ARMv8-M architecture or later."),
+				 input_bfd, sym_name);
+	  is_v8m = TRUE; /* Avoid multiple warning.  */
+	  ret = FALSE;
+	}
+
+      if (cmse_invalid)
+	{
+	  (*_bfd_error_handler) (_("%B: invalid special symbol `%s'."),
+				 input_bfd, sym_name);
+	  (*_bfd_error_handler) (_("It must be a global or weak function "
+				   "symbol."));
+	  ret = FALSE;
+	  if (i < ext_start)
+	    continue;
+	}
+
+      sym_name += strlen (CMSE_PREFIX);
+      hash = (struct elf32_arm_link_hash_entry *)
+	elf_link_hash_lookup (&(htab)->root, sym_name, FALSE, FALSE, TRUE);
+
+      /* No associated normal symbol or it is neither global nor weak.  */
+      if (!hash
+	  || (hash->root.root.type != bfd_link_hash_defined
+	      && hash->root.root.type != bfd_link_hash_defweak)
+	  || hash->root.type != STT_FUNC)
+	{
+	  /* Initialize here to avoid warning about use of possibly
+	     uninitialized variable.  */
+	  j = 0;
+
+	  if (!hash)
+	    {
+	      /* Searching for a normal symbol with local binding.  */
+	      for (; j < ext_start; j++)
+		{
+		  lsym_name =
+		    bfd_elf_string_from_elf_section (input_bfd,
+						     symtab_hdr->sh_link,
+						     local_syms[j].st_name);
+		  if (!strcmp (sym_name, lsym_name))
+		    break;
+		}
+	    }
+
+	  if (hash || j < ext_start)
+	    {
+	      (*_bfd_error_handler)
+		(_("%B: invalid standard symbol `%s'."), input_bfd, sym_name);
+	      (*_bfd_error_handler)
+		(_("It must be a global or weak function symbol."));
+	    }
+	  else
+	    (*_bfd_error_handler)
+	      (_("%B: absent standard symbol `%s'."), input_bfd, sym_name);
+	  ret = FALSE;
+	  if (!hash)
+	    continue;
+	}
+
+      sym_value = hash->root.root.u.def.value;
+      section = hash->root.root.u.def.section;
+
+      if (cmse_hash->root.root.u.def.section != section)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: `%s' and its special symbol are in different sections."),
+	     input_bfd, sym_name);
+	  ret = FALSE;
+	}
+      if (cmse_hash->root.root.u.def.value != sym_value)
+	continue; /* Ignore: could be an entry function starting with SG.  */
+
+	/* If this section is a link-once section that will be discarded, then
+	   don't create any stubs.  */
+      if (section->output_section == NULL)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: entry function `%s' not output."), input_bfd, sym_name);
+	  continue;
+	}
+
+      if (hash->root.size == 0)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: entry function `%s' is empty."), input_bfd, sym_name);
+	  ret = FALSE;
+	}
+
+      if (!ret)
+	continue;
+      branch_type = ARM_GET_SYM_BRANCH_TYPE (hash->root.target_internal);
+      created_stub
+	= elf32_arm_create_stub (htab, arm_stub_cmse_branch_thumb_only,
+				 NULL, NULL, section, hash, sym_name,
+				 sym_value, branch_type, &new_stub);
+
+      if (!created_stub)
+	 ret = FALSE;
+      else
+	{
+	  BFD_ASSERT (new_stub);
+	  *stub_changed = TRUE;
+	}
+    }
+
+  if (!symtab_hdr->contents)
+    free (local_syms);
+  return ret;
+}
+
 /* Determine and set the size of the stub section for a final link.
 
    The basic idea here is to examine all the relocations looking for
@@ -5369,8 +5642,9 @@ elf32_arm_size_stubs (bfd *output_bfd,
 						      unsigned int),
 		      void (*layout_sections_again) (void))
 {
+  obj_attribute *out_attr;
   bfd_size_type stub_group_size;
-  bfd_boolean stubs_always_after_branch;
+  bfd_boolean m_profile, stubs_always_after_branch, first_veneer_scan = TRUE;
   struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
   struct a8_erratum_fix *a8_fixes = NULL;
   unsigned int num_a8_fixes = 0, a8_fix_table_size = 10;
@@ -5399,6 +5673,8 @@ elf32_arm_size_stubs (bfd *output_bfd,
   htab->layout_sections_again = layout_sections_again;
   stubs_always_after_branch = group_size < 0;
 
+  out_attr = elf_known_obj_attributes_proc (output_bfd);
+  m_profile = out_attr[Tag_CPU_arch_profile].i == 'M';
   /* The Cortex-A8 erratum fix depends on stubs not being in the same 4K page
      as the first half of a 32-bit branch straddling two 4K pages.  This is a
      crude way of enforcing that.  */
@@ -5464,6 +5740,18 @@ elf32_arm_size_stubs (bfd *output_bfd,
 	  if (symtab_hdr->sh_info == 0)
 	    continue;
 
+	  /* Limit scan of symbols to object file whose profile is
+	     Microcontroller to not hinder performance in the general case.  */
+	  if (m_profile && first_veneer_scan)
+	    {
+	      struct elf_link_hash_entry **sym_hashes;
+
+	      sym_hashes = elf_sym_hashes (input_bfd);
+	      if (!cmse_scan (input_bfd, htab, out_attr, sym_hashes,
+			      &stub_changed))
+		goto error_ret_free_local;
+	    }
+
 	  /* Walk over each section attached to the input bfd.  */
 	  for (section = input_bfd->sections;
 	       section != NULL;
@@ -5850,6 +6138,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
 
       /* Ask the linker to do its stuff.  */
       (*htab->layout_sections_again) ();
+      first_veneer_scan = FALSE;
     }
 
   /* Add stubs for Cortex-A8 erratum fixes now.  */
@@ -9191,7 +9480,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
   /* Find out whether the symbol has a PLT.  Set ST_VALUE, BRANCH_TYPE and
      VALUE appropriately for relocations that we resolve at link time.  */
   has_iplt_entry = FALSE;
-  if (elf32_arm_get_plt_info (input_bfd, eh, r_symndx, &root_plt, &arm_plt)
+  if (elf32_arm_get_plt_info (input_bfd, globals, eh, r_symndx, &root_plt,
+			      &arm_plt)
       && root_plt->offset != (bfd_vma) -1)
     {
       plt_offset = root_plt->offset;
@@ -13603,7 +13893,8 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
 	}
 
       if (may_need_local_target_p
-	  && elf32_arm_get_plt_info (abfd, eh, r_symndx, &root_plt, &arm_plt))
+	  && elf32_arm_get_plt_info (abfd, globals, eh, r_symndx, &root_plt,
+				     &arm_plt))
 	{
 	  /* If PLT refcount book-keeping is wrong and too low, we'll
 	     see a zero value (going to -1) for the root PLT reference
@@ -14071,7 +14362,11 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
 }
 
 /* Unwinding tables are not referenced directly.  This pass marks them as
-   required if the corresponding code section is marked.  */
+   required if the corresponding code section is marked.  Similarly, ARMv8-M
+   secure entry functions can only be referenced by SG veneers which are
+   created after the GC process. They need to be marked in case they reside in
+   their own section (as would be the case if code was compiled with
+   -ffunction-sections).  */
 
 static bfd_boolean
 elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
@@ -14079,10 +14374,21 @@ elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
 {
   bfd *sub;
   Elf_Internal_Shdr **elf_shdrp;
-  bfd_boolean again;
+  asection *cmse_sec;
+  obj_attribute *out_attr;
+  Elf_Internal_Shdr *symtab_hdr;
+  unsigned i, sym_count, ext_start;
+  const struct elf_backend_data *bed;
+  struct elf_link_hash_entry **sym_hashes;
+  struct elf32_arm_link_hash_entry *cmse_hash;
+  bfd_boolean again, is_v8m, first_bfd_browse = TRUE;
 
   _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
 
+  out_attr = elf_known_obj_attributes_proc (info->output_bfd);
+  is_v8m = out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE
+	   && out_attr[Tag_CPU_arch_profile].i == 'M';
+
   /* Marking EH data may cause additional code sections to be marked,
      requiring multiple passes.  */
   again = TRUE;
@@ -14113,7 +14419,34 @@ elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
 		    return FALSE;
 		}
 	    }
+
+	  /* Mark section holding ARMv8-M secure entry functions.  We mark all
+	     of them so no need for a second browsing.  */
+	  if (is_v8m && first_bfd_browse)
+	    {
+	      sym_hashes = elf_sym_hashes (sub);
+	      bed = get_elf_backend_data (sub);
+	      symtab_hdr = &elf_tdata (sub)->symtab_hdr;
+	      sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym;
+	      ext_start = symtab_hdr->sh_info;
+
+	      /* Scan symbols.  */
+	      for (i = ext_start; i < sym_count; i++)
+		{
+		  cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]);
+
+		  /* Assume it is a special symbol.  If not, cmse_scan will
+		     warn about it and user can do something about it.  */
+		  if (ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal))
+		    {
+		      cmse_sec = cmse_hash->root.root.u.def.section;
+		      if (!_bfd_elf_gc_mark (info, cmse_sec, gc_mark_hook))
+			return FALSE;
+		    }
+		}
+	    }
 	}
+      first_bfd_browse = FALSE;
     }
 
   return TRUE;
@@ -17765,6 +18098,9 @@ elf32_arm_swap_symbol_in (bfd * abfd,
 			  const void *pshn,
 			  Elf_Internal_Sym *dst)
 {
+  Elf_Internal_Shdr *symtab_hdr;
+  const char *name = NULL;
+
   if (!bfd_elf32_swap_symbol_in (abfd, psrc, pshn, dst))
     return FALSE;
   dst->st_target_internal = 0;
@@ -17793,6 +18129,13 @@ elf32_arm_swap_symbol_in (bfd * abfd,
   else
     ARM_SET_SYM_BRANCH_TYPE (dst->st_target_internal, ST_BRANCH_UNKNOWN);
 
+  /* Mark CMSE special symbols.  */
+  symtab_hdr = & elf_symtab_hdr (abfd);
+  if (symtab_hdr->sh_size)
+    name = bfd_elf_sym_name (abfd, symtab_hdr, dst, NULL);
+  if (name && CONST_STRNEQ (name, CMSE_PREFIX))
+    ARM_SET_SYM_CMSE_SPCL (dst->st_target_internal);
+
   return TRUE;
 }
 
diff --git a/include/elf/arm.h b/include/elf/arm.h
index bafc03c52ee686671e847eff272ab5cc8a79398c..abad4731b335485f34a06b45d7edea475cfb321b 100644
--- a/include/elf/arm.h
+++ b/include/elf/arm.h
@@ -384,4 +384,11 @@ enum arm_st_branch_type {
 	   | ((TYPE) & ENUM_ARM_ST_BRANCH_TYPE_BITMASK))
 #endif
 
+/* Get or set whether a symbol is a special symbol of an entry function of CMSE
+   secure code.  */
+#define ARM_GET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
+  (((SYM_TARGET_INTERNAL) >> 2) & 1)
+#define ARM_SET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
+  (SYM_TARGET_INTERNAL) |= 4
+
 #endif /* _ELF_ARM_H */
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index bc16764b0554851217316c438ada863843915307..171ae6e55bc2bf2708a23e822218b8d4e53f8ee6 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -6853,6 +6853,12 @@ entries which only support 512Mb of code.
 The @samp{--no-apply-dynamic-relocs} option makes AArch64 linker do not apply
 link-time values for dynamic relocations.
 
+@cindex Placement of SG veneers
+All SG veneers are placed in the special output section @code{.gnu.sgstubs}.
+Its start address must be set, either with the command line option
+@samp{--section-start} or in a linker script, to indicate where to place these
+veneers in memory.
+
 @ifclear GENERIC
 @lowersections
 @end ifclear
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index db25a8d46c985f89e02ce68c8897923c23101661..84301626fb6ab24a6726315e810249b4375b5fdc 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -633,6 +633,33 @@ set armeabitests_nonacl {
      {{objdump -d jump-reloc-veneers-long.d}}
      "jump-reloc-veneers-long"}
 
+    {"Secure gateway veneers: no .gnu.sgstubs section" "" ""
+     "-march=armv8-m.base -mthumb"
+     {cmse-veneers.s}
+     {{ld cmse-veneers-no-gnu_sgstubs.out}}
+     "cmse-veneers-no-gnu_sgstubs"}
+    {"Secure gateway veneers: wrong entry functions" "" ""
+     "-march=armv7-m -mthumb --defsym CHECK_ERRORS=1"
+     {cmse-veneers.s}
+     {{ld cmse-veneers-wrong-entryfct.out}}
+     "cmse-veneers-wrong-entryfct"}
+    {"Secure gateway veneers (ARMv8-M Baseline)"
+     "-Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --gc-sections" ""
+     "-march=armv8-m.base -mthumb"
+     {cmse-veneers.s}
+     {{objdump {-d -j .gnu.sgstubs} cmse-veneers.d}
+      {objdump {-h -j .gnu.sgstubs} cmse-veneers.sd}
+      {nm {} cmse-veneers.rd}}
+     "cmse-veneers-baseline"}
+    {"Secure gateway veneers (ARMv8-M Mainline)"
+     "-Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --gc-sections" ""
+     "-march=armv8-m.main -mthumb"
+     {cmse-veneers.s}
+     {{objdump {-d -j .gnu.sgstubs} cmse-veneers.d}
+      {objdump {-h -j .gnu.sgstubs} cmse-veneers.sd}
+      {nm {} cmse-veneers.rd}}
+     "cmse-veneers-mainline"}
+
     {"R_ARM_THM_JUMP19 Relocation veneers: Short"
      "--section-start destsect=0x000108002 --section-start .text=0x8000" ""
      "-march=armv7-m -mthumb"
diff --git a/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out b/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out
new file mode 100644
index 0000000000000000000000000000000000000000..9d1e5ba3215ae8a29585fcf04ec1f94314670a29
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out
@@ -0,0 +1,3 @@
+.*: No address assigned to the veneers output section .gnu.sgstubs
+.*: cannot size stub section: Invalid operation
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
new file mode 100644
index 0000000000000000000000000000000000000000..fd4766ab877a4abbeb8b2c4c053ab11d3f86773c
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
@@ -0,0 +1,19 @@
+.*: .*: Special symbol `__acle_se_loc_entry_veneer1' only allowed for ARMv8-M architecture or later.
+.*: .*: invalid .* symbol `.*loc_entry_veneer1'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_loc_entry_veneer2'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_loc_entry_veneer4'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid standard symbol `loc_entry_veneer3'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid standard symbol `loc_entry_veneer5'.
+.*: It must be a global or weak function symbol.
+.*: .*: absent standard symbol `fake_entry_veneer1'.
+.*: .*: invalid standard symbol `obj_entry_veneer1'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_obj_entry_veneer2'.
+.*: It must be a global or weak function symbol.
+.*: .*: `fake_entry_veneer2' and its special symbol are in different sections.
+.*: cannot size stub section: Invalid operation
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers.d b/ld/testsuite/ld-arm/cmse-veneers.d
new file mode 100644
index 0000000000000000000000000000000000000000..6a44a2b5dce9de4f5d64fe644e41f5ab9840806e
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.d
@@ -0,0 +1,21 @@
+
+.*
+
+
+Disassembly of section \.gnu.sgstubs:
+
+00020000 <glob_entry_veneer2>:
+   20000:	e97f e97f 	sg
+   20004:	f7e8 b800 	b\.w	8008 <__acle_se_glob_entry_veneer2>
+
+00020008 <weak_entry_veneer2>:
+   20008:	e97f e97f 	sg
+   2000c:	f7e7 bffe 	b\.w	800c <__acle_se_weak_entry_veneer2>
+
+00020010 <glob_entry_veneer1>:
+   20010:	e97f e97f 	sg
+   20014:	f7e7 bff4 	b\.w	8000 <__acle_se_glob_entry_veneer1>
+
+00020018 <weak_entry_veneer1>:
+   20018:	e97f e97f 	sg
+   2001c:	f7e7 bff2 	b\.w	8004 <__acle_se_weak_entry_veneer1>
diff --git a/ld/testsuite/ld-arm/cmse-veneers.rd b/ld/testsuite/ld-arm/cmse-veneers.rd
new file mode 100644
index 0000000000000000000000000000000000000000..20fad961bd8803109c3cf57ef22e3b36da5b1500
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.rd
@@ -0,0 +1,9 @@
+#...
+[0-9a-f]+ T glob_entry_fct
+#...
+[0-9a-f]+ T glob_entry_veneer1
+[0-9a-f]+ T glob_entry_veneer2
+#...
+[0-9a-f]+ W weak_entry_veneer1
+[0-9a-f]+ W weak_entry_veneer2
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers.s b/ld/testsuite/ld-arm/cmse-veneers.s
new file mode 100644
index 0000000000000000000000000000000000000000..d5c57f646a78c4736e4f084d8ad6aff7efea554f
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.s
@@ -0,0 +1,97 @@
+	.syntax unified
+	.thumb
+	.file	"foo.c"
+	.text
+
+.macro	decltype	name, type
+.ifc \type,object
+	.data
+.else
+	.thumb
+	.thumb_func
+.endif
+	.type	\name, %\type
+.endm
+
+
+.macro	entry	name, type, vis, typespc, visspc, entry_fct
+	.align	2
+.ifb \visspc
+	.\vis	__acle_se_\name
+.else
+	.\visspc	__acle_se_\name
+.endif
+	.\vis	\name
+	.thumb
+	.thumb_func
+.ifb \typespc
+	decltype	__acle_se_\name, \type
+.else
+	decltype	__acle_se_\name, \typespc
+.endif
+	decltype	\name, \type
+__acle_se_\name:
+	\entry_fct
+\name:
+.ifc \type,object
+	.word 42
+.else
+	nop
+.endif
+	.size	\name, .-\name
+	.size	__acle_se_\name, .-__acle_se_\name
+.endm
+
+
+.ifndef CHECK_ERRORS
+	@ Valid setups for veneer generation
+	entry glob_entry_veneer1, function, global
+	entry weak_entry_veneer1, function, weak
+	entry glob_entry_veneer2, function, global, visspc=weak
+	entry weak_entry_veneer2, function, weak, visspc=global
+
+	@ Valid setup for entry function without SG veneer
+	entry glob_entry_fct, function, global, entry_fct=nop
+
+.else
+	@ Invalid setups for veneer generation (visibility)
+	entry loc_entry_veneer1, function, local
+	entry loc_entry_veneer2, function, global, visspc=local
+	entry loc_entry_veneer3, function, local, visspc=global
+	entry loc_entry_veneer4, function, weak, visspc=local
+	entry loc_entry_veneer5, function, local, visspc=weak
+
+	@ Invalid setups for veneer generation (absent standard symbol)
+	.align	2
+	.global	__acle_se_fake_entry_veneer1
+	.thumb
+	.thumb_func
+	.type	__acle_se_fake_entry_veneer1, %function
+__acle_se_fake_entry_veneer1:
+	nop
+	.size	__acle_se_fake_entry_veneer1, .-__acle_se_fake_entry_veneer1
+
+	@ Invalid setups for veneer generation (type)
+	entry obj_entry_veneer1, object, global, typespc=function
+	entry obj_entry_veneer2, function, global, typespc=object
+
+	@ Invalid setup for veneer generation (sections)
+	.section .text.sub1
+	.align	2
+	.thumb
+	.thumb_func
+	.global	__acle_se_fake_entry_veneer2
+	.type	__acle_se_fake_entry_veneer2, %function
+__acle_se_fake_entry_veneer2:
+	nop
+	.size	__acle_se_fake_entry_veneer2, .-__acle_se_fake_entry_veneer2
+	.section .text.sub2
+	.align	2
+	.thumb
+	.thumb_func
+	.global	fake_entry_veneer2
+	.type	fake_entry_veneer2, %function
+fake_entry_veneer2:
+	nop
+	.size	fake_entry_veneer2, .-fake_entry_veneer2
+.endif
diff --git a/ld/testsuite/ld-arm/cmse-veneers.sd b/ld/testsuite/ld-arm/cmse-veneers.sd
new file mode 100644
index 0000000000000000000000000000000000000000..99bfc8f37c25b7a57122b330b1145e27a9b087fd
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.sd
@@ -0,0 +1,7 @@
+
+.*
+
+Sections:
+Idx Name          Size      VMA       LMA       File off  Algn
+  \d+ \.gnu\.sgstubs  00000020  00020000  00020000  00010000  2\*\*5
+                  CONTENTS, ALLOC, LOAD, READONLY, CODE

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH, binutils, ARM 8/11, ping] Add support for ARMv8-M Secure Gateway veneer generation
  2016-07-07 15:27       ` Thomas Preudhomme
@ 2016-07-14  9:15         ` Thomas Preudhomme
  2016-07-26 11:07           ` [RFC PATCH, binutils, ARM 8/11, ping2] " Thomas Preudhomme
  0 siblings, 1 reply; 10+ messages in thread
From: Thomas Preudhomme @ 2016-07-14  9:15 UTC (permalink / raw)
  To: Richard Earnshaw (lists); +Cc: binutils

[-- Attachment #1: Type: text/plain, Size: 6584 bytes --]

Hi Richard,

On Thursday 07 July 2016 16:27:27 Thomas Preudhomme wrote:
> 
> On Thursday 07 July 2016 11:52:56 Richard Earnshaw wrote:
> > +   As per "ARMv8-M Security Extensions: Requirements on Development
> > Tools"
> > +   document, a secure gateway veneer is needed when there exists a
> > non-local
> > +   function symbol called "normal" symbol (eg. foo) with the same value
> > as a
> > +   symbol with the same type, binding a name save for a __acle_se_
> > prefix,
> > +   called a "special" symbol (eg. __acle_se_foo).  Entry functions
> > handling +   with secure state transition by themselves have these
> > symbols with different
> > +   values.
> > 
> > 
> > This is very unclear as to what is being/needs to be done.  Can you try
> > redrafting it?
> 
> What do you think of the attached updated patch?

Ping?

> 
> By the way, I realized I did not copy over the explanation for the changes
> to elf32_arm_get_plt_info from the original patch submission. I'm adding
> the full cover letter again here to have all the information in one email
> in the archive.
> 
> 
> 
> This patch is part of a patch series to add support for ARMv8-M security
> extension[1] to GNU ld. This specific patch adds support for creating
> ARMv8-M Secure Gateway veneers.
> 
> ARM v8-M security extensions require [3] secure gateway veneers to be
> generated for (secure) entry function in order for code to transition from
> non-secure state to secure state when calling these entry function. Unlike
> other veneers, these veneers are generated independently of relocations, ie
> a veneer can be generated in the absence of relocation. The condition for
> the generation is that the normal symbol (the one whose name is the same as
> in C) of an entry function has the same value as the special symbol (normal
> symbol prefixed with "__acle_se_"). When that happens, the normal symbol is
> rebound to the veneer generated. When the two symbols have different value
> it indicates that the entry function already contains an sg instruction to
> do the secure state transition and the normal symbol points to the sg
> instruction while the special symbol points after that.
> 
> This patch also makes use of the infrastructure laid out in previous patches
> to control the address of these veneers and to avoid the presence of the
> bit pattern of the SG instruction in non secure callable memory, as
> required [4] [5].
> 
> Finally, the patch also contains a small change to elf32_arm_get_plt_info ()
> to return FALSE when there is no PLT, ensuring that a NULL splt is not
> dereferenced in the block starting with "If the call goes through" in
> elf32_arm_final_relocate (). This was not necessary before because
> root_plt-
> >offset is set to -1 in elf32_arm_adjust_dynamic_symbol called by
> 
> _bfd_elf_adjust_dynamic_symbol from bfd_elf_size_dynamic_sections when
> dynobj is not NULL. However, dynobj is set in elf32_arm_check_relocs which
> is not called when there is no relocation in the input section. Such a
> situation is possible while still invoking elf32_arm_final_relocate () due
> to SG veneers being created in the absence of relocation but needing
> themselves relocation.
> 
> [1] Software requirements for ARMv8-M security extension are described in
> document ARM-ECM-0359818 [2]
> [2] Available on http://infocenter.arm.com in Developer guides and articles
> > Software development > ARM®v8-M Security Extensions: Requirements on
> Development Tools
> [3] See section 3.4.3 and requirement 44 of ARM-ECM-0359818 [2]
> [4] requirement 14 and following comment of ARM-ECM-0359818 [2]
> [5] requirement 12 and 13 and following comment of ARM-ECM-0359818 [2]
> 
> 
> ChangeLog entries remain unchanged:
> 
> *** bfd/ChangeLog ***
> 
> 2016-05-04  Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * elf32-arm.c (CMSE_PREFIX): Define macro.
>         (elf32_arm_stub_cmse_branch_thumb_only): Define stub sequence.
>         (cmse_branch_thumb_only): Declare stub.
>         (struct elf32_arm_link_hash_table): Define cmse_stub_sec field.
>         (elf32_arm_get_plt_info): Add globals parameter.  Use it to return
>         FALSE if there is no PLT.
>         (arm_type_of_stub): Adapt to new elf32_arm_get_plt_info signature.
>         (elf32_arm_final_link_relocate): Likewise.
>         (elf32_arm_gc_sweep_hook): Likewise.
>         (elf32_arm_gc_mark_extra_sections): Mark sections holding ARMv8-M
>         secure entry functions.
>         (arm_stub_is_thumb): Add case for arm_stub_cmse_branch_thumb_only.
>         (arm_dedicated_stub_output_section_required): Change to a switch
> case and add a case for arm_stub_cmse_branch_thumb_only.
>         (arm_dedicated_stub_output_section_required_alignment): Likewise.
>         (arm_stub_dedicated_output_section_name): Likewise.
>         (arm_stub_dedicated_input_section_ptr): Likewise and remove
>         ATTRIBUTE_UNUSED for htab parameter.
>         (arm_stub_required_alignment): Likewise.
>         (arm_stub_sym_claimed): Likewise.
>         (arm_dedicated_stub_section_padding): Likewise.
>         (cmse_scan): New function.
>         (elf32_arm_size_stubs): Call cmse_scan for ARM M profile targets.
>         Set stub_changed to TRUE if such veneers were created.
>         (elf32_arm_swap_symbol_in): Add detection code for CMSE special
>         symbols.
> 
> 
> *** include/elf/ChangeLog ***
> 
> 2015-12-16  Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * arm.h (ARM_GET_SYM_CMSE_SPCL): Define macro.
>         (ARM_SET_SYM_CMSE_SPCL): Likewise.
> 
> 
> *** ld/ChangeLog ***
> 
> 2016-02-17  Thomas Preud'homme  <thomas.preudhomme@arm.com>
> 
>         * ld.texinfo (Placement of SG veneers): New concept entry.
>         * testsuite/ld-arm/arm-elf.exp
>         (Secure gateway veneers: no .gnu.sgstubs section): New test.
>         (Secure gateway veneers: wrong entry functions): Likewise.
>         (Secure gateway veneers (ARMv8-M Baseline)): Likewise.
>         (Secure gateway veneers (ARMv8-M Mainline)): Likewise.
>         * testsuite/ld-arm/cmse-veneers.s: New file.
>         * testsuite/ld-arm/cmse-veneers.d: Likewise.
>         * testsuite/ld-arm/cmse-veneers.rd: Likewise.
>         * testsuite/ld-arm/cmse-veneers.sd: Likewise.
>         * testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out: Likewise.
>         * testsuite/ld-arm/cmse-veneers-wrong-entryfct.out: Likewise.
> 
> 
> Best regards,
> 
> Thomas

[-- Attachment #2: sg_veneers_support.patch --]
[-- Type: text/x-patch, Size: 28720 bytes --]

diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 8de01b46671cd2ac1cbd94ef4373db439a62a9c4..b5da179d266845c6bf2aa1c9359507a2c1f0e1d1 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -2138,6 +2138,8 @@ typedef unsigned short int insn16;
 
 #define STUB_ENTRY_NAME   "__%s_veneer"
 
+#define CMSE_PREFIX "__acle_se_"
+
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
 #define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
@@ -2543,6 +2545,13 @@ static const insn_sequence elf32_arm_stub_long_branch_arm_nacl_pic[] =
   DATA_WORD (0, R_ARM_NONE, 0),         /* .word 0 */
 };
 
+/* Stub used for transition to secure state (aka SG veneer).  */
+static const insn_sequence elf32_arm_stub_cmse_branch_thumb_only[] =
+{
+  THUMB32_INSN (0xe97fe97f),		/* sg.  */
+  THUMB32_B_INSN (0xf000b800, -4),	/* b.w original_branch_dest.  */
+};
+
 
 /* Cortex-A8 erratum-workaround stubs.  */
 
@@ -2622,6 +2631,7 @@ static const insn_sequence elf32_arm_stub_a8_veneer_blx[] =
   DEF_STUB(long_branch_v4t_thumb_tls_pic) \
   DEF_STUB(long_branch_arm_nacl) \
   DEF_STUB(long_branch_arm_nacl_pic) \
+  DEF_STUB(cmse_branch_thumb_only) \
   DEF_STUB(a8_veneer_b_cond) \
   DEF_STUB(a8_veneer_b) \
   DEF_STUB(a8_veneer_bl) \
@@ -3172,6 +3182,9 @@ struct elf32_arm_link_hash_table
      information on stub grouping.  */
   struct map_stub *stub_group;
 
+  /* Input stub section holding secure gateway veneers.  */
+  asection *cmse_stub_sec;
+
   /* Number of elements in stub_group.  */
   unsigned int top_id;
 
@@ -3320,12 +3333,16 @@ elf32_arm_create_local_iplt (bfd *abfd, unsigned long r_symndx)
    union and *ARM_PLT at the ARM-specific information.  */
 
 static bfd_boolean
-elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_entry *h,
+elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_table *globals,
+			struct elf32_arm_link_hash_entry *h,
 			unsigned long r_symndx, union gotplt_union **root_plt,
 			struct arm_plt_info **arm_plt)
 {
   struct arm_local_iplt_info *local_iplt;
 
+  if (globals->root.splt == NULL && globals->root.iplt == NULL)
+    return FALSE;
+
   if (h != NULL)
     {
       *root_plt = &h->root.plt;
@@ -3786,6 +3803,7 @@ arm_stub_is_thumb (enum elf32_arm_stub_type stub_type)
     case arm_stub_long_branch_v4t_thumb_arm_pic:
     case arm_stub_long_branch_v4t_thumb_tls_pic:
     case arm_stub_long_branch_thumb_only_pic:
+    case arm_stub_cmse_branch_thumb_only:
       return TRUE;
     case arm_stub_none:
       BFD_FAIL ();
@@ -3851,8 +3869,9 @@ arm_type_of_stub (struct bfd_link_info *info,
      the address of the appropriate trampoline.  */
   if (r_type != R_ARM_TLS_CALL
       && r_type != R_ARM_THM_TLS_CALL
-      && elf32_arm_get_plt_info (input_bfd, hash, ELF32_R_SYM (rel->r_info),
-				 &root_plt, &arm_plt)
+      && elf32_arm_get_plt_info (input_bfd, globals, hash,
+				 ELF32_R_SYM (rel->r_info), &root_plt,
+				 &arm_plt)
       && root_plt->offset != (bfd_vma) -1)
     {
       asection *splt;
@@ -4163,7 +4182,16 @@ arm_dedicated_stub_output_section_required (enum elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  return FALSE;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Required alignment (as a power of 2) for the dedicated section holding
@@ -4177,8 +4205,19 @@ arm_dedicated_stub_output_section_required_alignment
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
-  return 0;
+  switch (stub_type)
+    {
+    /* Vectors of Secure Gateway veneers must be aligned on 32byte
+       boundary.  */
+    case arm_stub_cmse_branch_thumb_only:
+      return 5;
+
+    default:
+      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
+      return 0;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Name of the dedicated output section to put veneers of type STUB_TYPE, or
@@ -4190,8 +4229,17 @@ arm_dedicated_stub_output_section_name (enum elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
-  return NULL;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return ".gnu.sgstubs";
+
+    default:
+      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
+      return NULL;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* If veneers of type STUB_TYPE should go in a dedicated output section,
@@ -4199,15 +4247,23 @@ arm_dedicated_stub_output_section_name (enum elf32_arm_stub_type stub_type)
    corresponding input section.  Otherwise, returns NULL.  */
 
 static asection **
-arm_dedicated_stub_input_section_ptr
-  (struct elf32_arm_link_hash_table *htab ATTRIBUTE_UNUSED,
-   enum elf32_arm_stub_type stub_type)
+arm_dedicated_stub_input_section_ptr (struct elf32_arm_link_hash_table *htab,
+				      enum elf32_arm_stub_type stub_type)
 {
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
-  return NULL;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return &htab->cmse_stub_sec;
+
+    default:
+      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
+      return NULL;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Find or create a stub section to contain a stub of type STUB_TYPE.  SECTION
@@ -4429,6 +4485,7 @@ arm_stub_required_alignment (enum elf32_arm_stub_type stub_type)
     case arm_stub_long_branch_thumb_only_pic:
     case arm_stub_long_branch_any_tls_pic:
     case arm_stub_long_branch_v4t_thumb_tls_pic:
+    case arm_stub_cmse_branch_thumb_only:
     case arm_stub_a8_veneer_blx:
       return 4;
 
@@ -4450,7 +4507,16 @@ arm_stub_sym_claimed (enum elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  return FALSE;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Returns the padding needed for the dedicated section used stubs of type
@@ -4462,7 +4528,16 @@ arm_dedicated_stub_section_padding (enum elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  return 0;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return 32;
+
+    default:
+      return 0;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 static bfd_boolean
@@ -5353,6 +5428,204 @@ elf32_arm_create_stub (struct elf32_arm_link_hash_table *htab,
   return TRUE;
 }
 
+/* Scan symbols in INPUT_BFD to identify secure entry functions needing a
+   gateway veneer to transition from non secure to secure state and create them
+   accordingly.
+
+   "ARMv8-M Security Extensions: Requirements on Development Tools" document
+   defines the conditions that govern Secure Gateway veneer creation for a
+   given symbol <SYM> as follows:
+   - it has function type
+   - it has non local binding
+   - a symbol named __acle_se_<SYM> (called special symbol) exists with the
+     same type, binding and value as <SYM> (called normal symbol).
+   An entry function can handle secure state transition itself in which case
+   its special symbol would have a different value from the normal symbol.
+
+   OUT_ATTR gives the output attributes, SYM_HASHES the symbol index to hash
+   entry mapping while HTAB gives the name to hash entry mapping.
+
+   If any secure gateway veneer is created, *STUB_CHANGED is set to TRUE.  The
+   return value gives whether a stub failed to be allocated.  */
+
+static bfd_boolean
+cmse_scan (bfd *input_bfd, struct elf32_arm_link_hash_table *htab,
+	   obj_attribute *out_attr, struct elf_link_hash_entry **sym_hashes,
+	   bfd_boolean *stub_changed)
+{
+  const struct elf_backend_data *bed;
+  Elf_Internal_Shdr *symtab_hdr;
+  unsigned i, j, sym_count, ext_start;
+  Elf_Internal_Sym *cmse_sym, *local_syms;
+  struct elf32_arm_link_hash_entry *hash, *cmse_hash = NULL;
+  enum arm_st_branch_type branch_type;
+  char *sym_name, *lsym_name;
+  bfd_vma sym_value;
+  asection *section;
+  bfd_boolean is_v8m, new_stub, created_stub, cmse_invalid, ret = TRUE;
+
+  bed = get_elf_backend_data (input_bfd);
+  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym;
+  ext_start = symtab_hdr->sh_info;
+  is_v8m = (out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE
+	    && out_attr[Tag_CPU_arch_profile].i == 'M');
+
+  local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+  if (local_syms == NULL)
+    local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
+				       symtab_hdr->sh_info, 0, NULL, NULL,
+				       NULL);
+  if (symtab_hdr->sh_info && local_syms == NULL)
+    return FALSE;
+
+  /* Scan symbols.  */
+  for (i = 0; i < sym_count; i++)
+    {
+      cmse_invalid = FALSE;
+
+      if (i < ext_start)
+	{
+	  cmse_sym = &local_syms[i];
+	  /* Not a special symbol.  */
+	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_sym->st_target_internal))
+	    continue;
+	  sym_name = bfd_elf_string_from_elf_section (input_bfd,
+						      symtab_hdr->sh_link,
+						      cmse_sym->st_name);
+	  /* Special symbol with local binding.  */
+	  cmse_invalid = TRUE;
+	}
+      else
+	{
+	  cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]);
+	  sym_name = (char *) cmse_hash->root.root.root.string;
+
+	  /* Not a special symbol.  */
+	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal))
+	    continue;
+
+	  /* Special symbol has incorrect binding or type.  */
+	  if ((cmse_hash->root.root.type != bfd_link_hash_defined
+	       && cmse_hash->root.root.type != bfd_link_hash_defweak)
+	      || cmse_hash->root.type != STT_FUNC)
+	    cmse_invalid = TRUE;
+	}
+
+      if (!is_v8m)
+	{
+	  (*_bfd_error_handler) (_("%B: Special symbol `%s' only allowed for "
+				   "ARMv8-M architecture or later."),
+				 input_bfd, sym_name);
+	  is_v8m = TRUE; /* Avoid multiple warning.  */
+	  ret = FALSE;
+	}
+
+      if (cmse_invalid)
+	{
+	  (*_bfd_error_handler) (_("%B: invalid special symbol `%s'."),
+				 input_bfd, sym_name);
+	  (*_bfd_error_handler) (_("It must be a global or weak function "
+				   "symbol."));
+	  ret = FALSE;
+	  if (i < ext_start)
+	    continue;
+	}
+
+      sym_name += strlen (CMSE_PREFIX);
+      hash = (struct elf32_arm_link_hash_entry *)
+	elf_link_hash_lookup (&(htab)->root, sym_name, FALSE, FALSE, TRUE);
+
+      /* No associated normal symbol or it is neither global nor weak.  */
+      if (!hash
+	  || (hash->root.root.type != bfd_link_hash_defined
+	      && hash->root.root.type != bfd_link_hash_defweak)
+	  || hash->root.type != STT_FUNC)
+	{
+	  /* Initialize here to avoid warning about use of possibly
+	     uninitialized variable.  */
+	  j = 0;
+
+	  if (!hash)
+	    {
+	      /* Searching for a normal symbol with local binding.  */
+	      for (; j < ext_start; j++)
+		{
+		  lsym_name =
+		    bfd_elf_string_from_elf_section (input_bfd,
+						     symtab_hdr->sh_link,
+						     local_syms[j].st_name);
+		  if (!strcmp (sym_name, lsym_name))
+		    break;
+		}
+	    }
+
+	  if (hash || j < ext_start)
+	    {
+	      (*_bfd_error_handler)
+		(_("%B: invalid standard symbol `%s'."), input_bfd, sym_name);
+	      (*_bfd_error_handler)
+		(_("It must be a global or weak function symbol."));
+	    }
+	  else
+	    (*_bfd_error_handler)
+	      (_("%B: absent standard symbol `%s'."), input_bfd, sym_name);
+	  ret = FALSE;
+	  if (!hash)
+	    continue;
+	}
+
+      sym_value = hash->root.root.u.def.value;
+      section = hash->root.root.u.def.section;
+
+      if (cmse_hash->root.root.u.def.section != section)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: `%s' and its special symbol are in different sections."),
+	     input_bfd, sym_name);
+	  ret = FALSE;
+	}
+      if (cmse_hash->root.root.u.def.value != sym_value)
+	continue; /* Ignore: could be an entry function starting with SG.  */
+
+	/* If this section is a link-once section that will be discarded, then
+	   don't create any stubs.  */
+      if (section->output_section == NULL)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: entry function `%s' not output."), input_bfd, sym_name);
+	  continue;
+	}
+
+      if (hash->root.size == 0)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: entry function `%s' is empty."), input_bfd, sym_name);
+	  ret = FALSE;
+	}
+
+      if (!ret)
+	continue;
+      branch_type = ARM_GET_SYM_BRANCH_TYPE (hash->root.target_internal);
+      created_stub
+	= elf32_arm_create_stub (htab, arm_stub_cmse_branch_thumb_only,
+				 NULL, NULL, section, hash, sym_name,
+				 sym_value, branch_type, &new_stub);
+
+      if (!created_stub)
+	 ret = FALSE;
+      else
+	{
+	  BFD_ASSERT (new_stub);
+	  *stub_changed = TRUE;
+	}
+    }
+
+  if (!symtab_hdr->contents)
+    free (local_syms);
+  return ret;
+}
+
 /* Determine and set the size of the stub section for a final link.
 
    The basic idea here is to examine all the relocations looking for
@@ -5369,8 +5642,9 @@ elf32_arm_size_stubs (bfd *output_bfd,
 						      unsigned int),
 		      void (*layout_sections_again) (void))
 {
+  obj_attribute *out_attr;
   bfd_size_type stub_group_size;
-  bfd_boolean stubs_always_after_branch;
+  bfd_boolean m_profile, stubs_always_after_branch, first_veneer_scan = TRUE;
   struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
   struct a8_erratum_fix *a8_fixes = NULL;
   unsigned int num_a8_fixes = 0, a8_fix_table_size = 10;
@@ -5399,6 +5673,8 @@ elf32_arm_size_stubs (bfd *output_bfd,
   htab->layout_sections_again = layout_sections_again;
   stubs_always_after_branch = group_size < 0;
 
+  out_attr = elf_known_obj_attributes_proc (output_bfd);
+  m_profile = out_attr[Tag_CPU_arch_profile].i == 'M';
   /* The Cortex-A8 erratum fix depends on stubs not being in the same 4K page
      as the first half of a 32-bit branch straddling two 4K pages.  This is a
      crude way of enforcing that.  */
@@ -5464,6 +5740,18 @@ elf32_arm_size_stubs (bfd *output_bfd,
 	  if (symtab_hdr->sh_info == 0)
 	    continue;
 
+	  /* Limit scan of symbols to object file whose profile is
+	     Microcontroller to not hinder performance in the general case.  */
+	  if (m_profile && first_veneer_scan)
+	    {
+	      struct elf_link_hash_entry **sym_hashes;
+
+	      sym_hashes = elf_sym_hashes (input_bfd);
+	      if (!cmse_scan (input_bfd, htab, out_attr, sym_hashes,
+			      &stub_changed))
+		goto error_ret_free_local;
+	    }
+
 	  /* Walk over each section attached to the input bfd.  */
 	  for (section = input_bfd->sections;
 	       section != NULL;
@@ -5850,6 +6138,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
 
       /* Ask the linker to do its stuff.  */
       (*htab->layout_sections_again) ();
+      first_veneer_scan = FALSE;
     }
 
   /* Add stubs for Cortex-A8 erratum fixes now.  */
@@ -9191,7 +9480,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
   /* Find out whether the symbol has a PLT.  Set ST_VALUE, BRANCH_TYPE and
      VALUE appropriately for relocations that we resolve at link time.  */
   has_iplt_entry = FALSE;
-  if (elf32_arm_get_plt_info (input_bfd, eh, r_symndx, &root_plt, &arm_plt)
+  if (elf32_arm_get_plt_info (input_bfd, globals, eh, r_symndx, &root_plt,
+			      &arm_plt)
       && root_plt->offset != (bfd_vma) -1)
     {
       plt_offset = root_plt->offset;
@@ -13603,7 +13893,8 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
 	}
 
       if (may_need_local_target_p
-	  && elf32_arm_get_plt_info (abfd, eh, r_symndx, &root_plt, &arm_plt))
+	  && elf32_arm_get_plt_info (abfd, globals, eh, r_symndx, &root_plt,
+				     &arm_plt))
 	{
 	  /* If PLT refcount book-keeping is wrong and too low, we'll
 	     see a zero value (going to -1) for the root PLT reference
@@ -14071,7 +14362,11 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
 }
 
 /* Unwinding tables are not referenced directly.  This pass marks them as
-   required if the corresponding code section is marked.  */
+   required if the corresponding code section is marked.  Similarly, ARMv8-M
+   secure entry functions can only be referenced by SG veneers which are
+   created after the GC process. They need to be marked in case they reside in
+   their own section (as would be the case if code was compiled with
+   -ffunction-sections).  */
 
 static bfd_boolean
 elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
@@ -14079,10 +14374,21 @@ elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
 {
   bfd *sub;
   Elf_Internal_Shdr **elf_shdrp;
-  bfd_boolean again;
+  asection *cmse_sec;
+  obj_attribute *out_attr;
+  Elf_Internal_Shdr *symtab_hdr;
+  unsigned i, sym_count, ext_start;
+  const struct elf_backend_data *bed;
+  struct elf_link_hash_entry **sym_hashes;
+  struct elf32_arm_link_hash_entry *cmse_hash;
+  bfd_boolean again, is_v8m, first_bfd_browse = TRUE;
 
   _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
 
+  out_attr = elf_known_obj_attributes_proc (info->output_bfd);
+  is_v8m = out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE
+	   && out_attr[Tag_CPU_arch_profile].i == 'M';
+
   /* Marking EH data may cause additional code sections to be marked,
      requiring multiple passes.  */
   again = TRUE;
@@ -14113,7 +14419,34 @@ elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
 		    return FALSE;
 		}
 	    }
+
+	  /* Mark section holding ARMv8-M secure entry functions.  We mark all
+	     of them so no need for a second browsing.  */
+	  if (is_v8m && first_bfd_browse)
+	    {
+	      sym_hashes = elf_sym_hashes (sub);
+	      bed = get_elf_backend_data (sub);
+	      symtab_hdr = &elf_tdata (sub)->symtab_hdr;
+	      sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym;
+	      ext_start = symtab_hdr->sh_info;
+
+	      /* Scan symbols.  */
+	      for (i = ext_start; i < sym_count; i++)
+		{
+		  cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]);
+
+		  /* Assume it is a special symbol.  If not, cmse_scan will
+		     warn about it and user can do something about it.  */
+		  if (ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal))
+		    {
+		      cmse_sec = cmse_hash->root.root.u.def.section;
+		      if (!_bfd_elf_gc_mark (info, cmse_sec, gc_mark_hook))
+			return FALSE;
+		    }
+		}
+	    }
 	}
+      first_bfd_browse = FALSE;
     }
 
   return TRUE;
@@ -17765,6 +18098,9 @@ elf32_arm_swap_symbol_in (bfd * abfd,
 			  const void *pshn,
 			  Elf_Internal_Sym *dst)
 {
+  Elf_Internal_Shdr *symtab_hdr;
+  const char *name = NULL;
+
   if (!bfd_elf32_swap_symbol_in (abfd, psrc, pshn, dst))
     return FALSE;
   dst->st_target_internal = 0;
@@ -17793,6 +18129,13 @@ elf32_arm_swap_symbol_in (bfd * abfd,
   else
     ARM_SET_SYM_BRANCH_TYPE (dst->st_target_internal, ST_BRANCH_UNKNOWN);
 
+  /* Mark CMSE special symbols.  */
+  symtab_hdr = & elf_symtab_hdr (abfd);
+  if (symtab_hdr->sh_size)
+    name = bfd_elf_sym_name (abfd, symtab_hdr, dst, NULL);
+  if (name && CONST_STRNEQ (name, CMSE_PREFIX))
+    ARM_SET_SYM_CMSE_SPCL (dst->st_target_internal);
+
   return TRUE;
 }
 
diff --git a/include/elf/arm.h b/include/elf/arm.h
index bafc03c52ee686671e847eff272ab5cc8a79398c..abad4731b335485f34a06b45d7edea475cfb321b 100644
--- a/include/elf/arm.h
+++ b/include/elf/arm.h
@@ -384,4 +384,11 @@ enum arm_st_branch_type {
 	   | ((TYPE) & ENUM_ARM_ST_BRANCH_TYPE_BITMASK))
 #endif
 
+/* Get or set whether a symbol is a special symbol of an entry function of CMSE
+   secure code.  */
+#define ARM_GET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
+  (((SYM_TARGET_INTERNAL) >> 2) & 1)
+#define ARM_SET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
+  (SYM_TARGET_INTERNAL) |= 4
+
 #endif /* _ELF_ARM_H */
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index bc16764b0554851217316c438ada863843915307..171ae6e55bc2bf2708a23e822218b8d4e53f8ee6 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -6853,6 +6853,12 @@ entries which only support 512Mb of code.
 The @samp{--no-apply-dynamic-relocs} option makes AArch64 linker do not apply
 link-time values for dynamic relocations.
 
+@cindex Placement of SG veneers
+All SG veneers are placed in the special output section @code{.gnu.sgstubs}.
+Its start address must be set, either with the command line option
+@samp{--section-start} or in a linker script, to indicate where to place these
+veneers in memory.
+
 @ifclear GENERIC
 @lowersections
 @end ifclear
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index db25a8d46c985f89e02ce68c8897923c23101661..84301626fb6ab24a6726315e810249b4375b5fdc 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -633,6 +633,33 @@ set armeabitests_nonacl {
      {{objdump -d jump-reloc-veneers-long.d}}
      "jump-reloc-veneers-long"}
 
+    {"Secure gateway veneers: no .gnu.sgstubs section" "" ""
+     "-march=armv8-m.base -mthumb"
+     {cmse-veneers.s}
+     {{ld cmse-veneers-no-gnu_sgstubs.out}}
+     "cmse-veneers-no-gnu_sgstubs"}
+    {"Secure gateway veneers: wrong entry functions" "" ""
+     "-march=armv7-m -mthumb --defsym CHECK_ERRORS=1"
+     {cmse-veneers.s}
+     {{ld cmse-veneers-wrong-entryfct.out}}
+     "cmse-veneers-wrong-entryfct"}
+    {"Secure gateway veneers (ARMv8-M Baseline)"
+     "-Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --gc-sections" ""
+     "-march=armv8-m.base -mthumb"
+     {cmse-veneers.s}
+     {{objdump {-d -j .gnu.sgstubs} cmse-veneers.d}
+      {objdump {-h -j .gnu.sgstubs} cmse-veneers.sd}
+      {nm {} cmse-veneers.rd}}
+     "cmse-veneers-baseline"}
+    {"Secure gateway veneers (ARMv8-M Mainline)"
+     "-Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --gc-sections" ""
+     "-march=armv8-m.main -mthumb"
+     {cmse-veneers.s}
+     {{objdump {-d -j .gnu.sgstubs} cmse-veneers.d}
+      {objdump {-h -j .gnu.sgstubs} cmse-veneers.sd}
+      {nm {} cmse-veneers.rd}}
+     "cmse-veneers-mainline"}
+
     {"R_ARM_THM_JUMP19 Relocation veneers: Short"
      "--section-start destsect=0x000108002 --section-start .text=0x8000" ""
      "-march=armv7-m -mthumb"
diff --git a/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out b/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out
new file mode 100644
index 0000000000000000000000000000000000000000..9d1e5ba3215ae8a29585fcf04ec1f94314670a29
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out
@@ -0,0 +1,3 @@
+.*: No address assigned to the veneers output section .gnu.sgstubs
+.*: cannot size stub section: Invalid operation
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
new file mode 100644
index 0000000000000000000000000000000000000000..fd4766ab877a4abbeb8b2c4c053ab11d3f86773c
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
@@ -0,0 +1,19 @@
+.*: .*: Special symbol `__acle_se_loc_entry_veneer1' only allowed for ARMv8-M architecture or later.
+.*: .*: invalid .* symbol `.*loc_entry_veneer1'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_loc_entry_veneer2'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_loc_entry_veneer4'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid standard symbol `loc_entry_veneer3'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid standard symbol `loc_entry_veneer5'.
+.*: It must be a global or weak function symbol.
+.*: .*: absent standard symbol `fake_entry_veneer1'.
+.*: .*: invalid standard symbol `obj_entry_veneer1'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_obj_entry_veneer2'.
+.*: It must be a global or weak function symbol.
+.*: .*: `fake_entry_veneer2' and its special symbol are in different sections.
+.*: cannot size stub section: Invalid operation
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers.d b/ld/testsuite/ld-arm/cmse-veneers.d
new file mode 100644
index 0000000000000000000000000000000000000000..6a44a2b5dce9de4f5d64fe644e41f5ab9840806e
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.d
@@ -0,0 +1,21 @@
+
+.*
+
+
+Disassembly of section \.gnu.sgstubs:
+
+00020000 <glob_entry_veneer2>:
+   20000:	e97f e97f 	sg
+   20004:	f7e8 b800 	b\.w	8008 <__acle_se_glob_entry_veneer2>
+
+00020008 <weak_entry_veneer2>:
+   20008:	e97f e97f 	sg
+   2000c:	f7e7 bffe 	b\.w	800c <__acle_se_weak_entry_veneer2>
+
+00020010 <glob_entry_veneer1>:
+   20010:	e97f e97f 	sg
+   20014:	f7e7 bff4 	b\.w	8000 <__acle_se_glob_entry_veneer1>
+
+00020018 <weak_entry_veneer1>:
+   20018:	e97f e97f 	sg
+   2001c:	f7e7 bff2 	b\.w	8004 <__acle_se_weak_entry_veneer1>
diff --git a/ld/testsuite/ld-arm/cmse-veneers.rd b/ld/testsuite/ld-arm/cmse-veneers.rd
new file mode 100644
index 0000000000000000000000000000000000000000..20fad961bd8803109c3cf57ef22e3b36da5b1500
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.rd
@@ -0,0 +1,9 @@
+#...
+[0-9a-f]+ T glob_entry_fct
+#...
+[0-9a-f]+ T glob_entry_veneer1
+[0-9a-f]+ T glob_entry_veneer2
+#...
+[0-9a-f]+ W weak_entry_veneer1
+[0-9a-f]+ W weak_entry_veneer2
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers.s b/ld/testsuite/ld-arm/cmse-veneers.s
new file mode 100644
index 0000000000000000000000000000000000000000..d5c57f646a78c4736e4f084d8ad6aff7efea554f
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.s
@@ -0,0 +1,97 @@
+	.syntax unified
+	.thumb
+	.file	"foo.c"
+	.text
+
+.macro	decltype	name, type
+.ifc \type,object
+	.data
+.else
+	.thumb
+	.thumb_func
+.endif
+	.type	\name, %\type
+.endm
+
+
+.macro	entry	name, type, vis, typespc, visspc, entry_fct
+	.align	2
+.ifb \visspc
+	.\vis	__acle_se_\name
+.else
+	.\visspc	__acle_se_\name
+.endif
+	.\vis	\name
+	.thumb
+	.thumb_func
+.ifb \typespc
+	decltype	__acle_se_\name, \type
+.else
+	decltype	__acle_se_\name, \typespc
+.endif
+	decltype	\name, \type
+__acle_se_\name:
+	\entry_fct
+\name:
+.ifc \type,object
+	.word 42
+.else
+	nop
+.endif
+	.size	\name, .-\name
+	.size	__acle_se_\name, .-__acle_se_\name
+.endm
+
+
+.ifndef CHECK_ERRORS
+	@ Valid setups for veneer generation
+	entry glob_entry_veneer1, function, global
+	entry weak_entry_veneer1, function, weak
+	entry glob_entry_veneer2, function, global, visspc=weak
+	entry weak_entry_veneer2, function, weak, visspc=global
+
+	@ Valid setup for entry function without SG veneer
+	entry glob_entry_fct, function, global, entry_fct=nop
+
+.else
+	@ Invalid setups for veneer generation (visibility)
+	entry loc_entry_veneer1, function, local
+	entry loc_entry_veneer2, function, global, visspc=local
+	entry loc_entry_veneer3, function, local, visspc=global
+	entry loc_entry_veneer4, function, weak, visspc=local
+	entry loc_entry_veneer5, function, local, visspc=weak
+
+	@ Invalid setups for veneer generation (absent standard symbol)
+	.align	2
+	.global	__acle_se_fake_entry_veneer1
+	.thumb
+	.thumb_func
+	.type	__acle_se_fake_entry_veneer1, %function
+__acle_se_fake_entry_veneer1:
+	nop
+	.size	__acle_se_fake_entry_veneer1, .-__acle_se_fake_entry_veneer1
+
+	@ Invalid setups for veneer generation (type)
+	entry obj_entry_veneer1, object, global, typespc=function
+	entry obj_entry_veneer2, function, global, typespc=object
+
+	@ Invalid setup for veneer generation (sections)
+	.section .text.sub1
+	.align	2
+	.thumb
+	.thumb_func
+	.global	__acle_se_fake_entry_veneer2
+	.type	__acle_se_fake_entry_veneer2, %function
+__acle_se_fake_entry_veneer2:
+	nop
+	.size	__acle_se_fake_entry_veneer2, .-__acle_se_fake_entry_veneer2
+	.section .text.sub2
+	.align	2
+	.thumb
+	.thumb_func
+	.global	fake_entry_veneer2
+	.type	fake_entry_veneer2, %function
+fake_entry_veneer2:
+	nop
+	.size	fake_entry_veneer2, .-fake_entry_veneer2
+.endif
diff --git a/ld/testsuite/ld-arm/cmse-veneers.sd b/ld/testsuite/ld-arm/cmse-veneers.sd
new file mode 100644
index 0000000000000000000000000000000000000000..99bfc8f37c25b7a57122b330b1145e27a9b087fd
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.sd
@@ -0,0 +1,7 @@
+
+.*
+
+Sections:
+Idx Name          Size      VMA       LMA       File off  Algn
+  \d+ \.gnu\.sgstubs  00000020  00020000  00020000  00010000  2\*\*5
+                  CONTENTS, ALLOC, LOAD, READONLY, CODE

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH, binutils, ARM 8/11, ping2] Add support for ARMv8-M Secure Gateway veneer generation
  2016-07-14  9:15         ` [RFC PATCH, binutils, ARM 8/11, ping] " Thomas Preudhomme
@ 2016-07-26 11:07           ` Thomas Preudhomme
  2016-08-03  8:52             ` [RFC PATCH, binutils, ARM 8/11, ping3] " Thomas Preudhomme
  0 siblings, 1 reply; 10+ messages in thread
From: Thomas Preudhomme @ 2016-07-26 11:07 UTC (permalink / raw)
  To: Richard Earnshaw (lists); +Cc: binutils

[-- Attachment #1: Type: text/plain, Size: 7006 bytes --]

Hi Richard,

Ping?

Best regards,

Thomas

On Thursday 14 July 2016 10:14:57 Thomas Preudhomme wrote:
> Hi Richard,
> 
> On Thursday 07 July 2016 16:27:27 Thomas Preudhomme wrote:
> > On Thursday 07 July 2016 11:52:56 Richard Earnshaw wrote:
> > > +   As per "ARMv8-M Security Extensions: Requirements on Development
> > > Tools"
> > > +   document, a secure gateway veneer is needed when there exists a
> > > non-local
> > > +   function symbol called "normal" symbol (eg. foo) with the same value
> > > as a
> > > +   symbol with the same type, binding a name save for a __acle_se_
> > > prefix,
> > > +   called a "special" symbol (eg. __acle_se_foo).  Entry functions
> > > handling +   with secure state transition by themselves have these
> > > symbols with different
> > > +   values.
> > > 
> > > 
> > > This is very unclear as to what is being/needs to be done.  Can you try
> > > redrafting it?
> > 
> > What do you think of the attached updated patch?
> 
> Ping?
> 
> > By the way, I realized I did not copy over the explanation for the changes
> > to elf32_arm_get_plt_info from the original patch submission. I'm adding
> > the full cover letter again here to have all the information in one email
> > in the archive.
> > 
> > 
> > 
> > This patch is part of a patch series to add support for ARMv8-M security
> > extension[1] to GNU ld. This specific patch adds support for creating
> > ARMv8-M Secure Gateway veneers.
> > 
> > ARM v8-M security extensions require [3] secure gateway veneers to be
> > generated for (secure) entry function in order for code to transition from
> > non-secure state to secure state when calling these entry function. Unlike
> > other veneers, these veneers are generated independently of relocations,
> > ie
> > a veneer can be generated in the absence of relocation. The condition for
> > the generation is that the normal symbol (the one whose name is the same
> > as
> > in C) of an entry function has the same value as the special symbol
> > (normal
> > symbol prefixed with "__acle_se_"). When that happens, the normal symbol
> > is
> > rebound to the veneer generated. When the two symbols have different value
> > it indicates that the entry function already contains an sg instruction to
> > do the secure state transition and the normal symbol points to the sg
> > instruction while the special symbol points after that.
> > 
> > This patch also makes use of the infrastructure laid out in previous
> > patches to control the address of these veneers and to avoid the presence
> > of the bit pattern of the SG instruction in non secure callable memory,
> > as required [4] [5].
> > 
> > Finally, the patch also contains a small change to elf32_arm_get_plt_info
> > () to return FALSE when there is no PLT, ensuring that a NULL splt is not
> > dereferenced in the block starting with "If the call goes through" in
> > elf32_arm_final_relocate (). This was not necessary before because
> > root_plt-
> > 
> > >offset is set to -1 in elf32_arm_adjust_dynamic_symbol called by
> > 
> > _bfd_elf_adjust_dynamic_symbol from bfd_elf_size_dynamic_sections when
> > dynobj is not NULL. However, dynobj is set in elf32_arm_check_relocs which
> > is not called when there is no relocation in the input section. Such a
> > situation is possible while still invoking elf32_arm_final_relocate () due
> > to SG veneers being created in the absence of relocation but needing
> > themselves relocation.
> > 
> > [1] Software requirements for ARMv8-M security extension are described in
> > document ARM-ECM-0359818 [2]
> > [2] Available on http://infocenter.arm.com in Developer guides and
> > articles
> > 
> > > Software development > ARM®v8-M Security Extensions: Requirements on
> > 
> > Development Tools
> > [3] See section 3.4.3 and requirement 44 of ARM-ECM-0359818 [2]
> > [4] requirement 14 and following comment of ARM-ECM-0359818 [2]
> > [5] requirement 12 and 13 and following comment of ARM-ECM-0359818 [2]
> > 
> > 
> > ChangeLog entries remain unchanged:
> > 
> > *** bfd/ChangeLog ***
> > 
> > 2016-05-04  Thomas Preud'homme  <thomas.preudhomme@arm.com>
> > 
> >         * elf32-arm.c (CMSE_PREFIX): Define macro.
> >         (elf32_arm_stub_cmse_branch_thumb_only): Define stub sequence.
> >         (cmse_branch_thumb_only): Declare stub.
> >         (struct elf32_arm_link_hash_table): Define cmse_stub_sec field.
> >         (elf32_arm_get_plt_info): Add globals parameter.  Use it to return
> >         FALSE if there is no PLT.
> >         (arm_type_of_stub): Adapt to new elf32_arm_get_plt_info signature.
> >         (elf32_arm_final_link_relocate): Likewise.
> >         (elf32_arm_gc_sweep_hook): Likewise.
> >         (elf32_arm_gc_mark_extra_sections): Mark sections holding ARMv8-M
> >         secure entry functions.
> >         (arm_stub_is_thumb): Add case for arm_stub_cmse_branch_thumb_only.
> >         (arm_dedicated_stub_output_section_required): Change to a switch
> > 
> > case and add a case for arm_stub_cmse_branch_thumb_only.
> > 
> >         (arm_dedicated_stub_output_section_required_alignment): Likewise.
> >         (arm_stub_dedicated_output_section_name): Likewise.
> >         (arm_stub_dedicated_input_section_ptr): Likewise and remove
> >         ATTRIBUTE_UNUSED for htab parameter.
> >         (arm_stub_required_alignment): Likewise.
> >         (arm_stub_sym_claimed): Likewise.
> >         (arm_dedicated_stub_section_padding): Likewise.
> >         (cmse_scan): New function.
> >         (elf32_arm_size_stubs): Call cmse_scan for ARM M profile targets.
> >         Set stub_changed to TRUE if such veneers were created.
> >         (elf32_arm_swap_symbol_in): Add detection code for CMSE special
> >         symbols.
> > 
> > *** include/elf/ChangeLog ***
> > 
> > 2015-12-16  Thomas Preud'homme  <thomas.preudhomme@arm.com>
> > 
> >         * arm.h (ARM_GET_SYM_CMSE_SPCL): Define macro.
> >         (ARM_SET_SYM_CMSE_SPCL): Likewise.
> > 
> > *** ld/ChangeLog ***
> > 
> > 2016-02-17  Thomas Preud'homme  <thomas.preudhomme@arm.com>
> > 
> >         * ld.texinfo (Placement of SG veneers): New concept entry.
> >         * testsuite/ld-arm/arm-elf.exp
> >         (Secure gateway veneers: no .gnu.sgstubs section): New test.
> >         (Secure gateway veneers: wrong entry functions): Likewise.
> >         (Secure gateway veneers (ARMv8-M Baseline)): Likewise.
> >         (Secure gateway veneers (ARMv8-M Mainline)): Likewise.
> >         * testsuite/ld-arm/cmse-veneers.s: New file.
> >         * testsuite/ld-arm/cmse-veneers.d: Likewise.
> >         * testsuite/ld-arm/cmse-veneers.rd: Likewise.
> >         * testsuite/ld-arm/cmse-veneers.sd: Likewise.
> >         * testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out: Likewise.
> >         * testsuite/ld-arm/cmse-veneers-wrong-entryfct.out: Likewise.
> > 
> > Best regards,
> > 
> > Thomas

[-- Attachment #2: sg_veneers_support.patch --]
[-- Type: text/x-patch, Size: 28720 bytes --]

diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 8de01b46671cd2ac1cbd94ef4373db439a62a9c4..b5da179d266845c6bf2aa1c9359507a2c1f0e1d1 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -2138,6 +2138,8 @@ typedef unsigned short int insn16;
 
 #define STUB_ENTRY_NAME   "__%s_veneer"
 
+#define CMSE_PREFIX "__acle_se_"
+
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
 #define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
@@ -2543,6 +2545,13 @@ static const insn_sequence elf32_arm_stub_long_branch_arm_nacl_pic[] =
   DATA_WORD (0, R_ARM_NONE, 0),         /* .word 0 */
 };
 
+/* Stub used for transition to secure state (aka SG veneer).  */
+static const insn_sequence elf32_arm_stub_cmse_branch_thumb_only[] =
+{
+  THUMB32_INSN (0xe97fe97f),		/* sg.  */
+  THUMB32_B_INSN (0xf000b800, -4),	/* b.w original_branch_dest.  */
+};
+
 
 /* Cortex-A8 erratum-workaround stubs.  */
 
@@ -2622,6 +2631,7 @@ static const insn_sequence elf32_arm_stub_a8_veneer_blx[] =
   DEF_STUB(long_branch_v4t_thumb_tls_pic) \
   DEF_STUB(long_branch_arm_nacl) \
   DEF_STUB(long_branch_arm_nacl_pic) \
+  DEF_STUB(cmse_branch_thumb_only) \
   DEF_STUB(a8_veneer_b_cond) \
   DEF_STUB(a8_veneer_b) \
   DEF_STUB(a8_veneer_bl) \
@@ -3172,6 +3182,9 @@ struct elf32_arm_link_hash_table
      information on stub grouping.  */
   struct map_stub *stub_group;
 
+  /* Input stub section holding secure gateway veneers.  */
+  asection *cmse_stub_sec;
+
   /* Number of elements in stub_group.  */
   unsigned int top_id;
 
@@ -3320,12 +3333,16 @@ elf32_arm_create_local_iplt (bfd *abfd, unsigned long r_symndx)
    union and *ARM_PLT at the ARM-specific information.  */
 
 static bfd_boolean
-elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_entry *h,
+elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_table *globals,
+			struct elf32_arm_link_hash_entry *h,
 			unsigned long r_symndx, union gotplt_union **root_plt,
 			struct arm_plt_info **arm_plt)
 {
   struct arm_local_iplt_info *local_iplt;
 
+  if (globals->root.splt == NULL && globals->root.iplt == NULL)
+    return FALSE;
+
   if (h != NULL)
     {
       *root_plt = &h->root.plt;
@@ -3786,6 +3803,7 @@ arm_stub_is_thumb (enum elf32_arm_stub_type stub_type)
     case arm_stub_long_branch_v4t_thumb_arm_pic:
     case arm_stub_long_branch_v4t_thumb_tls_pic:
     case arm_stub_long_branch_thumb_only_pic:
+    case arm_stub_cmse_branch_thumb_only:
       return TRUE;
     case arm_stub_none:
       BFD_FAIL ();
@@ -3851,8 +3869,9 @@ arm_type_of_stub (struct bfd_link_info *info,
      the address of the appropriate trampoline.  */
   if (r_type != R_ARM_TLS_CALL
       && r_type != R_ARM_THM_TLS_CALL
-      && elf32_arm_get_plt_info (input_bfd, hash, ELF32_R_SYM (rel->r_info),
-				 &root_plt, &arm_plt)
+      && elf32_arm_get_plt_info (input_bfd, globals, hash,
+				 ELF32_R_SYM (rel->r_info), &root_plt,
+				 &arm_plt)
       && root_plt->offset != (bfd_vma) -1)
     {
       asection *splt;
@@ -4163,7 +4182,16 @@ arm_dedicated_stub_output_section_required (enum elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  return FALSE;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Required alignment (as a power of 2) for the dedicated section holding
@@ -4177,8 +4205,19 @@ arm_dedicated_stub_output_section_required_alignment
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
-  return 0;
+  switch (stub_type)
+    {
+    /* Vectors of Secure Gateway veneers must be aligned on 32byte
+       boundary.  */
+    case arm_stub_cmse_branch_thumb_only:
+      return 5;
+
+    default:
+      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
+      return 0;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Name of the dedicated output section to put veneers of type STUB_TYPE, or
@@ -4190,8 +4229,17 @@ arm_dedicated_stub_output_section_name (enum elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
-  return NULL;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return ".gnu.sgstubs";
+
+    default:
+      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
+      return NULL;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* If veneers of type STUB_TYPE should go in a dedicated output section,
@@ -4199,15 +4247,23 @@ arm_dedicated_stub_output_section_name (enum elf32_arm_stub_type stub_type)
    corresponding input section.  Otherwise, returns NULL.  */
 
 static asection **
-arm_dedicated_stub_input_section_ptr
-  (struct elf32_arm_link_hash_table *htab ATTRIBUTE_UNUSED,
-   enum elf32_arm_stub_type stub_type)
+arm_dedicated_stub_input_section_ptr (struct elf32_arm_link_hash_table *htab,
+				      enum elf32_arm_stub_type stub_type)
 {
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
-  return NULL;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return &htab->cmse_stub_sec;
+
+    default:
+      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
+      return NULL;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Find or create a stub section to contain a stub of type STUB_TYPE.  SECTION
@@ -4429,6 +4485,7 @@ arm_stub_required_alignment (enum elf32_arm_stub_type stub_type)
     case arm_stub_long_branch_thumb_only_pic:
     case arm_stub_long_branch_any_tls_pic:
     case arm_stub_long_branch_v4t_thumb_tls_pic:
+    case arm_stub_cmse_branch_thumb_only:
     case arm_stub_a8_veneer_blx:
       return 4;
 
@@ -4450,7 +4507,16 @@ arm_stub_sym_claimed (enum elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  return FALSE;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Returns the padding needed for the dedicated section used stubs of type
@@ -4462,7 +4528,16 @@ arm_dedicated_stub_section_padding (enum elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  return 0;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return 32;
+
+    default:
+      return 0;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 static bfd_boolean
@@ -5353,6 +5428,204 @@ elf32_arm_create_stub (struct elf32_arm_link_hash_table *htab,
   return TRUE;
 }
 
+/* Scan symbols in INPUT_BFD to identify secure entry functions needing a
+   gateway veneer to transition from non secure to secure state and create them
+   accordingly.
+
+   "ARMv8-M Security Extensions: Requirements on Development Tools" document
+   defines the conditions that govern Secure Gateway veneer creation for a
+   given symbol <SYM> as follows:
+   - it has function type
+   - it has non local binding
+   - a symbol named __acle_se_<SYM> (called special symbol) exists with the
+     same type, binding and value as <SYM> (called normal symbol).
+   An entry function can handle secure state transition itself in which case
+   its special symbol would have a different value from the normal symbol.
+
+   OUT_ATTR gives the output attributes, SYM_HASHES the symbol index to hash
+   entry mapping while HTAB gives the name to hash entry mapping.
+
+   If any secure gateway veneer is created, *STUB_CHANGED is set to TRUE.  The
+   return value gives whether a stub failed to be allocated.  */
+
+static bfd_boolean
+cmse_scan (bfd *input_bfd, struct elf32_arm_link_hash_table *htab,
+	   obj_attribute *out_attr, struct elf_link_hash_entry **sym_hashes,
+	   bfd_boolean *stub_changed)
+{
+  const struct elf_backend_data *bed;
+  Elf_Internal_Shdr *symtab_hdr;
+  unsigned i, j, sym_count, ext_start;
+  Elf_Internal_Sym *cmse_sym, *local_syms;
+  struct elf32_arm_link_hash_entry *hash, *cmse_hash = NULL;
+  enum arm_st_branch_type branch_type;
+  char *sym_name, *lsym_name;
+  bfd_vma sym_value;
+  asection *section;
+  bfd_boolean is_v8m, new_stub, created_stub, cmse_invalid, ret = TRUE;
+
+  bed = get_elf_backend_data (input_bfd);
+  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym;
+  ext_start = symtab_hdr->sh_info;
+  is_v8m = (out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE
+	    && out_attr[Tag_CPU_arch_profile].i == 'M');
+
+  local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+  if (local_syms == NULL)
+    local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
+				       symtab_hdr->sh_info, 0, NULL, NULL,
+				       NULL);
+  if (symtab_hdr->sh_info && local_syms == NULL)
+    return FALSE;
+
+  /* Scan symbols.  */
+  for (i = 0; i < sym_count; i++)
+    {
+      cmse_invalid = FALSE;
+
+      if (i < ext_start)
+	{
+	  cmse_sym = &local_syms[i];
+	  /* Not a special symbol.  */
+	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_sym->st_target_internal))
+	    continue;
+	  sym_name = bfd_elf_string_from_elf_section (input_bfd,
+						      symtab_hdr->sh_link,
+						      cmse_sym->st_name);
+	  /* Special symbol with local binding.  */
+	  cmse_invalid = TRUE;
+	}
+      else
+	{
+	  cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]);
+	  sym_name = (char *) cmse_hash->root.root.root.string;
+
+	  /* Not a special symbol.  */
+	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal))
+	    continue;
+
+	  /* Special symbol has incorrect binding or type.  */
+	  if ((cmse_hash->root.root.type != bfd_link_hash_defined
+	       && cmse_hash->root.root.type != bfd_link_hash_defweak)
+	      || cmse_hash->root.type != STT_FUNC)
+	    cmse_invalid = TRUE;
+	}
+
+      if (!is_v8m)
+	{
+	  (*_bfd_error_handler) (_("%B: Special symbol `%s' only allowed for "
+				   "ARMv8-M architecture or later."),
+				 input_bfd, sym_name);
+	  is_v8m = TRUE; /* Avoid multiple warning.  */
+	  ret = FALSE;
+	}
+
+      if (cmse_invalid)
+	{
+	  (*_bfd_error_handler) (_("%B: invalid special symbol `%s'."),
+				 input_bfd, sym_name);
+	  (*_bfd_error_handler) (_("It must be a global or weak function "
+				   "symbol."));
+	  ret = FALSE;
+	  if (i < ext_start)
+	    continue;
+	}
+
+      sym_name += strlen (CMSE_PREFIX);
+      hash = (struct elf32_arm_link_hash_entry *)
+	elf_link_hash_lookup (&(htab)->root, sym_name, FALSE, FALSE, TRUE);
+
+      /* No associated normal symbol or it is neither global nor weak.  */
+      if (!hash
+	  || (hash->root.root.type != bfd_link_hash_defined
+	      && hash->root.root.type != bfd_link_hash_defweak)
+	  || hash->root.type != STT_FUNC)
+	{
+	  /* Initialize here to avoid warning about use of possibly
+	     uninitialized variable.  */
+	  j = 0;
+
+	  if (!hash)
+	    {
+	      /* Searching for a normal symbol with local binding.  */
+	      for (; j < ext_start; j++)
+		{
+		  lsym_name =
+		    bfd_elf_string_from_elf_section (input_bfd,
+						     symtab_hdr->sh_link,
+						     local_syms[j].st_name);
+		  if (!strcmp (sym_name, lsym_name))
+		    break;
+		}
+	    }
+
+	  if (hash || j < ext_start)
+	    {
+	      (*_bfd_error_handler)
+		(_("%B: invalid standard symbol `%s'."), input_bfd, sym_name);
+	      (*_bfd_error_handler)
+		(_("It must be a global or weak function symbol."));
+	    }
+	  else
+	    (*_bfd_error_handler)
+	      (_("%B: absent standard symbol `%s'."), input_bfd, sym_name);
+	  ret = FALSE;
+	  if (!hash)
+	    continue;
+	}
+
+      sym_value = hash->root.root.u.def.value;
+      section = hash->root.root.u.def.section;
+
+      if (cmse_hash->root.root.u.def.section != section)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: `%s' and its special symbol are in different sections."),
+	     input_bfd, sym_name);
+	  ret = FALSE;
+	}
+      if (cmse_hash->root.root.u.def.value != sym_value)
+	continue; /* Ignore: could be an entry function starting with SG.  */
+
+	/* If this section is a link-once section that will be discarded, then
+	   don't create any stubs.  */
+      if (section->output_section == NULL)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: entry function `%s' not output."), input_bfd, sym_name);
+	  continue;
+	}
+
+      if (hash->root.size == 0)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: entry function `%s' is empty."), input_bfd, sym_name);
+	  ret = FALSE;
+	}
+
+      if (!ret)
+	continue;
+      branch_type = ARM_GET_SYM_BRANCH_TYPE (hash->root.target_internal);
+      created_stub
+	= elf32_arm_create_stub (htab, arm_stub_cmse_branch_thumb_only,
+				 NULL, NULL, section, hash, sym_name,
+				 sym_value, branch_type, &new_stub);
+
+      if (!created_stub)
+	 ret = FALSE;
+      else
+	{
+	  BFD_ASSERT (new_stub);
+	  *stub_changed = TRUE;
+	}
+    }
+
+  if (!symtab_hdr->contents)
+    free (local_syms);
+  return ret;
+}
+
 /* Determine and set the size of the stub section for a final link.
 
    The basic idea here is to examine all the relocations looking for
@@ -5369,8 +5642,9 @@ elf32_arm_size_stubs (bfd *output_bfd,
 						      unsigned int),
 		      void (*layout_sections_again) (void))
 {
+  obj_attribute *out_attr;
   bfd_size_type stub_group_size;
-  bfd_boolean stubs_always_after_branch;
+  bfd_boolean m_profile, stubs_always_after_branch, first_veneer_scan = TRUE;
   struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
   struct a8_erratum_fix *a8_fixes = NULL;
   unsigned int num_a8_fixes = 0, a8_fix_table_size = 10;
@@ -5399,6 +5673,8 @@ elf32_arm_size_stubs (bfd *output_bfd,
   htab->layout_sections_again = layout_sections_again;
   stubs_always_after_branch = group_size < 0;
 
+  out_attr = elf_known_obj_attributes_proc (output_bfd);
+  m_profile = out_attr[Tag_CPU_arch_profile].i == 'M';
   /* The Cortex-A8 erratum fix depends on stubs not being in the same 4K page
      as the first half of a 32-bit branch straddling two 4K pages.  This is a
      crude way of enforcing that.  */
@@ -5464,6 +5740,18 @@ elf32_arm_size_stubs (bfd *output_bfd,
 	  if (symtab_hdr->sh_info == 0)
 	    continue;
 
+	  /* Limit scan of symbols to object file whose profile is
+	     Microcontroller to not hinder performance in the general case.  */
+	  if (m_profile && first_veneer_scan)
+	    {
+	      struct elf_link_hash_entry **sym_hashes;
+
+	      sym_hashes = elf_sym_hashes (input_bfd);
+	      if (!cmse_scan (input_bfd, htab, out_attr, sym_hashes,
+			      &stub_changed))
+		goto error_ret_free_local;
+	    }
+
 	  /* Walk over each section attached to the input bfd.  */
 	  for (section = input_bfd->sections;
 	       section != NULL;
@@ -5850,6 +6138,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
 
       /* Ask the linker to do its stuff.  */
       (*htab->layout_sections_again) ();
+      first_veneer_scan = FALSE;
     }
 
   /* Add stubs for Cortex-A8 erratum fixes now.  */
@@ -9191,7 +9480,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
   /* Find out whether the symbol has a PLT.  Set ST_VALUE, BRANCH_TYPE and
      VALUE appropriately for relocations that we resolve at link time.  */
   has_iplt_entry = FALSE;
-  if (elf32_arm_get_plt_info (input_bfd, eh, r_symndx, &root_plt, &arm_plt)
+  if (elf32_arm_get_plt_info (input_bfd, globals, eh, r_symndx, &root_plt,
+			      &arm_plt)
       && root_plt->offset != (bfd_vma) -1)
     {
       plt_offset = root_plt->offset;
@@ -13603,7 +13893,8 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
 	}
 
       if (may_need_local_target_p
-	  && elf32_arm_get_plt_info (abfd, eh, r_symndx, &root_plt, &arm_plt))
+	  && elf32_arm_get_plt_info (abfd, globals, eh, r_symndx, &root_plt,
+				     &arm_plt))
 	{
 	  /* If PLT refcount book-keeping is wrong and too low, we'll
 	     see a zero value (going to -1) for the root PLT reference
@@ -14071,7 +14362,11 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
 }
 
 /* Unwinding tables are not referenced directly.  This pass marks them as
-   required if the corresponding code section is marked.  */
+   required if the corresponding code section is marked.  Similarly, ARMv8-M
+   secure entry functions can only be referenced by SG veneers which are
+   created after the GC process. They need to be marked in case they reside in
+   their own section (as would be the case if code was compiled with
+   -ffunction-sections).  */
 
 static bfd_boolean
 elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
@@ -14079,10 +14374,21 @@ elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
 {
   bfd *sub;
   Elf_Internal_Shdr **elf_shdrp;
-  bfd_boolean again;
+  asection *cmse_sec;
+  obj_attribute *out_attr;
+  Elf_Internal_Shdr *symtab_hdr;
+  unsigned i, sym_count, ext_start;
+  const struct elf_backend_data *bed;
+  struct elf_link_hash_entry **sym_hashes;
+  struct elf32_arm_link_hash_entry *cmse_hash;
+  bfd_boolean again, is_v8m, first_bfd_browse = TRUE;
 
   _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
 
+  out_attr = elf_known_obj_attributes_proc (info->output_bfd);
+  is_v8m = out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE
+	   && out_attr[Tag_CPU_arch_profile].i == 'M';
+
   /* Marking EH data may cause additional code sections to be marked,
      requiring multiple passes.  */
   again = TRUE;
@@ -14113,7 +14419,34 @@ elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
 		    return FALSE;
 		}
 	    }
+
+	  /* Mark section holding ARMv8-M secure entry functions.  We mark all
+	     of them so no need for a second browsing.  */
+	  if (is_v8m && first_bfd_browse)
+	    {
+	      sym_hashes = elf_sym_hashes (sub);
+	      bed = get_elf_backend_data (sub);
+	      symtab_hdr = &elf_tdata (sub)->symtab_hdr;
+	      sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym;
+	      ext_start = symtab_hdr->sh_info;
+
+	      /* Scan symbols.  */
+	      for (i = ext_start; i < sym_count; i++)
+		{
+		  cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]);
+
+		  /* Assume it is a special symbol.  If not, cmse_scan will
+		     warn about it and user can do something about it.  */
+		  if (ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal))
+		    {
+		      cmse_sec = cmse_hash->root.root.u.def.section;
+		      if (!_bfd_elf_gc_mark (info, cmse_sec, gc_mark_hook))
+			return FALSE;
+		    }
+		}
+	    }
 	}
+      first_bfd_browse = FALSE;
     }
 
   return TRUE;
@@ -17765,6 +18098,9 @@ elf32_arm_swap_symbol_in (bfd * abfd,
 			  const void *pshn,
 			  Elf_Internal_Sym *dst)
 {
+  Elf_Internal_Shdr *symtab_hdr;
+  const char *name = NULL;
+
   if (!bfd_elf32_swap_symbol_in (abfd, psrc, pshn, dst))
     return FALSE;
   dst->st_target_internal = 0;
@@ -17793,6 +18129,13 @@ elf32_arm_swap_symbol_in (bfd * abfd,
   else
     ARM_SET_SYM_BRANCH_TYPE (dst->st_target_internal, ST_BRANCH_UNKNOWN);
 
+  /* Mark CMSE special symbols.  */
+  symtab_hdr = & elf_symtab_hdr (abfd);
+  if (symtab_hdr->sh_size)
+    name = bfd_elf_sym_name (abfd, symtab_hdr, dst, NULL);
+  if (name && CONST_STRNEQ (name, CMSE_PREFIX))
+    ARM_SET_SYM_CMSE_SPCL (dst->st_target_internal);
+
   return TRUE;
 }
 
diff --git a/include/elf/arm.h b/include/elf/arm.h
index bafc03c52ee686671e847eff272ab5cc8a79398c..abad4731b335485f34a06b45d7edea475cfb321b 100644
--- a/include/elf/arm.h
+++ b/include/elf/arm.h
@@ -384,4 +384,11 @@ enum arm_st_branch_type {
 	   | ((TYPE) & ENUM_ARM_ST_BRANCH_TYPE_BITMASK))
 #endif
 
+/* Get or set whether a symbol is a special symbol of an entry function of CMSE
+   secure code.  */
+#define ARM_GET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
+  (((SYM_TARGET_INTERNAL) >> 2) & 1)
+#define ARM_SET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
+  (SYM_TARGET_INTERNAL) |= 4
+
 #endif /* _ELF_ARM_H */
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index bc16764b0554851217316c438ada863843915307..171ae6e55bc2bf2708a23e822218b8d4e53f8ee6 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -6853,6 +6853,12 @@ entries which only support 512Mb of code.
 The @samp{--no-apply-dynamic-relocs} option makes AArch64 linker do not apply
 link-time values for dynamic relocations.
 
+@cindex Placement of SG veneers
+All SG veneers are placed in the special output section @code{.gnu.sgstubs}.
+Its start address must be set, either with the command line option
+@samp{--section-start} or in a linker script, to indicate where to place these
+veneers in memory.
+
 @ifclear GENERIC
 @lowersections
 @end ifclear
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index db25a8d46c985f89e02ce68c8897923c23101661..84301626fb6ab24a6726315e810249b4375b5fdc 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -633,6 +633,33 @@ set armeabitests_nonacl {
      {{objdump -d jump-reloc-veneers-long.d}}
      "jump-reloc-veneers-long"}
 
+    {"Secure gateway veneers: no .gnu.sgstubs section" "" ""
+     "-march=armv8-m.base -mthumb"
+     {cmse-veneers.s}
+     {{ld cmse-veneers-no-gnu_sgstubs.out}}
+     "cmse-veneers-no-gnu_sgstubs"}
+    {"Secure gateway veneers: wrong entry functions" "" ""
+     "-march=armv7-m -mthumb --defsym CHECK_ERRORS=1"
+     {cmse-veneers.s}
+     {{ld cmse-veneers-wrong-entryfct.out}}
+     "cmse-veneers-wrong-entryfct"}
+    {"Secure gateway veneers (ARMv8-M Baseline)"
+     "-Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --gc-sections" ""
+     "-march=armv8-m.base -mthumb"
+     {cmse-veneers.s}
+     {{objdump {-d -j .gnu.sgstubs} cmse-veneers.d}
+      {objdump {-h -j .gnu.sgstubs} cmse-veneers.sd}
+      {nm {} cmse-veneers.rd}}
+     "cmse-veneers-baseline"}
+    {"Secure gateway veneers (ARMv8-M Mainline)"
+     "-Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --gc-sections" ""
+     "-march=armv8-m.main -mthumb"
+     {cmse-veneers.s}
+     {{objdump {-d -j .gnu.sgstubs} cmse-veneers.d}
+      {objdump {-h -j .gnu.sgstubs} cmse-veneers.sd}
+      {nm {} cmse-veneers.rd}}
+     "cmse-veneers-mainline"}
+
     {"R_ARM_THM_JUMP19 Relocation veneers: Short"
      "--section-start destsect=0x000108002 --section-start .text=0x8000" ""
      "-march=armv7-m -mthumb"
diff --git a/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out b/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out
new file mode 100644
index 0000000000000000000000000000000000000000..9d1e5ba3215ae8a29585fcf04ec1f94314670a29
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out
@@ -0,0 +1,3 @@
+.*: No address assigned to the veneers output section .gnu.sgstubs
+.*: cannot size stub section: Invalid operation
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
new file mode 100644
index 0000000000000000000000000000000000000000..fd4766ab877a4abbeb8b2c4c053ab11d3f86773c
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
@@ -0,0 +1,19 @@
+.*: .*: Special symbol `__acle_se_loc_entry_veneer1' only allowed for ARMv8-M architecture or later.
+.*: .*: invalid .* symbol `.*loc_entry_veneer1'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_loc_entry_veneer2'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_loc_entry_veneer4'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid standard symbol `loc_entry_veneer3'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid standard symbol `loc_entry_veneer5'.
+.*: It must be a global or weak function symbol.
+.*: .*: absent standard symbol `fake_entry_veneer1'.
+.*: .*: invalid standard symbol `obj_entry_veneer1'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_obj_entry_veneer2'.
+.*: It must be a global or weak function symbol.
+.*: .*: `fake_entry_veneer2' and its special symbol are in different sections.
+.*: cannot size stub section: Invalid operation
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers.d b/ld/testsuite/ld-arm/cmse-veneers.d
new file mode 100644
index 0000000000000000000000000000000000000000..6a44a2b5dce9de4f5d64fe644e41f5ab9840806e
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.d
@@ -0,0 +1,21 @@
+
+.*
+
+
+Disassembly of section \.gnu.sgstubs:
+
+00020000 <glob_entry_veneer2>:
+   20000:	e97f e97f 	sg
+   20004:	f7e8 b800 	b\.w	8008 <__acle_se_glob_entry_veneer2>
+
+00020008 <weak_entry_veneer2>:
+   20008:	e97f e97f 	sg
+   2000c:	f7e7 bffe 	b\.w	800c <__acle_se_weak_entry_veneer2>
+
+00020010 <glob_entry_veneer1>:
+   20010:	e97f e97f 	sg
+   20014:	f7e7 bff4 	b\.w	8000 <__acle_se_glob_entry_veneer1>
+
+00020018 <weak_entry_veneer1>:
+   20018:	e97f e97f 	sg
+   2001c:	f7e7 bff2 	b\.w	8004 <__acle_se_weak_entry_veneer1>
diff --git a/ld/testsuite/ld-arm/cmse-veneers.rd b/ld/testsuite/ld-arm/cmse-veneers.rd
new file mode 100644
index 0000000000000000000000000000000000000000..20fad961bd8803109c3cf57ef22e3b36da5b1500
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.rd
@@ -0,0 +1,9 @@
+#...
+[0-9a-f]+ T glob_entry_fct
+#...
+[0-9a-f]+ T glob_entry_veneer1
+[0-9a-f]+ T glob_entry_veneer2
+#...
+[0-9a-f]+ W weak_entry_veneer1
+[0-9a-f]+ W weak_entry_veneer2
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers.s b/ld/testsuite/ld-arm/cmse-veneers.s
new file mode 100644
index 0000000000000000000000000000000000000000..d5c57f646a78c4736e4f084d8ad6aff7efea554f
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.s
@@ -0,0 +1,97 @@
+	.syntax unified
+	.thumb
+	.file	"foo.c"
+	.text
+
+.macro	decltype	name, type
+.ifc \type,object
+	.data
+.else
+	.thumb
+	.thumb_func
+.endif
+	.type	\name, %\type
+.endm
+
+
+.macro	entry	name, type, vis, typespc, visspc, entry_fct
+	.align	2
+.ifb \visspc
+	.\vis	__acle_se_\name
+.else
+	.\visspc	__acle_se_\name
+.endif
+	.\vis	\name
+	.thumb
+	.thumb_func
+.ifb \typespc
+	decltype	__acle_se_\name, \type
+.else
+	decltype	__acle_se_\name, \typespc
+.endif
+	decltype	\name, \type
+__acle_se_\name:
+	\entry_fct
+\name:
+.ifc \type,object
+	.word 42
+.else
+	nop
+.endif
+	.size	\name, .-\name
+	.size	__acle_se_\name, .-__acle_se_\name
+.endm
+
+
+.ifndef CHECK_ERRORS
+	@ Valid setups for veneer generation
+	entry glob_entry_veneer1, function, global
+	entry weak_entry_veneer1, function, weak
+	entry glob_entry_veneer2, function, global, visspc=weak
+	entry weak_entry_veneer2, function, weak, visspc=global
+
+	@ Valid setup for entry function without SG veneer
+	entry glob_entry_fct, function, global, entry_fct=nop
+
+.else
+	@ Invalid setups for veneer generation (visibility)
+	entry loc_entry_veneer1, function, local
+	entry loc_entry_veneer2, function, global, visspc=local
+	entry loc_entry_veneer3, function, local, visspc=global
+	entry loc_entry_veneer4, function, weak, visspc=local
+	entry loc_entry_veneer5, function, local, visspc=weak
+
+	@ Invalid setups for veneer generation (absent standard symbol)
+	.align	2
+	.global	__acle_se_fake_entry_veneer1
+	.thumb
+	.thumb_func
+	.type	__acle_se_fake_entry_veneer1, %function
+__acle_se_fake_entry_veneer1:
+	nop
+	.size	__acle_se_fake_entry_veneer1, .-__acle_se_fake_entry_veneer1
+
+	@ Invalid setups for veneer generation (type)
+	entry obj_entry_veneer1, object, global, typespc=function
+	entry obj_entry_veneer2, function, global, typespc=object
+
+	@ Invalid setup for veneer generation (sections)
+	.section .text.sub1
+	.align	2
+	.thumb
+	.thumb_func
+	.global	__acle_se_fake_entry_veneer2
+	.type	__acle_se_fake_entry_veneer2, %function
+__acle_se_fake_entry_veneer2:
+	nop
+	.size	__acle_se_fake_entry_veneer2, .-__acle_se_fake_entry_veneer2
+	.section .text.sub2
+	.align	2
+	.thumb
+	.thumb_func
+	.global	fake_entry_veneer2
+	.type	fake_entry_veneer2, %function
+fake_entry_veneer2:
+	nop
+	.size	fake_entry_veneer2, .-fake_entry_veneer2
+.endif
diff --git a/ld/testsuite/ld-arm/cmse-veneers.sd b/ld/testsuite/ld-arm/cmse-veneers.sd
new file mode 100644
index 0000000000000000000000000000000000000000..99bfc8f37c25b7a57122b330b1145e27a9b087fd
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.sd
@@ -0,0 +1,7 @@
+
+.*
+
+Sections:
+Idx Name          Size      VMA       LMA       File off  Algn
+  \d+ \.gnu\.sgstubs  00000020  00020000  00020000  00010000  2\*\*5
+                  CONTENTS, ALLOC, LOAD, READONLY, CODE

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH, binutils, ARM 8/11, ping3] Add support for ARMv8-M Secure Gateway veneer generation
  2016-07-26 11:07           ` [RFC PATCH, binutils, ARM 8/11, ping2] " Thomas Preudhomme
@ 2016-08-03  8:52             ` Thomas Preudhomme
  2016-08-04  8:59               ` Richard Earnshaw (lists)
  0 siblings, 1 reply; 10+ messages in thread
From: Thomas Preudhomme @ 2016-08-03  8:52 UTC (permalink / raw)
  To: Richard Earnshaw (lists); +Cc: binutils

[-- Attachment #1: Type: text/plain, Size: 7675 bytes --]

Hi Richard,

How do you find the reworded comment for cmse_scan?

Best regards,

Thomas

On Tuesday 26 July 2016 12:07:26 Thomas Preudhomme wrote:
> Hi Richard,
> 
> Ping?
> 
> Best regards,
> 
> Thomas
> 
> On Thursday 14 July 2016 10:14:57 Thomas Preudhomme wrote:
> > Hi Richard,
> > 
> > On Thursday 07 July 2016 16:27:27 Thomas Preudhomme wrote:
> > > On Thursday 07 July 2016 11:52:56 Richard Earnshaw wrote:
> > > > +   As per "ARMv8-M Security Extensions: Requirements on Development
> > > > Tools"
> > > > +   document, a secure gateway veneer is needed when there exists a
> > > > non-local
> > > > +   function symbol called "normal" symbol (eg. foo) with the same
> > > > value
> > > > as a
> > > > +   symbol with the same type, binding a name save for a __acle_se_
> > > > prefix,
> > > > +   called a "special" symbol (eg. __acle_se_foo).  Entry functions
> > > > handling +   with secure state transition by themselves have these
> > > > symbols with different
> > > > +   values.
> > > > 
> > > > 
> > > > This is very unclear as to what is being/needs to be done.  Can you
> > > > try
> > > > redrafting it?
> > > 
> > > What do you think of the attached updated patch?
> > 
> > Ping?
> > 
> > > By the way, I realized I did not copy over the explanation for the
> > > changes
> > > to elf32_arm_get_plt_info from the original patch submission. I'm adding
> > > the full cover letter again here to have all the information in one
> > > email
> > > in the archive.
> > > 
> > > 
> > > 
> > > This patch is part of a patch series to add support for ARMv8-M security
> > > extension[1] to GNU ld. This specific patch adds support for creating
> > > ARMv8-M Secure Gateway veneers.
> > > 
> > > ARM v8-M security extensions require [3] secure gateway veneers to be
> > > generated for (secure) entry function in order for code to transition
> > > from
> > > non-secure state to secure state when calling these entry function.
> > > Unlike
> > > other veneers, these veneers are generated independently of relocations,
> > > ie
> > > a veneer can be generated in the absence of relocation. The condition
> > > for
> > > the generation is that the normal symbol (the one whose name is the same
> > > as
> > > in C) of an entry function has the same value as the special symbol
> > > (normal
> > > symbol prefixed with "__acle_se_"). When that happens, the normal symbol
> > > is
> > > rebound to the veneer generated. When the two symbols have different
> > > value
> > > it indicates that the entry function already contains an sg instruction
> > > to
> > > do the secure state transition and the normal symbol points to the sg
> > > instruction while the special symbol points after that.
> > > 
> > > This patch also makes use of the infrastructure laid out in previous
> > > patches to control the address of these veneers and to avoid the
> > > presence
> > > of the bit pattern of the SG instruction in non secure callable memory,
> > > as required [4] [5].
> > > 
> > > Finally, the patch also contains a small change to
> > > elf32_arm_get_plt_info
> > > () to return FALSE when there is no PLT, ensuring that a NULL splt is
> > > not
> > > dereferenced in the block starting with "If the call goes through" in
> > > elf32_arm_final_relocate (). This was not necessary before because
> > > root_plt-
> > > 
> > > >offset is set to -1 in elf32_arm_adjust_dynamic_symbol called by
> > > 
> > > _bfd_elf_adjust_dynamic_symbol from bfd_elf_size_dynamic_sections when
> > > dynobj is not NULL. However, dynobj is set in elf32_arm_check_relocs
> > > which
> > > is not called when there is no relocation in the input section. Such a
> > > situation is possible while still invoking elf32_arm_final_relocate ()
> > > due
> > > to SG veneers being created in the absence of relocation but needing
> > > themselves relocation.
> > > 
> > > [1] Software requirements for ARMv8-M security extension are described
> > > in
> > > document ARM-ECM-0359818 [2]
> > > [2] Available on http://infocenter.arm.com in Developer guides and
> > > articles
> > > 
> > > > Software development > ARM®v8-M Security Extensions: Requirements on
> > > 
> > > Development Tools
> > > [3] See section 3.4.3 and requirement 44 of ARM-ECM-0359818 [2]
> > > [4] requirement 14 and following comment of ARM-ECM-0359818 [2]
> > > [5] requirement 12 and 13 and following comment of ARM-ECM-0359818 [2]
> > > 
> > > 
> > > ChangeLog entries remain unchanged:
> > > 
> > > *** bfd/ChangeLog ***
> > > 
> > > 2016-05-04  Thomas Preud'homme  <thomas.preudhomme@arm.com>
> > > 
> > >         * elf32-arm.c (CMSE_PREFIX): Define macro.
> > >         (elf32_arm_stub_cmse_branch_thumb_only): Define stub sequence.
> > >         (cmse_branch_thumb_only): Declare stub.
> > >         (struct elf32_arm_link_hash_table): Define cmse_stub_sec field.
> > >         (elf32_arm_get_plt_info): Add globals parameter.  Use it to
> > >         return
> > >         FALSE if there is no PLT.
> > >         (arm_type_of_stub): Adapt to new elf32_arm_get_plt_info
> > >         signature.
> > >         (elf32_arm_final_link_relocate): Likewise.
> > >         (elf32_arm_gc_sweep_hook): Likewise.
> > >         (elf32_arm_gc_mark_extra_sections): Mark sections holding
> > >         ARMv8-M
> > >         secure entry functions.
> > >         (arm_stub_is_thumb): Add case for
> > >         arm_stub_cmse_branch_thumb_only.
> > >         (arm_dedicated_stub_output_section_required): Change to a switch
> > > 
> > > case and add a case for arm_stub_cmse_branch_thumb_only.
> > > 
> > >         (arm_dedicated_stub_output_section_required_alignment):
> > >         Likewise.
> > >         (arm_stub_dedicated_output_section_name): Likewise.
> > >         (arm_stub_dedicated_input_section_ptr): Likewise and remove
> > >         ATTRIBUTE_UNUSED for htab parameter.
> > >         (arm_stub_required_alignment): Likewise.
> > >         (arm_stub_sym_claimed): Likewise.
> > >         (arm_dedicated_stub_section_padding): Likewise.
> > >         (cmse_scan): New function.
> > >         (elf32_arm_size_stubs): Call cmse_scan for ARM M profile
> > >         targets.
> > >         Set stub_changed to TRUE if such veneers were created.
> > >         (elf32_arm_swap_symbol_in): Add detection code for CMSE special
> > >         symbols.
> > > 
> > > *** include/elf/ChangeLog ***
> > > 
> > > 2015-12-16  Thomas Preud'homme  <thomas.preudhomme@arm.com>
> > > 
> > >         * arm.h (ARM_GET_SYM_CMSE_SPCL): Define macro.
> > >         (ARM_SET_SYM_CMSE_SPCL): Likewise.
> > > 
> > > *** ld/ChangeLog ***
> > > 
> > > 2016-02-17  Thomas Preud'homme  <thomas.preudhomme@arm.com>
> > > 
> > >         * ld.texinfo (Placement of SG veneers): New concept entry.
> > >         * testsuite/ld-arm/arm-elf.exp
> > >         (Secure gateway veneers: no .gnu.sgstubs section): New test.
> > >         (Secure gateway veneers: wrong entry functions): Likewise.
> > >         (Secure gateway veneers (ARMv8-M Baseline)): Likewise.
> > >         (Secure gateway veneers (ARMv8-M Mainline)): Likewise.
> > >         * testsuite/ld-arm/cmse-veneers.s: New file.
> > >         * testsuite/ld-arm/cmse-veneers.d: Likewise.
> > >         * testsuite/ld-arm/cmse-veneers.rd: Likewise.
> > >         * testsuite/ld-arm/cmse-veneers.sd: Likewise.
> > >         * testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out: Likewise.
> > >         * testsuite/ld-arm/cmse-veneers-wrong-entryfct.out: Likewise.
> > > 
> > > Best regards,
> > > 
> > > Thomas

[-- Attachment #2: sg_veneers_support.patch --]
[-- Type: text/x-patch, Size: 28720 bytes --]

diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 8de01b46671cd2ac1cbd94ef4373db439a62a9c4..b5da179d266845c6bf2aa1c9359507a2c1f0e1d1 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -2138,6 +2138,8 @@ typedef unsigned short int insn16;
 
 #define STUB_ENTRY_NAME   "__%s_veneer"
 
+#define CMSE_PREFIX "__acle_se_"
+
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
 #define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
@@ -2543,6 +2545,13 @@ static const insn_sequence elf32_arm_stub_long_branch_arm_nacl_pic[] =
   DATA_WORD (0, R_ARM_NONE, 0),         /* .word 0 */
 };
 
+/* Stub used for transition to secure state (aka SG veneer).  */
+static const insn_sequence elf32_arm_stub_cmse_branch_thumb_only[] =
+{
+  THUMB32_INSN (0xe97fe97f),		/* sg.  */
+  THUMB32_B_INSN (0xf000b800, -4),	/* b.w original_branch_dest.  */
+};
+
 
 /* Cortex-A8 erratum-workaround stubs.  */
 
@@ -2622,6 +2631,7 @@ static const insn_sequence elf32_arm_stub_a8_veneer_blx[] =
   DEF_STUB(long_branch_v4t_thumb_tls_pic) \
   DEF_STUB(long_branch_arm_nacl) \
   DEF_STUB(long_branch_arm_nacl_pic) \
+  DEF_STUB(cmse_branch_thumb_only) \
   DEF_STUB(a8_veneer_b_cond) \
   DEF_STUB(a8_veneer_b) \
   DEF_STUB(a8_veneer_bl) \
@@ -3172,6 +3182,9 @@ struct elf32_arm_link_hash_table
      information on stub grouping.  */
   struct map_stub *stub_group;
 
+  /* Input stub section holding secure gateway veneers.  */
+  asection *cmse_stub_sec;
+
   /* Number of elements in stub_group.  */
   unsigned int top_id;
 
@@ -3320,12 +3333,16 @@ elf32_arm_create_local_iplt (bfd *abfd, unsigned long r_symndx)
    union and *ARM_PLT at the ARM-specific information.  */
 
 static bfd_boolean
-elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_entry *h,
+elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_table *globals,
+			struct elf32_arm_link_hash_entry *h,
 			unsigned long r_symndx, union gotplt_union **root_plt,
 			struct arm_plt_info **arm_plt)
 {
   struct arm_local_iplt_info *local_iplt;
 
+  if (globals->root.splt == NULL && globals->root.iplt == NULL)
+    return FALSE;
+
   if (h != NULL)
     {
       *root_plt = &h->root.plt;
@@ -3786,6 +3803,7 @@ arm_stub_is_thumb (enum elf32_arm_stub_type stub_type)
     case arm_stub_long_branch_v4t_thumb_arm_pic:
     case arm_stub_long_branch_v4t_thumb_tls_pic:
     case arm_stub_long_branch_thumb_only_pic:
+    case arm_stub_cmse_branch_thumb_only:
       return TRUE;
     case arm_stub_none:
       BFD_FAIL ();
@@ -3851,8 +3869,9 @@ arm_type_of_stub (struct bfd_link_info *info,
      the address of the appropriate trampoline.  */
   if (r_type != R_ARM_TLS_CALL
       && r_type != R_ARM_THM_TLS_CALL
-      && elf32_arm_get_plt_info (input_bfd, hash, ELF32_R_SYM (rel->r_info),
-				 &root_plt, &arm_plt)
+      && elf32_arm_get_plt_info (input_bfd, globals, hash,
+				 ELF32_R_SYM (rel->r_info), &root_plt,
+				 &arm_plt)
       && root_plt->offset != (bfd_vma) -1)
     {
       asection *splt;
@@ -4163,7 +4182,16 @@ arm_dedicated_stub_output_section_required (enum elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  return FALSE;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Required alignment (as a power of 2) for the dedicated section holding
@@ -4177,8 +4205,19 @@ arm_dedicated_stub_output_section_required_alignment
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
-  return 0;
+  switch (stub_type)
+    {
+    /* Vectors of Secure Gateway veneers must be aligned on 32byte
+       boundary.  */
+    case arm_stub_cmse_branch_thumb_only:
+      return 5;
+
+    default:
+      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
+      return 0;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Name of the dedicated output section to put veneers of type STUB_TYPE, or
@@ -4190,8 +4229,17 @@ arm_dedicated_stub_output_section_name (enum elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
-  return NULL;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return ".gnu.sgstubs";
+
+    default:
+      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
+      return NULL;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* If veneers of type STUB_TYPE should go in a dedicated output section,
@@ -4199,15 +4247,23 @@ arm_dedicated_stub_output_section_name (enum elf32_arm_stub_type stub_type)
    corresponding input section.  Otherwise, returns NULL.  */
 
 static asection **
-arm_dedicated_stub_input_section_ptr
-  (struct elf32_arm_link_hash_table *htab ATTRIBUTE_UNUSED,
-   enum elf32_arm_stub_type stub_type)
+arm_dedicated_stub_input_section_ptr (struct elf32_arm_link_hash_table *htab,
+				      enum elf32_arm_stub_type stub_type)
 {
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
-  return NULL;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return &htab->cmse_stub_sec;
+
+    default:
+      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
+      return NULL;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Find or create a stub section to contain a stub of type STUB_TYPE.  SECTION
@@ -4429,6 +4485,7 @@ arm_stub_required_alignment (enum elf32_arm_stub_type stub_type)
     case arm_stub_long_branch_thumb_only_pic:
     case arm_stub_long_branch_any_tls_pic:
     case arm_stub_long_branch_v4t_thumb_tls_pic:
+    case arm_stub_cmse_branch_thumb_only:
     case arm_stub_a8_veneer_blx:
       return 4;
 
@@ -4450,7 +4507,16 @@ arm_stub_sym_claimed (enum elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  return FALSE;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 /* Returns the padding needed for the dedicated section used stubs of type
@@ -4462,7 +4528,16 @@ arm_dedicated_stub_section_padding (enum elf32_arm_stub_type stub_type)
   if (stub_type >= max_stub_type)
     abort ();  /* Should be unreachable.  */
 
-  return 0;
+  switch (stub_type)
+    {
+    case arm_stub_cmse_branch_thumb_only:
+      return 32;
+
+    default:
+      return 0;
+    }
+
+  abort ();  /* Should be unreachable.  */
 }
 
 static bfd_boolean
@@ -5353,6 +5428,204 @@ elf32_arm_create_stub (struct elf32_arm_link_hash_table *htab,
   return TRUE;
 }
 
+/* Scan symbols in INPUT_BFD to identify secure entry functions needing a
+   gateway veneer to transition from non secure to secure state and create them
+   accordingly.
+
+   "ARMv8-M Security Extensions: Requirements on Development Tools" document
+   defines the conditions that govern Secure Gateway veneer creation for a
+   given symbol <SYM> as follows:
+   - it has function type
+   - it has non local binding
+   - a symbol named __acle_se_<SYM> (called special symbol) exists with the
+     same type, binding and value as <SYM> (called normal symbol).
+   An entry function can handle secure state transition itself in which case
+   its special symbol would have a different value from the normal symbol.
+
+   OUT_ATTR gives the output attributes, SYM_HASHES the symbol index to hash
+   entry mapping while HTAB gives the name to hash entry mapping.
+
+   If any secure gateway veneer is created, *STUB_CHANGED is set to TRUE.  The
+   return value gives whether a stub failed to be allocated.  */
+
+static bfd_boolean
+cmse_scan (bfd *input_bfd, struct elf32_arm_link_hash_table *htab,
+	   obj_attribute *out_attr, struct elf_link_hash_entry **sym_hashes,
+	   bfd_boolean *stub_changed)
+{
+  const struct elf_backend_data *bed;
+  Elf_Internal_Shdr *symtab_hdr;
+  unsigned i, j, sym_count, ext_start;
+  Elf_Internal_Sym *cmse_sym, *local_syms;
+  struct elf32_arm_link_hash_entry *hash, *cmse_hash = NULL;
+  enum arm_st_branch_type branch_type;
+  char *sym_name, *lsym_name;
+  bfd_vma sym_value;
+  asection *section;
+  bfd_boolean is_v8m, new_stub, created_stub, cmse_invalid, ret = TRUE;
+
+  bed = get_elf_backend_data (input_bfd);
+  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym;
+  ext_start = symtab_hdr->sh_info;
+  is_v8m = (out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE
+	    && out_attr[Tag_CPU_arch_profile].i == 'M');
+
+  local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+  if (local_syms == NULL)
+    local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
+				       symtab_hdr->sh_info, 0, NULL, NULL,
+				       NULL);
+  if (symtab_hdr->sh_info && local_syms == NULL)
+    return FALSE;
+
+  /* Scan symbols.  */
+  for (i = 0; i < sym_count; i++)
+    {
+      cmse_invalid = FALSE;
+
+      if (i < ext_start)
+	{
+	  cmse_sym = &local_syms[i];
+	  /* Not a special symbol.  */
+	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_sym->st_target_internal))
+	    continue;
+	  sym_name = bfd_elf_string_from_elf_section (input_bfd,
+						      symtab_hdr->sh_link,
+						      cmse_sym->st_name);
+	  /* Special symbol with local binding.  */
+	  cmse_invalid = TRUE;
+	}
+      else
+	{
+	  cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]);
+	  sym_name = (char *) cmse_hash->root.root.root.string;
+
+	  /* Not a special symbol.  */
+	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal))
+	    continue;
+
+	  /* Special symbol has incorrect binding or type.  */
+	  if ((cmse_hash->root.root.type != bfd_link_hash_defined
+	       && cmse_hash->root.root.type != bfd_link_hash_defweak)
+	      || cmse_hash->root.type != STT_FUNC)
+	    cmse_invalid = TRUE;
+	}
+
+      if (!is_v8m)
+	{
+	  (*_bfd_error_handler) (_("%B: Special symbol `%s' only allowed for "
+				   "ARMv8-M architecture or later."),
+				 input_bfd, sym_name);
+	  is_v8m = TRUE; /* Avoid multiple warning.  */
+	  ret = FALSE;
+	}
+
+      if (cmse_invalid)
+	{
+	  (*_bfd_error_handler) (_("%B: invalid special symbol `%s'."),
+				 input_bfd, sym_name);
+	  (*_bfd_error_handler) (_("It must be a global or weak function "
+				   "symbol."));
+	  ret = FALSE;
+	  if (i < ext_start)
+	    continue;
+	}
+
+      sym_name += strlen (CMSE_PREFIX);
+      hash = (struct elf32_arm_link_hash_entry *)
+	elf_link_hash_lookup (&(htab)->root, sym_name, FALSE, FALSE, TRUE);
+
+      /* No associated normal symbol or it is neither global nor weak.  */
+      if (!hash
+	  || (hash->root.root.type != bfd_link_hash_defined
+	      && hash->root.root.type != bfd_link_hash_defweak)
+	  || hash->root.type != STT_FUNC)
+	{
+	  /* Initialize here to avoid warning about use of possibly
+	     uninitialized variable.  */
+	  j = 0;
+
+	  if (!hash)
+	    {
+	      /* Searching for a normal symbol with local binding.  */
+	      for (; j < ext_start; j++)
+		{
+		  lsym_name =
+		    bfd_elf_string_from_elf_section (input_bfd,
+						     symtab_hdr->sh_link,
+						     local_syms[j].st_name);
+		  if (!strcmp (sym_name, lsym_name))
+		    break;
+		}
+	    }
+
+	  if (hash || j < ext_start)
+	    {
+	      (*_bfd_error_handler)
+		(_("%B: invalid standard symbol `%s'."), input_bfd, sym_name);
+	      (*_bfd_error_handler)
+		(_("It must be a global or weak function symbol."));
+	    }
+	  else
+	    (*_bfd_error_handler)
+	      (_("%B: absent standard symbol `%s'."), input_bfd, sym_name);
+	  ret = FALSE;
+	  if (!hash)
+	    continue;
+	}
+
+      sym_value = hash->root.root.u.def.value;
+      section = hash->root.root.u.def.section;
+
+      if (cmse_hash->root.root.u.def.section != section)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: `%s' and its special symbol are in different sections."),
+	     input_bfd, sym_name);
+	  ret = FALSE;
+	}
+      if (cmse_hash->root.root.u.def.value != sym_value)
+	continue; /* Ignore: could be an entry function starting with SG.  */
+
+	/* If this section is a link-once section that will be discarded, then
+	   don't create any stubs.  */
+      if (section->output_section == NULL)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: entry function `%s' not output."), input_bfd, sym_name);
+	  continue;
+	}
+
+      if (hash->root.size == 0)
+	{
+	  (*_bfd_error_handler)
+	    (_("%B: entry function `%s' is empty."), input_bfd, sym_name);
+	  ret = FALSE;
+	}
+
+      if (!ret)
+	continue;
+      branch_type = ARM_GET_SYM_BRANCH_TYPE (hash->root.target_internal);
+      created_stub
+	= elf32_arm_create_stub (htab, arm_stub_cmse_branch_thumb_only,
+				 NULL, NULL, section, hash, sym_name,
+				 sym_value, branch_type, &new_stub);
+
+      if (!created_stub)
+	 ret = FALSE;
+      else
+	{
+	  BFD_ASSERT (new_stub);
+	  *stub_changed = TRUE;
+	}
+    }
+
+  if (!symtab_hdr->contents)
+    free (local_syms);
+  return ret;
+}
+
 /* Determine and set the size of the stub section for a final link.
 
    The basic idea here is to examine all the relocations looking for
@@ -5369,8 +5642,9 @@ elf32_arm_size_stubs (bfd *output_bfd,
 						      unsigned int),
 		      void (*layout_sections_again) (void))
 {
+  obj_attribute *out_attr;
   bfd_size_type stub_group_size;
-  bfd_boolean stubs_always_after_branch;
+  bfd_boolean m_profile, stubs_always_after_branch, first_veneer_scan = TRUE;
   struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
   struct a8_erratum_fix *a8_fixes = NULL;
   unsigned int num_a8_fixes = 0, a8_fix_table_size = 10;
@@ -5399,6 +5673,8 @@ elf32_arm_size_stubs (bfd *output_bfd,
   htab->layout_sections_again = layout_sections_again;
   stubs_always_after_branch = group_size < 0;
 
+  out_attr = elf_known_obj_attributes_proc (output_bfd);
+  m_profile = out_attr[Tag_CPU_arch_profile].i == 'M';
   /* The Cortex-A8 erratum fix depends on stubs not being in the same 4K page
      as the first half of a 32-bit branch straddling two 4K pages.  This is a
      crude way of enforcing that.  */
@@ -5464,6 +5740,18 @@ elf32_arm_size_stubs (bfd *output_bfd,
 	  if (symtab_hdr->sh_info == 0)
 	    continue;
 
+	  /* Limit scan of symbols to object file whose profile is
+	     Microcontroller to not hinder performance in the general case.  */
+	  if (m_profile && first_veneer_scan)
+	    {
+	      struct elf_link_hash_entry **sym_hashes;
+
+	      sym_hashes = elf_sym_hashes (input_bfd);
+	      if (!cmse_scan (input_bfd, htab, out_attr, sym_hashes,
+			      &stub_changed))
+		goto error_ret_free_local;
+	    }
+
 	  /* Walk over each section attached to the input bfd.  */
 	  for (section = input_bfd->sections;
 	       section != NULL;
@@ -5850,6 +6138,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
 
       /* Ask the linker to do its stuff.  */
       (*htab->layout_sections_again) ();
+      first_veneer_scan = FALSE;
     }
 
   /* Add stubs for Cortex-A8 erratum fixes now.  */
@@ -9191,7 +9480,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
   /* Find out whether the symbol has a PLT.  Set ST_VALUE, BRANCH_TYPE and
      VALUE appropriately for relocations that we resolve at link time.  */
   has_iplt_entry = FALSE;
-  if (elf32_arm_get_plt_info (input_bfd, eh, r_symndx, &root_plt, &arm_plt)
+  if (elf32_arm_get_plt_info (input_bfd, globals, eh, r_symndx, &root_plt,
+			      &arm_plt)
       && root_plt->offset != (bfd_vma) -1)
     {
       plt_offset = root_plt->offset;
@@ -13603,7 +13893,8 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
 	}
 
       if (may_need_local_target_p
-	  && elf32_arm_get_plt_info (abfd, eh, r_symndx, &root_plt, &arm_plt))
+	  && elf32_arm_get_plt_info (abfd, globals, eh, r_symndx, &root_plt,
+				     &arm_plt))
 	{
 	  /* If PLT refcount book-keeping is wrong and too low, we'll
 	     see a zero value (going to -1) for the root PLT reference
@@ -14071,7 +14362,11 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
 }
 
 /* Unwinding tables are not referenced directly.  This pass marks them as
-   required if the corresponding code section is marked.  */
+   required if the corresponding code section is marked.  Similarly, ARMv8-M
+   secure entry functions can only be referenced by SG veneers which are
+   created after the GC process. They need to be marked in case they reside in
+   their own section (as would be the case if code was compiled with
+   -ffunction-sections).  */
 
 static bfd_boolean
 elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
@@ -14079,10 +14374,21 @@ elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
 {
   bfd *sub;
   Elf_Internal_Shdr **elf_shdrp;
-  bfd_boolean again;
+  asection *cmse_sec;
+  obj_attribute *out_attr;
+  Elf_Internal_Shdr *symtab_hdr;
+  unsigned i, sym_count, ext_start;
+  const struct elf_backend_data *bed;
+  struct elf_link_hash_entry **sym_hashes;
+  struct elf32_arm_link_hash_entry *cmse_hash;
+  bfd_boolean again, is_v8m, first_bfd_browse = TRUE;
 
   _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
 
+  out_attr = elf_known_obj_attributes_proc (info->output_bfd);
+  is_v8m = out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE
+	   && out_attr[Tag_CPU_arch_profile].i == 'M';
+
   /* Marking EH data may cause additional code sections to be marked,
      requiring multiple passes.  */
   again = TRUE;
@@ -14113,7 +14419,34 @@ elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
 		    return FALSE;
 		}
 	    }
+
+	  /* Mark section holding ARMv8-M secure entry functions.  We mark all
+	     of them so no need for a second browsing.  */
+	  if (is_v8m && first_bfd_browse)
+	    {
+	      sym_hashes = elf_sym_hashes (sub);
+	      bed = get_elf_backend_data (sub);
+	      symtab_hdr = &elf_tdata (sub)->symtab_hdr;
+	      sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym;
+	      ext_start = symtab_hdr->sh_info;
+
+	      /* Scan symbols.  */
+	      for (i = ext_start; i < sym_count; i++)
+		{
+		  cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]);
+
+		  /* Assume it is a special symbol.  If not, cmse_scan will
+		     warn about it and user can do something about it.  */
+		  if (ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal))
+		    {
+		      cmse_sec = cmse_hash->root.root.u.def.section;
+		      if (!_bfd_elf_gc_mark (info, cmse_sec, gc_mark_hook))
+			return FALSE;
+		    }
+		}
+	    }
 	}
+      first_bfd_browse = FALSE;
     }
 
   return TRUE;
@@ -17765,6 +18098,9 @@ elf32_arm_swap_symbol_in (bfd * abfd,
 			  const void *pshn,
 			  Elf_Internal_Sym *dst)
 {
+  Elf_Internal_Shdr *symtab_hdr;
+  const char *name = NULL;
+
   if (!bfd_elf32_swap_symbol_in (abfd, psrc, pshn, dst))
     return FALSE;
   dst->st_target_internal = 0;
@@ -17793,6 +18129,13 @@ elf32_arm_swap_symbol_in (bfd * abfd,
   else
     ARM_SET_SYM_BRANCH_TYPE (dst->st_target_internal, ST_BRANCH_UNKNOWN);
 
+  /* Mark CMSE special symbols.  */
+  symtab_hdr = & elf_symtab_hdr (abfd);
+  if (symtab_hdr->sh_size)
+    name = bfd_elf_sym_name (abfd, symtab_hdr, dst, NULL);
+  if (name && CONST_STRNEQ (name, CMSE_PREFIX))
+    ARM_SET_SYM_CMSE_SPCL (dst->st_target_internal);
+
   return TRUE;
 }
 
diff --git a/include/elf/arm.h b/include/elf/arm.h
index bafc03c52ee686671e847eff272ab5cc8a79398c..abad4731b335485f34a06b45d7edea475cfb321b 100644
--- a/include/elf/arm.h
+++ b/include/elf/arm.h
@@ -384,4 +384,11 @@ enum arm_st_branch_type {
 	   | ((TYPE) & ENUM_ARM_ST_BRANCH_TYPE_BITMASK))
 #endif
 
+/* Get or set whether a symbol is a special symbol of an entry function of CMSE
+   secure code.  */
+#define ARM_GET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
+  (((SYM_TARGET_INTERNAL) >> 2) & 1)
+#define ARM_SET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
+  (SYM_TARGET_INTERNAL) |= 4
+
 #endif /* _ELF_ARM_H */
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index bc16764b0554851217316c438ada863843915307..171ae6e55bc2bf2708a23e822218b8d4e53f8ee6 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -6853,6 +6853,12 @@ entries which only support 512Mb of code.
 The @samp{--no-apply-dynamic-relocs} option makes AArch64 linker do not apply
 link-time values for dynamic relocations.
 
+@cindex Placement of SG veneers
+All SG veneers are placed in the special output section @code{.gnu.sgstubs}.
+Its start address must be set, either with the command line option
+@samp{--section-start} or in a linker script, to indicate where to place these
+veneers in memory.
+
 @ifclear GENERIC
 @lowersections
 @end ifclear
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index db25a8d46c985f89e02ce68c8897923c23101661..84301626fb6ab24a6726315e810249b4375b5fdc 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -633,6 +633,33 @@ set armeabitests_nonacl {
      {{objdump -d jump-reloc-veneers-long.d}}
      "jump-reloc-veneers-long"}
 
+    {"Secure gateway veneers: no .gnu.sgstubs section" "" ""
+     "-march=armv8-m.base -mthumb"
+     {cmse-veneers.s}
+     {{ld cmse-veneers-no-gnu_sgstubs.out}}
+     "cmse-veneers-no-gnu_sgstubs"}
+    {"Secure gateway veneers: wrong entry functions" "" ""
+     "-march=armv7-m -mthumb --defsym CHECK_ERRORS=1"
+     {cmse-veneers.s}
+     {{ld cmse-veneers-wrong-entryfct.out}}
+     "cmse-veneers-wrong-entryfct"}
+    {"Secure gateway veneers (ARMv8-M Baseline)"
+     "-Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --gc-sections" ""
+     "-march=armv8-m.base -mthumb"
+     {cmse-veneers.s}
+     {{objdump {-d -j .gnu.sgstubs} cmse-veneers.d}
+      {objdump {-h -j .gnu.sgstubs} cmse-veneers.sd}
+      {nm {} cmse-veneers.rd}}
+     "cmse-veneers-baseline"}
+    {"Secure gateway veneers (ARMv8-M Mainline)"
+     "-Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --gc-sections" ""
+     "-march=armv8-m.main -mthumb"
+     {cmse-veneers.s}
+     {{objdump {-d -j .gnu.sgstubs} cmse-veneers.d}
+      {objdump {-h -j .gnu.sgstubs} cmse-veneers.sd}
+      {nm {} cmse-veneers.rd}}
+     "cmse-veneers-mainline"}
+
     {"R_ARM_THM_JUMP19 Relocation veneers: Short"
      "--section-start destsect=0x000108002 --section-start .text=0x8000" ""
      "-march=armv7-m -mthumb"
diff --git a/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out b/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out
new file mode 100644
index 0000000000000000000000000000000000000000..9d1e5ba3215ae8a29585fcf04ec1f94314670a29
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out
@@ -0,0 +1,3 @@
+.*: No address assigned to the veneers output section .gnu.sgstubs
+.*: cannot size stub section: Invalid operation
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
new file mode 100644
index 0000000000000000000000000000000000000000..fd4766ab877a4abbeb8b2c4c053ab11d3f86773c
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
@@ -0,0 +1,19 @@
+.*: .*: Special symbol `__acle_se_loc_entry_veneer1' only allowed for ARMv8-M architecture or later.
+.*: .*: invalid .* symbol `.*loc_entry_veneer1'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_loc_entry_veneer2'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_loc_entry_veneer4'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid standard symbol `loc_entry_veneer3'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid standard symbol `loc_entry_veneer5'.
+.*: It must be a global or weak function symbol.
+.*: .*: absent standard symbol `fake_entry_veneer1'.
+.*: .*: invalid standard symbol `obj_entry_veneer1'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid special symbol `__acle_se_obj_entry_veneer2'.
+.*: It must be a global or weak function symbol.
+.*: .*: `fake_entry_veneer2' and its special symbol are in different sections.
+.*: cannot size stub section: Invalid operation
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers.d b/ld/testsuite/ld-arm/cmse-veneers.d
new file mode 100644
index 0000000000000000000000000000000000000000..6a44a2b5dce9de4f5d64fe644e41f5ab9840806e
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.d
@@ -0,0 +1,21 @@
+
+.*
+
+
+Disassembly of section \.gnu.sgstubs:
+
+00020000 <glob_entry_veneer2>:
+   20000:	e97f e97f 	sg
+   20004:	f7e8 b800 	b\.w	8008 <__acle_se_glob_entry_veneer2>
+
+00020008 <weak_entry_veneer2>:
+   20008:	e97f e97f 	sg
+   2000c:	f7e7 bffe 	b\.w	800c <__acle_se_weak_entry_veneer2>
+
+00020010 <glob_entry_veneer1>:
+   20010:	e97f e97f 	sg
+   20014:	f7e7 bff4 	b\.w	8000 <__acle_se_glob_entry_veneer1>
+
+00020018 <weak_entry_veneer1>:
+   20018:	e97f e97f 	sg
+   2001c:	f7e7 bff2 	b\.w	8004 <__acle_se_weak_entry_veneer1>
diff --git a/ld/testsuite/ld-arm/cmse-veneers.rd b/ld/testsuite/ld-arm/cmse-veneers.rd
new file mode 100644
index 0000000000000000000000000000000000000000..20fad961bd8803109c3cf57ef22e3b36da5b1500
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.rd
@@ -0,0 +1,9 @@
+#...
+[0-9a-f]+ T glob_entry_fct
+#...
+[0-9a-f]+ T glob_entry_veneer1
+[0-9a-f]+ T glob_entry_veneer2
+#...
+[0-9a-f]+ W weak_entry_veneer1
+[0-9a-f]+ W weak_entry_veneer2
+#...
diff --git a/ld/testsuite/ld-arm/cmse-veneers.s b/ld/testsuite/ld-arm/cmse-veneers.s
new file mode 100644
index 0000000000000000000000000000000000000000..d5c57f646a78c4736e4f084d8ad6aff7efea554f
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.s
@@ -0,0 +1,97 @@
+	.syntax unified
+	.thumb
+	.file	"foo.c"
+	.text
+
+.macro	decltype	name, type
+.ifc \type,object
+	.data
+.else
+	.thumb
+	.thumb_func
+.endif
+	.type	\name, %\type
+.endm
+
+
+.macro	entry	name, type, vis, typespc, visspc, entry_fct
+	.align	2
+.ifb \visspc
+	.\vis	__acle_se_\name
+.else
+	.\visspc	__acle_se_\name
+.endif
+	.\vis	\name
+	.thumb
+	.thumb_func
+.ifb \typespc
+	decltype	__acle_se_\name, \type
+.else
+	decltype	__acle_se_\name, \typespc
+.endif
+	decltype	\name, \type
+__acle_se_\name:
+	\entry_fct
+\name:
+.ifc \type,object
+	.word 42
+.else
+	nop
+.endif
+	.size	\name, .-\name
+	.size	__acle_se_\name, .-__acle_se_\name
+.endm
+
+
+.ifndef CHECK_ERRORS
+	@ Valid setups for veneer generation
+	entry glob_entry_veneer1, function, global
+	entry weak_entry_veneer1, function, weak
+	entry glob_entry_veneer2, function, global, visspc=weak
+	entry weak_entry_veneer2, function, weak, visspc=global
+
+	@ Valid setup for entry function without SG veneer
+	entry glob_entry_fct, function, global, entry_fct=nop
+
+.else
+	@ Invalid setups for veneer generation (visibility)
+	entry loc_entry_veneer1, function, local
+	entry loc_entry_veneer2, function, global, visspc=local
+	entry loc_entry_veneer3, function, local, visspc=global
+	entry loc_entry_veneer4, function, weak, visspc=local
+	entry loc_entry_veneer5, function, local, visspc=weak
+
+	@ Invalid setups for veneer generation (absent standard symbol)
+	.align	2
+	.global	__acle_se_fake_entry_veneer1
+	.thumb
+	.thumb_func
+	.type	__acle_se_fake_entry_veneer1, %function
+__acle_se_fake_entry_veneer1:
+	nop
+	.size	__acle_se_fake_entry_veneer1, .-__acle_se_fake_entry_veneer1
+
+	@ Invalid setups for veneer generation (type)
+	entry obj_entry_veneer1, object, global, typespc=function
+	entry obj_entry_veneer2, function, global, typespc=object
+
+	@ Invalid setup for veneer generation (sections)
+	.section .text.sub1
+	.align	2
+	.thumb
+	.thumb_func
+	.global	__acle_se_fake_entry_veneer2
+	.type	__acle_se_fake_entry_veneer2, %function
+__acle_se_fake_entry_veneer2:
+	nop
+	.size	__acle_se_fake_entry_veneer2, .-__acle_se_fake_entry_veneer2
+	.section .text.sub2
+	.align	2
+	.thumb
+	.thumb_func
+	.global	fake_entry_veneer2
+	.type	fake_entry_veneer2, %function
+fake_entry_veneer2:
+	nop
+	.size	fake_entry_veneer2, .-fake_entry_veneer2
+.endif
diff --git a/ld/testsuite/ld-arm/cmse-veneers.sd b/ld/testsuite/ld-arm/cmse-veneers.sd
new file mode 100644
index 0000000000000000000000000000000000000000..99bfc8f37c25b7a57122b330b1145e27a9b087fd
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-veneers.sd
@@ -0,0 +1,7 @@
+
+.*
+
+Sections:
+Idx Name          Size      VMA       LMA       File off  Algn
+  \d+ \.gnu\.sgstubs  00000020  00020000  00020000  00010000  2\*\*5
+                  CONTENTS, ALLOC, LOAD, READONLY, CODE

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH, binutils, ARM 8/11, ping3] Add support for ARMv8-M Secure Gateway veneer generation
  2016-08-03  8:52             ` [RFC PATCH, binutils, ARM 8/11, ping3] " Thomas Preudhomme
@ 2016-08-04  8:59               ` Richard Earnshaw (lists)
  2016-08-04 15:02                 ` Thomas Preudhomme
  0 siblings, 1 reply; 10+ messages in thread
From: Richard Earnshaw (lists) @ 2016-08-04  8:59 UTC (permalink / raw)
  To: Thomas Preudhomme; +Cc: binutils

On 03/08/16 09:52, Thomas Preudhomme wrote:
> Hi Richard,
> 
> How do you find the reworded comment for cmse_scan?
> 

Yes, much better.  Thanks.

Sorry for the delay replying.  This patch is OK.

R.

> Best regards,
> 
> Thomas
> 
> On Tuesday 26 July 2016 12:07:26 Thomas Preudhomme wrote:
>> Hi Richard,
>>
>> Ping?
>>
>> Best regards,
>>
>> Thomas
>>
>> On Thursday 14 July 2016 10:14:57 Thomas Preudhomme wrote:
>>> Hi Richard,
>>>
>>> On Thursday 07 July 2016 16:27:27 Thomas Preudhomme wrote:
>>>> On Thursday 07 July 2016 11:52:56 Richard Earnshaw wrote:
>>>>> +   As per "ARMv8-M Security Extensions: Requirements on Development
>>>>> Tools"
>>>>> +   document, a secure gateway veneer is needed when there exists a
>>>>> non-local
>>>>> +   function symbol called "normal" symbol (eg. foo) with the same
>>>>> value
>>>>> as a
>>>>> +   symbol with the same type, binding a name save for a __acle_se_
>>>>> prefix,
>>>>> +   called a "special" symbol (eg. __acle_se_foo).  Entry functions
>>>>> handling +   with secure state transition by themselves have these
>>>>> symbols with different
>>>>> +   values.
>>>>>
>>>>>
>>>>> This is very unclear as to what is being/needs to be done.  Can you
>>>>> try
>>>>> redrafting it?
>>>>
>>>> What do you think of the attached updated patch?
>>>
>>> Ping?
>>>
>>>> By the way, I realized I did not copy over the explanation for the
>>>> changes
>>>> to elf32_arm_get_plt_info from the original patch submission. I'm adding
>>>> the full cover letter again here to have all the information in one
>>>> email
>>>> in the archive.
>>>>
>>>>
>>>>
>>>> This patch is part of a patch series to add support for ARMv8-M security
>>>> extension[1] to GNU ld. This specific patch adds support for creating
>>>> ARMv8-M Secure Gateway veneers.
>>>>
>>>> ARM v8-M security extensions require [3] secure gateway veneers to be
>>>> generated for (secure) entry function in order for code to transition
>>>> from
>>>> non-secure state to secure state when calling these entry function.
>>>> Unlike
>>>> other veneers, these veneers are generated independently of relocations,
>>>> ie
>>>> a veneer can be generated in the absence of relocation. The condition
>>>> for
>>>> the generation is that the normal symbol (the one whose name is the same
>>>> as
>>>> in C) of an entry function has the same value as the special symbol
>>>> (normal
>>>> symbol prefixed with "__acle_se_"). When that happens, the normal symbol
>>>> is
>>>> rebound to the veneer generated. When the two symbols have different
>>>> value
>>>> it indicates that the entry function already contains an sg instruction
>>>> to
>>>> do the secure state transition and the normal symbol points to the sg
>>>> instruction while the special symbol points after that.
>>>>
>>>> This patch also makes use of the infrastructure laid out in previous
>>>> patches to control the address of these veneers and to avoid the
>>>> presence
>>>> of the bit pattern of the SG instruction in non secure callable memory,
>>>> as required [4] [5].
>>>>
>>>> Finally, the patch also contains a small change to
>>>> elf32_arm_get_plt_info
>>>> () to return FALSE when there is no PLT, ensuring that a NULL splt is
>>>> not
>>>> dereferenced in the block starting with "If the call goes through" in
>>>> elf32_arm_final_relocate (). This was not necessary before because
>>>> root_plt-
>>>>
>>>>> offset is set to -1 in elf32_arm_adjust_dynamic_symbol called by
>>>>
>>>> _bfd_elf_adjust_dynamic_symbol from bfd_elf_size_dynamic_sections when
>>>> dynobj is not NULL. However, dynobj is set in elf32_arm_check_relocs
>>>> which
>>>> is not called when there is no relocation in the input section. Such a
>>>> situation is possible while still invoking elf32_arm_final_relocate ()
>>>> due
>>>> to SG veneers being created in the absence of relocation but needing
>>>> themselves relocation.
>>>>
>>>> [1] Software requirements for ARMv8-M security extension are described
>>>> in
>>>> document ARM-ECM-0359818 [2]
>>>> [2] Available on http://infocenter.arm.com in Developer guides and
>>>> articles
>>>>
>>>>> Software development > ARM®v8-M Security Extensions: Requirements on
>>>>
>>>> Development Tools
>>>> [3] See section 3.4.3 and requirement 44 of ARM-ECM-0359818 [2]
>>>> [4] requirement 14 and following comment of ARM-ECM-0359818 [2]
>>>> [5] requirement 12 and 13 and following comment of ARM-ECM-0359818 [2]
>>>>
>>>>
>>>> ChangeLog entries remain unchanged:
>>>>
>>>> *** bfd/ChangeLog ***
>>>>
>>>> 2016-05-04  Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>
>>>>         * elf32-arm.c (CMSE_PREFIX): Define macro.
>>>>         (elf32_arm_stub_cmse_branch_thumb_only): Define stub sequence.
>>>>         (cmse_branch_thumb_only): Declare stub.
>>>>         (struct elf32_arm_link_hash_table): Define cmse_stub_sec field.
>>>>         (elf32_arm_get_plt_info): Add globals parameter.  Use it to
>>>>         return
>>>>         FALSE if there is no PLT.
>>>>         (arm_type_of_stub): Adapt to new elf32_arm_get_plt_info
>>>>         signature.
>>>>         (elf32_arm_final_link_relocate): Likewise.
>>>>         (elf32_arm_gc_sweep_hook): Likewise.
>>>>         (elf32_arm_gc_mark_extra_sections): Mark sections holding
>>>>         ARMv8-M
>>>>         secure entry functions.
>>>>         (arm_stub_is_thumb): Add case for
>>>>         arm_stub_cmse_branch_thumb_only.
>>>>         (arm_dedicated_stub_output_section_required): Change to a switch
>>>>
>>>> case and add a case for arm_stub_cmse_branch_thumb_only.
>>>>
>>>>         (arm_dedicated_stub_output_section_required_alignment):
>>>>         Likewise.
>>>>         (arm_stub_dedicated_output_section_name): Likewise.
>>>>         (arm_stub_dedicated_input_section_ptr): Likewise and remove
>>>>         ATTRIBUTE_UNUSED for htab parameter.
>>>>         (arm_stub_required_alignment): Likewise.
>>>>         (arm_stub_sym_claimed): Likewise.
>>>>         (arm_dedicated_stub_section_padding): Likewise.
>>>>         (cmse_scan): New function.
>>>>         (elf32_arm_size_stubs): Call cmse_scan for ARM M profile
>>>>         targets.
>>>>         Set stub_changed to TRUE if such veneers were created.
>>>>         (elf32_arm_swap_symbol_in): Add detection code for CMSE special
>>>>         symbols.
>>>>
>>>> *** include/elf/ChangeLog ***
>>>>
>>>> 2015-12-16  Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>
>>>>         * arm.h (ARM_GET_SYM_CMSE_SPCL): Define macro.
>>>>         (ARM_SET_SYM_CMSE_SPCL): Likewise.
>>>>
>>>> *** ld/ChangeLog ***
>>>>
>>>> 2016-02-17  Thomas Preud'homme  <thomas.preudhomme@arm.com>
>>>>
>>>>         * ld.texinfo (Placement of SG veneers): New concept entry.
>>>>         * testsuite/ld-arm/arm-elf.exp
>>>>         (Secure gateway veneers: no .gnu.sgstubs section): New test.
>>>>         (Secure gateway veneers: wrong entry functions): Likewise.
>>>>         (Secure gateway veneers (ARMv8-M Baseline)): Likewise.
>>>>         (Secure gateway veneers (ARMv8-M Mainline)): Likewise.
>>>>         * testsuite/ld-arm/cmse-veneers.s: New file.
>>>>         * testsuite/ld-arm/cmse-veneers.d: Likewise.
>>>>         * testsuite/ld-arm/cmse-veneers.rd: Likewise.
>>>>         * testsuite/ld-arm/cmse-veneers.sd: Likewise.
>>>>         * testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out: Likewise.
>>>>         * testsuite/ld-arm/cmse-veneers-wrong-entryfct.out: Likewise.
>>>>
>>>> Best regards,
>>>>
>>>> Thomas
>>>>
>>>> sg_veneers_support.patch
>>>>
>>>>
>>>> diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
>>>> index 8de01b46671cd2ac1cbd94ef4373db439a62a9c4..b5da179d266845c6bf2aa1c9359507a2c1f0e1d1 100644
>>>> --- a/bfd/elf32-arm.c
>>>> +++ b/bfd/elf32-arm.c
>>>> @@ -2138,6 +2138,8 @@ typedef unsigned short int insn16;
>>>>  
>>>>  #define STUB_ENTRY_NAME   "__%s_veneer"
>>>>  
>>>> +#define CMSE_PREFIX "__acle_se_"
>>>> +
>>>>  /* The name of the dynamic interpreter.  This is put in the .interp
>>>>     section.  */
>>>>  #define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
>>>> @@ -2543,6 +2545,13 @@ static const insn_sequence elf32_arm_stub_long_branch_arm_nacl_pic[] =
>>>>    DATA_WORD (0, R_ARM_NONE, 0),         /* .word 0 */
>>>>  };
>>>>  
>>>> +/* Stub used for transition to secure state (aka SG veneer).  */
>>>> +static const insn_sequence elf32_arm_stub_cmse_branch_thumb_only[] =
>>>> +{
>>>> +  THUMB32_INSN (0xe97fe97f),		/* sg.  */
>>>> +  THUMB32_B_INSN (0xf000b800, -4),	/* b.w original_branch_dest.  */
>>>> +};
>>>> +
>>>>  
>>>>  /* Cortex-A8 erratum-workaround stubs.  */
>>>>  
>>>> @@ -2622,6 +2631,7 @@ static const insn_sequence elf32_arm_stub_a8_veneer_blx[] =
>>>>    DEF_STUB(long_branch_v4t_thumb_tls_pic) \
>>>>    DEF_STUB(long_branch_arm_nacl) \
>>>>    DEF_STUB(long_branch_arm_nacl_pic) \
>>>> +  DEF_STUB(cmse_branch_thumb_only) \
>>>>    DEF_STUB(a8_veneer_b_cond) \
>>>>    DEF_STUB(a8_veneer_b) \
>>>>    DEF_STUB(a8_veneer_bl) \
>>>> @@ -3172,6 +3182,9 @@ struct elf32_arm_link_hash_table
>>>>       information on stub grouping.  */
>>>>    struct map_stub *stub_group;
>>>>  
>>>> +  /* Input stub section holding secure gateway veneers.  */
>>>> +  asection *cmse_stub_sec;
>>>> +
>>>>    /* Number of elements in stub_group.  */
>>>>    unsigned int top_id;
>>>>  
>>>> @@ -3320,12 +3333,16 @@ elf32_arm_create_local_iplt (bfd *abfd, unsigned long r_symndx)
>>>>     union and *ARM_PLT at the ARM-specific information.  */
>>>>  
>>>>  static bfd_boolean
>>>> -elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_entry *h,
>>>> +elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_table *globals,
>>>> +			struct elf32_arm_link_hash_entry *h,
>>>>  			unsigned long r_symndx, union gotplt_union **root_plt,
>>>>  			struct arm_plt_info **arm_plt)
>>>>  {
>>>>    struct arm_local_iplt_info *local_iplt;
>>>>  
>>>> +  if (globals->root.splt == NULL && globals->root.iplt == NULL)
>>>> +    return FALSE;
>>>> +
>>>>    if (h != NULL)
>>>>      {
>>>>        *root_plt = &h->root.plt;
>>>> @@ -3786,6 +3803,7 @@ arm_stub_is_thumb (enum elf32_arm_stub_type stub_type)
>>>>      case arm_stub_long_branch_v4t_thumb_arm_pic:
>>>>      case arm_stub_long_branch_v4t_thumb_tls_pic:
>>>>      case arm_stub_long_branch_thumb_only_pic:
>>>> +    case arm_stub_cmse_branch_thumb_only:
>>>>        return TRUE;
>>>>      case arm_stub_none:
>>>>        BFD_FAIL ();
>>>> @@ -3851,8 +3869,9 @@ arm_type_of_stub (struct bfd_link_info *info,
>>>>       the address of the appropriate trampoline.  */
>>>>    if (r_type != R_ARM_TLS_CALL
>>>>        && r_type != R_ARM_THM_TLS_CALL
>>>> -      && elf32_arm_get_plt_info (input_bfd, hash, ELF32_R_SYM (rel->r_info),
>>>> -				 &root_plt, &arm_plt)
>>>> +      && elf32_arm_get_plt_info (input_bfd, globals, hash,
>>>> +				 ELF32_R_SYM (rel->r_info), &root_plt,
>>>> +				 &arm_plt)
>>>>        && root_plt->offset != (bfd_vma) -1)
>>>>      {
>>>>        asection *splt;
>>>> @@ -4163,7 +4182,16 @@ arm_dedicated_stub_output_section_required (enum elf32_arm_stub_type stub_type)
>>>>    if (stub_type >= max_stub_type)
>>>>      abort ();  /* Should be unreachable.  */
>>>>  
>>>> -  return FALSE;
>>>> +  switch (stub_type)
>>>> +    {
>>>> +    case arm_stub_cmse_branch_thumb_only:
>>>> +      return TRUE;
>>>> +
>>>> +    default:
>>>> +      return FALSE;
>>>> +    }
>>>> +
>>>> +  abort ();  /* Should be unreachable.  */
>>>>  }
>>>>  
>>>>  /* Required alignment (as a power of 2) for the dedicated section holding
>>>> @@ -4177,8 +4205,19 @@ arm_dedicated_stub_output_section_required_alignment
>>>>    if (stub_type >= max_stub_type)
>>>>      abort ();  /* Should be unreachable.  */
>>>>  
>>>> -  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
>>>> -  return 0;
>>>> +  switch (stub_type)
>>>> +    {
>>>> +    /* Vectors of Secure Gateway veneers must be aligned on 32byte
>>>> +       boundary.  */
>>>> +    case arm_stub_cmse_branch_thumb_only:
>>>> +      return 5;
>>>> +
>>>> +    default:
>>>> +      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
>>>> +      return 0;
>>>> +    }
>>>> +
>>>> +  abort ();  /* Should be unreachable.  */
>>>>  }
>>>>  
>>>>  /* Name of the dedicated output section to put veneers of type STUB_TYPE, or
>>>> @@ -4190,8 +4229,17 @@ arm_dedicated_stub_output_section_name (enum elf32_arm_stub_type stub_type)
>>>>    if (stub_type >= max_stub_type)
>>>>      abort ();  /* Should be unreachable.  */
>>>>  
>>>> -  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
>>>> -  return NULL;
>>>> +  switch (stub_type)
>>>> +    {
>>>> +    case arm_stub_cmse_branch_thumb_only:
>>>> +      return ".gnu.sgstubs";
>>>> +
>>>> +    default:
>>>> +      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
>>>> +      return NULL;
>>>> +    }
>>>> +
>>>> +  abort ();  /* Should be unreachable.  */
>>>>  }
>>>>  
>>>>  /* If veneers of type STUB_TYPE should go in a dedicated output section,
>>>> @@ -4199,15 +4247,23 @@ arm_dedicated_stub_output_section_name (enum elf32_arm_stub_type stub_type)
>>>>     corresponding input section.  Otherwise, returns NULL.  */
>>>>  
>>>>  static asection **
>>>> -arm_dedicated_stub_input_section_ptr
>>>> -  (struct elf32_arm_link_hash_table *htab ATTRIBUTE_UNUSED,
>>>> -   enum elf32_arm_stub_type stub_type)
>>>> +arm_dedicated_stub_input_section_ptr (struct elf32_arm_link_hash_table *htab,
>>>> +				      enum elf32_arm_stub_type stub_type)
>>>>  {
>>>>    if (stub_type >= max_stub_type)
>>>>      abort ();  /* Should be unreachable.  */
>>>>  
>>>> -  BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
>>>> -  return NULL;
>>>> +  switch (stub_type)
>>>> +    {
>>>> +    case arm_stub_cmse_branch_thumb_only:
>>>> +      return &htab->cmse_stub_sec;
>>>> +
>>>> +    default:
>>>> +      BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type));
>>>> +      return NULL;
>>>> +    }
>>>> +
>>>> +  abort ();  /* Should be unreachable.  */
>>>>  }
>>>>  
>>>>  /* Find or create a stub section to contain a stub of type STUB_TYPE.  SECTION
>>>> @@ -4429,6 +4485,7 @@ arm_stub_required_alignment (enum elf32_arm_stub_type stub_type)
>>>>      case arm_stub_long_branch_thumb_only_pic:
>>>>      case arm_stub_long_branch_any_tls_pic:
>>>>      case arm_stub_long_branch_v4t_thumb_tls_pic:
>>>> +    case arm_stub_cmse_branch_thumb_only:
>>>>      case arm_stub_a8_veneer_blx:
>>>>        return 4;
>>>>  
>>>> @@ -4450,7 +4507,16 @@ arm_stub_sym_claimed (enum elf32_arm_stub_type stub_type)
>>>>    if (stub_type >= max_stub_type)
>>>>      abort ();  /* Should be unreachable.  */
>>>>  
>>>> -  return FALSE;
>>>> +  switch (stub_type)
>>>> +    {
>>>> +    case arm_stub_cmse_branch_thumb_only:
>>>> +      return TRUE;
>>>> +
>>>> +    default:
>>>> +      return FALSE;
>>>> +    }
>>>> +
>>>> +  abort ();  /* Should be unreachable.  */
>>>>  }
>>>>  
>>>>  /* Returns the padding needed for the dedicated section used stubs of type
>>>> @@ -4462,7 +4528,16 @@ arm_dedicated_stub_section_padding (enum elf32_arm_stub_type stub_type)
>>>>    if (stub_type >= max_stub_type)
>>>>      abort ();  /* Should be unreachable.  */
>>>>  
>>>> -  return 0;
>>>> +  switch (stub_type)
>>>> +    {
>>>> +    case arm_stub_cmse_branch_thumb_only:
>>>> +      return 32;
>>>> +
>>>> +    default:
>>>> +      return 0;
>>>> +    }
>>>> +
>>>> +  abort ();  /* Should be unreachable.  */
>>>>  }
>>>>  
>>>>  static bfd_boolean
>>>> @@ -5353,6 +5428,204 @@ elf32_arm_create_stub (struct elf32_arm_link_hash_table *htab,
>>>>    return TRUE;
>>>>  }
>>>>  
>>>> +/* Scan symbols in INPUT_BFD to identify secure entry functions needing a
>>>> +   gateway veneer to transition from non secure to secure state and create them
>>>> +   accordingly.
>>>> +
>>>> +   "ARMv8-M Security Extensions: Requirements on Development Tools" document
>>>> +   defines the conditions that govern Secure Gateway veneer creation for a
>>>> +   given symbol <SYM> as follows:
>>>> +   - it has function type
>>>> +   - it has non local binding
>>>> +   - a symbol named __acle_se_<SYM> (called special symbol) exists with the
>>>> +     same type, binding and value as <SYM> (called normal symbol).
>>>> +   An entry function can handle secure state transition itself in which case
>>>> +   its special symbol would have a different value from the normal symbol.
>>>> +
>>>> +   OUT_ATTR gives the output attributes, SYM_HASHES the symbol index to hash
>>>> +   entry mapping while HTAB gives the name to hash entry mapping.
>>>> +
>>>> +   If any secure gateway veneer is created, *STUB_CHANGED is set to TRUE.  The
>>>> +   return value gives whether a stub failed to be allocated.  */
>>>> +
>>>> +static bfd_boolean
>>>> +cmse_scan (bfd *input_bfd, struct elf32_arm_link_hash_table *htab,
>>>> +	   obj_attribute *out_attr, struct elf_link_hash_entry **sym_hashes,
>>>> +	   bfd_boolean *stub_changed)
>>>> +{
>>>> +  const struct elf_backend_data *bed;
>>>> +  Elf_Internal_Shdr *symtab_hdr;
>>>> +  unsigned i, j, sym_count, ext_start;
>>>> +  Elf_Internal_Sym *cmse_sym, *local_syms;
>>>> +  struct elf32_arm_link_hash_entry *hash, *cmse_hash = NULL;
>>>> +  enum arm_st_branch_type branch_type;
>>>> +  char *sym_name, *lsym_name;
>>>> +  bfd_vma sym_value;
>>>> +  asection *section;
>>>> +  bfd_boolean is_v8m, new_stub, created_stub, cmse_invalid, ret = TRUE;
>>>> +
>>>> +  bed = get_elf_backend_data (input_bfd);
>>>> +  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
>>>> +  sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym;
>>>> +  ext_start = symtab_hdr->sh_info;
>>>> +  is_v8m = (out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE
>>>> +	    && out_attr[Tag_CPU_arch_profile].i == 'M');
>>>> +
>>>> +  local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
>>>> +  if (local_syms == NULL)
>>>> +    local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
>>>> +				       symtab_hdr->sh_info, 0, NULL, NULL,
>>>> +				       NULL);
>>>> +  if (symtab_hdr->sh_info && local_syms == NULL)
>>>> +    return FALSE;
>>>> +
>>>> +  /* Scan symbols.  */
>>>> +  for (i = 0; i < sym_count; i++)
>>>> +    {
>>>> +      cmse_invalid = FALSE;
>>>> +
>>>> +      if (i < ext_start)
>>>> +	{
>>>> +	  cmse_sym = &local_syms[i];
>>>> +	  /* Not a special symbol.  */
>>>> +	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_sym->st_target_internal))
>>>> +	    continue;
>>>> +	  sym_name = bfd_elf_string_from_elf_section (input_bfd,
>>>> +						      symtab_hdr->sh_link,
>>>> +						      cmse_sym->st_name);
>>>> +	  /* Special symbol with local binding.  */
>>>> +	  cmse_invalid = TRUE;
>>>> +	}
>>>> +      else
>>>> +	{
>>>> +	  cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]);
>>>> +	  sym_name = (char *) cmse_hash->root.root.root.string;
>>>> +
>>>> +	  /* Not a special symbol.  */
>>>> +	  if (!ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal))
>>>> +	    continue;
>>>> +
>>>> +	  /* Special symbol has incorrect binding or type.  */
>>>> +	  if ((cmse_hash->root.root.type != bfd_link_hash_defined
>>>> +	       && cmse_hash->root.root.type != bfd_link_hash_defweak)
>>>> +	      || cmse_hash->root.type != STT_FUNC)
>>>> +	    cmse_invalid = TRUE;
>>>> +	}
>>>> +
>>>> +      if (!is_v8m)
>>>> +	{
>>>> +	  (*_bfd_error_handler) (_("%B: Special symbol `%s' only allowed for "
>>>> +				   "ARMv8-M architecture or later."),
>>>> +				 input_bfd, sym_name);
>>>> +	  is_v8m = TRUE; /* Avoid multiple warning.  */
>>>> +	  ret = FALSE;
>>>> +	}
>>>> +
>>>> +      if (cmse_invalid)
>>>> +	{
>>>> +	  (*_bfd_error_handler) (_("%B: invalid special symbol `%s'."),
>>>> +				 input_bfd, sym_name);
>>>> +	  (*_bfd_error_handler) (_("It must be a global or weak function "
>>>> +				   "symbol."));
>>>> +	  ret = FALSE;
>>>> +	  if (i < ext_start)
>>>> +	    continue;
>>>> +	}
>>>> +
>>>> +      sym_name += strlen (CMSE_PREFIX);
>>>> +      hash = (struct elf32_arm_link_hash_entry *)
>>>> +	elf_link_hash_lookup (&(htab)->root, sym_name, FALSE, FALSE, TRUE);
>>>> +
>>>> +      /* No associated normal symbol or it is neither global nor weak.  */
>>>> +      if (!hash
>>>> +	  || (hash->root.root.type != bfd_link_hash_defined
>>>> +	      && hash->root.root.type != bfd_link_hash_defweak)
>>>> +	  || hash->root.type != STT_FUNC)
>>>> +	{
>>>> +	  /* Initialize here to avoid warning about use of possibly
>>>> +	     uninitialized variable.  */
>>>> +	  j = 0;
>>>> +
>>>> +	  if (!hash)
>>>> +	    {
>>>> +	      /* Searching for a normal symbol with local binding.  */
>>>> +	      for (; j < ext_start; j++)
>>>> +		{
>>>> +		  lsym_name =
>>>> +		    bfd_elf_string_from_elf_section (input_bfd,
>>>> +						     symtab_hdr->sh_link,
>>>> +						     local_syms[j].st_name);
>>>> +		  if (!strcmp (sym_name, lsym_name))
>>>> +		    break;
>>>> +		}
>>>> +	    }
>>>> +
>>>> +	  if (hash || j < ext_start)
>>>> +	    {
>>>> +	      (*_bfd_error_handler)
>>>> +		(_("%B: invalid standard symbol `%s'."), input_bfd, sym_name);
>>>> +	      (*_bfd_error_handler)
>>>> +		(_("It must be a global or weak function symbol."));
>>>> +	    }
>>>> +	  else
>>>> +	    (*_bfd_error_handler)
>>>> +	      (_("%B: absent standard symbol `%s'."), input_bfd, sym_name);
>>>> +	  ret = FALSE;
>>>> +	  if (!hash)
>>>> +	    continue;
>>>> +	}
>>>> +
>>>> +      sym_value = hash->root.root.u.def.value;
>>>> +      section = hash->root.root.u.def.section;
>>>> +
>>>> +      if (cmse_hash->root.root.u.def.section != section)
>>>> +	{
>>>> +	  (*_bfd_error_handler)
>>>> +	    (_("%B: `%s' and its special symbol are in different sections."),
>>>> +	     input_bfd, sym_name);
>>>> +	  ret = FALSE;
>>>> +	}
>>>> +      if (cmse_hash->root.root.u.def.value != sym_value)
>>>> +	continue; /* Ignore: could be an entry function starting with SG.  */
>>>> +
>>>> +	/* If this section is a link-once section that will be discarded, then
>>>> +	   don't create any stubs.  */
>>>> +      if (section->output_section == NULL)
>>>> +	{
>>>> +	  (*_bfd_error_handler)
>>>> +	    (_("%B: entry function `%s' not output."), input_bfd, sym_name);
>>>> +	  continue;
>>>> +	}
>>>> +
>>>> +      if (hash->root.size == 0)
>>>> +	{
>>>> +	  (*_bfd_error_handler)
>>>> +	    (_("%B: entry function `%s' is empty."), input_bfd, sym_name);
>>>> +	  ret = FALSE;
>>>> +	}
>>>> +
>>>> +      if (!ret)
>>>> +	continue;
>>>> +      branch_type = ARM_GET_SYM_BRANCH_TYPE (hash->root.target_internal);
>>>> +      created_stub
>>>> +	= elf32_arm_create_stub (htab, arm_stub_cmse_branch_thumb_only,
>>>> +				 NULL, NULL, section, hash, sym_name,
>>>> +				 sym_value, branch_type, &new_stub);
>>>> +
>>>> +      if (!created_stub)
>>>> +	 ret = FALSE;
>>>> +      else
>>>> +	{
>>>> +	  BFD_ASSERT (new_stub);
>>>> +	  *stub_changed = TRUE;
>>>> +	}
>>>> +    }
>>>> +
>>>> +  if (!symtab_hdr->contents)
>>>> +    free (local_syms);
>>>> +  return ret;
>>>> +}
>>>> +
>>>>  /* Determine and set the size of the stub section for a final link.
>>>>  
>>>>     The basic idea here is to examine all the relocations looking for
>>>> @@ -5369,8 +5642,9 @@ elf32_arm_size_stubs (bfd *output_bfd,
>>>>  						      unsigned int),
>>>>  		      void (*layout_sections_again) (void))
>>>>  {
>>>> +  obj_attribute *out_attr;
>>>>    bfd_size_type stub_group_size;
>>>> -  bfd_boolean stubs_always_after_branch;
>>>> +  bfd_boolean m_profile, stubs_always_after_branch, first_veneer_scan = TRUE;
>>>>    struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info);
>>>>    struct a8_erratum_fix *a8_fixes = NULL;
>>>>    unsigned int num_a8_fixes = 0, a8_fix_table_size = 10;
>>>> @@ -5399,6 +5673,8 @@ elf32_arm_size_stubs (bfd *output_bfd,
>>>>    htab->layout_sections_again = layout_sections_again;
>>>>    stubs_always_after_branch = group_size < 0;
>>>>  
>>>> +  out_attr = elf_known_obj_attributes_proc (output_bfd);
>>>> +  m_profile = out_attr[Tag_CPU_arch_profile].i == 'M';
>>>>    /* The Cortex-A8 erratum fix depends on stubs not being in the same 4K page
>>>>       as the first half of a 32-bit branch straddling two 4K pages.  This is a
>>>>       crude way of enforcing that.  */
>>>> @@ -5464,6 +5740,18 @@ elf32_arm_size_stubs (bfd *output_bfd,
>>>>  	  if (symtab_hdr->sh_info == 0)
>>>>  	    continue;
>>>>  
>>>> +	  /* Limit scan of symbols to object file whose profile is
>>>> +	     Microcontroller to not hinder performance in the general case.  */
>>>> +	  if (m_profile && first_veneer_scan)
>>>> +	    {
>>>> +	      struct elf_link_hash_entry **sym_hashes;
>>>> +
>>>> +	      sym_hashes = elf_sym_hashes (input_bfd);
>>>> +	      if (!cmse_scan (input_bfd, htab, out_attr, sym_hashes,
>>>> +			      &stub_changed))
>>>> +		goto error_ret_free_local;
>>>> +	    }
>>>> +
>>>>  	  /* Walk over each section attached to the input bfd.  */
>>>>  	  for (section = input_bfd->sections;
>>>>  	       section != NULL;
>>>> @@ -5850,6 +6138,7 @@ elf32_arm_size_stubs (bfd *output_bfd,
>>>>  
>>>>        /* Ask the linker to do its stuff.  */
>>>>        (*htab->layout_sections_again) ();
>>>> +      first_veneer_scan = FALSE;
>>>>      }
>>>>  
>>>>    /* Add stubs for Cortex-A8 erratum fixes now.  */
>>>> @@ -9191,7 +9480,8 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
>>>>    /* Find out whether the symbol has a PLT.  Set ST_VALUE, BRANCH_TYPE and
>>>>       VALUE appropriately for relocations that we resolve at link time.  */
>>>>    has_iplt_entry = FALSE;
>>>> -  if (elf32_arm_get_plt_info (input_bfd, eh, r_symndx, &root_plt, &arm_plt)
>>>> +  if (elf32_arm_get_plt_info (input_bfd, globals, eh, r_symndx, &root_plt,
>>>> +			      &arm_plt)
>>>>        && root_plt->offset != (bfd_vma) -1)
>>>>      {
>>>>        plt_offset = root_plt->offset;
>>>> @@ -13603,7 +13893,8 @@ elf32_arm_gc_sweep_hook (bfd *                     abfd,
>>>>  	}
>>>>  
>>>>        if (may_need_local_target_p
>>>> -	  && elf32_arm_get_plt_info (abfd, eh, r_symndx, &root_plt, &arm_plt))
>>>> +	  && elf32_arm_get_plt_info (abfd, globals, eh, r_symndx, &root_plt,
>>>> +				     &arm_plt))
>>>>  	{
>>>>  	  /* If PLT refcount book-keeping is wrong and too low, we'll
>>>>  	     see a zero value (going to -1) for the root PLT reference
>>>> @@ -14071,7 +14362,11 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
>>>>  }
>>>>  
>>>>  /* Unwinding tables are not referenced directly.  This pass marks them as
>>>> -   required if the corresponding code section is marked.  */
>>>> +   required if the corresponding code section is marked.  Similarly, ARMv8-M
>>>> +   secure entry functions can only be referenced by SG veneers which are
>>>> +   created after the GC process. They need to be marked in case they reside in
>>>> +   their own section (as would be the case if code was compiled with
>>>> +   -ffunction-sections).  */
>>>>  
>>>>  static bfd_boolean
>>>>  elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
>>>> @@ -14079,10 +14374,21 @@ elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
>>>>  {
>>>>    bfd *sub;
>>>>    Elf_Internal_Shdr **elf_shdrp;
>>>> -  bfd_boolean again;
>>>> +  asection *cmse_sec;
>>>> +  obj_attribute *out_attr;
>>>> +  Elf_Internal_Shdr *symtab_hdr;
>>>> +  unsigned i, sym_count, ext_start;
>>>> +  const struct elf_backend_data *bed;
>>>> +  struct elf_link_hash_entry **sym_hashes;
>>>> +  struct elf32_arm_link_hash_entry *cmse_hash;
>>>> +  bfd_boolean again, is_v8m, first_bfd_browse = TRUE;
>>>>  
>>>>    _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook);
>>>>  
>>>> +  out_attr = elf_known_obj_attributes_proc (info->output_bfd);
>>>> +  is_v8m = out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE
>>>> +	   && out_attr[Tag_CPU_arch_profile].i == 'M';
>>>> +
>>>>    /* Marking EH data may cause additional code sections to be marked,
>>>>       requiring multiple passes.  */
>>>>    again = TRUE;
>>>> @@ -14113,7 +14419,34 @@ elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info,
>>>>  		    return FALSE;
>>>>  		}
>>>>  	    }
>>>> +
>>>> +	  /* Mark section holding ARMv8-M secure entry functions.  We mark all
>>>> +	     of them so no need for a second browsing.  */
>>>> +	  if (is_v8m && first_bfd_browse)
>>>> +	    {
>>>> +	      sym_hashes = elf_sym_hashes (sub);
>>>> +	      bed = get_elf_backend_data (sub);
>>>> +	      symtab_hdr = &elf_tdata (sub)->symtab_hdr;
>>>> +	      sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym;
>>>> +	      ext_start = symtab_hdr->sh_info;
>>>> +
>>>> +	      /* Scan symbols.  */
>>>> +	      for (i = ext_start; i < sym_count; i++)
>>>> +		{
>>>> +		  cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]);
>>>> +
>>>> +		  /* Assume it is a special symbol.  If not, cmse_scan will
>>>> +		     warn about it and user can do something about it.  */
>>>> +		  if (ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal))
>>>> +		    {
>>>> +		      cmse_sec = cmse_hash->root.root.u.def.section;
>>>> +		      if (!_bfd_elf_gc_mark (info, cmse_sec, gc_mark_hook))
>>>> +			return FALSE;
>>>> +		    }
>>>> +		}
>>>> +	    }
>>>>  	}
>>>> +      first_bfd_browse = FALSE;
>>>>      }
>>>>  
>>>>    return TRUE;
>>>> @@ -17765,6 +18098,9 @@ elf32_arm_swap_symbol_in (bfd * abfd,
>>>>  			  const void *pshn,
>>>>  			  Elf_Internal_Sym *dst)
>>>>  {
>>>> +  Elf_Internal_Shdr *symtab_hdr;
>>>> +  const char *name = NULL;
>>>> +
>>>>    if (!bfd_elf32_swap_symbol_in (abfd, psrc, pshn, dst))
>>>>      return FALSE;
>>>>    dst->st_target_internal = 0;
>>>> @@ -17793,6 +18129,13 @@ elf32_arm_swap_symbol_in (bfd * abfd,
>>>>    else
>>>>      ARM_SET_SYM_BRANCH_TYPE (dst->st_target_internal, ST_BRANCH_UNKNOWN);
>>>>  
>>>> +  /* Mark CMSE special symbols.  */
>>>> +  symtab_hdr = & elf_symtab_hdr (abfd);
>>>> +  if (symtab_hdr->sh_size)
>>>> +    name = bfd_elf_sym_name (abfd, symtab_hdr, dst, NULL);
>>>> +  if (name && CONST_STRNEQ (name, CMSE_PREFIX))
>>>> +    ARM_SET_SYM_CMSE_SPCL (dst->st_target_internal);
>>>> +
>>>>    return TRUE;
>>>>  }
>>>>  
>>>> diff --git a/include/elf/arm.h b/include/elf/arm.h
>>>> index bafc03c52ee686671e847eff272ab5cc8a79398c..abad4731b335485f34a06b45d7edea475cfb321b 100644
>>>> --- a/include/elf/arm.h
>>>> +++ b/include/elf/arm.h
>>>> @@ -384,4 +384,11 @@ enum arm_st_branch_type {
>>>>  	   | ((TYPE) & ENUM_ARM_ST_BRANCH_TYPE_BITMASK))
>>>>  #endif
>>>>  
>>>> +/* Get or set whether a symbol is a special symbol of an entry function of CMSE
>>>> +   secure code.  */
>>>> +#define ARM_GET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
>>>> +  (((SYM_TARGET_INTERNAL) >> 2) & 1)
>>>> +#define ARM_SET_SYM_CMSE_SPCL(SYM_TARGET_INTERNAL) \
>>>> +  (SYM_TARGET_INTERNAL) |= 4
>>>> +
>>>>  #endif /* _ELF_ARM_H */
>>>> diff --git a/ld/ld.texinfo b/ld/ld.texinfo
>>>> index bc16764b0554851217316c438ada863843915307..171ae6e55bc2bf2708a23e822218b8d4e53f8ee6 100644
>>>> --- a/ld/ld.texinfo
>>>> +++ b/ld/ld.texinfo
>>>> @@ -6853,6 +6853,12 @@ entries which only support 512Mb of code.
>>>>  The @samp{--no-apply-dynamic-relocs} option makes AArch64 linker do not apply
>>>>  link-time values for dynamic relocations.
>>>>  
>>>> +@cindex Placement of SG veneers
>>>> +All SG veneers are placed in the special output section @code{.gnu.sgstubs}.
>>>> +Its start address must be set, either with the command line option
>>>> +@samp{--section-start} or in a linker script, to indicate where to place these
>>>> +veneers in memory.
>>>> +
>>>>  @ifclear GENERIC
>>>>  @lowersections
>>>>  @end ifclear
>>>> diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
>>>> index db25a8d46c985f89e02ce68c8897923c23101661..84301626fb6ab24a6726315e810249b4375b5fdc 100644
>>>> --- a/ld/testsuite/ld-arm/arm-elf.exp
>>>> +++ b/ld/testsuite/ld-arm/arm-elf.exp
>>>> @@ -633,6 +633,33 @@ set armeabitests_nonacl {
>>>>       {{objdump -d jump-reloc-veneers-long.d}}
>>>>       "jump-reloc-veneers-long"}
>>>>  
>>>> +    {"Secure gateway veneers: no .gnu.sgstubs section" "" ""
>>>> +     "-march=armv8-m.base -mthumb"
>>>> +     {cmse-veneers.s}
>>>> +     {{ld cmse-veneers-no-gnu_sgstubs.out}}
>>>> +     "cmse-veneers-no-gnu_sgstubs"}
>>>> +    {"Secure gateway veneers: wrong entry functions" "" ""
>>>> +     "-march=armv7-m -mthumb --defsym CHECK_ERRORS=1"
>>>> +     {cmse-veneers.s}
>>>> +     {{ld cmse-veneers-wrong-entryfct.out}}
>>>> +     "cmse-veneers-wrong-entryfct"}
>>>> +    {"Secure gateway veneers (ARMv8-M Baseline)"
>>>> +     "-Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --gc-sections" ""
>>>> +     "-march=armv8-m.base -mthumb"
>>>> +     {cmse-veneers.s}
>>>> +     {{objdump {-d -j .gnu.sgstubs} cmse-veneers.d}
>>>> +      {objdump {-h -j .gnu.sgstubs} cmse-veneers.sd}
>>>> +      {nm {} cmse-veneers.rd}}
>>>> +     "cmse-veneers-baseline"}
>>>> +    {"Secure gateway veneers (ARMv8-M Mainline)"
>>>> +     "-Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --gc-sections" ""
>>>> +     "-march=armv8-m.main -mthumb"
>>>> +     {cmse-veneers.s}
>>>> +     {{objdump {-d -j .gnu.sgstubs} cmse-veneers.d}
>>>> +      {objdump {-h -j .gnu.sgstubs} cmse-veneers.sd}
>>>> +      {nm {} cmse-veneers.rd}}
>>>> +     "cmse-veneers-mainline"}
>>>> +
>>>>      {"R_ARM_THM_JUMP19 Relocation veneers: Short"
>>>>       "--section-start destsect=0x000108002 --section-start .text=0x8000" ""
>>>>       "-march=armv7-m -mthumb"
>>>> diff --git a/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out b/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out
>>>> new file mode 100644
>>>> index 0000000000000000000000000000000000000000..9d1e5ba3215ae8a29585fcf04ec1f94314670a29
>>>> --- /dev/null
>>>> +++ b/ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out
>>>> @@ -0,0 +1,3 @@
>>>> +.*: No address assigned to the veneers output section .gnu.sgstubs
>>>> +.*: cannot size stub section: Invalid operation
>>>> +#...
>>>> diff --git a/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
>>>> new file mode 100644
>>>> index 0000000000000000000000000000000000000000..fd4766ab877a4abbeb8b2c4c053ab11d3f86773c
>>>> --- /dev/null
>>>> +++ b/ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out
>>>> @@ -0,0 +1,19 @@
>>>> +.*: .*: Special symbol `__acle_se_loc_entry_veneer1' only allowed for ARMv8-M architecture or later.
>>>> +.*: .*: invalid .* symbol `.*loc_entry_veneer1'.
>>>> +.*: It must be a global or weak function symbol.
>>>> +.*: .*: invalid special symbol `__acle_se_loc_entry_veneer2'.
>>>> +.*: It must be a global or weak function symbol.
>>>> +.*: .*: invalid special symbol `__acle_se_loc_entry_veneer4'.
>>>> +.*: It must be a global or weak function symbol.
>>>> +.*: .*: invalid standard symbol `loc_entry_veneer3'.
>>>> +.*: It must be a global or weak function symbol.
>>>> +.*: .*: invalid standard symbol `loc_entry_veneer5'.
>>>> +.*: It must be a global or weak function symbol.
>>>> +.*: .*: absent standard symbol `fake_entry_veneer1'.
>>>> +.*: .*: invalid standard symbol `obj_entry_veneer1'.
>>>> +.*: It must be a global or weak function symbol.
>>>> +.*: .*: invalid special symbol `__acle_se_obj_entry_veneer2'.
>>>> +.*: It must be a global or weak function symbol.
>>>> +.*: .*: `fake_entry_veneer2' and its special symbol are in different sections.
>>>> +.*: cannot size stub section: Invalid operation
>>>> +#...
>>>> diff --git a/ld/testsuite/ld-arm/cmse-veneers.d b/ld/testsuite/ld-arm/cmse-veneers.d
>>>> new file mode 100644
>>>> index 0000000000000000000000000000000000000000..6a44a2b5dce9de4f5d64fe644e41f5ab9840806e
>>>> --- /dev/null
>>>> +++ b/ld/testsuite/ld-arm/cmse-veneers.d
>>>> @@ -0,0 +1,21 @@
>>>> +
>>>> +.*
>>>> +
>>>> +
>>>> +Disassembly of section \.gnu.sgstubs:
>>>> +
>>>> +00020000 <glob_entry_veneer2>:
>>>> +   20000:	e97f e97f 	sg
>>>> +   20004:	f7e8 b800 	b\.w	8008 <__acle_se_glob_entry_veneer2>
>>>> +
>>>> +00020008 <weak_entry_veneer2>:
>>>> +   20008:	e97f e97f 	sg
>>>> +   2000c:	f7e7 bffe 	b\.w	800c <__acle_se_weak_entry_veneer2>
>>>> +
>>>> +00020010 <glob_entry_veneer1>:
>>>> +   20010:	e97f e97f 	sg
>>>> +   20014:	f7e7 bff4 	b\.w	8000 <__acle_se_glob_entry_veneer1>
>>>> +
>>>> +00020018 <weak_entry_veneer1>:
>>>> +   20018:	e97f e97f 	sg
>>>> +   2001c:	f7e7 bff2 	b\.w	8004 <__acle_se_weak_entry_veneer1>
>>>> diff --git a/ld/testsuite/ld-arm/cmse-veneers.rd b/ld/testsuite/ld-arm/cmse-veneers.rd
>>>> new file mode 100644
>>>> index 0000000000000000000000000000000000000000..20fad961bd8803109c3cf57ef22e3b36da5b1500
>>>> --- /dev/null
>>>> +++ b/ld/testsuite/ld-arm/cmse-veneers.rd
>>>> @@ -0,0 +1,9 @@
>>>> +#...
>>>> +[0-9a-f]+ T glob_entry_fct
>>>> +#...
>>>> +[0-9a-f]+ T glob_entry_veneer1
>>>> +[0-9a-f]+ T glob_entry_veneer2
>>>> +#...
>>>> +[0-9a-f]+ W weak_entry_veneer1
>>>> +[0-9a-f]+ W weak_entry_veneer2
>>>> +#...
>>>> diff --git a/ld/testsuite/ld-arm/cmse-veneers.s b/ld/testsuite/ld-arm/cmse-veneers.s
>>>> new file mode 100644
>>>> index 0000000000000000000000000000000000000000..d5c57f646a78c4736e4f084d8ad6aff7efea554f
>>>> --- /dev/null
>>>> +++ b/ld/testsuite/ld-arm/cmse-veneers.s
>>>> @@ -0,0 +1,97 @@
>>>> +	.syntax unified
>>>> +	.thumb
>>>> +	.file	"foo.c"
>>>> +	.text
>>>> +
>>>> +.macro	decltype	name, type
>>>> +.ifc \type,object
>>>> +	.data
>>>> +.else
>>>> +	.thumb
>>>> +	.thumb_func
>>>> +.endif
>>>> +	.type	\name, %\type
>>>> +.endm
>>>> +
>>>> +
>>>> +.macro	entry	name, type, vis, typespc, visspc, entry_fct
>>>> +	.align	2
>>>> +.ifb \visspc
>>>> +	.\vis	__acle_se_\name
>>>> +.else
>>>> +	.\visspc	__acle_se_\name
>>>> +.endif
>>>> +	.\vis	\name
>>>> +	.thumb
>>>> +	.thumb_func
>>>> +.ifb \typespc
>>>> +	decltype	__acle_se_\name, \type
>>>> +.else
>>>> +	decltype	__acle_se_\name, \typespc
>>>> +.endif
>>>> +	decltype	\name, \type
>>>> +__acle_se_\name:
>>>> +	\entry_fct
>>>> +\name:
>>>> +.ifc \type,object
>>>> +	.word 42
>>>> +.else
>>>> +	nop
>>>> +.endif
>>>> +	.size	\name, .-\name
>>>> +	.size	__acle_se_\name, .-__acle_se_\name
>>>> +.endm
>>>> +
>>>> +
>>>> +.ifndef CHECK_ERRORS
>>>> +	@ Valid setups for veneer generation
>>>> +	entry glob_entry_veneer1, function, global
>>>> +	entry weak_entry_veneer1, function, weak
>>>> +	entry glob_entry_veneer2, function, global, visspc=weak
>>>> +	entry weak_entry_veneer2, function, weak, visspc=global
>>>> +
>>>> +	@ Valid setup for entry function without SG veneer
>>>> +	entry glob_entry_fct, function, global, entry_fct=nop
>>>> +
>>>> +.else
>>>> +	@ Invalid setups for veneer generation (visibility)
>>>> +	entry loc_entry_veneer1, function, local
>>>> +	entry loc_entry_veneer2, function, global, visspc=local
>>>> +	entry loc_entry_veneer3, function, local, visspc=global
>>>> +	entry loc_entry_veneer4, function, weak, visspc=local
>>>> +	entry loc_entry_veneer5, function, local, visspc=weak
>>>> +
>>>> +	@ Invalid setups for veneer generation (absent standard symbol)
>>>> +	.align	2
>>>> +	.global	__acle_se_fake_entry_veneer1
>>>> +	.thumb
>>>> +	.thumb_func
>>>> +	.type	__acle_se_fake_entry_veneer1, %function
>>>> +__acle_se_fake_entry_veneer1:
>>>> +	nop
>>>> +	.size	__acle_se_fake_entry_veneer1, .-__acle_se_fake_entry_veneer1
>>>> +
>>>> +	@ Invalid setups for veneer generation (type)
>>>> +	entry obj_entry_veneer1, object, global, typespc=function
>>>> +	entry obj_entry_veneer2, function, global, typespc=object
>>>> +
>>>> +	@ Invalid setup for veneer generation (sections)
>>>> +	.section .text.sub1
>>>> +	.align	2
>>>> +	.thumb
>>>> +	.thumb_func
>>>> +	.global	__acle_se_fake_entry_veneer2
>>>> +	.type	__acle_se_fake_entry_veneer2, %function
>>>> +__acle_se_fake_entry_veneer2:
>>>> +	nop
>>>> +	.size	__acle_se_fake_entry_veneer2, .-__acle_se_fake_entry_veneer2
>>>> +	.section .text.sub2
>>>> +	.align	2
>>>> +	.thumb
>>>> +	.thumb_func
>>>> +	.global	fake_entry_veneer2
>>>> +	.type	fake_entry_veneer2, %function
>>>> +fake_entry_veneer2:
>>>> +	nop
>>>> +	.size	fake_entry_veneer2, .-fake_entry_veneer2
>>>> +.endif
>>>> diff --git a/ld/testsuite/ld-arm/cmse-veneers.sd b/ld/testsuite/ld-arm/cmse-veneers.sd
>>>> new file mode 100644
>>>> index 0000000000000000000000000000000000000000..99bfc8f37c25b7a57122b330b1145e27a9b087fd
>>>> --- /dev/null
>>>> +++ b/ld/testsuite/ld-arm/cmse-veneers.sd
>>>> @@ -0,0 +1,7 @@
>>>> +
>>>> +.*
>>>> +
>>>> +Sections:
>>>> +Idx Name          Size      VMA       LMA       File off  Algn
>>>> +  \d+ \.gnu\.sgstubs  00000020  00020000  00020000  00010000  2\*\*5
>>>> +                  CONTENTS, ALLOC, LOAD, READONLY, CODE

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH, binutils, ARM 8/11, ping3] Add support for ARMv8-M Secure Gateway veneer generation
  2016-08-04  8:59               ` Richard Earnshaw (lists)
@ 2016-08-04 15:02                 ` Thomas Preudhomme
  0 siblings, 0 replies; 10+ messages in thread
From: Thomas Preudhomme @ 2016-08-04 15:02 UTC (permalink / raw)
  To: Richard Earnshaw (lists); +Cc: binutils

On Thursday 04 August 2016 09:59:11 Richard Earnshaw wrote:
> On 03/08/16 09:52, Thomas Preudhomme wrote:
> > Hi Richard,
> > 
> > How do you find the reworded comment for cmse_scan?
> 
> Yes, much better.  Thanks.
> 
> Sorry for the delay replying.  This patch is OK.

Committed, thanks.

Best regards,

Thomas

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2016-08-04 15:02 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-23  7:59 [RFC PATCH, binutils, ARM 6/9] Add support for ARMv8-M Secure Gateway veneer generation Thomas Preud'homme
2016-03-29 14:42 ` [RFC PATCH, binutils, ARM 8/11] " Thomas Preudhomme
2016-05-18 16:30   ` Thomas Preudhomme
2016-07-07 10:53     ` Richard Earnshaw (lists)
2016-07-07 15:27       ` Thomas Preudhomme
2016-07-14  9:15         ` [RFC PATCH, binutils, ARM 8/11, ping] " Thomas Preudhomme
2016-07-26 11:07           ` [RFC PATCH, binutils, ARM 8/11, ping2] " Thomas Preudhomme
2016-08-03  8:52             ` [RFC PATCH, binutils, ARM 8/11, ping3] " Thomas Preudhomme
2016-08-04  8:59               ` Richard Earnshaw (lists)
2016-08-04 15:02                 ` Thomas Preudhomme

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).