This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[RFC PATCH, binutils, ARM 8/9] Add support for creating ARM v8-M secure extensions import libraries
- From: "Thomas Preud'homme" <thomas dot preudhomme at foss dot arm dot com>
- To: <binutils at sourceware dot org>
- Date: Wed, 23 Dec 2015 16:01:50 +0800
- Subject: [RFC PATCH, binutils, ARM 8/9] Add support for creating ARM v8-M secure extensions import libraries
- Authentication-results: sourceware.org; auth=none
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]
ChangeLog entries are as follow:
*** 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 ***
2015-11-02 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.
*** ld/testsuite/ChangeLog ***
2015-10-30 Thomas Preud'homme <thomas.preudhomme@arm.com>
* ld-arm/arm-elf.exp (Secure gateway import library generation): New
test.
(Secure gateway import library generation: errors): Likewise.
* ld-arm/cmse-implib.s: New file.
* ld-arm/cmse-implib-errors.out: Likewise.
* ld-arm/cmse-implib.rd: Likewise.
diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index 7abc058..d4f0bf4 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 8aeb5d1..864988d 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 ee491aa..37aede1 100644
--- a/bfd/elf32-arm.c
+++ b/bfd/elf32-arm.c
@@ -3071,6 +3071,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;
@@ -7936,7 +7940,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;
@@ -7963,6 +7967,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;
@@ -16327,6 +16332,84 @@ 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)
+{
+ 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;
+
+ for (src_count = 0; src_count < symcount; src_count++)
+ {
+ struct elf32_arm_link_hash_entry *cmse_hash;
+ asymbol *sym = syms[src_count];
+ flagword flags = sym->flags;
+ char *cmse_name, *name = (char *) bfd_asymbol_name (sym);
+
+ if ((flags & BSF_FUNCTION) != BSF_FUNCTION)
+ continue;
+ if (!(flags & (BSF_GLOBAL | BSF_WEAK)))
+ continue;
+
+ if (name == NULL)
+ continue;
+
+ cmse_name = (char *) bfd_malloc (sizeof (CMSE_PREFIX) + strlen (name)
+ + 1);
+ sprintf (cmse_name, "%s%s", CMSE_PREFIX, name);
+ cmse_hash = (struct elf32_arm_link_hash_entry *)
+ elf_link_hash_lookup (&(htab)->root, cmse_name, FALSE, FALSE, TRUE);
+ free (cmse_name);
+
+ 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;
+ }
+
+ 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
@@ -18037,6 +18120,7 @@ elf32_arm_get_synthetic_symtab (bfd *abfd,
#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
diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em
index 19da7c6..ec6dca2 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)
@@ -511,7 +512,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,
@@ -580,6 +581,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
@@ -606,6 +608,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='
@@ -626,6 +629,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\
@@ -746,6 +751,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 b9e7f7c..234716b 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -6804,6 +6804,13 @@ 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.
+@kindex --cmse-implib
+@cindex Secure gateway import library
+The @samp{--cmse-implib} option requests that the import library
+specified by @samp{--out-implib} option is a secure gateway import
+library, 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 d40003b..95b8881 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -605,6 +605,18 @@ set armeabitests_nonacl {
{objdump {-h -j .sgstubs} cmse-veneers.sd}
{nm {} cmse-veneers.rd}}
"cmse-veneers-mainline"}
+ {"Secure gateway import library generation: errors"
+ "--section-start .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 .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 0000000..0026f6b
--- /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 0000000..8b11637
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-implib.rd
@@ -0,0 +1,12 @@
+File: tmpdir/cmse-implib.lib
+
+Symbol table '.symtab' contains 4 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_veneer1
+ 2: [0-9a-f]+ 6 FUNC GLOBAL DEFAULT ABS exported_entry_fct
+ 3: 00020009 8 FUNC GLOBAL DEFAULT ABS exported_entry_veneer2
+
+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 0000000..99fa90c
--- /dev/null
+++ b/ld/testsuite/ld-arm/cmse-implib.s
@@ -0,0 +1,57 @@
+ .syntax unified
+ .text
+
+.macro entry name, entry_fct
+ .align 2
+ .global \name
+ .global __acle_se_\name
+ .thumb
+ .thumb_func
+ .type \name, %function
+ .type __acle_se_\name, %function
+\name:
+.ifnb \entry_fct
+ sg
+.endif
+__acle_se_\name:
+ nop
+ .size \name, .-\name
+ .size __acle_se_\name, .-__acle_se_\name
+.endm
+
+ @ Valid setups for veneer generation
+ entry exported_entry_veneer1
+ entry exported_entry_veneer2
+
+ @ Valid setup for entry function without veneer generation
+ entry exported_entry_fct, entry_fct
+
+ @ 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
The patch doesn't show any regression when running the binutils-gdb testsuite for the arm-none-eabi target.
Any comments?
Best regards,
Thomas