diff options
author | Alan Modra <amodra@gmail.com> | 2021-01-13 13:33:34 +1030 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2021-01-13 22:06:02 +1030 |
commit | b209b5a6b8a4433be961a0f016439f381de65bfc (patch) | |
tree | b540de64953f26165ed65e17c6b96a58b95e30c8 | |
parent | 8c4645b4887660eb704f152f2a14c5108d56c9d7 (diff) | |
download | gdb-b209b5a6b8a4433be961a0f016439f381de65bfc.zip gdb-b209b5a6b8a4433be961a0f016439f381de65bfc.tar.gz gdb-b209b5a6b8a4433be961a0f016439f381de65bfc.tar.bz2 |
SHF_LINK_ORDER fixup_link_order in ld
This moves the SHF_LINK_ORDER sorting from bfd_elf_final_link to
the linker which means generic ELF targets now support SHF_LINK_ORDER
and we cope with odd cases that require resizing of output sections.
The patch also fixes two bugs in the current implementation,
introduced by commit cd6d537c48fa. The pattern test used by that
commit meant that sections matching something like
"*(.IA_64.unwind* .gnu.linkonce.ia64unw.*)" would not properly sort a
mix of sections matching the two wildcards. That commit also assumed
a stable qsort.
bfd/
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.
ld/
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.
-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 +.+ |