RFC: ld: Add --text-section-ordering-file (version 2)
Alan Modra
amodra@gmail.com
Fri Apr 26 12:43:48 GMT 2024
On Fri, Apr 26, 2024 at 10:59:00AM +0100, Nick Clifton wrote:
> It could be done, but I like keeping things simple.
Here's a completely untested implementation of the idea I'm proposing,
written just to show that the linker modifications are relatively
small. (There is a very good chance I've messed up list handling..)
What appears inside the --section-ordering-file output sections is
spliced in to corresponding output sections in the default script,
before the first input wild statement.
I like keeping things simple too. This should work without modifying
default linker scripts (and user scripts!), and allows all the usual
ways of specifying input sections. That means you can use constructs
like EXCLUDE_FILE, SORT, KEEP, *(.text .rdata) vs. *(.text) *(.rdata)
and so on.
diff --git a/ld/ld.h b/ld/ld.h
index fcdd9a2c083..15d9dc262b6 100644
--- a/ld/ld.h
+++ b/ld/ld.h
@@ -196,6 +196,8 @@ typedef struct
/* Default linker script. */
char *default_script;
+
+ char *section_ordering_file;
} args_type;
extern args_type command_line;
@@ -325,6 +327,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);
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 54d1af62ebe..f9fb50e99ec 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -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,19 @@ 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 ? 1 : 2);
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 +7636,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"),
@@ -8127,9 +8131,33 @@ reset_resolved_wilds (void)
lang_for_each_statement (reset_one_wild);
}
+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;
+ if (*where == NULL)
+ where = &os->children.head;
+ lang_list_insert_after (&os->children, &os->sort_children, where);
+ lang_list_init (&os->sort_children);
+ }
+ }
+}
+
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 +8845,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 (¤t_section->region,
¤t_section->lma_region,
memspec, lma_memspec,
@@ -8825,7 +8857,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. */
diff --git a/ld/ldlang.h b/ld/ldlang.h
index ea1c26d00f3..91947c56fda 100644
--- a/ld/ldlang.h
+++ b/ld/ldlang.h
@@ -162,6 +162,8 @@ typedef struct lang_output_section_statement_struct
lang_output_section_phdr_list *phdrs;
+ lang_statement_list_type sort_children;
+
/* Used by ELF SHF_LINK_ORDER sorting. */
void *data;
diff --git a/ld/ldlex.h b/ld/ldlex.h
index d575562a357..5708e6f5e34 100644
--- a/ld/ldlex.h
+++ b/ld/ldlex.h
@@ -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,
diff --git a/ld/ldmain.c b/ld/ldmain.c
index fe389681bd3..77b57a9fd32 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -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;
@@ -446,6 +448,19 @@ 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);
+ saved_script_handle = hold_script_handle;
+ in_section_ordering = true;
+ parser_input = input_script;
+ yyparse ();
+ in_section_ordering = false;
+ }
+
if (command_line.force_group_allocation
|| !bfd_link_relocatable (&link_info))
link_info.resolve_section_groups = true;
diff --git a/ld/lexsup.c b/ld/lexsup.c
index dad3b6059ed..0c337a4d170 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -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,9 @@ parse_args (unsigned argc, char **argv)
einfo (_("%F%P: invalid section sorting option: %s\n"),
optarg);
break;
+ case OPTION_SECTION_ORDERING_FILE:
+ command_line.section_ordering_file = optarg;
+ break;
case OPTION_STATS:
config.stats = true;
break;
--
Alan Modra
More information about the Binutils
mailing list