[RFC PATCH, binutils, ARM 10/11] Add support for creating ARM v8-M secure extensions import libraries

Thomas Preudhomme thomas.preudhomme@foss.arm.com
Tue Mar 29 14:46:00 GMT 2016


On Wednesday 23 December 2015 16:01:50 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
> *Secure Gateway* import libraries.
> 
> ARM v8-M security extensions require [3] a secure gateway import library to
> be generated for non-secure executable to link against entry points in
> secure executable. Such an import library must contain all global function
> symbols from the secure executable that have a corresponding special (ie
> prefixed by "__acle_se_") symbol and these symbol should be made absolute.
> 
> This patch adds support for generating such an import library. It reuses the
> code to generate an import library by requiring the user to add an extra
> --cmse-implib option for him/her to state the intent to create a *secure
> gateway* import library.
> 
> 
> [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 requirement 9 of
> ARM-ECM-0359818 [2]

Please find an updated patch below.

*** bfd/ChangeLog ***

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

        * bfd-in.h (bfd_elf32_arm_set_target_relocs): Add one parameter.
        * bfd-in2.h: Regenerate.
        * elf32-arm.c (struct elf32_arm_link_hash_table): Declare new
        cmse_implib field.
        (bfd_elf32_arm_set_target_relocs): Add new parameter to initialize
        cmse_implib field in struct elf32_arm_link_hash_table.
        (elf32_arm_filter_cmse_symbols): New function.
        (elf32_arm_filter_implib_symbols): Likewise.
        (elf_backend_filter_implib_symbols): Define to
        elf32_arm_filter_implib_symbols.


*** ld/ChangeLog ***

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

        * emultempl/armelf.em (cmse_implib): Declare and define this new
        static variable.
        (arm_elf_create_output_section_statements): Add new cmse_implib
        parameter.
        (OPTION_CMSE_IMPLIB): Define macro.
        (PARSE_AND_LIST_LONGOPTS): Add entry for new --cmse-implib switch.
        (PARSE_AND_LIST_OPTIONS): Likewise.
        (PARSE_AND_LIST_ARGS_CASES): Handle OPTION_CMSE_IMPLIB case.
        * ld.texinfo (--cmse-implib): Document new option.
        * testsuite/ld-arm/arm-elf.exp
        (Secure gateway import library generation): New test.
        (Secure gateway import library generation: errors): Likewise.
        * testsuite/ld-arm/cmse-implib.s: New file.
        * testsuite/ld-arm/cmse-implib-errors.out: Likewise.
        * testsuite/ld-arm/cmse-implib.rd: Likewise.


diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index 
c66ce3bba1ad1d1ce670f7404e465834cbf43fb1..7e3483b9984b04c534e53f2f9026abf26d37592a 
100644
--- a/bfd/bfd-in.h
+++ b/bfd/bfd-in.h
@@ -895,7 +895,7 @@ extern bfd_boolean bfd_elf32_arm_process_before_allocation
 
 void bfd_elf32_arm_set_target_relocs
   (bfd *, struct bfd_link_info *, int, char *, int, int, bfd_arm_vfp11_fix,
-   bfd_arm_stm32l4xx_fix, int, int, int, int, int);
+   bfd_arm_stm32l4xx_fix, int, int, int, int, int, int);
 
 extern bfd_boolean bfd_elf32_arm_get_bfd_for_interworking
   (bfd *, struct bfd_link_info *);
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 
afaca4ef19e49cf9899952a84a90c60fcd3fc8dd..55e1cdde2d0a899238a224c6915d20197b72f085 
100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -902,7 +902,7 @@ extern bfd_boolean bfd_elf32_arm_process_before_allocation
 
 void bfd_elf32_arm_set_target_relocs
   (bfd *, struct bfd_link_info *, int, char *, int, int, bfd_arm_vfp11_fix,
-   bfd_arm_stm32l4xx_fix, int, int, int, int, int);
+   bfd_arm_stm32l4xx_fix, int, int, int, int, int, int);
 
 extern bfd_boolean bfd_elf32_arm_get_bfd_for_interworking
   (bfd *, struct bfd_link_info *);
diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c
index 
126c30df9fbf5ee11020b9fa4efb59c61bc1c352..a8aee085bb80159d6877508a8eef044b05a8a4df 
100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -3123,6 +3123,10 @@ struct elf32_arm_link_hash_table
   /* True if the target uses REL relocations.  */
   int use_rel;
 
+  /* Nonzero if import library must be a secure gateway import library
+     as per ARMv8-M Security Extensions.  */
+  int cmse_implib;
+
   /* The index of the next unused R_ARM_TLS_DESC slot in .rel.plt.  */
   bfd_vma next_tls_desc_index;
 
