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