]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Add support for ARMv8-M SG veneer creation
authorThomas Preud'homme <thomas.preudhomme@arm.com>
Tue, 29 Mar 2016 19:12:44 +0000 (20:12 +0100)
committerThomas Preud'homme <thomas.preudhomme@arm.com>
Tue, 29 Mar 2016 19:32:50 +0000 (20:32 +0100)
2016-03-29  Thomas Preud'homme  <thomas.preudhomme@arm.com>

bfd/
* 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/
* arm.h (ARM_GET_SYM_CMSE_SPCL): Define macro.
(ARM_SET_SYM_CMSE_SPCL): Likewise.

ld/
* 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.

ld/testsuite/
* 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-gnu_sgstubs.out: Likewise.
* ld-arm/cmse-veneers-wrong-entryfct.out: Likewise.

14 files changed:
bfd/ChangeLog.arm
bfd/elf32-arm.c
include/elf/ChangeLog.arm
include/elf/arm.h
ld/ChangeLog.arm
ld/ld.texinfo
ld/testsuite/ChangeLog.arm
ld/testsuite/ld-arm/arm-elf.exp
ld/testsuite/ld-arm/cmse-veneers-no-gnu_sgstubs.out [new file with mode: 0644]
ld/testsuite/ld-arm/cmse-veneers-wrong-entryfct.out [new file with mode: 0644]
ld/testsuite/ld-arm/cmse-veneers.d [new file with mode: 0644]
ld/testsuite/ld-arm/cmse-veneers.rd [new file with mode: 0644]
ld/testsuite/ld-arm/cmse-veneers.s [new file with mode: 0644]
ld/testsuite/ld-arm/cmse-veneers.sd [new file with mode: 0644]

index fec9d2d2cd4af01bd5aa4f3bb1508dbbf00d590d..cabe693bf9be645041456ec01ab591cfa8eb8382 100644 (file)
@@ -1,3 +1,29 @@
+2016-03-29  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.
+
 2016-03-29  Thomas Preud'homme  <thomas.preudhomme@arm.com>
 
        * elf32-arm.c (arm_dedicated_stub_section_padding): New function.
index 874ff6b73d1cbb2fe1958923ec83218a02f9b82a..8c4fb10e60ba895d2f5a259aaed87f2f4039963d 100644 (file)
@@ -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.  */
 
@@ -2564,6 +2573,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) \
@@ -3112,6 +3122,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;
 
@@ -3260,12 +3273,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;
@@ -3705,6 +3722,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 ();
@@ -3770,8 +3788,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;
@@ -4084,6 +4103,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;
     }
@@ -4104,6 +4126,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;
@@ -4123,6 +4150,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;
@@ -4136,15 +4166,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;
@@ -4372,6 +4404,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;
 
@@ -4395,6 +4428,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;
     }
@@ -4413,6 +4449,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;
     }
@@ -5308,6 +5347,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
@@ -5324,8 +5555,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;
@@ -5354,6 +5586,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.  */
@@ -5419,6 +5653,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;
@@ -5791,6 +6037,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.  */
@@ -9132,7 +9379,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;
@@ -13512,7 +13760,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
@@ -17584,6 +17833,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;
@@ -17612,6 +17864,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;
 }
 
index 77205bd9e833053228bd97fd8fdc1e005b1fb536..1392b89b0394f2ed4ae5e5d8cf8379bc3c9397ea 100644 (file)
@@ -1,3 +1,8 @@
+2016-03-29  Thomas Preud'homme  <thomas.preudhomme@arm.com>
+
+       * arm.h (ARM_GET_SYM_CMSE_SPCL): Define macro.
+       (ARM_SET_SYM_CMSE_SPCL): Likewise.
+
 2016-03-29  Thomas Preud'homme  <thomas.preudhomme@arm.com>
 
        * arm.h (ARM_SYM_BRANCH_TYPE): Replace by ...
index 8ec6fa34904c55b5e04ed9920372485a11d1f85a..a1cc42cc02002e76cab71462beb3f1d7724c6cb4 100644 (file)
@@ -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 */
index 21498ebd9fe4c7b6187652eed5fca790b57e2a8c..0adb6ba8835c9535400dce4f9db851699b924d22 100644 (file)
@@ -1,3 +1,12 @@
+2016-03-29  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.
+
 2016-03-29  Thomas Preud'homme  <thomas.preudhomme@arm.com>
 
        * emultempl/armelf.em (arm_elf_before_allocation): Call
index 23896611932389157811e638064cfc0487e263fc..9df74c8a1f4f560b95a1cbb6a1156fd8b49790aa 100644 (file)
@@ -6810,6 +6810,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
index ef620bfb1961ebad4becb178837e9ac61c554812..091c47dacca21f8a2e70f324b3ad6f88e7332bb3 100644 (file)
@@ -1,3 +1,12 @@
+2016-03-29  Thomas Preud'homme  <thomas.preudhomme@arm.com>
+
+       * 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-gnu_sgstubs.out: Likewise.
+       * ld-arm/cmse-veneers-wrong-entryfct.out: Likewise.
+
 2016-03-29  Thomas Preud'homme  <thomas.preudhomme@arm.com>
 
        * ld-arm/arm-elf.exp (EABI attribute merging 10 (DSP)): New test.
index a991c39717791837691f5b01e6a642aec9941e5e..b40e3f0d75dc0313022a0097d6ec6510965736c8 100644 (file)
@@ -597,6 +597,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 (file)
index 0000000..9d1e5ba
--- /dev/null
@@ -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 (file)
index 0000000..fd4766a
--- /dev/null
@@ -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 (file)
index 0000000..6a44a2b
--- /dev/null
@@ -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 (file)
index 0000000..20fad96
--- /dev/null
@@ -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 (file)
index 0000000..d5c57f6
--- /dev/null
@@ -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 (file)
index 0000000..99bfc8f
--- /dev/null
@@ -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