aboutsummaryrefslogtreecommitdiff
path: root/ld
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2021-01-13 13:33:34 +1030
committerAlan Modra <amodra@gmail.com>2021-01-13 22:06:02 +1030
commitb209b5a6b8a4433be961a0f016439f381de65bfc (patch)
treeb540de64953f26165ed65e17c6b96a58b95e30c8 /ld
parent8c4645b4887660eb704f152f2a14c5108d56c9d7 (diff)
downloadfsf-binutils-gdb-b209b5a6b8a4433be961a0f016439f381de65bfc.zip
fsf-binutils-gdb-b209b5a6b8a4433be961a0f016439f381de65bfc.tar.gz
fsf-binutils-gdb-b209b5a6b8a4433be961a0f016439f381de65bfc.tar.bz2
SHF_LINK_ORDER fixup_link_order in ld
This moves the SHF_LINK_ORDER sorting from bfd_elf_final_link to the linker which means generic ELF targets now support SHF_LINK_ORDER and we cope with odd cases that require resizing of output sections. The patch also fixes two bugs in the current implementation, introduced by commit cd6d537c48fa. The pattern test used by that commit meant that sections matching something like "*(.IA_64.unwind* .gnu.linkonce.ia64unw.*)" would not properly sort a mix of sections matching the two wildcards. That commit also assumed a stable qsort. bfd/ PR 27160 * section.c (struct bfd_section): Remove pattern field. (BFD_FAKE_SECTION): Adjust to suit. * bfd-in2.h: Regenerate. * elflink.c (compare_link_order, elf_fixup_link_order): Delete. (bfd_elf_final_link): Don't call elf_fixup_link_order. ld/ PR 27160 * ldlang.h (lang_output_section_statement_type): Add data field. (lang_input_section_type, lang_section_bst_type): Add pattern field. (statement_list): Declare. (lang_add_section): Adjust prototype. * emultempl/aarch64elf.em: Adjust lang_add_section calls. * emultempl/armelf.em: Likewise. * emultempl/beos.em: Likewise. * emultempl/cskyelf.em: Likewise. * emultempl/hppaelf.em: Likewise. * emultempl/m68hc1xelf.em: Likewise. * emultempl/metagelf.em: Likewise. * emultempl/mipself.em: Likewise. * emultempl/mmo.em: Likewise. * emultempl/msp430.em: Likewise. * emultempl/nios2elf.em: Likewise. * emultempl/pe.em: Likewise. * emultempl/pep.em: Likewise. * emultempl/ppc64elf.em: Likewise. * emultempl/spuelf.em: Likewise. * emultempl/vms.em: Likewise. * ldelf.c: Likewise. * ldelfgen.c: Include ldctor.h. (struct os_sections): New. (add_link_order_input_section, link_order_scan): New functions. (compare_link_order, fixup_link_order): New functions. (ldelf_map_segments): Call link_order_scan and fixup_link_order. * ldlang.c (statement_list): Make global. (output_section_callback_fast): Save pattern in tree node. (lang_add_section): Add pattern parameter, save in lang_input_section. (output_section_callback_tree_to_list): Adjust lang_add_section calls. (lang_insert_orphan, output_section_callback): Likewise. (ldlang_place_orphan): Likewise. (gc_section_callback): Don't set section->pattern * testsuite/ld-elf/pr26256-2a.d: Don't xfail generic. * testsuite/ld-elf/pr26256-3b.d: Likewise. * testsuite/ld-elf/pr26256-2b.d: Likewise. notarget xgate.
Diffstat (limited to 'ld')
-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
24 files changed, 336 insertions, 46 deletions
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 +.+