From daa4adae63f91377fe9b3e8d7421a0ceb4a51e26 Mon Sep 17 00:00:00 2001 From: Thomas Preud'homme Date: Mon, 23 May 2016 09:38:32 +0100 Subject: [PATCH] Support for dedicated output section for some ARM veneer types 2016-05-23 Thomas Preud'homme bfd/ * bfd-in.h (bfd_elf32_arm_keep_private_stub_output_sections): Declare bfd hook. * bfd-in2.h: Regenerate. * elf32-arm.c (arm_dedicated_stub_output_section_required): New function. (arm_dedicated_stub_output_section_required_alignment): Likewise. (arm_dedicated_stub_output_section_name): Likewise. (arm_dedicated_stub_input_section_ptr): Likewise. (elf32_arm_create_or_find_stub_sec): Add stub type parameter and function description comment. Add support for dedicated output stub section to given stub types. (elf32_arm_add_stub): Add a stub type parameter and pass it down to elf32_arm_create_or_find_stub_sec. (elf32_arm_create_stub): Pass stub type down to elf32_arm_add_stub. (elf32_arm_size_stubs): Pass stub type when calling elf32_arm_create_or_find_stub_sec for Cortex-A8 erratum veneers. (bfd_elf32_arm_keep_private_stub_output_sections): New function. ld/ * emultempl/armelf.em (arm_elf_before_allocation): Call bfd_elf32_arm_keep_private_stub_output_sections before generic before_allocation function. --- bfd/ChangeLog | 20 +++++ bfd/bfd-in.h | 3 + bfd/bfd-in2.h | 3 + bfd/elf32-arm.c | 196 +++++++++++++++++++++++++++++++++++++++---------- ld/ChangeLog | 6 ++ ld/emultempl/armelf.em | 4 + 6 files changed, 193 insertions(+), 39 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 45dbbe4..5a99dcf 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,23 @@ +2016-05-23 Thomas Preud'homme + + * bfd-in.h (bfd_elf32_arm_keep_private_stub_output_sections): Declare + bfd hook. + * bfd-in2.h: Regenerate. + * elf32-arm.c (arm_dedicated_stub_output_section_required): New + function. + (arm_dedicated_stub_output_section_required_alignment): Likewise. + (arm_dedicated_stub_output_section_name): Likewise. + (arm_dedicated_stub_input_section_ptr): Likewise. + (elf32_arm_create_or_find_stub_sec): Add stub type parameter and + function description comment. Add support for dedicated output stub + section to given stub types. + (elf32_arm_add_stub): Add a stub type parameter and pass it down to + elf32_arm_create_or_find_stub_sec. + (elf32_arm_create_stub): Pass stub type down to elf32_arm_add_stub. + (elf32_arm_size_stubs): Pass stub type when calling + elf32_arm_create_or_find_stub_sec for Cortex-A8 erratum veneers. + (bfd_elf32_arm_keep_private_stub_output_sections): New function. + 2016-05-20 H.J. Lu * elf32-i386.c (elf_i386_check_relocs): Don't check R_386_GOT32 diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h index a3a28e5..196bd70 100644 --- a/bfd/bfd-in.h +++ b/bfd/bfd-in.h @@ -903,6 +903,9 @@ extern bfd_boolean bfd_elf32_arm_get_bfd_for_interworking extern bfd_boolean bfd_elf32_arm_add_glue_sections_to_bfd (bfd *, struct bfd_link_info *); +extern void bfd_elf32_arm_keep_private_stub_output_sections + (struct bfd_link_info *); + /* ELF ARM mapping symbol support. */ #define BFD_ARM_SPECIAL_SYM_TYPE_MAP (1 << 0) #define BFD_ARM_SPECIAL_SYM_TYPE_TAG (1 << 1) diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index dbb00e8..f900da6 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -910,6 +910,9 @@ extern bfd_boolean bfd_elf32_arm_get_bfd_for_interworking extern bfd_boolean bfd_elf32_arm_add_glue_sections_to_bfd (bfd *, struct bfd_link_info *); +extern void bfd_elf32_arm_keep_private_stub_output_sections + (struct bfd_link_info *); + /* ELF ARM mapping symbol support. */ #define BFD_ARM_SPECIAL_SYM_TYPE_MAP (1 << 0) #define BFD_ARM_SPECIAL_SYM_TYPE_TAG (1 << 1) diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index 8698fff..e5c69f5 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -4136,68 +4136,155 @@ elf32_arm_get_stub_entry (const asection *input_section, return stub_entry; } -/* Find or create a stub section. Returns a pointer to the stub section, and - the section to which the stub section will be attached (in *LINK_SEC_P). +/* Whether veneers of type STUB_TYPE require to be in a dedicated output + section. */ + +static bfd_boolean +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; +} + +/* Required alignment (as a power of 2) for the dedicated section holding + veneers of type STUB_TYPE, or 0 if veneers of this type are interspersed + with input sections. */ + +static int +arm_dedicated_stub_output_section_required_alignment + (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 0; +} + +/* Name of the dedicated output section to put veneers of type STUB_TYPE, or + NULL if veneers of this type are interspersed with input sections. */ + +static const char * +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; +} + +/* If veneers of type STUB_TYPE should go in a dedicated output section, + returns the address of the hash table field in HTAB holding a pointer to the + 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) +{ + if (stub_type >= max_stub_type) + abort (); /* Should be unreachable. */ + + BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type)); + return NULL; +} + +/* Find or create a stub section to contain a stub of type STUB_TYPE. SECTION + is the section that branch into veneer and can be NULL if stub should go in + a dedicated output section. Returns a pointer to the stub section, and the + section to which the stub section will be attached (in *LINK_SEC_P). LINK_SEC_P may be NULL. */ static asection * elf32_arm_create_or_find_stub_sec (asection **link_sec_p, asection *section, - struct elf32_arm_link_hash_table *htab) + struct elf32_arm_link_hash_table *htab, + enum elf32_arm_stub_type stub_type) { - asection *link_sec; - asection *stub_sec; - asection *out_sec; - - link_sec = htab->stub_group[section->id].link_sec; - BFD_ASSERT (link_sec != NULL); - stub_sec = htab->stub_group[section->id].stub_sec; + asection *link_sec, *out_sec, **stub_sec_p; + const char *stub_sec_prefix; + bfd_boolean dedicated_output_section = + arm_dedicated_stub_output_section_required (stub_type); + int align; - if (stub_sec == NULL) + if (dedicated_output_section) { - stub_sec = htab->stub_group[link_sec->id].stub_sec; - if (stub_sec == NULL) + bfd *output_bfd = htab->obfd; + const char *out_sec_name = + arm_dedicated_stub_output_section_name (stub_type); + link_sec = NULL; + stub_sec_p = arm_dedicated_stub_input_section_ptr (htab, stub_type); + stub_sec_prefix = out_sec_name; + align = arm_dedicated_stub_output_section_required_alignment (stub_type); + out_sec = bfd_get_section_by_name (output_bfd, out_sec_name); + if (out_sec == NULL) { - size_t namelen; - bfd_size_type len; - char *s_name; - - namelen = strlen (link_sec->name); - len = namelen + sizeof (STUB_SUFFIX); - s_name = (char *) bfd_alloc (htab->stub_bfd, len); - if (s_name == NULL) - return NULL; - - memcpy (s_name, link_sec->name, namelen); - memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX)); - out_sec = link_sec->output_section; - stub_sec = (*htab->add_stub_section) (s_name, out_sec, link_sec, - htab->nacl_p ? 4 : 3); - if (stub_sec == NULL) - return NULL; - htab->stub_group[link_sec->id].stub_sec = stub_sec; + (*_bfd_error_handler) (_("No address assigned to the veneers output " + "section %s"), out_sec_name); + return NULL; } - htab->stub_group[section->id].stub_sec = stub_sec; } + else + { + link_sec = htab->stub_group[section->id].link_sec; + BFD_ASSERT (link_sec != NULL); + stub_sec_p = &htab->stub_group[section->id].stub_sec; + if (*stub_sec_p == NULL) + stub_sec_p = &htab->stub_group[link_sec->id].stub_sec; + stub_sec_prefix = link_sec->name; + out_sec = link_sec->output_section; + align = htab->nacl_p ? 4 : 3; + } + + if (*stub_sec_p == NULL) + { + size_t namelen; + bfd_size_type len; + char *s_name; + + namelen = strlen (stub_sec_prefix); + len = namelen + sizeof (STUB_SUFFIX); + s_name = (char *) bfd_alloc (htab->stub_bfd, len); + if (s_name == NULL) + return NULL; + + memcpy (s_name, stub_sec_prefix, namelen); + memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX)); + *stub_sec_p = (*htab->add_stub_section) (s_name, out_sec, link_sec, + align); + if (*stub_sec_p == NULL) + return NULL; + + out_sec->flags |= SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE + | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY + | SEC_KEEP; + } + + if (!dedicated_output_section) + htab->stub_group[section->id].stub_sec = *stub_sec_p; if (link_sec_p) *link_sec_p = link_sec; - return stub_sec; + return *stub_sec_p; } /* Add a new stub entry to the stub hash. Not all fields of the new stub entry are initialised. */ static struct elf32_arm_stub_hash_entry * -elf32_arm_add_stub (const char *stub_name, - asection *section, - struct elf32_arm_link_hash_table *htab) +elf32_arm_add_stub (const char *stub_name, asection *section, + struct elf32_arm_link_hash_table *htab, + enum elf32_arm_stub_type stub_type) { asection *link_sec; asection *stub_sec; struct elf32_arm_stub_hash_entry *stub_entry; - stub_sec = elf32_arm_create_or_find_stub_sec (&link_sec, section, htab); + stub_sec = elf32_arm_create_or_find_stub_sec (&link_sec, section, htab, + stub_type); if (stub_sec == NULL) return NULL; @@ -5187,7 +5274,7 @@ elf32_arm_create_stub (struct elf32_arm_link_hash_table *htab, return TRUE; } - stub_entry = elf32_arm_add_stub (stub_name, section, htab); + stub_entry = elf32_arm_add_stub (stub_name, section, htab, stub_type); if (stub_entry == NULL) { if (!sym_claimed) @@ -5700,7 +5787,7 @@ elf32_arm_size_stubs (bfd *output_bfd, for (i = 0; i < num_a8_fixes; i++) { stub_sec = elf32_arm_create_or_find_stub_sec (NULL, - a8_fixes[i].section, htab); + a8_fixes[i].section, htab, a8_fixes[i].stub_type); if (stub_sec == NULL) return FALSE; @@ -6491,6 +6578,37 @@ bfd_elf32_arm_add_glue_sections_to_bfd (bfd *abfd, && arm_make_glue_section (abfd, STM32L4XX_ERRATUM_VENEER_SECTION_NAME); } +/* Mark output sections of veneers needing a dedicated one with SEC_KEEP. This + ensures they are not marked for deletion by + strip_excluded_output_sections () when veneers are going to be created + later. Not doing so would trigger assert on empty section size in + lang_size_sections_1 (). */ + +void +bfd_elf32_arm_keep_private_stub_output_sections (struct bfd_link_info *info) +{ + enum elf32_arm_stub_type stub_type; + + /* If we are only performing a partial + link do not bother adding the glue. */ + if (bfd_link_relocatable (info)) + return; + + for (stub_type = arm_stub_none + 1; stub_type < max_stub_type; stub_type++) + { + asection *out_sec; + const char *out_sec_name; + + if (!arm_dedicated_stub_output_section_required (stub_type)) + continue; + + out_sec_name = arm_dedicated_stub_output_section_name (stub_type); + out_sec = bfd_get_section_by_name (info->output_bfd, out_sec_name); + if (out_sec != NULL) + out_sec->flags |= SEC_KEEP; + } +} + /* Select a BFD to be used to hold the sections used by the glue code. This function is called from the linker scripts in ld/emultempl/ {armelf/pe}.em. */ diff --git a/ld/ChangeLog b/ld/ChangeLog index 334d49a..7f8d690 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,9 @@ +2016-05-23 Thomas Preud'homme + + * emultempl/armelf.em (arm_elf_before_allocation): Call + bfd_elf32_arm_keep_private_stub_output_sections before generic + before_allocation function. + 2016-05-20 Maciej W. Rozycki * testsuite/ld-mips-elf/jalx-addend.d: New test. diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em index caa2fbf..6074824 100644 --- a/ld/emultempl/armelf.em +++ b/ld/emultempl/armelf.em @@ -83,6 +83,10 @@ arm_elf_before_allocation (void) /* Auto-select Cortex-A8 erratum fix if it wasn't explicitly specified. */ bfd_elf32_arm_set_cortex_a8_fix (link_info.output_bfd, &link_info); + /* Ensure the output sections of veneers needing a dedicated one is not + removed. */ + bfd_elf32_arm_keep_private_stub_output_sections (&link_info); + /* We should be able to set the size of the interworking stub section. We can't do it until later if we have dynamic sections, though. */ if (elf_hash_table (&link_info)->dynobj == NULL) -- 2.7.4