+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
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
/* 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 \
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. */
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;
. 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
. {* 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 \
+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.
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;
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;
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;
}
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;
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;
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;
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;
/* 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;
(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;
}
/* 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);
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)
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;
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;
}
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;
}
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;
}
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;
}
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;
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;
}
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;
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
&& (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;
}
|| !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;
}
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;
}
&& 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;
}
#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))
{
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;
/* 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
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)
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)
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)
{
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)
{
/* 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
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. */
&& (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
{
&& (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)
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
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)
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. */
lang_output_section_phdr_list *phdrs;
+ /* Used by ELF SHF_LINK_ORDER sorting. */
+ void *data;
+
unsigned int block_value;
int constraint;
flagword flags;
{
lang_statement_header_type header;
asection *section;
+ void *pattern;
} lang_input_section_type;
struct map_symbol_def {
typedef struct lang_section_bst
{
asection *section;
+ void *pattern;
struct lang_section_bst *left;
struct lang_section_bst *right;
} lang_section_bst_type;
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;
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 *,
#source: pr26256-2.s
#ld: -e _start -T pr26256-2.t
#nm: -n
-#xfail: [is_generic]
#...
[0-9a-f]+ R linkorder2
#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.
#...
#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 +.+