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 cd6d537c48
. 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.
This commit is contained in:
parent
8c4645b488
commit
b209b5a6b8
28 changed files with 349 additions and 250 deletions
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
194
bfd/elflink.c
194
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;
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
40
ld/ChangeLog
40
ld/ChangeLog
|
@ -1,3 +1,43 @@
|
|||
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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
243
ld/ldelfgen.c
243
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))
|
||||
{
|
||||
|
|
37
ld/ldlang.c
37
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. */
|
||||
|
|
|
@ -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 *,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
#...
|
||||
|
|
|
@ -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 +.+
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue