diff options
-rw-r--r-- | bfd/ChangeLog | 9 | ||||
-rw-r--r-- | bfd/bfd-in2.h | 7 | ||||
-rw-r--r-- | bfd/elflink.c | 194 | ||||
-rw-r--r-- | bfd/section.c | 7 | ||||
-rw-r--r-- | ld/ChangeLog | 40 | ||||
-rw-r--r-- | ld/emultempl/aarch64elf.em | 2 | ||||
-rw-r--r-- | ld/emultempl/armelf.em | 2 | ||||
-rw-r--r-- | ld/emultempl/beos.em | 2 | ||||
-rw-r--r-- | ld/emultempl/cskyelf.em | 2 | ||||
-rw-r--r-- | ld/emultempl/hppaelf.em | 2 | ||||
-rw-r--r-- | ld/emultempl/m68hc1xelf.em | 2 | ||||
-rw-r--r-- | ld/emultempl/metagelf.em | 2 | ||||
-rw-r--r-- | ld/emultempl/mipself.em | 2 | ||||
-rw-r--r-- | ld/emultempl/mmo.em | 2 | ||||
-rw-r--r-- | ld/emultempl/msp430.em | 5 | ||||
-rw-r--r-- | ld/emultempl/nios2elf.em | 2 | ||||
-rw-r--r-- | ld/emultempl/pe.em | 4 | ||||
-rw-r--r-- | ld/emultempl/pep.em | 4 | ||||
-rw-r--r-- | ld/emultempl/ppc64elf.em | 2 | ||||
-rw-r--r-- | ld/emultempl/spuelf.em | 4 | ||||
-rw-r--r-- | ld/emultempl/vms.em | 2 | ||||
-rw-r--r-- | ld/ldelf.c | 8 | ||||
-rw-r--r-- | ld/ldelfgen.c | 243 | ||||
-rw-r--r-- | ld/ldlang.c | 37 | ||||
-rw-r--r-- | ld/ldlang.h | 8 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/pr26256-2a.d | 1 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/pr26256-2b.d | 3 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/pr26256-3b.d | 1 |
28 files changed, 349 insertions, 250 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 158b798..0e12e74 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,12 @@ +2021-01-13 Alan Modra <amodra@gmail.com> + + PR 27160 + * section.c (struct bfd_section): Remove pattern field. + (BFD_FAKE_SECTION): Adjust to suit. + * bfd-in2.h: Regenerate. + * elflink.c (compare_link_order, elf_fixup_link_order): Delete. + (bfd_elf_final_link): Don't call elf_fixup_link_order. + 2021-01-12 H.J. Lu <hongjiu.lu@intel.com> PR binutils/26792 diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 7eff85b..d142bb5 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -1184,9 +1184,6 @@ 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 @@ -1380,8 +1377,8 @@ discarded_section (const asection *sec) /* target_index, used_by_bfd, constructor_chain, owner, */ \ 0, NULL, NULL, NULL, \ \ - /* symbol, symbol_ptr_ptr, pattern, */ \ - (struct bfd_symbol *) SYM, &SEC.symbol, NULL, \ + /* symbol, symbol_ptr_ptr, */ \ + (struct bfd_symbol *) SYM, &SEC.symbol, \ \ /* map_head, map_tail, already_assigned */ \ { NULL }, { NULL }, NULL \ diff --git a/bfd/elflink.c b/bfd/elflink.c index acc959d..d20857e 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -11863,193 +11863,6 @@ elf_reloc_link_order (bfd *output_bfd, return TRUE; } - -/* Compare two sections based on the locations of the sections they are - linked to. Used by elf_fixup_link_order. */ - -static int -compare_link_order (const void *a, const void *b) -{ - const struct bfd_link_order *alo = *(const struct bfd_link_order **) a; - 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, bpos; - - /* Check if any sections are unordered. */ - if (asec == NULL || bsec == NULL) - { - /* Place unordered sections before ordered 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; - if (apos > bpos) - return 1; - - /* The only way we should get matching LMAs is when the first of two - sections has zero size. */ - if (asec->size < bsec->size) - return -1; - if (asec->size > bsec->size) - return 1; - - /* If they are both zero size then they almost certainly have the same - VMA and thus are not ordered with respect to each other. Test VMA - anyway, and fall back to id to make the result reproducible across - qsort implementations. */ - apos = asec->output_section->vma + asec->output_offset; - bpos = bsec->output_section->vma + bsec->output_offset; - if (apos < bpos) - return -1; - if (apos > bpos) - return 1; - - return asec->id - bsec->id; -} - - -/* Looks for sections with SHF_LINK_ORDER set. Rearranges them into the same - order as their linked sections. Returns false if this could not be done - because an output section includes both ordered and unordered - sections. Ideally we'd do this in the linker proper. */ - -static bfd_boolean -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, **indirect_sections; - asection *other_sec, *linkorder_sec; - bfd_vma offset; /* Octets. */ - - other_sec = NULL; - linkorder_sec = NULL; - seen_other = 0; - seen_linkorder = 0; - for (p = o->map_head.link_order; p != NULL; p = p->next) - { - if (p->type == bfd_indirect_link_order) - { - asection *s = p->u.indirect.section; - sub = s->owner; - if ((s->flags & SEC_LINKER_CREATED) == 0 - && bfd_get_flavour (sub) == bfd_target_elf_flavour - && elf_section_data (s) != NULL - && elf_linked_to_section (s) != NULL) - { - seen_linkorder++; - linkorder_sec = s; - } - else - { - seen_other++; - other_sec = s; - } - } - else - seen_other++; - - /* 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 - /* xgettext:c-format */ - (_("%pA has both ordered [`%pA' in %pB] " - "and unordered [`%pA' in %pB] sections"), - o, linkorder_sec, linkorder_sec->owner, - other_sec, other_sec->owner); - else - _bfd_error_handler - (_("%pA has both ordered and unordered sections"), o); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - - 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; - - seen_linkorder = 0; - for (p = o->map_head.link_order; p != NULL; p = p->next) - sections[seen_linkorder++] = p; - - for (indirect_sections = sections, n = 0; - n < seen_linkorder; - indirect_sections++, n++) - { - /* 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; - } - } - - /* Change the offsets of the bfd_indirect_link_order sections. */ - offset = 0; - for (n = 0; n < seen_linkorder; n++) - 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); - - /* Verify that fixing up SHF_LINK_ORDER doesn't increase the section - size. */ - if (offset > o->size) - info->callbacks->einfo - (_("%F%P: %pA has ordered sections with incompatible alignments\n"), - o); - - return TRUE; -} - /* Generate an import library in INFO->implib_bfd from symbols in ABFD. Returns TRUE upon success, FALSE otherwise. */ @@ -12683,13 +12496,6 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) htab->tls_size = end - base; } - /* Reorder SHF_LINK_ORDER sections. */ - for (o = abfd->sections; o != NULL; o = o->next) - { - if (!elf_fixup_link_order (info, abfd, o)) - return FALSE; - } - if (!_bfd_elf_fixup_eh_frame_hdr (info)) return FALSE; diff --git a/bfd/section.c b/bfd/section.c index 10efc3c..3e6ba0c 100644 --- a/bfd/section.c +++ b/bfd/section.c @@ -541,9 +541,6 @@ 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 @@ -737,8 +734,8 @@ CODE_FRAGMENT . {* target_index, used_by_bfd, constructor_chain, owner, *} \ . 0, NULL, NULL, NULL, \ . \ -. {* symbol, symbol_ptr_ptr, pattern, *} \ -. (struct bfd_symbol *) SYM, &SEC.symbol, NULL, \ +. {* symbol, symbol_ptr_ptr, *} \ +. (struct bfd_symbol *) SYM, &SEC.symbol, \ . \ . {* map_head, map_tail, already_assigned *} \ . { NULL }, { NULL }, NULL \ diff --git a/ld/ChangeLog b/ld/ChangeLog index 0224aef..b1db011 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,5 +1,45 @@ 2021-01-13 Alan Modra <amodra@gmail.com> + PR 27160 + * ldlang.h (lang_output_section_statement_type): Add data field. + (lang_input_section_type, lang_section_bst_type): Add pattern field. + (statement_list): Declare. + (lang_add_section): Adjust prototype. + * emultempl/aarch64elf.em: Adjust lang_add_section calls. + * emultempl/armelf.em: Likewise. + * emultempl/beos.em: Likewise. + * emultempl/cskyelf.em: Likewise. + * emultempl/hppaelf.em: Likewise. + * emultempl/m68hc1xelf.em: Likewise. + * emultempl/metagelf.em: Likewise. + * emultempl/mipself.em: Likewise. + * emultempl/mmo.em: Likewise. + * emultempl/msp430.em: Likewise. + * emultempl/nios2elf.em: Likewise. + * emultempl/pe.em: Likewise. + * emultempl/pep.em: Likewise. + * emultempl/ppc64elf.em: Likewise. + * emultempl/spuelf.em: Likewise. + * emultempl/vms.em: Likewise. + * ldelf.c: Likewise. + * ldelfgen.c: Include ldctor.h. + (struct os_sections): New. + (add_link_order_input_section, link_order_scan): New functions. + (compare_link_order, fixup_link_order): New functions. + (ldelf_map_segments): Call link_order_scan and fixup_link_order. + * ldlang.c (statement_list): Make global. + (output_section_callback_fast): Save pattern in tree node. + (lang_add_section): Add pattern parameter, save in lang_input_section. + (output_section_callback_tree_to_list): Adjust lang_add_section calls. + (lang_insert_orphan, output_section_callback): Likewise. + (ldlang_place_orphan): Likewise. + (gc_section_callback): Don't set section->pattern. + * testsuite/ld-elf/pr26256-2a.d: Don't xfail generic. + * testsuite/ld-elf/pr26256-3b.d: Likewise. + * testsuite/ld-elf/pr26256-2b.d: Likewise. notarget xgate. + +2021-01-13 Alan Modra <amodra@gmail.com> + * ldlang.h (callback_t): Remove flag_info function parameter. * ldlang.c (walk_wild_consider_section): Adjust to suit. (walk_wild_section_general): Likewise. diff --git a/ld/emultempl/aarch64elf.em b/ld/emultempl/aarch64elf.em index bda5afc..a185560 100644 --- a/ld/emultempl/aarch64elf.em +++ b/ld/emultempl/aarch64elf.em @@ -192,7 +192,7 @@ elf${ELFSIZE}_aarch64_add_stub_section (const char *stub_sec_name, info.input_section = input_section; lang_list_init (&info.add); - lang_add_section (&info.add, stub_sec, NULL, os); + lang_add_section (&info.add, stub_sec, NULL, NULL, os); if (info.add.head == NULL) goto err_ret; diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em index 0c03108..a4cf93b 100644 --- a/ld/emultempl/armelf.em +++ b/ld/emultempl/armelf.em @@ -246,7 +246,7 @@ elf32_arm_add_stub_section (const char * stub_sec_name, info.input_section = after_input_section; lang_list_init (&info.add); - lang_add_section (&info.add, stub_sec, NULL, os); + lang_add_section (&info.add, stub_sec, NULL, NULL, os); if (info.add.head == NULL) goto err_ret; diff --git a/ld/emultempl/beos.em b/ld/emultempl/beos.em index 64c0e11..bb4395f 100644 --- a/ld/emultempl/beos.em +++ b/ld/emultempl/beos.em @@ -704,7 +704,7 @@ gld${EMULATION_NAME}_place_orphan (asection *s, The sections still have to be sorted, but that has to wait until all such sections have been processed by us. The sorting is done by sort_sections. */ - lang_add_section (&l->wild_statement.children, s, NULL, os); + lang_add_section (&l->wild_statement.children, s, NULL, NULL, os); return os; } diff --git a/ld/emultempl/cskyelf.em b/ld/emultempl/cskyelf.em index ce4047b..ca38cf6 100644 --- a/ld/emultempl/cskyelf.em +++ b/ld/emultempl/cskyelf.em @@ -189,7 +189,7 @@ elf32_csky_add_stub_section (const char *stub_sec_name, info.input_section = input_section; lang_list_init (&info.add); - lang_add_section (&info.add, stub_sec, NULL, os); + lang_add_section (&info.add, stub_sec, NULL, NULL, os); if (info.add.head == NULL) goto err_ret; diff --git a/ld/emultempl/hppaelf.em b/ld/emultempl/hppaelf.em index bbb8b7f..f195a17 100644 --- a/ld/emultempl/hppaelf.em +++ b/ld/emultempl/hppaelf.em @@ -193,7 +193,7 @@ hppaelf_add_stub_section (const char *stub_sec_name, asection *input_section) info.input_section = input_section; lang_list_init (&info.add); - lang_add_section (&info.add, stub_sec, NULL, os); + lang_add_section (&info.add, stub_sec, NULL, NULL, os); if (info.add.head == NULL) goto err_ret; diff --git a/ld/emultempl/m68hc1xelf.em b/ld/emultempl/m68hc1xelf.em index c4546c6..212db7c 100644 --- a/ld/emultempl/m68hc1xelf.em +++ b/ld/emultempl/m68hc1xelf.em @@ -275,7 +275,7 @@ m68hc11elf_add_stub_section (const char *stub_sec_name, at the correct place. */ info.input_section = tramp_section; lang_list_init (&info.add); - lang_add_section (&info.add, stub_sec, NULL, os); + lang_add_section (&info.add, stub_sec, NULL, NULL, os); if (info.add.head == NULL) goto err_ret; diff --git a/ld/emultempl/metagelf.em b/ld/emultempl/metagelf.em index 51bec07..41ada3f 100644 --- a/ld/emultempl/metagelf.em +++ b/ld/emultempl/metagelf.em @@ -169,7 +169,7 @@ metagelf_add_stub_section (const char *stub_sec_name, asection *input_section) info.input_section = input_section; lang_list_init (&info.add); - lang_add_section (&info.add, stub_sec, NULL, os); + lang_add_section (&info.add, stub_sec, NULL, NULL, os); if (info.add.head == NULL) goto err_ret; diff --git a/ld/emultempl/mipself.em b/ld/emultempl/mipself.em index d27aa76..e27e53c 100644 --- a/ld/emultempl/mipself.em +++ b/ld/emultempl/mipself.em @@ -175,7 +175,7 @@ mips_add_stub_section (const char *stub_sec_name, asection *input_section, /* Initialize a statement list that contains only the new statement. */ lang_list_init (&info.add); - lang_add_section (&info.add, stub_sec, NULL, os); + lang_add_section (&info.add, stub_sec, NULL, NULL, os); if (info.add.head == NULL) goto err_ret; diff --git a/ld/emultempl/mmo.em b/ld/emultempl/mmo.em index 4289e77..fa0b19a 100644 --- a/ld/emultempl/mmo.em +++ b/ld/emultempl/mmo.em @@ -102,7 +102,7 @@ mmo_place_orphan (asection *s, (regardless of whether the linker script lists it as input). */ if (os != NULL) { - lang_add_section (&os->children, s, NULL, os); + lang_add_section (&os->children, s, NULL, NULL, os); return os; } diff --git a/ld/emultempl/msp430.em b/ld/emultempl/msp430.em index e3ea3c6..7e364af 100644 --- a/ld/emultempl/msp430.em +++ b/ld/emultempl/msp430.em @@ -325,7 +325,7 @@ gld${EMULATION_NAME}_place_orphan (asection * s, /* Always place orphaned sections in lower. Optimal placement of either sections is performed later, once section sizes have been finalized. */ - lang_add_section (& lower->children, s, NULL, lower); + lang_add_section (& lower->children, s, NULL, NULL, lower); end: free (upper_name); free (lower_name); @@ -358,7 +358,8 @@ change_output_section (lang_statement_union_type **head, lang_statement_list_type *old_list = (lang_statement_list_type *) &old_os->children; s->output_section = NULL; - lang_add_section (&new_os->children, s, NULL, new_os); + lang_add_section (&new_os->children, s, + curr->input_section.pattern, NULL, new_os); /* Remove the section from the old output section. */ if (prev == NULL) diff --git a/ld/emultempl/nios2elf.em b/ld/emultempl/nios2elf.em index 2905980..fcc2756 100644 --- a/ld/emultempl/nios2elf.em +++ b/ld/emultempl/nios2elf.em @@ -186,7 +186,7 @@ nios2elf_add_stub_section (const char *stub_sec_name, asection *input_section, info.input_section = input_section; lang_list_init (&info.add); - lang_add_section (&info.add, stub_sec, NULL, os); + lang_add_section (&info.add, stub_sec, NULL, NULL, os); if (info.add.head == NULL) goto err_ret; diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em index ab7d4c4..f9060be 100644 --- a/ld/emultempl/pe.em +++ b/ld/emultempl/pe.em @@ -2085,7 +2085,7 @@ gld_${EMULATION_NAME}_place_orphan (asection *s, If the section already exists but does not have any flags set, then it has been created by the linker, probably as a result of a --section-start command line switch. */ - lang_add_section (&add_child, s, NULL, os); + lang_add_section (&add_child, s, NULL, NULL, os); break; } @@ -2099,7 +2099,7 @@ gld_${EMULATION_NAME}_place_orphan (asection *s, unused one and use that. */ if (os == NULL && match_by_name) { - lang_add_section (&match_by_name->children, s, NULL, match_by_name); + lang_add_section (&match_by_name->children, s, NULL, NULL, match_by_name); return match_by_name; } diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em index 3fdd605..ca335b5 100644 --- a/ld/emultempl/pep.em +++ b/ld/emultempl/pep.em @@ -1905,7 +1905,7 @@ gld_${EMULATION_NAME}_place_orphan (asection *s, If the section already exists but does not have any flags set, then it has been created by the linker, probably as a result of a --section-start command line switch. */ - lang_add_section (&add_child, s, NULL, os); + lang_add_section (&add_child, s, NULL, NULL, os); break; } @@ -1919,7 +1919,7 @@ gld_${EMULATION_NAME}_place_orphan (asection *s, unused one and use that. */ if (os == NULL && match_by_name) { - lang_add_section (&match_by_name->children, s, NULL, match_by_name); + lang_add_section (&match_by_name->children, s, NULL, NULL, match_by_name); return match_by_name; } diff --git a/ld/emultempl/ppc64elf.em b/ld/emultempl/ppc64elf.em index 403fd09..8253604 100644 --- a/ld/emultempl/ppc64elf.em +++ b/ld/emultempl/ppc64elf.em @@ -445,7 +445,7 @@ ppc_add_stub_section (const char *stub_sec_name, asection *input_section) info.input_section = input_section; lang_list_init (&info.add); - lang_add_section (&info.add, stub_sec, NULL, os); + lang_add_section (&info.add, stub_sec, NULL, NULL, os); if (info.add.head == NULL) goto err_ret; diff --git a/ld/emultempl/spuelf.em b/ld/emultempl/spuelf.em index 2afad3e..0c51b8e 100644 --- a/ld/emultempl/spuelf.em +++ b/ld/emultempl/spuelf.em @@ -151,7 +151,7 @@ spu_place_special_section (asection *s, asection *o, const char *output_name) lang_statement_list_type add; lang_list_init (&add); - lang_add_section (&add, s, NULL, os); + lang_add_section (&add, s, NULL, NULL, os); *add.tail = os->children.head; os->children.head = add.head; } @@ -168,7 +168,7 @@ spu_place_special_section (asection *s, asection *o, const char *output_name) lang_add_assignment (exp_assign (".", e_size, FALSE)); pop_stat_ptr (); } - lang_add_section (&os->children, s, NULL, os); + lang_add_section (&os->children, s, NULL, NULL, os); } s->output_section->size += s->size; diff --git a/ld/emultempl/vms.em b/ld/emultempl/vms.em index 3aa00e3..4c86962 100644 --- a/ld/emultempl/vms.em +++ b/ld/emultempl/vms.em @@ -116,7 +116,7 @@ vms_place_orphan (asection *s, if (hold_data.os != NULL) { - lang_add_section (&hold_data.os->children, s, NULL, hold_data.os); + lang_add_section (&hold_data.os->children, s, NULL, NULL, hold_data.os); return hold_data.os; } else @@ -2006,7 +2006,7 @@ ldelf_place_orphan (asection *s, const char *secname, int constraint) && (elf_section_data (os->bfd_section)->this_hdr.sh_info == elf_section_data (s)->this_hdr.sh_info)) { - lang_add_section (&os->children, s, NULL, os); + lang_add_section (&os->children, s, NULL, NULL, os); return os; } @@ -2049,7 +2049,7 @@ ldelf_place_orphan (asection *s, const char *secname, int constraint) || !elfoutput || elf_orphan_compatible (s, os->bfd_section))))) { - lang_add_section (&os->children, s, NULL, os); + lang_add_section (&os->children, s, NULL, NULL, os); return os; } @@ -2063,7 +2063,7 @@ ldelf_place_orphan (asection *s, const char *secname, int constraint) unused one and use that. */ if (match_by_name) { - lang_add_section (&match_by_name->children, s, NULL, match_by_name); + lang_add_section (&match_by_name->children, s, NULL, NULL, match_by_name); return match_by_name; } @@ -2088,7 +2088,7 @@ ldelf_place_orphan (asection *s, const char *secname, int constraint) && hold[orphan_text].os != NULL) { os = hold[orphan_text].os; - lang_add_section (&os->children, s, NULL, os); + lang_add_section (&os->children, s, NULL, NULL, os); return os; } diff --git a/ld/ldelfgen.c b/ld/ldelfgen.c index f0502ef..8014e22 100644 --- a/ld/ldelfgen.c +++ b/ld/ldelfgen.c @@ -27,20 +27,263 @@ #include "ldmisc.h" #include "ldexp.h" #include "ldlang.h" +#include "ldctor.h" #include "elf-bfd.h" #include "elf/internal.h" #include "ldelfgen.h" +/* Info attached to an output_section_statement about input sections, + used when sorting SHF_LINK_ORDER sections. */ + +struct os_sections +{ + /* Size allocated for isec. */ + unsigned int alloc; + /* Used entries in isec. */ + unsigned int count; + /* How many are SHF_LINK_ORDER. */ + unsigned int ordered; + /* Input sections attached to this output section. */ + struct os_sections_input { + lang_input_section_type *is; + unsigned int idx; + } isec[1]; +}; + +/* Add IS to data kept for OS. */ + +static bfd_boolean +add_link_order_input_section (lang_input_section_type *is, + lang_output_section_statement_type *os) +{ + struct os_sections *os_info = os->data; + asection *s; + + if (os_info == NULL) + { + os_info = xmalloc (sizeof (*os_info) + 63 * sizeof (*os_info->isec)); + os_info->alloc = 64; + os_info->count = 0; + os_info->ordered = 0; + os->data = os_info; + } + if (os_info->count == os_info->alloc) + { + size_t want; + os_info->alloc *= 2; + want = sizeof (*os_info) + (os_info->alloc - 1) * sizeof (*os_info->isec); + os_info = xrealloc (os_info, want); + os->data = os_info; + } + os_info->isec[os_info->count].is = is; + os_info->isec[os_info->count].idx = os_info->count; + os_info->count++; + s = is->section; + if ((s->flags & SEC_LINKER_CREATED) == 0 + && elf_section_data (s) != NULL + && elf_linked_to_section (s) != NULL) + os_info->ordered++; + return FALSE; +} + +/* Run over the linker's statement list, extracting info about input + sections attached to each output section. */ + +static bfd_boolean +link_order_scan (lang_statement_union_type *u, + lang_output_section_statement_type *os) +{ + asection *s; + bfd_boolean ret = FALSE; + + for (; u != NULL; u = u->header.next) + { + switch (u->header.type) + { + case lang_wild_statement_enum: + if (link_order_scan (u->wild_statement.children.head, os)) + ret = TRUE; + break; + case lang_constructors_statement_enum: + if (link_order_scan (constructor_list.head, os)) + ret = TRUE; + break; + case lang_output_section_statement_enum: + if (u->output_section_statement.constraint != -1 + && link_order_scan (u->output_section_statement.children.head, + &u->output_section_statement)) + ret = TRUE; + break; + case lang_group_statement_enum: + if (link_order_scan (u->group_statement.children.head, os)) + ret = TRUE; + break; + case lang_input_section_enum: + s = u->input_section.section; + if (s->output_section != NULL + && s->output_section->owner == link_info.output_bfd + && (s->output_section->flags & SEC_EXCLUDE) == 0 + && ((s->output_section->flags & SEC_HAS_CONTENTS) != 0 + || ((s->output_section->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) + == (SEC_LOAD | SEC_THREAD_LOCAL)))) + if (add_link_order_input_section (&u->input_section, os)) + ret = TRUE; + break; + default: + break; + } + } + return ret; +} + +/* Compare two sections based on the locations of the sections they are + linked to. Used by fixup_link_order. */ + +static int +compare_link_order (const void *a, const void *b) +{ + const struct os_sections_input *ai = a; + const struct os_sections_input *bi = b; + asection *asec = elf_linked_to_section (ai->is->section); + asection *bsec = elf_linked_to_section (bi->is->section); + bfd_vma apos, bpos; + + /* Place unordered sections before ordered sections. */ + if (asec == NULL || bsec == NULL) + { + if (bsec != NULL) + return -1; + else if (asec != NULL) + return 1; + return ai->idx - bi->idx; + } + + apos = asec->output_section->lma + asec->output_offset; + bpos = bsec->output_section->lma + bsec->output_offset; + + if (apos < bpos) + return -1; + else if (apos > bpos) + return 1; + + /* The only way we should get matching LMAs is when the first of two + sections has zero size. */ + if (asec->size < bsec->size) + return -1; + else if (asec->size > bsec->size) + return 1; + + /* If they are both zero size then they almost certainly have the same + VMA and thus are not ordered with respect to each other. Test VMA + anyway, and fall back to id to make the result reproducible across + qsort implementations. */ + apos = asec->output_section->vma + asec->output_offset; + bpos = bsec->output_section->vma + bsec->output_offset; + if (apos < bpos) + return -1; + else if (apos > bpos) + return 1; + + return asec->id - bsec->id; +} + +/* Rearrange sections with SHF_LINK_ORDER into the same order as their + linked sections. */ + +static bfd_boolean +fixup_link_order (lang_output_section_statement_type *os) +{ + struct os_sections *os_info = os->data; + unsigned int i, j; + lang_input_section_type **orig_is; + asection **save_s; + + for (i = 0; i < os_info->count; i = j) + { + /* Normally a linker script will select SHF_LINK_ORDER sections + with an input section wildcard something like the following: + *(.IA_64.unwind* .gnu.linkonce.ia64unw.*) + However if some other random sections are smashed into an + output section, or if SHF_LINK_ORDER are split up by the + linker script, then we only want to sort sections matching a + given wildcard. That's the purpose of the pattern test. */ + for (j = i + 1; j < os_info->count; j++) + if (os_info->isec[j].is->pattern != os_info->isec[i].is->pattern) + break; + if (j - i > 1) + qsort (&os_info->isec[i], j - i, sizeof (*os_info->isec), + compare_link_order); + } + for (i = 0; i < os_info->count; i++) + if (os_info->isec[i].idx != i) + break; + if (i == os_info->count) + return FALSE; + + /* Now reorder the linker input section statements to reflect the + proper sorting. The is done by rewriting the existing statements + rather than fiddling with lists, since the only thing we need to + change is the bfd section pointer. */ + orig_is = xmalloc (os_info->count * sizeof (*orig_is)); + save_s = xmalloc (os_info->count * sizeof (*save_s)); + for (i = 0; i < os_info->count; i++) + { + orig_is[os_info->isec[i].idx] = os_info->isec[i].is; + save_s[i] = os_info->isec[i].is->section; + } + for (i = 0; i < os_info->count; i++) + if (os_info->isec[i].idx != i) + { + orig_is[i]->section = save_s[i]; + /* Restore os_info to pristine state before the qsort, for the + next pass over sections. */ + os_info->isec[i].is = orig_is[i]; + os_info->isec[i].idx = i; + } + free (save_s); + free (orig_is); + return TRUE; +} + void ldelf_map_segments (bfd_boolean need_layout) { int tries = 10; + static bfd_boolean done_link_order_scan = FALSE; do { lang_relax_sections (need_layout); need_layout = FALSE; + if (link_info.output_bfd->xvec->flavour == bfd_target_elf_flavour) + { + lang_output_section_statement_type *os; + if (!done_link_order_scan) + { + link_order_scan (statement_list.head, NULL); + done_link_order_scan = TRUE; + } + for (os = (void *) lang_os_list.head; os != NULL; os = os->next) + { + struct os_sections *os_info = os->data; + if (os_info != NULL && os_info->ordered != 0) + { + if (os_info->ordered != os_info->count + && bfd_link_relocatable (&link_info)) + { + einfo (_("%F%P: " + "%pA has both ordered and unordered sections"), + os->bfd_section); + return; + } + if (os_info->count > 1 + && fixup_link_order (os)) + need_layout = TRUE; + } + } + } + if (link_info.output_bfd->xvec->flavour == bfd_target_elf_flavour && !bfd_link_relocatable (&link_info)) { diff --git a/ld/ldlang.c b/ld/ldlang.c index 4d3560f..4ae9cec 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -69,13 +69,6 @@ static bfd_boolean map_option_f; static bfd_vma print_dot; static lang_input_statement_type *first_file; static const char *current_target; -/* Header for list of statements corresponding to any files involved in the - link, either specified from the command-line or added implicitely (eg. - archive member used to resolved undefined symbol, wildcard statement from - linker script, etc.). Next pointer is in next field of a - lang_statement_header_type (reached via header field in a - lang_statement_union). */ -static lang_statement_list_type statement_list; static lang_statement_list_type *stat_save[10]; static lang_statement_list_type **stat_save_ptr = &stat_save[0]; static struct unique_sections *unique_section_list; @@ -103,6 +96,13 @@ static void lang_do_memory_regions (bfd_boolean); /* Exported variables. */ const char *output_target; lang_output_section_statement_type *abs_output_section; +/* Header for list of statements corresponding to any files involved in the + link, either specified from the command-line or added implicitely (eg. + archive member used to resolved undefined symbol, wildcard statement from + linker script, etc.). Next pointer is in next field of a + lang_statement_header_type (reached via header field in a + lang_statement_union). */ +lang_statement_list_type statement_list; lang_statement_list_type lang_os_list; lang_statement_list_type *stat_ptr = &statement_list; /* Header for list of statements corresponding to files used in the final @@ -582,6 +582,7 @@ output_section_callback_fast (lang_wild_statement_type *ptr, node->left = 0; node->right = 0; node->section = section; + node->pattern = ptr->section_list; tree = wild_sort_fast (ptr, sec, file, section); if (tree != NULL) @@ -598,7 +599,7 @@ output_section_callback_tree_to_list (lang_wild_statement_type *ptr, if (tree->left) output_section_callback_tree_to_list (ptr, tree->left, output); - lang_add_section (&ptr->children, tree->section, NULL, + lang_add_section (&ptr->children, tree->section, tree->pattern, NULL, (lang_output_section_statement_type *) output); if (tree->right) @@ -1896,7 +1897,7 @@ lang_insert_orphan (asection *s, if (add_child == NULL) add_child = &os->children; - lang_add_section (add_child, s, NULL, os); + lang_add_section (add_child, s, NULL, NULL, os); if (after && (s->flags & (SEC_LOAD | SEC_ALLOC)) != 0) { @@ -2537,6 +2538,7 @@ lang_discard_section_p (asection *section) void lang_add_section (lang_statement_list_type *ptr, asection *section, + struct wildcard_list *pattern, struct flag_info *sflag_info, lang_output_section_statement_type *output) { @@ -2717,6 +2719,7 @@ lang_add_section (lang_statement_list_type *ptr, /* Add a section reference to the list. */ new_section = new_stat (lang_input_section, ptr); new_section->section = section; + new_section->pattern = pattern; } /* Handle wildcard sorting. This returns the lang_input_section which @@ -2842,14 +2845,16 @@ output_section_callback (lang_wild_statement_type *ptr, of the current list. */ if (before == NULL) - lang_add_section (&ptr->children, section, ptr->section_flag_list, os); + lang_add_section (&ptr->children, section, ptr->section_list, + ptr->section_flag_list, os); else { lang_statement_list_type list; lang_statement_union_type **pp; lang_list_init (&list); - lang_add_section (&list, section, ptr->section_flag_list, os); + lang_add_section (&list, section, ptr->section_list, + ptr->section_flag_list, os); /* If we are discarding the section, LIST.HEAD will be NULL. */ @@ -7204,7 +7209,7 @@ ldlang_place_orphan (asection *s) && (bfd_link_relocatable (&link_info) || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)) os->addr_tree = exp_intop (0); - lang_add_section (&os->children, s, NULL, os); + lang_add_section (&os->children, s, NULL, NULL, os); } else { @@ -7227,7 +7232,7 @@ ldlang_place_orphan (asection *s) && (bfd_link_relocatable (&link_info) || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)) os->addr_tree = exp_intop (0); - lang_add_section (&os->children, s, NULL, os); + lang_add_section (&os->children, s, NULL, NULL, os); } if (config.orphan_handling == orphan_handling_warn) @@ -7271,7 +7276,7 @@ lang_place_orphans (void) default_common_section = lang_output_section_statement_lookup (".bss", 0, 1); lang_add_section (&default_common_section->children, s, - NULL, default_common_section); + NULL, NULL, default_common_section); } } else @@ -7485,7 +7490,7 @@ lang_reset_memory_regions (void) static void gc_section_callback (lang_wild_statement_type *ptr, - struct wildcard_list *sec, + struct wildcard_list *sec ATTRIBUTE_UNUSED, asection *section, lang_input_statement_type *file ATTRIBUTE_UNUSED, void *data ATTRIBUTE_UNUSED) @@ -7494,8 +7499,6 @@ gc_section_callback (lang_wild_statement_type *ptr, 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. */ diff --git a/ld/ldlang.h b/ld/ldlang.h index 205c305..3463d4c 100644 --- a/ld/ldlang.h +++ b/ld/ldlang.h @@ -158,6 +158,9 @@ typedef struct lang_output_section_statement_struct lang_output_section_phdr_list *phdrs; + /* Used by ELF SHF_LINK_ORDER sorting. */ + void *data; + unsigned int block_value; int constraint; flagword flags; @@ -323,6 +326,7 @@ typedef struct { lang_statement_header_type header; asection *section; + void *pattern; } lang_input_section_type; struct map_symbol_def { @@ -364,6 +368,7 @@ typedef bfd_boolean (*lang_match_sec_type_func) (bfd *, const asection *, typedef struct lang_section_bst { asection *section; + void *pattern; struct lang_section_bst *left; struct lang_section_bst *right; } lang_section_bst_type; @@ -506,6 +511,7 @@ extern lang_output_section_statement_type *abs_output_section; extern lang_statement_list_type lang_os_list; extern struct lang_input_statement_flags input_flags; extern bfd_boolean lang_has_input_file; +extern lang_statement_list_type statement_list; extern lang_statement_list_type *stat_ptr; extern bfd_boolean delete_output_file_on_failure; @@ -650,7 +656,7 @@ extern void lang_enter_group extern void lang_leave_group (void); extern void lang_add_section - (lang_statement_list_type *, asection *, + (lang_statement_list_type *, asection *, struct wildcard_list *, struct flag_info *, lang_output_section_statement_type *); extern void lang_new_phdr (const char *, etree_type *, bfd_boolean, bfd_boolean, etree_type *, diff --git a/ld/testsuite/ld-elf/pr26256-2a.d b/ld/testsuite/ld-elf/pr26256-2a.d index 03804d8..24e8e67 100644 --- a/ld/testsuite/ld-elf/pr26256-2a.d +++ b/ld/testsuite/ld-elf/pr26256-2a.d @@ -1,7 +1,6 @@ #source: pr26256-2.s #ld: -e _start -T pr26256-2.t #nm: -n -#xfail: [is_generic] #... [0-9a-f]+ R linkorder2 diff --git a/ld/testsuite/ld-elf/pr26256-2b.d b/ld/testsuite/ld-elf/pr26256-2b.d index 60c3bff..3f8c37e 100644 --- a/ld/testsuite/ld-elf/pr26256-2b.d +++ b/ld/testsuite/ld-elf/pr26256-2b.d @@ -1,8 +1,7 @@ #source: pr26256-2.s #ld: -e _start #nm: -n -#xfail: [is_generic] -#notarget: fr30-*-* iq2000-*-* ip2k-*-* xstormy16-*-* +#notarget: fr30-*-* iq2000-*-* ip2k-*-* xgate-*-* xstormy16-*-* # These targets place .linkorder sections before .text sections. #... diff --git a/ld/testsuite/ld-elf/pr26256-3b.d b/ld/testsuite/ld-elf/pr26256-3b.d index 7d6dff2..8a5e6dd 100644 --- a/ld/testsuite/ld-elf/pr26256-3b.d +++ b/ld/testsuite/ld-elf/pr26256-3b.d @@ -1,7 +1,6 @@ #source: pr26256-3.s #ld: -e _start -T pr26256-3b.t #readelf: -x .rodata -x .text -#xfail: [is_generic] Hex dump of section \'.rodata\': 0x[a-f0-9]+ +00020301 +040907 +.+ |