]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Add --section-ordering command line option to the bfd linker.
authorNick Clifton <nickc@redhat.com>
Fri, 10 May 2024 15:59:05 +0000 (16:59 +0100)
committerNick Clifton <nickc@redhat.com>
Fri, 10 May 2024 15:59:05 +0000 (16:59 +0100)
22 files changed:
ld/NEWS
ld/ld.h
ld/ld.texi
ld/ldfile.c
ld/ldfile.h
ld/ldgram.y
ld/ldlang.c
ld/ldlang.h
ld/ldlex.h
ld/ldlex.l
ld/ldmain.c
ld/lexsup.c
ld/testsuite/ld-scripts/section-order-1a.d [new file with mode: 0644]
ld/testsuite/ld-scripts/section-order-1a.s [new file with mode: 0644]
ld/testsuite/ld-scripts/section-order-1a.t [new file with mode: 0644]
ld/testsuite/ld-scripts/section-order-1b.d [new file with mode: 0644]
ld/testsuite/ld-scripts/section-order-1b.s [new file with mode: 0644]
ld/testsuite/ld-scripts/section-order-1b.t [new file with mode: 0644]
ld/testsuite/ld-scripts/section-order-1c.d [new file with mode: 0644]
ld/testsuite/ld-scripts/section-order-1d.d [new file with mode: 0644]
ld/testsuite/ld-scripts/section-order.exp [new file with mode: 0644]
ld/testsuite/ld-scripts/start.s [new file with mode: 0644]

diff --git a/ld/NEWS b/ld/NEWS
index f70d21573399b4a914cc6070f209ce71907ed70e..00eb46047d137e7b3621fb36a1049380642a666c 100644 (file)
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* Add --section-ordering-file <FILE> option to add extra mapping of input
+  sections to output sections.
+
 * Add -plugin-save-temps to store plugin intermediate files permanently.
 
 Changes in 2.42:
diff --git a/ld/ld.h b/ld/ld.h
index fcdd9a2c083b3f5819df8ecc9e35523be16b3e4d..0dee944cf2aa0ab0a2e2e08fae532ef824d401a2 100644 (file)
--- a/ld/ld.h
+++ b/ld/ld.h
@@ -196,6 +196,9 @@ typedef struct
 
   /* Default linker script.  */
   char *default_script;
+
+  /* Linker script fragment provided by the --section-order command line option.  */
+  char *section_ordering_file;
 } args_type;
 
 extern args_type command_line;
@@ -325,6 +328,7 @@ extern ld_config_type config;
 
 extern FILE * saved_script_handle;
 extern bool force_make_executable;
+extern bool in_section_ordering;
 
 extern int yyparse (void);
 extern void add_cref (const char *, bfd *, asection *, bfd_vma);
index ca9574dfc71bf46f3ace541fb544cdcbb061c497..b32bb463f3f2d13c4c2718fc20de4eb8c0b7585f 100644 (file)
@@ -302,6 +302,7 @@ and the script command language.  If @emph{no} binary input files at all
 are specified, the linker does not produce any output, and issues the
 message @samp{No input files}.
 
