diff -rup binutils.orig/bfd/bfd-in2.h binutils-2.35.1/bfd/bfd-in2.h --- binutils.orig/bfd/bfd-in2.h 2021-01-04 13:18:10.234368481 +0000 +++ binutils-2.35.1/bfd/bfd-in2.h 2021-01-04 13:18:20.596301287 +0000 @@ -1177,6 +1177,9 @@ typedef struct bfd_section struct bfd_symbol *symbol; struct bfd_symbol **symbol_ptr_ptr; + /* The matching section name pattern in linker script. */ + const char *pattern; + /* Early in the link process, map_head and map_tail are used to build a list of input sections attached to an output section. Later, output sections use these fields for a list of bfd_link_order @@ -1370,8 +1373,8 @@ discarded_section (const asection *sec) /* target_index, used_by_bfd, constructor_chain, owner, */ \ 0, NULL, NULL, NULL, \ \ - /* symbol, symbol_ptr_ptr, */ \ - (struct bfd_symbol *) SYM, &SEC.symbol, \ + /* symbol, symbol_ptr_ptr, pattern, */ \ + (struct bfd_symbol *) SYM, &SEC.symbol, NULL, \ \ /* map_head, map_tail, already_assigned */ \ { NULL }, { NULL }, NULL \ diff -rup binutils.orig/bfd/elflink.c binutils-2.35.1/bfd/elflink.c --- binutils.orig/bfd/elflink.c 2021-01-04 13:18:10.223368552 +0000 +++ binutils-2.35.1/bfd/elflink.c 2021-01-04 13:18:20.599301268 +0000 @@ -11662,8 +11662,21 @@ compare_link_order (const void *a, const const struct bfd_link_order *blo = *(const struct bfd_link_order **) b; asection *asec = elf_linked_to_section (alo->u.indirect.section); asection *bsec = elf_linked_to_section (blo->u.indirect.section); - bfd_vma apos = asec->output_section->lma + asec->output_offset; - bfd_vma bpos = bsec->output_section->lma + bsec->output_offset; + bfd_vma apos, bpos; + + /* Check if any sections are unordered. */ + if (asec == NULL || bsec == NULL) + { + /* Place ordered sections before unordered sections. */ + if (bsec != NULL) + return 1; + else if (asec != NULL) + return -1; + return 0; + } + + apos = asec->output_section->lma + asec->output_offset; + bpos = bsec->output_section->lma + bsec->output_offset; if (apos < bpos) return -1; @@ -11698,14 +11711,14 @@ compare_link_order (const void *a, const sections. Ideally we'd do this in the linker proper. */ static bfd_boolean -elf_fixup_link_order (bfd *abfd, asection *o) +elf_fixup_link_order (struct bfd_link_info *info, bfd *abfd, asection *o) { size_t seen_linkorder; size_t seen_other; size_t n; struct bfd_link_order *p; bfd *sub; - struct bfd_link_order **sections; + struct bfd_link_order **sections, **indirect_sections; asection *other_sec, *linkorder_sec; bfd_vma offset; /* Octets. */ @@ -11736,7 +11749,9 @@ elf_fixup_link_order (bfd *abfd, asectio else seen_other++; - if (seen_other && seen_linkorder) + /* Allow mixed ordered and unordered input sections for + non-relocatable link. */ + if (bfd_link_relocatable (info) && seen_other && seen_linkorder) { if (other_sec && linkorder_sec) _bfd_error_handler @@ -11756,6 +11771,10 @@ elf_fixup_link_order (bfd *abfd, asectio if (!seen_linkorder) return TRUE; + /* Non-relocatable output can have both ordered and unordered input + sections. */ + seen_linkorder += seen_other; + sections = bfd_malloc (seen_linkorder * sizeof (*sections)); if (sections == NULL) return FALSE; @@ -11764,22 +11783,51 @@ elf_fixup_link_order (bfd *abfd, asectio for (p = o->map_head.link_order; p != NULL; p = p->next) sections[seen_linkorder++] = p; - /* Sort the input sections in the order of their linked section. */ - qsort (sections, seen_linkorder, sizeof (*sections), compare_link_order); + for (indirect_sections = sections, n = 0; n < seen_linkorder;) + { + /* Find the first bfd_indirect_link_order section. */ + if (indirect_sections[0]->type == bfd_indirect_link_order) + { + /* Count the consecutive bfd_indirect_link_order sections + with the same pattern. */ + size_t i, n_indirect; + const char *pattern + = indirect_sections[0]->u.indirect.section->pattern; + for (i = n + 1; i < seen_linkorder; i++) + if (sections[i]->type != bfd_indirect_link_order + || sections[i]->u.indirect.section->pattern != pattern) + break; + n_indirect = i - n; + /* Sort the bfd_indirect_link_order sections in the order of + their linked section. */ + qsort (indirect_sections, n_indirect, sizeof (*sections), + compare_link_order); + indirect_sections += n_indirect; + n += n_indirect; + } + else + { + indirect_sections++; + n++; + } + } - /* Change the offsets of the sections. */ + /* Change the offsets of the bfd_indirect_link_order sections. */ offset = 0; for (n = 0; n < seen_linkorder; n++) - { - bfd_vma mask; - asection *s = sections[n]->u.indirect.section; - unsigned int opb = bfd_octets_per_byte (abfd, s); - - mask = ~(bfd_vma) 0 << s->alignment_power * opb; - offset = (offset + ~mask) & mask; - sections[n]->offset = s->output_offset = offset / opb; - offset += sections[n]->size; - } + if (sections[n]->type == bfd_indirect_link_order) + { + bfd_vma mask; + asection *s = sections[n]->u.indirect.section; + unsigned int opb = bfd_octets_per_byte (abfd, s); + + mask = ~(bfd_vma) 0 << s->alignment_power * opb; + offset = (offset + ~mask) & mask; + sections[n]->offset = s->output_offset = offset / opb; + offset += sections[n]->size; + } + else + offset = sections[n]->offset + sections[n]->size; free (sections); return TRUE; @@ -12408,7 +12456,7 @@ bfd_elf_final_link (bfd *abfd, struct bf /* Reorder SHF_LINK_ORDER sections. */ for (o = abfd->sections; o != NULL; o = o->next) { - if (!elf_fixup_link_order (abfd, o)) + if (!elf_fixup_link_order (info, abfd, o)) return FALSE; } diff -rup binutils.orig/bfd/section.c binutils-2.35.1/bfd/section.c --- binutils.orig/bfd/section.c 2021-01-04 13:18:10.233368487 +0000 +++ binutils-2.35.1/bfd/section.c 2021-01-04 13:18:20.599301268 +0000 @@ -541,6 +541,9 @@ CODE_FRAGMENT . struct bfd_symbol *symbol; . struct bfd_symbol **symbol_ptr_ptr; . +. {* The matching section name pattern in linker script. *} +. const char *pattern; +. . {* Early in the link process, map_head and map_tail are used to build . a list of input sections attached to an output section. Later, . output sections use these fields for a list of bfd_link_order @@ -734,8 +737,8 @@ CODE_FRAGMENT . {* target_index, used_by_bfd, constructor_chain, owner, *} \ . 0, NULL, NULL, NULL, \ . \ -. {* symbol, symbol_ptr_ptr, *} \ -. (struct bfd_symbol *) SYM, &SEC.symbol, \ +. {* symbol, symbol_ptr_ptr, pattern, *} \ +. (struct bfd_symbol *) SYM, &SEC.symbol, NULL, \ . \ . {* map_head, map_tail, already_assigned *} \ . { NULL }, { NULL }, NULL \ diff -rup binutils.orig/gas/config/obj-elf.c binutils-2.35.1/gas/config/obj-elf.c --- binutils.orig/gas/config/obj-elf.c 2021-01-04 13:18:09.942370375 +0000 +++ binutils-2.35.1/gas/config/obj-elf.c 2021-01-04 13:18:20.599301268 +0000 @@ -659,7 +659,9 @@ obj_elf_change_section (const char *name } } - if (old_sec == NULL && ((attr & ~(SHF_MASKOS | SHF_MASKPROC)) + if (old_sec == NULL && ((attr & ~(SHF_LINK_ORDER + | SHF_MASKOS + | SHF_MASKPROC)) & ~ssect->attr) != 0) { /* As a GNU extension, we permit a .note section to be diff -rup binutils.orig/ld/ldlang.c binutils-2.35.1/ld/ldlang.c --- binutils.orig/ld/ldlang.c 2021-01-04 13:18:09.691372002 +0000 +++ binutils-2.35.1/ld/ldlang.c 2021-01-04 13:18:20.600301261 +0000 @@ -7421,7 +7421,7 @@ lang_reset_memory_regions (void) static void gc_section_callback (lang_wild_statement_type *ptr, - struct wildcard_list *sec ATTRIBUTE_UNUSED, + struct wildcard_list *sec, asection *section, struct flag_info *sflag_info ATTRIBUTE_UNUSED, lang_input_statement_type *file ATTRIBUTE_UNUSED, @@ -7431,6 +7431,8 @@ gc_section_callback (lang_wild_statement should be as well. */ if (ptr->keep_sections) section->flags |= SEC_KEEP; + if (sec) + section->pattern = sec->spec.name; } /* Iterate over sections marking them against GC. */