aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog9
-rw-r--r--bfd/bfd-in2.h7
-rw-r--r--bfd/elflink.c194
-rw-r--r--bfd/section.c7
-rw-r--r--ld/ChangeLog40
-rw-r--r--ld/emultempl/aarch64elf.em2
-rw-r--r--ld/emultempl/armelf.em2
-rw-r--r--ld/emultempl/beos.em2
-rw-r--r--ld/emultempl/cskyelf.em2
-rw-r--r--ld/emultempl/hppaelf.em2
-rw-r--r--ld/emultempl/m68hc1xelf.em2
-rw-r--r--ld/emultempl/metagelf.em2
-rw-r--r--ld/emultempl/mipself.em2
-rw-r--r--ld/emultempl/mmo.em2
-rw-r--r--ld/emultempl/msp430.em5
-rw-r--r--ld/emultempl/nios2elf.em2
-rw-r--r--ld/emultempl/pe.em4
-rw-r--r--ld/emultempl/pep.em4
-rw-r--r--ld/emultempl/ppc64elf.em2
-rw-r--r--ld/emultempl/spuelf.em4
-rw-r--r--ld/emultempl/vms.em2
-rw-r--r--ld/ldelf.c8
-rw-r--r--ld/ldelfgen.c243
-rw-r--r--ld/ldlang.c37
-rw-r--r--ld/ldlang.h8
-rw-r--r--ld/testsuite/ld-elf/pr26256-2a.d1
-rw-r--r--ld/testsuite/ld-elf/pr26256-2b.d3
-rw-r--r--ld/testsuite/ld-elf/pr26256-3b.d1
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
diff --git a/ld/ldelf.c b/ld/ldelf.c
index f7407ab..9887e53 100644
--- a/ld/ldelf.c
+++ b/ld/ldelf.c
@@ -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 +.+