@@ -8179,7 +8183,7 @@ bfd_elf32_arm_set_target_relocs (struct bfd *output_bfd,
 				 bfd_arm_stm32l4xx_fix stm32l4xx_fix,
 				 int no_enum_warn, int no_wchar_warn,
 				 int pic_veneer, int fix_cortex_a8,
-				 int fix_arm1176)
+				 int fix_arm1176, int cmse_implib)
 {
   struct elf32_arm_link_hash_table *globals;
 
@@ -8206,6 +8210,7 @@ bfd_elf32_arm_set_target_relocs (struct bfd *output_bfd,
   globals->pic_veneer = pic_veneer;
   globals->fix_cortex_a8 = fix_cortex_a8;
   globals->fix_arm1176 = fix_arm1176;
+  globals->cmse_implib = cmse_implib;
 
   BFD_ASSERT (is_arm_elf (output_bfd));
   elf_arm_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
@@ -16692,6 +16697,95 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd,
   return TRUE;
 }
 
+/* Filter normal symbols of CMSE entry functions of ABFD to include in
+   the import library.  All SYMCOUNT symbols of ABFD can be examined
+   from their pointers in SYMS.  Pointers of symbols to keep should be
+   stored continuously at the beginning of that array.
+
+   Returns the number of symbols to keep.  */
+
+static unsigned int
+elf32_arm_filter_cmse_symbols (bfd *abfd ATTRIBUTE_UNUSED,
+			       struct bfd_link_info *info,
+			       asymbol **syms, long symcount)
+{
+  size_t maxnamelen;
+  char *cmse_name;
+  long src_count, dst_count = 0;
+  struct elf32_arm_link_hash_table *htab;
+
+  htab = elf32_arm_hash_table (info);
+  if (!htab->stub_bfd || !htab->stub_bfd->sections)
+    symcount = 0;
+
+  maxnamelen = 128;
+  cmse_name = (char *) bfd_malloc (maxnamelen);
+  for (src_count = 0; src_count < symcount; src_count++)
+    {
+      struct elf32_arm_link_hash_entry *cmse_hash;
+      asymbol *sym;
+      flagword flags;
+      char *name;
+      size_t namelen;
+
+      sym = syms[src_count];
+      flags = sym->flags;
+      name = (char *) bfd_asymbol_name (sym);
+
+      if ((flags & BSF_FUNCTION) != BSF_FUNCTION)
+	continue;
+      if (!(flags & (BSF_GLOBAL | BSF_WEAK)))
+	continue;
+
+      namelen = strlen (name) + sizeof (CMSE_PREFIX) + 1;
+      if (namelen > maxnamelen)
+	{
+	  cmse_name = (char *)
+	    bfd_realloc (cmse_name, namelen);
+	  maxnamelen = namelen;
+	}
+      snprintf (cmse_name, maxnamelen, "%s%s", CMSE_PREFIX, name);
+      cmse_hash = (struct elf32_arm_link_hash_entry *)
+	elf_link_hash_lookup (&(htab)->root, cmse_name, FALSE, FALSE, TRUE);
+
+      if (!cmse_hash
+	  || (cmse_hash->root.root.type != bfd_link_hash_defined
+	      && cmse_hash->root.root.type != bfd_link_hash_defweak)
+	  || cmse_hash->root.type != STT_FUNC)
+	continue;
+
+      if (!ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal))
+	continue;
+
+      syms[dst_count++] = sym;
+    }
+  free (cmse_name);
+
+  syms[dst_count] = NULL;
+
+  return dst_count;
+}
+
+/* Filter symbols of ABFD to include in the import library.  All
+   SYMCOUNT symbols of ABFD can be examined from their pointers in
+   SYMS.  Pointers of symbols to keep should be stored continuously at
+   the beginning of that array.
+
+   Returns the number of symbols to keep.  */
+
+static unsigned int
+elf32_arm_filter_implib_symbols (bfd *abfd ATTRIBUTE_UNUSED,
+				 struct bfd_link_info *info,
+				 asymbol **syms, long symcount)
+{
+  struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (info);
+
+  if (globals->cmse_implib)
+    return elf32_arm_filter_cmse_symbols (abfd, info, syms, symcount);
+  else
+    return _bfd_elf_filter_global_symbols (abfd, info, syms, symcount);
+}
+
 /* Allocate target specific section data.  */
 
 static bfd_boolean
@@ -18480,6 +18574,7 @@ elf32_arm_count_additional_relocs (asection *sec)
 #define elf_backend_modify_segment_map		elf32_arm_modify_segment_map
 #define elf_backend_additional_program_headers  
elf32_arm_additional_program_headers
 #define elf_backend_output_arch_local_syms      
