SHF_LINK_ORDER fixup_link_order in ld
authorAlan Modra <amodra@gmail.com>
Wed, 13 Jan 2021 03:03:34 +0000 (13:33 +1030)
committerAlan Modra <amodra@gmail.com>
Wed, 13 Jan 2021 11:36:02 +0000 (22:06 +1030)
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.

28 files changed:
bfd/ChangeLog
bfd/bfd-in2.h
bfd/elflink.c
bfd/section.c
ld/ChangeLog
ld/emultempl/aarch64elf.em
ld/emultempl/armelf.em
ld/emultempl/beos.em
ld/emultempl/cskyelf.em
ld/emultempl/hppaelf.em
ld/emultempl/m68hc1xelf.em
ld/emultempl/metagelf.em
ld/emultempl/mipself.em
ld/emultempl/mmo.em
ld/emultempl/msp430.em
ld/emultempl/nios2elf.em
ld/emultempl/pe.em
ld/emultempl/pep.em
ld/emultempl/ppc64elf.em
ld/emultempl/spuelf.em
ld/emultempl/vms.em
ld/ldelf.c
ld/ldelfgen.c
ld/ldlang.c
ld/ldlang.h
ld/testsuite/ld-elf/pr26256-2a.d
ld/testsuite/ld-elf/pr26256-2b.d
ld/testsuite/ld-elf/pr26256-3b.d

index 158b798c35ca597db87a9ade250fef12ca5b7927..0e12e74ea6ed1fccd4846583de2b229d734caf08 100644 (file)
@@ -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
index 7eff85b7eaa6e58e26baf24b6dae06597688c18a..d142bb5221348554039a8ba9504f3a65c7eb7a3e 100644 (file)
@@ -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                                          \
index acc959d526a9adecb8314ddfbae560a6922ff080..d20857eb6bd063ed60122d526e69b7ab7f32ce4c 100644 (file)
@@ -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;
 
index 10efc3c4aa7bf1030e9f5a639a01d895f79dbc22..3e6ba0c09389c21b149e6fc8dff599050b4f7282 100644 (file)
@@ -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                                         \
index 0224aef5a32cf6a230d7b248464acd7218236dda..b1db01110d71b73c42773e590473da01ae15e8c6 100644 (file)
@@ -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.
index bda5afcb1e935d9a10c3267b370e939caf5cf916..a1855607327ec4942e5902d2e605788f60741558 100644 (file)
@@ -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;
index 0c031080bdb51420bc4f5181149ce4ef7c08c067..a4cf93b493daab32c754197aae4847879b10306e 100644 (file)
@@ -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;
index 64c0e1102e3286e8c9349608407ef777ca2a1c02..bb4395f63ae964e5e71333cc4629417af770d799 100644 (file)
@@ -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;
 }
index ce4047b49bb66c77640fcf67c7f70f634ed075df..ca38cf62b9826b7b1c58d6b3943b284232f91b62 100644 (file)
@@ -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;
index bbb8b7f4d70b6a79c00a1499dbe7990bfd1c52b4..f195a177aba28c0089dbcf173ccf0cd3d680cd16 100644 (file)
@@ -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;
index c4546c62777b798071decb63d340e15e75cec957..212db7c4e107464e0a3af381fc4d6c944130331d 100644 (file)
@@ -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;
index 51bec07f3c68614c91f35f9864a260266714724f..41ada3fbebbb56252700551da7ceba6f543ef2e0 100644 (file)
@@ -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;
index d27aa769f83bb4205aea36373bdf3b8a0a402218..e27e53cf556f2b175cf5fe127609e8acb7842064 100644 (file)
@@ -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;
 
index 4289e779bcb7336b97370816c31754fac6eb6fc2..fa0b19ae64672618d316dbd3aa84cb8f4e0cb86f 100644 (file)
@@ -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;
     }
 
index e3ea3c69a909b48b8b0bcbd76196da3e37b0b284..7e364afda818895ecc975d131ff3b567dcd57436 100644 (file)
@@ -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)
index 29059809f11f5e85158151a1c4c75cc145f31e76..fcc2756114005ec0e7ac24340e06d31833307b13 100644 (file)
@@ -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;
index ab7d4c485d2f9142baceff272be962a71e9be41f..f9060be8c6cf760e550fcd9e7eaeb0024d512a33 100644 (file)
@@ -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;
     }
 
index 3fdd605baf36c09f3d92e935d2f7e56585fc3e76..ca335b5aa6eb8d242c026b16bf3c69782d771128 100644 (file)
@@ -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;
     }
 
index 403fd094c921285a862324470f7c8c8cc0986c4f..8253604539538e9dd479483189134f1c6e3f517b 100644 (file)
@@ -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;
index 2afad3e4dc54026badbfed07fa0619a59d4a0b7b..0c51b8e98f8a7c82a3a29224feab12adf4df1cd0 100644 (file)
@@ -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;
index 3aa00e3ab965debdcf745d688d8373c905be19f2..4c869626b9b3a7fda65c68c71225054712390c87 100644 (file)
@@ -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
index f7407ab55a7e24f26a6bfb413e325aba5b278d2c..9887e53c17ff5ecc865063fbd7879b7d2b512a1e 100644 (file)
@@ -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;
     }
 
index f0502efaa2735489a861eab199ec61206bb1d758..8014e2229b97e78a6931a60c48264cb3fecb9f33 100644 (file)
 #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))
        {
index 4d3560fb1d266454932f2a284b428b441d047ceb..4ae9cec8853c9ce742e79b60e3a05c03af261244 100644 (file)
@@ -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.  */
index 205c305cceaf8ed90038d5961c1f0e276b5d23f7..3463d4ca0cc81b7f67e9c8b9b8d62f4bca28763d 100644 (file)
@@ -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 *,
index 03804d844d7474e13e6f4eab645e9f5b59e4046f..24e8e67ec36e0196ffdaba1c92aadc81ecc971c7 100644 (file)
@@ -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
index 60c3bff7cd300f73b4e1247f70bab3b5be9fabc3..3f8c37e267b0c3f59d65823305f87929e15710e6 100644 (file)
@@ -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.
 
 #...
index 7d6dff24fbdcea41f4856839aa2e65a3d6796d48..8a5e6dd59eb7d084b20ead9386a75f590fc34a6d 100644 (file)
@@ -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 +.+