+@anchor{unrecognised-input-files}
 If the linker cannot recognize the format of an object file, it will
 assume that it is a linker script.  A script specified in this way
 augments the main linker script used for the link (either the default
@@ -1163,18 +1164,32 @@ a linker bug report.
 @itemx --script=@var{scriptfile}
 Use @var{scriptfile} as the linker script.  This script replaces
 @command{ld}'s default linker script (rather than adding to it),
-unless the script contains @code{INSERT}, so
-@var{commandfile} must specify everything necessary to describe the
-output file.  @xref{Scripts}.  If @var{scriptfile} does not exist in
-the current directory, @code{ld} looks for it in the directories
-specified by any preceding @samp{-L} options.  Multiple @samp{-T}
-options accumulate.
+unless the script contains @code{INSERT}, so @var{commandfile} must
+specify everything necessary to describe the output file.
+@xref{Scripts}.
+
+If @var{scriptfile} does not exist in the current directory, @code{ld}
+looks for it in the directories specified by any preceding @samp{-L}
+options.
+
+Command line options that appear before the @option{-T} option can
+affect the script, but command line options that appear after it do
+not.
+
+Multiple @samp{-T} options will accumulate if they are augmenting the
+current script, otherwise the last, non-augmenting, @option{-T} option
+will be used.
+
+There are other ways of specifying linker scripts.  See
+@xref{--default-script}, @xref{--section-ordering-file} and
+@xref{unrecognised-input-files}.
 
 @kindex -dT @var{script}
 @kindex --default-script=@var{script}
 @cindex script files
 @item -dT @var{scriptfile}
 @itemx --default-script=@var{scriptfile}
+@anchor{--default-script}
 Use @var{scriptfile} as the default linker script.  @xref{Scripts}.
 
 This option is similar to the @option{--script} option except that
@@ -2521,6 +2536,51 @@ warning and continue with the link.
 
 @end ifset
 
+@kindex --section-ordering-file
+@item --section-ordering-file=@var{script}
+@anchor{--section-ordering-file}
+This option is used to augment the current linker script with
+additional mapping of input sections to output sections.  This file
+must use the same syntax for @code{SECTIONS} as is used in normal
+linker scripts, but it should not do anything other than place input
+sections into output sections. @pxref{SECTIONS}
+
+A second constraint on the section ordering script is that it can only
+reference output sections that are already defined by whichever linker
+script is currently in use.  (Ie the default linker script or a script
+specified on the command line).  The benefit of the section ordering
+script however is that the input sections are mapped to the start of
+the output sections, so that they can ensure the ordering of sections
+in the output section.  For example, imagine that the default linker
+script looks like this:
+
+@smallexample
+SECTIONS @{
+  .text : @{ *(.text.hot) ; *(.text .text.*) @}
+  .data : @{ *(.data.big) ; *(.data .data.*) @}
+  @}
+@end smallexample
+
+Then if a section ordering file like this is used:
+
+@smallexample
+  .text : @{ *(.text.first) ; *(.text.z*) @}
+  .data : @{ foo.o(.data.first) ; *(.data.small) @}
+@end smallexample
+
+This would be equivalent to a linker script like this:
+
+@smallexample
+SECTIONS @{
+  .text : @{ *(.text.first) ; *(.text.z*) ; *(.text.hot) ; *(.text .text.*) @}
+  .data : @{ foo.o(.data.first) ; *(.data.small) ; *(.data.big) ; *(.data .data.*) @}
+  @}
+@end smallexample
+
+The advantage of the section ordering file is that it can be used to
+order those sections that matter to the user without having to worry
+about any other sections, or memory regions, or anything else.
+
 @kindex -shared
 @kindex -Bshareable
 @item -shared
index dc9875d8813c96c0da7b33f9d18fd31cc6f05326..f1107a1b7d793a51ea7f6f7a6b492db518992bf4 100644 (file)
@@ -871,19 +871,7 @@ ldfile_find_command_file (const char *name,
   return result;
 }
 
-enum script_open_style {
-  script_nonT,
-  script_T,
-  script_defaultT
-};
-
-struct script_name_list
-{
-  struct script_name_list *next;
-  enum script_open_style open_how;
-  char name[1];
-};
-
+struct script_name_list *processed_scripts = NULL;
 /* Open command file NAME.  */
 
 static void
@@ -891,7 +879,6 @@ ldfile_open_command_file_1 (const char *name, enum script_open_style open_how)
 {
   FILE *ldlex_input_stack;
   bool sysrooted;
-  static struct script_name_list *processed_scripts = NULL;
   struct script_name_list *script;
   size_t len;
 
index f17677e9e9aaebf6245134bb839198162772fd59..f79abf2310db86fdd10a69993f406b5a4b337c10 100644 (file)
@@ -29,7 +29,8 @@ extern const char *ldfile_output_machine_name;
 /* Structure used to hold the list of directories to search for
    libraries.  */
 
-typedef struct search_dirs {
+typedef struct search_dirs
+{
   /* Next directory on list.  */
   struct search_dirs *next;
   /* Name of directory.  */
@@ -38,6 +39,22 @@ typedef struct search_dirs {
   bool cmdline;
 } search_dirs_type;
 
+enum script_open_style
+{
+  script_nonT,
+  script_T,
+  script_defaultT
+};
+
+struct script_name_list
+{
+  struct script_name_list *  next;
+  enum script_open_style     open_how;
+  char                       name[1];
+};
+
+extern struct script_name_list * processed_scripts;
+
 extern search_dirs_type *search_head;
 
 extern void ldfile_add_arch
index 0d531fddfa1c3a9ee15b4806729406e8fbf6968f..07c19ba8692a6fef85c409a10883180807c2a543 100644 (file)
@@ -157,7 +157,7 @@ static void yyerror (const char *);
 %token LOG2CEIL FORMAT PUBLIC DEFSYMEND BASE ALIAS TRUNCATE REL
 %token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN START
 %token <name> VERS_TAG VERS_IDENTIFIER
-%token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT
+%token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT INPUT_SECTION_ORDERING_SCRIPT
 %token KEEP ONLY_IF_RO ONLY_IF_RW SPECIAL INPUT_SECTION_FLAGS ALIGN_WITH_INPUT
 %token EXCLUDE_FILE
 %token CONSTANT
@@ -172,6 +172,7 @@ file:
                INPUT_SCRIPT script_file
        |       INPUT_MRI_SCRIPT mri_script_file
        |       INPUT_VERSION_SCRIPT version_script_file
+       |       INPUT_SECTION_ORDERING_SCRIPT section_ordering_script_file
        |       INPUT_DYNAMIC_LIST dynamic_list_file
        |       INPUT_DEFSYM defsym_expr
        ;
@@ -1539,6 +1540,39 @@ opt_semicolon:
        |       ';'
        ;
 
+section_ordering_script_file:
+               {
+                 ldlex_script ();
+                 PUSH_ERROR (_("section-ordering-file script"));
+               }
+               section_ordering_list
+               {
+                 ldlex_popstate ();
+                 POP_ERROR ();
+               }
+       ;
+
+section_ordering_list:
+               section_ordering_list section_order
+       |       section_ordering_list statement_anywhere
+       |
+       ;
+
+section_order: NAME ':'
+               {
+                 ldlex_wild ();
+                 lang_enter_output_section_statement
+                   ($1, NULL, 0, NULL, NULL, NULL, NULL, 0, 0);
+               }
+               '{'
+               statement_list_opt
+               '}'
+               {
+                 ldlex_popstate ();
+                 lang_leave_output_section_statement (NULL, NULL, NULL, NULL);
+               }
+               opt_comma
+
 %%
 static void
 yyerror (const char *arg)
index 54d1af62ebe4b7b2043c86ddde31e30f6664f41a..9e8cc224f4d0218cca759f32225104fdc957c8fa 100644 (file)
@@ -1299,6 +1299,7 @@ output_section_statement_newfunc (struct bfd_hash_entry *entry,
   ret->s.output_section_statement.section_alignment = NULL;
   ret->s.output_section_statement.block_value = 1;
   lang_list_init (&ret->s.output_section_statement.children);
+  lang_list_init (&ret->s.output_section_statement.sort_children);
   lang_statement_append (stat_ptr, &ret->s, &ret->s.header.next);
 
   /* For every output section statement added to the list, except the
@@ -7613,13 +7614,22 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
   lang_output_section_statement_type *os;
 
   os = lang_output_section_statement_lookup (output_section_statement_name,
-                                            constraint, 2);
+                                            constraint,
+                                            in_section_ordering ? 0 : 2);
+  if (os == NULL) /* && in_section_ordering */
+    einfo (_("%F%P:%pS: error: output section '%s' must already exist\n"),
+          NULL, output_section_statement_name);
   current_section = os;
 
+  /* Make next things chain into subchain of this.  */
+  push_stat_ptr (in_section_ordering ? &os->sort_children : &os->children);
+
+  if (in_section_ordering)
+    return os;
+
   if (os->addr_tree == NULL)
-    {
-      os->addr_tree = address_exp;
-    }
+    os->addr_tree = address_exp;
+
   os->sectype = sectype;
   if (sectype == type_section || sectype == typed_readonly_section)
     os->sectype_value = sectype_value;
@@ -7629,9 +7639,6 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
     os->flags = SEC_NO_FLAGS;
   os->block_value = 1;
 
-  /* Make next things chain into subchain of this.  */
-  push_stat_ptr (&os->children);
-
   os->align_lma_with_input = align_with_input == ALIGN_WITH_INPUT;
   if (os->align_lma_with_input && align != NULL)
     einfo (_("%F%P:%pS: error: align with input and explicit align specified\n"),
@@ -7971,21 +7978,6 @@ find_rescan_insertion (lang_input_statement_type *add)
   return iter;
 }
 
-/* Insert SRCLIST into DESTLIST after given element by chaining
-   on FIELD as the next-pointer.  (Counterintuitively does not need
-   a pointer to the actual after-node itself, just its chain field.)  */
-
-static void
-lang_list_insert_after (lang_statement_list_type *destlist,
-                       lang_statement_list_type *srclist,
-                       lang_statement_union_type **field)
-{
-  *(srclist->tail) = *field;
-  *field = srclist->head;
-  if (destlist->tail == field)
-    destlist->tail = srclist->tail;
-}
-
 /* Detach new nodes added to DESTLIST since the time ORIGLIST
    was taken as a copy of it and leave them in ORIGLIST.  */
 
@@ -8033,6 +8025,21 @@ find_next_input_statement (lang_statement_union_type **s)
 }
 #endif /* BFD_SUPPORTS_PLUGINS */
 
+/* Insert SRCLIST into DESTLIST after given element by chaining
+   on FIELD as the next-pointer.  (Counterintuitively does not need
+   a pointer to the actual after-node itself, just its chain field.)  */
+
+static void
+lang_list_insert_after (lang_statement_list_type *destlist,
+                       lang_statement_list_type *srclist,
+                       lang_statement_union_type **field)
+{
+  *(srclist->tail) = *field;
+  *field = srclist->head;
+  if (destlist->tail == field)
+    destlist->tail = srclist->tail;
+}
+
 /* Add NAME to the list of garbage collection entry points.  */
 
 void
@@ -8127,9 +8134,34 @@ reset_resolved_wilds (void)
   lang_for_each_statement (reset_one_wild);
 }
 
+/* For each output section statement, splice any entries on the
+   sort_children list before the first wild statement on the children
+   list.  */
+
+static void
+lang_os_merge_sort_children (void)
+{
+  lang_output_section_statement_type *os;
+  for (os = (void *) lang_os_list.head; os != NULL; os = os->next)
+    {
+      if (os->sort_children.head != NULL)
+       {
+         lang_statement_union_type **where;
+         for (where = &os->children.head;
+              *where != NULL;
+              where = &(*where)->header.next)
+           if ((*where)->header.type == lang_wild_statement_enum)
+             break;
+         lang_list_insert_after (&os->children, &os->sort_children, where);
+       }
+    }
+}
+
 void
 lang_process (void)
 {
+  lang_os_merge_sort_children ();
+
   /* Finalize dynamic list.  */
   if (link_info.dynamic_list)
     lang_finalize_version_expr_head (&link_info.dynamic_list->head);
@@ -8817,6 +8849,10 @@ lang_leave_output_section_statement (fill_type *fill, const char *memspec,
                                     lang_output_section_phdr_list *phdrs,
                                     const char *lma_memspec)
 {
+  pop_stat_ptr ();
+  if (in_section_ordering)
+    return;
+
   lang_get_regions (&current_section->region,
                    &current_section->lma_region,
                    memspec, lma_memspec,
@@ -8825,7 +8861,6 @@ lang_leave_output_section_statement (fill_type *fill, const char *memspec,
 
   current_section->fill = fill;
   current_section->phdrs = phdrs;
-  pop_stat_ptr ();
 }
 
 /* Set the output format type.  -oformat overrides scripts.  */
index ea1c26d00f366c763cd2c36b97cb1623adeb8530..4c1bb002f8e136f2be7a3e5a2c4a542312b865e0 100644 (file)
@@ -141,7 +141,12 @@ typedef struct lang_output_section_phdr_list
 typedef struct lang_output_section_statement_struct
 {
   lang_statement_header_type header;
+  /* Input sections to be mapped to this output section.  */
   lang_statement_list_type children;
+  /* Input sections to be mapped to the start of this output section.
+     These sections are provided by the --section-ordering file, if used.  */
+  lang_statement_list_type sort_children;
+
   struct lang_output_section_statement_struct *next;
   struct lang_output_section_statement_struct *prev;
   const char *name;
index d575562a357f410c222f7bb58407d9ac95aa21d4..7a0c3b4be94d5e0c2b904e78f611ba79a28b0d3c 100644 (file)
@@ -62,6 +62,7 @@ enum option_values
   OPTION_SONAME,
   OPTION_SORT_COMMON,
   OPTION_SORT_SECTION,
+  OPTION_SECTION_ORDERING_FILE,
   OPTION_STATS,
   OPTION_SYMBOLIC,
   OPTION_SYMBOLIC_FUNCTIONS,
@@ -477,6 +478,7 @@ typedef enum input_enum
   input_script,
   input_mri_script,
   input_version_script,
+  input_section_ordering_script,
   input_dynamic_list,
   input_defsym
 } input_type;
index e113c90812bb8d356a9648ac4393f9c403eae135..aa613100db0cd23fbc126f6ffc4876c816d4cbe9 100644 (file)
@@ -120,11 +120,12 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
       parser_input = input_selected;
       switch (t)
        {
-       case input_script: return INPUT_SCRIPT; break;
-       case input_mri_script: return INPUT_MRI_SCRIPT; break;
-       case input_version_script: return INPUT_VERSION_SCRIPT; break;
-       case input_dynamic_list: return INPUT_DYNAMIC_LIST; break;
-       case input_defsym: return INPUT_DEFSYM; break;
+       case input_script: return INPUT_SCRIPT;
+       case input_mri_script: return INPUT_MRI_SCRIPT;
+       case input_version_script: return INPUT_VERSION_SCRIPT;
+       case input_section_ordering_script: return INPUT_SECTION_ORDERING_SCRIPT;
+       case input_dynamic_list: return INPUT_DYNAMIC_LIST;
+       case input_defsym: return INPUT_DEFSYM;
        default: abort ();
        }
     }
index fe389681bd3c3cad0b0919a82ee2b1430eb60eb6..037099b9d37352437744c3507757df096250de24 100644 (file)
@@ -90,6 +90,8 @@ bool version_printed;
 /* TRUE if we should demangle symbol names.  */
 bool demangling;
 
+bool in_section_ordering;
+
 args_type command_line;
 
 ld_config_type config;
@@ -246,6 +248,26 @@ ld_bfd_error_handler (const char *fmt, va_list ap)
   (*default_bfd_error_handler) (fmt, ap);
 }
 
+static void
+display_external_script (void)
+{
+  if (saved_script_handle == NULL)
+    return;
+  
+  static const int ld_bufsz = 8193;
+  size_t n;
+  char *buf = (char *) xmalloc (ld_bufsz);
+
+  rewind (saved_script_handle);
+  while ((n = fread (buf, 1, ld_bufsz - 1, saved_script_handle)) > 0)
+    {
+      buf[n] = 0;
+      info_msg ("%s", buf);
+    }
+  rewind (saved_script_handle);
+  free (buf);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -416,26 +438,13 @@ main (int argc, char **argv)
   if (verbose)
     {
       if (saved_script_handle)
-       info_msg (_("using external linker script:"));
+       info_msg (_("using external linker script: %s"), processed_scripts->name);
       else
        info_msg (_("using internal linker script:"));
       info_msg ("\n==================================================\n");
 
       if (saved_script_handle)
-       {
-         static const int ld_bufsz = 8193;
-         size_t n;
-         char *buf = (char *) xmalloc (ld_bufsz);
-
-         rewind (saved_script_handle);
-         while ((n = fread (buf, 1, ld_bufsz - 1, saved_script_handle)) > 0)
-           {
-             buf[n] = 0;
-             info_msg ("%s", buf);
-           }
-         rewind (saved_script_handle);
-         free (buf);
-       }
+       display_external_script ();
       else
        {
          int isfile;
@@ -446,6 +455,22 @@ main (int argc, char **argv)
       info_msg ("\n==================================================\n");
     }
 
+  if (command_line.section_ordering_file)
+    {
+      FILE *hold_script_handle;
+
+      hold_script_handle = saved_script_handle;
+      ldfile_open_command_file (command_line.section_ordering_file);
+      if (verbose)
+       display_external_script ();
+      saved_script_handle = hold_script_handle;
+      in_section_ordering = true;
+      parser_input = input_section_ordering_script;
+      yyparse ();
+      in_section_ordering = false;
+
+    }
+
   if (command_line.force_group_allocation
       || !bfd_link_relocatable (&link_info))
     link_info.resolve_section_groups = true;
index dad3b6059edfe1fe31f46c454fdc90d55b0aed5b..4125d849f2caa115e3e8b92c2dc1fbf9f25e0f47 100644 (file)
@@ -487,6 +487,9 @@ static const struct ld_option ld_options[] =
   { {"sort-section", required_argument, NULL, OPTION_SORT_SECTION},
     '\0', N_("name|alignment"),
     N_("Sort sections by name or maximum alignment"), TWO_DASHES },
+  { {"section-ordering-file", required_argument, NULL, OPTION_SECTION_ORDERING_FILE},
+    '\0', N_("FILE"),
+    N_("Sort sections by statements in FILE"), TWO_DASHES },
   { {"spare-dynamic-tags", required_argument, NULL, OPTION_SPARE_DYNAMIC_TAGS},
     '\0', N_("COUNT"), N_("How many tags to reserve in .dynamic section"),
     TWO_DASHES },
@@ -1400,6 +1403,12 @@ parse_args (unsigned argc, char **argv)
            einfo (_("%F%P: invalid section sorting option: %s\n"),
                   optarg);
          break;
+       case OPTION_SECTION_ORDERING_FILE:
+         if (command_line.section_ordering_file != NULL
+             && strcmp (optarg, command_line.section_ordering_file) != 0)
+           einfo (_("%P: warning: section ordering file changed.  Ignoring earlier definition\n"));
+         command_line.section_ordering_file = optarg;
+         break;
        case OPTION_STATS:
          config.stats = true;
          break;
diff --git a/ld/testsuite/ld-scripts/section-order-1a.d b/ld/testsuite/ld-scripts/section-order-1a.d
new file mode 100644 (file)
index 0000000..40730b8
--- /dev/null
@@ -0,0 +1,22 @@
+#name: Text Section Ordering (section-order-1a)
+#source: section-order-1b.s
+#source: section-order-1a.s
+#source: start.s
+#ld: --section-ordering-file section-order-1a.t
+#nm: -n
+
+#...
+[0-9a-f]+ T yyy
+#...
+[0-9a-f]+ T bar
+#...
+[0-9a-f]+ T [_]+start
+#...
+[0-9a-f]+ T xxx
+#...
+[0-9a-f]+ T foo
+#...
+[0-9a-f]+ T qqq
+#...
+[0-9a-f]+ T zzz
+#pass
diff --git a/ld/testsuite/ld-scripts/section-order-1a.s b/ld/testsuite/ld-scripts/section-order-1a.s
new file mode 100644 (file)
index 0000000..2394a7b
--- /dev/null
@@ -0,0 +1,29 @@
+       .section .text.foo
+       .globl  foo
+foo:
+       .dc.a 0
+
+       .section .text.bar
+       .globl  bar
+bar:
+       .dc.a 0
+
+       .section .data.small
+       .globl small
+small:
+       .dc.a 0
+
+       .section .bar
+       .global bar
+bart:
+       .dc.a 0
+
+       .section .text.zzz
+       .global zzz
+zzz:
+       .dc.a 0
+
+       .section .data.bbb
+       .global bbb
+bbb:
+       .dc.a 0
diff --git a/ld/testsuite/ld-scripts/section-order-1a.t b/ld/testsuite/ld-scripts/section-order-1a.t
new file mode 100644 (file)
index 0000000..2e28bfa
--- /dev/null
@@ -0,0 +1,14 @@
+.text : {
+    *(.text.yyy)
+    *(.text.b?r)
+    *(.text)
+    *(.text.xxx .text.foo)
+}
+
+.data : {
+    *(.data.small)
+    *(.big*)
+    *(.bar .baz*)
+    *(.data.ccc)
+}
+
diff --git a/ld/testsuite/ld-scripts/section-order-1b.d b/ld/testsuite/ld-scripts/section-order-1b.d
new file mode 100644 (file)
index 0000000..caf713d
--- /dev/null
@@ -0,0 +1,18 @@
+#name: Text Section Ordering (section-order-1b)
+#source: section-order-1a.s
+#source: section-order-1b.s
+#source: start.s
+#ld: --section-ordering-file section-order-1b.t
+#nm: -n
+
+#...
+[0-9a-f]+ T yyy
+#...
+[0-9a-f]+ T bar
+#...
+[0-9a-f]+ T [_]+start
+#...
+[0-9a-f]+ T xxx
+#...
+[0-9a-f]+ T foo
+#pass
diff --git a/ld/testsuite/ld-scripts/section-order-1b.s b/ld/testsuite/ld-scripts/section-order-1b.s
new file mode 100644 (file)
index 0000000..49a0b32
--- /dev/null
@@ -0,0 +1,34 @@
+       .section .text.xxx
+       .globl  xxx
+xxx:
+       .dc.a 0
+
+       .section .text.yyy
+       .globl  yyy
+yyy:
+       .dc.a 0
+
+       .section .big
+       .global big
+big:
+       .dc.a 0
+
+       .section .baz
+       .global baz
+baz:
+       .dc.a 0
+
+       .section .text.qqq
+       .global qqq
+qqq:
+       .dc.a 0
+
+       .section .data.ccc
+       .global ccc
+ccc:
+       .dc.a 0
+
+       .data
+       .global data_symbol
+data_symbol:
+       .dc.a 0
diff --git a/ld/testsuite/ld-scripts/section-order-1b.t b/ld/testsuite/ld-scripts/section-order-1b.t
new file mode 100644 (file)
index 0000000..6a36250
--- /dev/null
@@ -0,0 +1,7 @@
+.text : {
+  *(.text.yyy)
+  *(.text.b?r)
+  *(*t)
+  *(.text.xxx)
+  *(.text.foo)
+}
diff --git a/ld/testsuite/ld-scripts/section-order-1c.d b/ld/testsuite/ld-scripts/section-order-1c.d
new file mode 100644 (file)
index 0000000..ad06d4a
--- /dev/null
@@ -0,0 +1,14 @@
+#name: Data Section Ordering (section-order-1c)
+#source: section-order-1b.s
+#source: section-order-1a.s
+#source: start.s
+#ld: --section-ordering-file section-order-1a.t
+#nm: -n
+
+#...
+[0-9a-f]+ D small
+#...
+[0-9a-f]+ D big
+#...
+[0-9a-f]+ D ba.*
+#pass
diff --git a/ld/testsuite/ld-scripts/section-order-1d.d b/ld/testsuite/ld-scripts/section-order-1d.d
new file mode 100644 (file)
index 0000000..d016505
--- /dev/null
@@ -0,0 +1,18 @@
+#name: Data Section Ordering (section-order-1d)
+#source: section-order-1a.s
+#source: section-order-1b.s
+#source: start.s
+#ld: --section-ordering-file section-order-1a.t
+#nm: -n
+
+#...
+[0-9a-f]+ D small
+#...
+[0-9a-f]+ D big
+#...
+[0-9a-f]+ d bart
+#...
+[0-9a-f]+ D ccc
+#...
+[0-9a-f]+ D bbb
+#pass
diff --git a/ld/testsuite/ld-scripts/section-order.exp b/ld/testsuite/ld-scripts/section-order.exp
new file mode 100644 (file)
index 0000000..9b87e74
--- /dev/null
@@ -0,0 +1,45 @@
+# Test for --section-ordering-file FILE.
+# Copyright (C) 2024 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# The --section-ordering-file option is only supported by ELF and
+# PE COFF linkers, which allow for arbitrarily named sections, eg:
+# .text.*
+if { !([is_elf_format] || [is_pecoff_format]) } {
+    return
+}
+
+set old_ldflags $LDFLAGS
+if { [istarget spu*-*-*] } then {
+    set LDFLAGS "$LDFLAGS --local-store 0:0 --no-overlays"
+} elseif { [is_pecoff_format] } then {
+    set LDFLAGS "$LDFLAGS --image-base 0"
+} elseif { [is_xcoff_format] } then {
+    set LDFLAGS "$LDFLAGS -bnogc"
+}
+
+set test_list [lsort [glob -nocomplain $srcdir/$subdir/section-order*.d]]
+foreach test_file $test_list {
+    set test_name [file rootname $test_file]
+    set map_file "tmpdir/[file tail $test_name].map"
+    verbose $test_name
+    run_dump_test $test_name
+}
+
+set LDFLAGS $old_ldflags
diff --git a/ld/testsuite/ld-scripts/start.s b/ld/testsuite/ld-scripts/start.s
new file mode 100644 (file)
index 0000000..3f64626
--- /dev/null
@@ -0,0 +1,14 @@
+       .text
+       .global start   /* Used by SH targets.  */
+start:
+       .global _start
+_start:
+       .global __start
+__start:
+       .global _mainCRTStartup /* Used by PE targets.  */
+_mainCRTStartup:
+       .global main    /* Used by HPPA targets.  */
+main:
+       .globl  _main   /* Used by LynxOS targets.  */
+_main:
+       .dc.a 0