elf32_arm_output_arch_local_syms
+#define elf_backend_filter_implib_symbols	elf32_arm_filter_implib_symbols
 #define elf_backend_begin_write_processing      
elf32_arm_begin_write_processing
 #define elf_backend_add_symbol_hook		elf32_arm_add_symbol_hook
 #define elf_backend_count_additional_relocs	elf32_arm_count_additional_relocs
diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em
index 
6074824f72d6f607449000702e7c5945bfe412ef..c21f6a82335a58a0ab37f3719c73c95e73e6211c 
100644
--- a/ld/emultempl/armelf.em
+++ b/ld/emultempl/armelf.em
@@ -42,6 +42,7 @@ static int no_wchar_size_warning = 0;
 static int pic_veneer = 0;
 static int merge_exidx_entries = -1;
 static int fix_arm1176 = 1;
+static int cmse_implib = 0;
 
 static void
 gld${EMULATION_NAME}_before_parse (void)
@@ -514,7 +515,7 @@ arm_elf_create_output_section_statements (void)
 				   no_enum_size_warning,
 				   no_wchar_size_warning,
 				   pic_veneer, fix_cortex_a8,
-				   fix_arm1176);
+				   fix_arm1176, cmse_implib);
 
   stub_file = lang_add_input_file ("linker stubs",
  				   lang_input_file_is_fake_enum,
@@ -583,6 +584,7 @@ PARSE_AND_LIST_PROLOGUE='
 #define OPTION_NO_FIX_ARM1176		318
 #define OPTION_LONG_PLT			319
 #define OPTION_STM32L4XX_FIX		320
+#define OPTION_CMSE_IMPLIB		321
 '
 
 PARSE_AND_LIST_SHORTOPTS=p
@@ -609,6 +611,7 @@ PARSE_AND_LIST_LONGOPTS='
   { "fix-arm1176", no_argument, NULL, OPTION_FIX_ARM1176 },
   { "no-fix-arm1176", no_argument, NULL, OPTION_NO_FIX_ARM1176 },
   { "long-plt", no_argument, NULL, OPTION_LONG_PLT },
+  { "cmse-implib", no_argument, NULL, OPTION_CMSE_IMPLIB },
 '
 
 PARSE_AND_LIST_OPTIONS='
@@ -629,6 +632,8 @@ PARSE_AND_LIST_OPTIONS='
   fprintf (file, _("  --pic-veneer                Always generate PIC 
interworking veneers\n"));
   fprintf (file, _("  --long-plt                  Generate long .plt 
entries\n"
            "                              to handle large .plt/.got 
displacements\n"));
+  fprintf (file, _("  --cmse-implib               Make import library to be a 
secure gateway import\n"
+                   "                                library as per ARMv8-M 
Security Extensions\n"));
   fprintf (file, _("\
   --stub-group-size=N         Maximum size of a group of input sections 
that\n\
                                can be handled by one stub section.  A 
negative\n\
@@ -749,6 +754,10 @@ PARSE_AND_LIST_ARGS_CASES='
    case OPTION_LONG_PLT:
       bfd_elf32_arm_use_long_plt ();
       break;
+
+   case OPTION_CMSE_IMPLIB:
+      cmse_implib = 1;
+      break;
 '
 
 # We have our own before_allocation etc. functions, but they call
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 
a2e864199ab21469fdf1e35364ad43ccbf1a3734..82b40355a698958d84b566c09901960370139b27 
100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -6810,6 +6810,13 @@ 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.
 
+@kindex --cmse-implib
+@cindex Secure gateway import library
+The @samp{--cmse-implib} option requests that the import libraries
+specified by the @samp{--out-implib} and @samp{--in-implib} options are
+secure gateway import libraries, suitable for linking a non-secure
+executable against secure code as per ARMv8-M Security Extensions.
+
 @ifclear GENERIC
 @lowersections
 @end ifclear
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index 
d6e20504e45f4210a1af6a814fe48d30ff91f6fc..da4bf7e0302de9f1c76bbacf8b64a9318d44c46a 
100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -661,6 +661,18 @@ set armeabitests_nonacl {
       {objdump {-h -j .gnu.sgstubs} cmse-veneers.sd}
       {nm {} cmse-veneers.rd}}
      "cmse-veneers-mainline"}
+    {"Secure gateway import library generation: errors"
+     "--section-start .gnu.sgstubs=0x20000 --out-implib=tmpdir/cmse-
implib.lib --cmse-implib" ""
+     "-march=armv8-m.base -mthumb --defsym CHECK_ERRORS=1"
+     {cmse-implib.s}
+     {{ld cmse-implib-errors.out}}
+     "cmse-implib"}
+    {"Secure gateway import library generation"
+     "--section-start .gnu.sgstubs=0x20000 --out-implib=tmpdir/cmse-
implib.lib --cmse-implib" ""
+     "-march=armv8-m.base -mthumb"
+     {cmse-implib.s}
+     {{readelf {-s tmpdir/cmse-implib.lib} cmse-implib.rd}}
+     "cmse-implib"}
 
     {"R_ARM_THM_JUMP19 Relocation veneers: Short"
      "--section-start destsect=0x000108002 --section-start .text=0x8000" ""
diff --git a/ld/testsuite/ld-arm/cmse-implib-errors.out b/ld/testsuite/ld-
arm/cmse-implib-errors.out
new file mode 100644
index 
0000000000000000000000000000000000000000..0026f6be97e682c963ac9cc462784c2cf34fd003
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-implib-errors.out
@@ -0,0 +1,7 @@
+.*: .*: absent standard symbol `not_exported_fct2'.
+.*: .*: invalid special symbol `__acle_se_not_exported_pseudoentry_var'.
+.*: It must be a global or weak function symbol.
+.*: .*: invalid standard symbol `not_exported_pseudoentry_var'.
+.*: It must be a global or weak function symbol.
+.* cannot size stub section: Invalid operation
+#...
diff --git a/ld/testsuite/ld-arm/cmse-implib.rd b/ld/testsuite/ld-arm/cmse-
implib.rd
new file mode 100644
index 
0000000000000000000000000000000000000000..c5f7aef8c32bf5b4d693d98f9f9cdbae023861b5
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-implib.rd
@@ -0,0 +1,13 @@
+File: tmpdir/cmse-implib.lib
+
+Symbol table '.symtab' contains 5 entries:
+   Num:    Value  Size Type    Bind   Vis      Ndx Name
+     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
+     1: 00020001     8 FUNC    GLOBAL DEFAULT  ABS exported_entry_veneer3
+     2: [0-9a-f]+     6 FUNC    GLOBAL DEFAULT  ABS exported_entry_fct1
+     3: 00020009     8 FUNC    GLOBAL DEFAULT  ABS exported_entry_veneer2
+     4: [0-9a-f]+     6 FUNC    GLOBAL DEFAULT  ABS exported_entry_fct2
+
+File: tmpdir/cmse-implib
+
+#...
diff --git a/ld/testsuite/ld-arm/cmse-implib.s b/ld/testsuite/ld-arm/cmse-
implib.s
new file mode 100644
index 
0000000000000000000000000000000000000000..a42da63fffebe5322be83f278931754262b0f7ae
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-implib.s
@@ -0,0 +1,58 @@
+	.syntax unified
+	.text
+
+.macro	entry	name, vis, entry_fct
+	.align	2
+	.\vis	\name
+	.\vis	__acle_se_\name
+	.thumb
+	.thumb_func
+	.type	\name, %function
+	.type	__acle_se_\name, %function
+\name:
+.ifnb \entry_fct
+	\entry_fct
+.endif
+__acle_se_\name:
+	nop
+	.size	\name, .-\name
+	.size	__acle_se_\name, .-__acle_se_\name
+.endm
+
+	@ Valid setups for veneer generation
+	entry exported_entry_veneer2, global
+	entry exported_entry_veneer3, global
+
+	@ Valid setup for entry function without veneer generation
+	entry exported_entry_fct1, global, sg
+	entry exported_entry_fct2, global, sg
+
+	@ Normal symbol not exported to SG import library
+	.align	2
+	.global	not_exported_fct1
+	.type	not_exported_fct1, %function
+not_exported_fct1:
+	nop
+	.size	not_exported_fct1, .-not_exported_fct1
+
+.ifdef CHECK_ERRORS
+	@ Invalid setups for export to SG import library
+	.align	2
+	.global	__acle_se_not_exported_fct2
+	.type	__acle_se_not_exported_fct2, %function
+__acle_se_not_exported_fct2:
+	nop
+	.size	__acle_se_not_exported_fct2, .-__acle_se_not_exported_fct2
+
+	.align	2
+	.global	__acle_se_not_exported_pseudoentry_var
+	.global	not_exported_pseudoentry_var
+	.data
+	.type	__acle_se_not_exported_pseudoentry_var, %object
+	.type	not_exported_pseudoentry_var, %object
+	.size	not_exported_pseudoentry_var, 4
+	.size	__acle_se_not_exported_pseudoentry_var, 4
+__acle_se_not_exported_pseudoentry_var:
+not_exported_pseudoentry_var:
+	.word	42
+.endif


Is this ok for master branch?

Best regards,

Thomas



More information about the Binutils mailing list