From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 57216 invoked by alias); 23 Dec 2015 08:02:57 -0000 Mailing-List: contact binutils-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sourceware.org Received: (qmail 57202 invoked by uid 89); 23 Dec 2015 08:02:56 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=4.4 required=5.0 tests=AWL,BAYES_99,BAYES_999,KAM_LAZY_DOMAIN_SECURITY,KAM_STOCKGEN,RP_MATCHES_RCVD autolearn=no version=3.3.2 spammy=Posting, 322, ABS, ARMv8M X-HELO: foss.arm.com Received: from foss.arm.com (HELO foss.arm.com) (217.140.101.70) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 23 Dec 2015 08:02:53 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id A66BD49 for ; Wed, 23 Dec 2015 00:02:24 -0800 (PST) Received: from SHAWIN202 (unknown [10.164.6.62]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 53D8C3F21A for ; Wed, 23 Dec 2015 00:02:50 -0800 (PST) From: "Thomas Preud'homme" To: Subject: [RFC PATCH, binutils, ARM 9/9] Add support for stable secure gateway veneers addresses Date: Wed, 23 Dec 2015 08:02:00 -0000 Message-ID: <005601d13d58$522afb60$f680f220$@foss.arm.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-SW-Source: 2015-12/txt/msg00359.txt.bz2 Hi, [Posting patch series as RFC] This patch is part of a patch series to add support for ARMv8-M security ex= tension[1] to GNU ld. This specific patch adds support for allowing Secure = Gateway veneers to have stable addresses when relinking a secure executable. ARM v8-M security extensions allow code running in a device to be divided i= nto secure and non-secure code expected to be developed by independent (tea= ms of) people. To allow updating the secure code without the need to relink= the non-secure code against it, it is necessary for the toolchain to provi= de a way to fix the addresses of the secure gateway veneers that serve as e= ntry points for non-secure code to call secure code. This is also a require= ment [2] to claim support for ARM v8-M security extensions. This patch adds a --in-implib=3D option which, when use= d in conjunction of --cmse-implib will ensure that the veneers whose symbol= s are defined in the import library $in_implib_filename will remain at the = same address in the executable. In the absence of a --out-implib option, th= e code will warn about new secure gateway veneers being created, otherwise = these are allowed. [1] Software requirements for ARMv8-M security extension are described in d= ocument ARM-ECM-0359818 [2] [2] Available on http://infocenter.arm.com in Developer guides and articles= > Software development > ARM=C2=AEv8-M Security Extensions: Requirements o= n Development Tools [3] See requirement 15 of ARM-ECM-0359818 [2] ChangeLog entries are as follow: *** bfd/ChangeLog *** 2015-10-30 Thomas Preud'homme * bfd-in.h (bfd_elf32_arm_set_target_relocs): Add a new parameter f= or the input import library bfd. * bfd-in2.h: Regenerate. * elf32-arm.c (struct elf32_arm_link_hash_table): New in_implib_bfd and new_cmse_veneers_offset fields. (stub_hash_newfunc): Initialize stub_offset to -1. (elf32_arm_add_stub): Likewise. (arm_build_one_stub): Only allocate a stub_offset is it's -1. (elf32_arm_create_stub): Change stub_changed parameter into an inte= ger pointer parameter cmse_stub_created to count the number of stub created. (cmse_entry_fct_p): New function. (arm_list_new_cmse_stub): Likewise. (set_cmse_veneer_addr_from_implib): Likewise. (elf32_arm_size_stubs): Define cmse_stub_created, pass its address = to cmse_scan instead of that of cmse_stub_changed to compute the number of stub created and use it to initialize stub_changed. Call set_cmse_veneer_addr_from_implib after cmse_scan. Use htab->new_cmse_veneers_offset to initialize size of secure gateway veneers section. Initialize stub_offset of Cortex-A8 erratum fix to -1. Use ret to hold return value. (elf32_arm_build_stubs): Use htab->new_cmse_veneers_offset to initialize size of secure gateway veneers section. Add comment to stress the importance of zeroing veneer section content. (bfd_elf32_arm_set_target_relocs): Add new in_implib_bfd parameter = to initialize eponymous field in struct elf32_arm_link_hash_table. *** ld/ChangeLog *** 2015-11-02 Thomas Preud'homme * emultempl/armelf.em (in_implib_filename): Declare and initialize = new variable. (arm_elf_create_output_section_statements): Open import input libra= ry file for writing and pass resulting in_implib_bfd to bfd_elf32_arm_set_target_relocs. (PARSE_AND_LIST_PROLOGUE): Define OPTION_IN_IMPLIB option. (PARSE_AND_LIST_LONGOPTS): Define --in-implib option. (PARSE_AND_LIST_OPTIONS): Add help message for --in-implib option. (PARSE_AND_LIST_ARGS_CASES): Handle new OPTION_IN_IMPLIB case. * ld.texinfo (--cmse-implib): Update to mention --in-implib. (--in-implib): Document new option. *** ld/testsuite/ChangeLog *** 2015-10-30 Thomas Preud'homme * ld-arm/arm-elf.exp (Secure gateway import library generation): add --defsym VER=3D1 to gas CLI. (Secure gateway import library generation: errors): Likewise. (Input secure gateway import library): New test. (Input secure gateway import library: no output import library): Likewise. (Input secure gateway import library: earlier stub section base): Likewise. (Input secure gateway import library: later stub section base): Likewise. (Input secure gateway import library: entry function change): Likewise. * ld-arm/cmse-implib.s: Add input import library testing. * ld-arm/cmse-implib.rd: Update accordingly. * ld-arm/cmse-new-implib.out: New file. * ld-arm/cmse-new-implib.rd: Likewise. * ld-arm/cmse-new-later-implib.out: Likewise. * ld-arm/cmse-new-wrong-implib.out: Likewise. * ld-arm/cmse-new-implib-no-output.out: Likewise. diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h index d4f0bf4..b12946c 100644 --- a/bfd/bfd-in.h +++ b/bfd/bfd-in.h @@ -895,7 +895,7 @@ extern bfd_boolean bfd_elf32_arm_process_before_allocat= ion =20 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, int); + bfd_arm_stm32l4xx_fix, int, int, int, int, int, int, bfd *); =20 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 864988d..406fd6b 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -902,7 +902,7 @@ extern bfd_boolean bfd_elf32_arm_process_before_allocat= ion =20 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, int); + bfd_arm_stm32l4xx_fix, int, int, int, int, int, int, bfd *); =20 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 37aede1..90f1333 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -3075,6 +3075,10 @@ struct elf32_arm_link_hash_table as per ARMv8-M security extensions. */ int cmse_implib; =20 + /* The import library whose symbols' address must remain stable in + the import library generated. */ + bfd *in_implib_bfd; + /* The index of the next unused R_ARM_TLS_DESC slot in .rel.plt. */ bfd_vma next_tls_desc_index; =20 @@ -3136,6 +3140,10 @@ struct elf32_arm_link_hash_table /* Input stub section holding secure gateway veneers. */ asection *cmse_stub_sec; =20 + /* Offset in cmse_stub_sec where new SG veneers (not in input import lib= rary) + start to be allocated. */ + bfd_vma new_cmse_veneers_offset; + /* Number of elements in stub_group. */ unsigned int top_id; =20 @@ -3383,7 +3391,7 @@ stub_hash_newfunc (struct bfd_hash_entry *entry, /* Initialize the local fields. */ eh =3D (struct elf32_arm_stub_hash_entry *) entry; eh->stub_sec =3D NULL; - eh->stub_offset =3D 0; + eh->stub_offset =3D (bfd_vma) -1; eh->source_value =3D 0; eh->target_value =3D 0; eh->target_section =3D NULL; @@ -4200,7 +4208,7 @@ elf32_arm_add_stub (const char *stub_name, asection *= section, } =20 stub_entry->stub_sec =3D stub_sec; - stub_entry->stub_offset =3D 0; + stub_entry->stub_offset =3D (bfd_vma) -1; stub_entry->id_sec =3D link_sec; =20 return stub_entry; @@ -4334,13 +4342,10 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entr= y, bfd *stub_bfd; bfd_byte *loc; bfd_vma sym_value; - int template_size; - int size; + int i, size, template_size, just_allocated =3D 0, nrelocs =3D 0; const insn_sequence *template_sequence; - int i; int stub_reloc_idx[MAXRELOCS] =3D {-1, -1}; int stub_reloc_offset[MAXRELOCS] =3D {0, 0}; - int nrelocs =3D 0; =20 /* Massage our args to the form they really have. */ stub_entry =3D (struct elf32_arm_stub_hash_entry *) gen_entry; @@ -4357,8 +4362,12 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, /* We have to do less-strictly-aligned fixes last. */ return TRUE; =20 - /* Make a note of the offset within the stubs for this entry. */ - stub_entry->stub_offset =3D stub_sec->size; + /* Assign a slot at the end of section if none assigned yet. */ + if (stub_entry->stub_offset =3D=3D (bfd_vma) -1) + { + stub_entry->stub_offset =3D stub_sec->size; + just_allocated =3D 1; + } loc =3D stub_sec->contents + stub_entry->stub_offset; =20 stub_bfd =3D stub_sec->owner; @@ -4432,7 +4441,8 @@ arm_build_one_stub (struct bfd_hash_entry *gen_entry, } } =20 - stub_sec->size +=3D size; + if (just_allocated) + stub_sec->size +=3D size; =20 /* Stub size has already been computed in arm_size_one_stub. Check consistency. */ @@ -4550,6 +4560,10 @@ arm_size_one_stub (struct bfd_hash_entry *gen_entry, stub_entry->stub_template =3D template_sequence; stub_entry->stub_template_size =3D template_size; =20 + /* Already accounted for. */ + if (stub_entry->stub_offset !=3D (bfd_vma) -1) + return TRUE; + size =3D (size + 7) & ~7; stub_entry->stub_sec->size +=3D size; =20 @@ -5211,15 +5225,15 @@ elf32_arm_create_stub (struct elf32_arm_link_hash_t= able *htab, =20 /* Scan symbols in INPUT_BFD for secure gateway veneers to create. OUT_AT= TR gives the output attributes, SYM_HASHES the symbol index to hash entry - mapping while HTAB gives the name to hash entry mapping. + mapping while HTAB gives the name to hash entry mapping. *CMSE_STUB_CRE= ATED + is increased by the number of secure gateway veneer created. =20 - If any secure gateway veneer is created, *STUB_CHANGED is set to TRUE. = The - return value gives whether a stub failed to be allocated. */ + The return value gives whether a stub failed to be allocated. */ =20 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) + int *cmse_stub_created) { const struct elf_backend_data *bed; Elf_Internal_Shdr *symtab_hdr; @@ -5379,7 +5393,7 @@ cmse_scan (bfd *input_bfd, struct elf32_arm_link_hash= _table *htab, else { BFD_ASSERT (new_stub); - *stub_changed =3D TRUE; + (*cmse_stub_created)++; } } =20 @@ -5388,6 +5402,246 @@ cmse_scan (bfd *input_bfd, struct elf32_arm_link_ha= sh_table *htab, return ret; } =20 +/* Return whether a symbol identified by its linker HASH entry is an entry + function, ie can be called from non secure code without using a veneer.= */ + +static bfd_boolean +cmse_entry_fct_p (struct elf32_arm_link_hash_entry *hash) +{ + uint32_t first_insn; + asection *section; + file_ptr offset; + bfd *abfd; + + /* Defined symbol of function type. */ + if (hash->root.root.type !=3D bfd_link_hash_defined + && hash->root.root.type !=3D bfd_link_hash_defweak) + return FALSE; + if (hash->root.type !=3D STT_FUNC) + return FALSE; + + /* Read first instruction. */ + section =3D hash->root.root.u.def.section; + abfd =3D section->owner; + offset =3D hash->root.root.u.def.value - section->vma; + if (!bfd_get_section_contents (abfd, section, &first_insn, offset, + sizeof (first_insn))) + return FALSE; + + /* Start by SG instruction. */ + return first_insn =3D=3D 0xe97fe97f; +} + +/* Output the name (in symbol table) of the veneer GEN_ENTRY if it is a new + secure gateway veneers (ie. the veneers was not in the input import lib= rary) + and there is no output import library (GEN_INFO->out_implib_bfd is NULL= . */ + +static bfd_boolean +arm_list_new_cmse_stub (struct bfd_hash_entry *gen_entry, void *gen_info) +{ + struct elf32_arm_stub_hash_entry *stub_entry; + struct bfd_link_info *info; + + /* Massage our args to the form they really have. */ + stub_entry =3D (struct elf32_arm_stub_hash_entry *) gen_entry; + info =3D (struct bfd_link_info *) gen_info; + + if (info->out_implib_bfd) + return TRUE; + + if (stub_entry->stub_type !=3D arm_stub_cmse_branch_thumb_only) + return TRUE; + + if (stub_entry->stub_offset =3D=3D (bfd_vma) -1) + (*_bfd_error_handler) (" %s", stub_entry->output_name); + + return TRUE; +} + +/* Set offset of secure gateway veneers so that their address remain ident= ical + to the one in the input import library referred by HTAB->in_implib_bfd.= A + warning is issued for veneers that disappeared (present in input import + library but absent from the executable being linked) or if new veneers + appeared and there is no output import library (INFO->out_implib_bfd is= NULL + and CMSE_STUB_CREATED is bigger than the number of secure gateway venee= rs + found in the input import library. + + The function returns whether an error occured and + HTAB->new_cmse_veneers_offset is set to the biggest veneer observed set= for + new veneers to be layed out after. */ + +static bfd_boolean +set_cmse_veneer_addr_from_implib (struct bfd_link_info *info, + struct elf32_arm_link_hash_table *htab, + int cmse_stub_created) +{ + long symsize; + char *sym_name; + flagword flags; + long i, symcount; + bfd *in_implib_bfd; + bfd_boolean ret =3D TRUE; + Elf_Internal_Sym *intsym; + int cmse_stub_template_size; + bfd_size_type cmse_stub_size; + asymbol **sympp =3D NULL, *sym; + asection *cmse_stub_out_sec; + struct elf32_arm_link_hash_entry *hash; + const insn_sequence *cmse_stub_template; + struct elf32_arm_stub_hash_entry *stub_entry; + bfd_vma veneer_value, stub_offset, new_cmse_veneers_offset, stub_sec_vma= =3D 0; + + /* No input secure gateway import library. */ + if (!htab->in_implib_bfd) + return TRUE; + else if (!htab->cmse_implib) + return FALSE; + + /* Get symbol table size. */ + in_implib_bfd =3D htab->in_implib_bfd; + symsize =3D bfd_get_symtab_upper_bound (in_implib_bfd); + if (symsize < 0) + return FALSE; + + /* Read in the input secure gateway import library's symbol table. */ + sympp =3D (asymbol **) xmalloc (symsize); + symcount =3D bfd_canonicalize_symtab (in_implib_bfd, sympp); + if (symcount < 0) + { + ret =3D FALSE; + goto free_sym_buf; + } + + htab->new_cmse_veneers_offset =3D 0; + cmse_stub_size =3D + find_stub_size_and_template (arm_stub_cmse_branch_thumb_only, + &cmse_stub_template, + &cmse_stub_template_size); + cmse_stub_out_sec =3D + bfd_get_section_by_name (htab->obfd, CMSE_STUB_OUT_SEC_NAME); + if (cmse_stub_out_sec =3D=3D NULL) + { + (*_bfd_error_handler) (_("No address assigned to the secure gateway " + "veneers output section %s"), + CMSE_STUB_OUT_SEC_NAME); + stub_sec_vma =3D 0; + ret =3D FALSE; + } + else + stub_sec_vma =3D cmse_stub_out_sec->vma; + + /* Set addresses of veneers mentionned in input secure gateway import + library's symbol table. */ + for (i =3D 0; i < symcount; i++) + { + sym =3D sympp[i]; + flags =3D sym->flags; + intsym =3D &((elf_symbol_type *) sym)->internal_elf_sym; + + if (sym->section !=3D bfd_abs_section_ptr + || !(flags & (BSF_GLOBAL | BSF_WEAK)) + || (flags & BSF_FUNCTION) !=3D BSF_FUNCTION + || (ARM_GET_SYM_BRANCH_TYPE (intsym->st_target_internal) + !=3D ST_BRANCH_TO_THUMB)) + { + (*_bfd_error_handler) (_("%B: invalid import library entry: `%s'."), + in_implib_bfd, sym_name); + (*_bfd_error_handler) (_("Symbol should be absolute, global and " + "refer to Thumb functions.")); + ret =3D FALSE; + continue; + } + + sym_name =3D (char *) bfd_asymbol_name (sym); + veneer_value =3D bfd_asymbol_value (sym); + stub_offset =3D veneer_value - stub_sec_vma; + stub_entry =3D arm_stub_hash_lookup (&htab->stub_hash_table, sym_nam= e, + FALSE, FALSE); + hash =3D (struct elf32_arm_link_hash_entry *) + elf_link_hash_lookup (&(htab)->root, sym_name, FALSE, FALSE, TRUE); + + /* Stub entry should have been created by cmse_scan or the symbol be= of + a secure function callable from non secure code. */ + if (!stub_entry && !hash) + (*_bfd_error_handler) + (_("Entry function `%s' disappeared from secure code."), sym_name); + /* Symbol found is not callable from non secure code. */ + else if (!stub_entry) + { + if (!cmse_entry_fct_p (hash)) + { + (*_bfd_error_handler) (_("`%s' refers to a non entry function."), + sym_name); + ret =3D FALSE; + } + continue; + } + else + { + /* Only stub for SG veneers should have been created. */ + BFD_ASSERT (stub_entry->stub_type =3D=3D arm_stub_cmse_branch_thumb_onl= y); + + /* Check visibility hasn't changed. */ + if (!!(flags & BSF_GLOBAL) + !=3D (hash->root.root.type =3D=3D bfd_link_hash_defined)) + (*_bfd_error_handler) + (_("%B: visibility of symbol `%s' has changed."), in_implib_bfd, + sym_name); + + stub_entry->stub_offset =3D stub_offset; + } + + /* Size should match that of a SG veneer. */ + if (intsym->st_size !=3D cmse_stub_size) + { + (*_bfd_error_handler) (_("%B: incorrect size for symbol `%s'."), + in_implib_bfd, sym_name); + ret =3D FALSE; + } + + /* Previous veneer address is before current SG veneer section. */ + if (veneer_value < stub_sec_vma) + { + (*_bfd_error_handler) + (_("Veneer for entry function `%s' before veneer section start."), + sym_name); + if (stub_entry) + stub_entry->stub_offset =3D 0; /* Avoid offset underflow. */ + ret =3D FALSE; + } + + /* Complain if stub offset not a multiple of stub size. */ + if (stub_offset % cmse_stub_size) + { + (*_bfd_error_handler) + (_("Offset of veneer for entry function `%s' not a multiple of " + "its size."), sym_name); + ret =3D FALSE; + } + + if (!ret) + continue; + + cmse_stub_created--; + new_cmse_veneers_offset =3D stub_offset + ((cmse_stub_size + 7) & ~7= ); + if (new_cmse_veneers_offset > htab->new_cmse_veneers_offset) + htab->new_cmse_veneers_offset =3D new_cmse_veneers_offset; + } + + if (!info->out_implib_bfd && cmse_stub_created !=3D 0) + { + BFD_ASSERT (cmse_stub_created > 0); + (*_bfd_error_handler) + (_("new entry function(s) introduced but no output import library " + "specified:")); + bfd_hash_traverse (&htab->stub_hash_table, arm_list_new_cmse_stub, i= nfo); + } + +free_sym_buf: + free (sympp); + return ret; +} + /* Determine and set the size of the stub section for a final link. =20 The basic idea here is to examine all the relocations looking for @@ -5404,9 +5658,10 @@ elf32_arm_size_stubs (bfd *output_bfd, unsigned int), void (*layout_sections_again) (void)) { + int cmse_stub_created =3D 0; obj_attribute *out_attr; bfd_size_type stub_group_size; - bfd_boolean stubs_always_after_branch, cmse_stub_changed =3D FALSE; + bfd_boolean stubs_always_after_branch, ret =3D TRUE; struct elf32_arm_link_hash_table *htab =3D elf32_arm_hash_table (info); struct a8_erratum_fix *a8_fixes =3D NULL; unsigned int num_a8_fixes =3D 0, a8_fix_table_size =3D 10; @@ -5449,9 +5704,11 @@ elf32_arm_size_stubs (bfd *output_bfd, struct elf_link_hash_entry **sym_hashes =3D elf_sym_hashes (input_bfd); =20 if (!cmse_scan (input_bfd, htab, out_attr, sym_hashes, - &cmse_stub_changed)) + &cmse_stub_created)) goto error_ret_free_local; } + if (!set_cmse_veneer_addr_from_implib (info, htab, cmse_stub_created= )) + ret =3D FALSE; } =20 /* The Cortex-A8 erratum fix depends on stubs not being in the same 4K p= age @@ -5496,11 +5753,11 @@ elf32_arm_size_stubs (bfd *output_bfd, bfd *input_bfd; unsigned int bfd_indx; asection *stub_sec; - bfd_boolean stub_changed =3D cmse_stub_changed; + bfd_boolean stub_changed =3D cmse_stub_created !=3D 0; unsigned prev_num_a8_fixes =3D num_a8_fixes; =20 num_a8_fixes =3D 0; - cmse_stub_changed =3D FALSE; + cmse_stub_created =3D 0; for (input_bfd =3D info->input_bfds, bfd_indx =3D 0; input_bfd !=3D NULL; input_bfd =3D input_bfd->link.next, bfd_indx++) @@ -5851,7 +6108,11 @@ elf32_arm_size_stubs (bfd *output_bfd, if (!strstr (stub_sec->name, STUB_SUFFIX)) continue; =20 - stub_sec->size =3D 0; + /* Append new SG veneers after those in input import library. */ + if (stub_sec =3D=3D htab->cmse_stub_sec) + stub_sec->size =3D htab->new_cmse_veneers_offset; + else + stub_sec->size =3D 0; } =20 bfd_hash_traverse (&htab->stub_hash_table, arm_size_one_stub, htab); @@ -5908,7 +6169,7 @@ elf32_arm_size_stubs (bfd *output_bfd, } =20 stub_entry->stub_sec =3D stub_sec; - stub_entry->stub_offset =3D 0; + stub_entry->stub_offset =3D (bfd_vma) -1; stub_entry->id_sec =3D link_sec; stub_entry->stub_type =3D a8_fixes[i].stub_type; stub_entry->source_value =3D a8_fixes[i].offset; @@ -5936,7 +6197,7 @@ elf32_arm_size_stubs (bfd *output_bfd, htab->a8_erratum_fixes =3D NULL; htab->num_a8_erratum_fixes =3D 0; } - return TRUE; + return ret; =20 error_ret_free_local: return FALSE; @@ -5969,12 +6230,19 @@ elf32_arm_build_stubs (struct bfd_link_info *info) if (!strstr (stub_sec->name, STUB_SUFFIX)) continue; =20 - /* Allocate memory to hold the linker stubs. */ + /* Allocate memory to hold the linker stubs. Zeroing the stub secti= on + ensures that a non secure application branching to a removed SG veneer + will cause an error. */ size =3D stub_sec->size; stub_sec->contents =3D (unsigned char *) bfd_zalloc (htab->stub_bfd,= size); if (stub_sec->contents =3D=3D NULL && size !=3D 0) return FALSE; - stub_sec->size =3D 0; + + /* Append new SG veneers after those in input import library. */ + if (stub_sec =3D=3D htab->cmse_stub_sec) + stub_sec->size =3D htab->new_cmse_veneers_offset; + else + stub_sec->size =3D 0; } =20 /* Build the stubs as directed by the stub hash table. */ @@ -7940,7 +8208,8 @@ bfd_elf32_arm_set_target_relocs (struct bfd *output_b= fd, 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 cmse_implib) + int fix_arm1176, int cmse_implib, + bfd *in_implib_bfd) { struct elf32_arm_link_hash_table *globals; =20 @@ -7968,6 +8237,7 @@ bfd_elf32_arm_set_target_relocs (struct bfd *output_b= fd, globals->fix_cortex_a8 =3D fix_cortex_a8; globals->fix_arm1176 =3D fix_arm1176; globals->cmse_implib =3D cmse_implib; + globals->in_implib_bfd =3D in_implib_bfd; =20 BFD_ASSERT (is_arm_elf (output_bfd)); elf_arm_tdata (output_bfd)->no_enum_size_warning =3D no_enum_warn; diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em index ec6dca2..0e4d1bd 100644 --- a/ld/emultempl/armelf.em +++ b/ld/emultempl/armelf.em @@ -43,6 +43,7 @@ static int pic_veneer =3D 0; static int merge_exidx_entries =3D -1; static int fix_arm1176 =3D 1; static int cmse_implib =3D 0; +static char *in_implib_filename =3D NULL; =20 static void gld${EMULATION_NAME}_before_parse (void) @@ -495,6 +496,8 @@ gld${EMULATION_NAME}_finish (void) static void arm_elf_create_output_section_statements (void) { + bfd *in_implib_bfd; + if (strstr (bfd_get_target (link_info.output_bfd), "arm") =3D=3D NULL) { /* The arm backend needs special fields in the output hash structure. @@ -505,6 +508,20 @@ arm_elf_create_output_section_statements (void) return; } =20 + if (in_implib_filename) + { + in_implib_bfd =3D bfd_openr (in_implib_filename, + bfd_get_target (link_info.output_bfd)); + + if (in_implib_bfd =3D=3D NULL) + einfo ("%F%s: Can't open: %E\n", in_implib_filename); + + if (!bfd_check_format (in_implib_bfd, bfd_object)) + einfo ("%F%s: Not a relocatable file: %E\n", in_implib_filename); + } + else + in_implib_bfd =3D NULL; + bfd_elf32_arm_set_target_relocs (link_info.output_bfd, &link_info, target1_is_rel, target2_type, fix_v4bx, use_blx, @@ -512,7 +529,7 @@ arm_elf_create_output_section_statements (void) no_enum_size_warning, no_wchar_size_warning, pic_veneer, fix_cortex_a8, - fix_arm1176, cmse_implib); + fix_arm1176, cmse_implib, in_implib_bfd); =20 stub_file =3D lang_add_input_file ("linker stubs", lang_input_file_is_fake_enum, @@ -582,6 +599,7 @@ PARSE_AND_LIST_PROLOGUE=3D' #define OPTION_LONG_PLT 319 #define OPTION_STM32L4XX_FIX 320 #define OPTION_CMSE_IMPLIB 321 +#define OPTION_IN_IMPLIB 322 ' =20 PARSE_AND_LIST_SHORTOPTS=3Dp @@ -609,6 +627,7 @@ PARSE_AND_LIST_LONGOPTS=3D' { "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 }, + { "in-implib", required_argument, NULL, OPTION_IN_IMPLIB }, ' =20 PARSE_AND_LIST_OPTIONS=3D' @@ -631,6 +650,8 @@ PARSE_AND_LIST_OPTIONS=3D' " to handle large .plt/.got displa= cements\n")); fprintf (file, _(" --cmse-implib Make import library to b= e a secure gateway import\n" " library as per ARMv8-M= security extensions\n")); + fprintf (file, _(" --in-implib Import library whose sym= bols address must\n" + " remain stable\n")); fprintf (file, _("\ --stub-group-size=3DN Maximum size of a group of input sections = that\n\ can be handled by one stub section. A nega= tive\n\ @@ -755,6 +776,10 @@ PARSE_AND_LIST_ARGS_CASES=3D' case OPTION_CMSE_IMPLIB: cmse_implib =3D 1; break; + + case OPTION_IN_IMPLIB: + in_implib_filename =3D optarg; + break; ' =20 # We have our own before_allocation etc. functions, but they call diff --git a/ld/ld.texinfo b/ld/ld.texinfo index 234716b..851c7fa 100644 --- a/ld/ld.texinfo +++ b/ld/ld.texinfo @@ -6806,10 +6806,20 @@ entries which only support 512Mb of code. =20 @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. +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. + +@kindex --in-implib +@cindex Input import library +The @samp{--in-implib} option specifies an import library whose symbols +must keep the same address in the executable being produced. A warning +is given if @samp{--out-implib} is not specified but new symbols would +end up in the output import library if it was. Otherwise, if +@samp{--out-implib} is specified, the symbols are silently added to the +output import library. This option is only effective for Secure +Gateway import libraries, ie. when @samp{--cmse-implib} is specified. =20 @ifclear GENERIC @lowersections diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.= exp index 95b8881..5c6de60 100644 --- a/ld/testsuite/ld-arm/arm-elf.exp +++ b/ld/testsuite/ld-arm/arm-elf.exp @@ -607,16 +607,48 @@ set armeabitests_nonacl { "cmse-veneers-mainline"} {"Secure gateway import library generation: errors" "--section-start .sgstubs=3D0x20000 --out-implib=3Dtmpdir/cmse-implib= .lib --cmse-implib" "" - "-march=3Darmv8-m.base -mthumb --defsym CHECK_ERRORS=3D1" + "-march=3Darmv8-m.base -mthumb --defsym CHECK_ERRORS=3D1 --defsym VER= =3D1" {cmse-implib.s} {{ld cmse-implib-errors.out}} "cmse-implib"} {"Secure gateway import library generation" "--section-start .sgstubs=3D0x20000 --out-implib=3Dtmpdir/cmse-implib= .lib --cmse-implib" "" - "-march=3Darmv8-m.base -mthumb" + "-march=3Darmv8-m.base -mthumb --defsym VER=3D1" {cmse-implib.s} {{readelf {-s tmpdir/cmse-implib.lib} cmse-implib.rd}} "cmse-implib"} + {"Input secure gateway import library" + "--section-start .sgstubs=3D0x20000 --out-implib=3Dtmpdir/cmse-new-im= plib.lib --in-implib=3Dtmpdir/cmse-implib.lib --cmse-implib" "" + "-march=3Darmv8-m.base -mthumb --defsym VER=3D2" + {cmse-implib.s} + {{ld cmse-new-implib.out} + {readelf {-s tmpdir/cmse-new-implib.lib} cmse-new-implib.rd}} + "cmse-new-implib"} + {"Input secure gateway import library: no output import library" + "--section-start .sgstubs=3D0x20000 --in-implib=3Dtmpdir/cmse-implib.= lib --cmse-implib" "" + "-march=3Darmv8-m.base -mthumb --defsym VER=3D2" + {cmse-implib.s} + {{ld cmse-new-implib-no-output.out}} + "cmse-new-implib-no-output"} + {"Input secure gateway import library: earlier stub section base" + "--section-start .sgstubs=3D0x19000 --out-implib=3Dtmpdir/cmse-new-ea= rlier-implib.lib --in-implib=3Dtmpdir/cmse-implib.lib --cmse-implib" "" + "-march=3Darmv8-m.base -mthumb --defsym VER=3D2" + {cmse-implib.s} + {{ld cmse-new-implib.out} + {readelf {-s tmpdir/cmse-new-earlier-implib.lib} cmse-new-implib.rd}} + "cmse-new-earlier-implib"} + {"Input secure gateway import library: later stub section base" + "--section-start .sgstubs=3D0x30000 --out-implib=3Dtmpdir/cmse-new-la= ter-implib.lib --in-implib=3Dtmpdir/cmse-implib.lib --cmse-implib" "" + "-march=3Darmv8-m.base -mthumb --defsym VER=3D2" + {cmse-implib.s} + {{ld cmse-new-later-implib.out}} + "cmse-new-later-implib"} + {"Input secure gateway import library: entry function change" + "--section-start .sgstubs=3D0x20000 --out-implib=3Dtmpdir/cmse-new-wr= ong-implib.lib --in-implib=3Dtmpdir/cmse-implib.lib --cmse-implib" "" + "-march=3Darmv8-m.base -mthumb --defsym VER=3D3" + {cmse-implib.s} + {{ld cmse-new-wrong-implib.out}} + "cmse-new-wrong-implib"} =20 {"R_ARM_THM_JUMP19 Relocation veneers: Short" "--section-start destsect=3D0x000108002 --section-start .text=3D0x800= 0" "" diff --git a/ld/testsuite/ld-arm/cmse-implib.rd b/ld/testsuite/ld-arm/cmse-= implib.rd index 8b11637..c5f7aef 100644 --- a/ld/testsuite/ld-arm/cmse-implib.rd +++ b/ld/testsuite/ld-arm/cmse-implib.rd @@ -1,11 +1,12 @@ File: tmpdir/cmse-implib.lib =20 -Symbol table '.symtab' contains 4 entries: +Symbol table '.symtab' contains 5 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND=20 - 1: 00020001 8 FUNC GLOBAL DEFAULT ABS exported_entry_veneer1 - 2: [0-9a-f]+ 6 FUNC GLOBAL DEFAULT ABS exported_entry_fct + 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 =20 File: tmpdir/cmse-implib =20 diff --git a/ld/testsuite/ld-arm/cmse-implib.s b/ld/testsuite/ld-arm/cmse-i= mplib.s index 99fa90c..a841130 100644 --- a/ld/testsuite/ld-arm/cmse-implib.s +++ b/ld/testsuite/ld-arm/cmse-implib.s @@ -1,17 +1,17 @@ .syntax unified .text =20 -.macro entry name, entry_fct +.macro entry name, vis, entry_fct .align 2 - .global \name - .global __acle_se_\name + .\vis \name + .\vis __acle_se_\name .thumb .thumb_func .type \name, %function .type __acle_se_\name, %function \name: .ifnb \entry_fct - sg + \entry_fct .endif __acle_se_\name: nop @@ -20,11 +20,28 @@ __acle_se_\name: .endm =20 @ Valid setups for veneer generation - entry exported_entry_veneer1 - entry exported_entry_veneer2 +.if (VER >=3D 2) + entry exported_entry_veneer1, global +.endif +.if (VER < 3) + entry exported_entry_veneer2, global +.else + entry exported_entry_veneer2, weak +.endif +.if (VER =3D=3D 1) + entry exported_entry_veneer3, global +.else + entry exported_entry_veneer4, global +.endif =20 @ Valid setup for entry function without veneer generation - entry exported_entry_fct, entry_fct + entry exported_entry_fct1, global, sg +.if (VER < 3) + entry exported_entry_fct2, global, sg +.else + @ Invalid setup for entry function without veneer generation + entry exported_entry_fct2, global, nop +.endif =20 @ Normal symbol not exported to SG import library .align 2 diff --git a/ld/testsuite/ld-arm/cmse-new-implib-no-output.out b/ld/testsui= te/ld-arm/cmse-new-implib-no-output.out new file mode 100644 index 0000000..0590b71 --- /dev/null +++ b/ld/testsuite/ld-arm/cmse-new-implib-no-output.out @@ -0,0 +1,4 @@ +.*: Entry function `exported_entry_veneer3' disappeared from secure code. +.*: new entry function\(s\) introduced but no output import library specif= ied: +.*: exported_entry_veneer4 +.*: exported_entry_veneer1 diff --git a/ld/testsuite/ld-arm/cmse-new-implib.out b/ld/testsuite/ld-arm/= cmse-new-implib.out new file mode 100644 index 0000000..c8af280 --- /dev/null +++ b/ld/testsuite/ld-arm/cmse-new-implib.out @@ -0,0 +1 @@ +.*: Entry function `exported_entry_veneer3' disappeared from secure code. diff --git a/ld/testsuite/ld-arm/cmse-new-implib.rd b/ld/testsuite/ld-arm/c= mse-new-implib.rd new file mode 100644 index 0000000..9ff0fd8 --- /dev/null +++ b/ld/testsuite/ld-arm/cmse-new-implib.rd @@ -0,0 +1,14 @@ +File: tmpdir/cmse-new-.*implib.lib + +Symbol table '.symtab' contains 6 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: 00000000 0 NOTYPE LOCAL DEFAULT UND=20 + 1: 00020011 8 FUNC GLOBAL DEFAULT ABS exported_entry_veneer4 + 2: 00020019 8 FUNC GLOBAL DEFAULT ABS exported_entry_veneer1 + 3: [0-9a-f]+ 6 FUNC GLOBAL DEFAULT ABS exported_entry_fct1 + 4: 00020009 8 FUNC GLOBAL DEFAULT ABS exported_entry_veneer2 + 5: [0-9a-f]+ 6 FUNC GLOBAL DEFAULT ABS exported_entry_fct2 + +File: tmpdir/cmse-new-.*implib + +#... diff --git a/ld/testsuite/ld-arm/cmse-new-later-implib.out b/ld/testsuite/l= d-arm/cmse-new-later-implib.out new file mode 100644 index 0000000..9652759 --- /dev/null +++ b/ld/testsuite/ld-arm/cmse-new-later-implib.out @@ -0,0 +1,4 @@ +.*: Entry function `exported_entry_veneer3' disappeared from secure code. +.*: Veneer for entry function `exported_entry_veneer3' before veneer secti= on start. +.*: Veneer for entry function `exported_entry_veneer2' before veneer secti= on start. +.*: cannot size stub section: Invalid operation diff --git a/ld/testsuite/ld-arm/cmse-new-wrong-implib.out b/ld/testsuite/l= d-arm/cmse-new-wrong-implib.out new file mode 100644 index 0000000..95733b2 --- /dev/null +++ b/ld/testsuite/ld-arm/cmse-new-wrong-implib.out @@ -0,0 +1,4 @@ +.*: Entry function `exported_entry_veneer3' disappeared from secure code. +.*: .*: visibility of symbol `exported_entry_veneer2' has changed. +.*: `exported_entry_fct2' refers to a non entry function. +.*: cannot size stub section: Invalid operation The patch doesn't show any regression when running the binutils-gdb testsui= te for the arm-none-eabi target. Any comments? Best regards, Thomas