From: Nick Clifton Date: Wed, 1 Nov 2023 13:51:17 +0000 (+0000) Subject: ld: Support input section description keyword: REVERSE X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=85921e9a2588bf4820b827fc1630f5d7da22cb1c;p=binutils-gdb.git ld: Support input section description keyword: REVERSE PR 27565 * ldlex.l: Add REVERSE. * ldgram.y: Allow REVERSE to be used wherever a sorting command can be used. * ld.h (struct wildcard_spec): Add 'reversed' field. * ldlang.h (lang_wild_statement_struct): Add 'filenames_reversed' field. * ldlang.c (compare_sections): Add reversed parameter. (wild_sort): Reverse the comparison if requested. (print_wild_statement): Handle the reversed field. * ld.texi: Document the new feature. * NEWS: Mention the new feature. * testsuite/ld-scripts/sort-file-reversed-1.d: New test driver. * testsuite/ld-scripts/sort-file-reversed-1.t: New test source. * testsuite/ld-scripts/sort-file-reversed-2.t: New test source. * testsuite/ld-scripts/sort-file-reversed-2.d: New test driver. * testsuite/ld-scripts/sort-sections-reversed-1.d: New test driver. * testsuite/ld-scripts/sort-sections-reversed-1.t: New test source. * testsuite/ld-scripts/sort-sections-reversed-2.t: New test source. * testsuite/ld-scripts/sort-sections-reversed-2.d: New test driver. * testsuite/ld-scripts/sort-sections-reversed-3.d: New test driver. * testsuite/ld-scripts/sort-sections-reversed-3.t: New test source. --- diff --git a/ld/ChangeLog b/ld/ChangeLog index 49c73eb9f36..95f4712453a 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,27 @@ +2023-11-01 Nick Clifton + + PR 27565 + * ldlex.l: Add REVERSE. + * ldgram.y: Allow REVERSE to be used wherever a sorting command + can be used. + * ld.h (struct wildcard_spec): Add 'reversed' field. + * ldlang.h (lang_wild_statement_struct): Add 'filenames_reversed' field. + * ldlang.c (compare_sections): Add reversed parameter. + (wild_sort): Reverse the comparison if requested. + (print_wild_statement): Handle the reversed field. + * ld.texi: Document the new feature. + * NEWS: Mention the new feature. + * testsuite/ld-scripts/sort-file-reversed-1.d: New test driver. + * testsuite/ld-scripts/sort-file-reversed-1.t: New test source. + * testsuite/ld-scripts/sort-file-reversed-2.t: New test source. + * testsuite/ld-scripts/sort-file-reversed-2.d: New test driver. + * testsuite/ld-scripts/sort-sections-reversed-1.d: New test driver. + * testsuite/ld-scripts/sort-sections-reversed-1.t: New test source. + * testsuite/ld-scripts/sort-sections-reversed-2.t: New test source. + * testsuite/ld-scripts/sort-sections-reversed-2.d: New test driver. + * testsuite/ld-scripts/sort-sections-reversed-3.d: New test driver. + * testsuite/ld-scripts/sort-sections-reversed-3.t: New test source. + 2023-10-30 Nick Clifton * po/ka.po: New Georgian translation. diff --git a/ld/NEWS b/ld/NEWS index 4b990c755f4..e696bba5501 100644 --- a/ld/NEWS +++ b/ld/NEWS @@ -12,6 +12,10 @@ Changes in 2.41: * The linker command line option --print-map-locals can be used to include local symbols in a linker map. (ELF targets only). +* A new linker script sorting directive has been added: REVERSE. This reverses + the order of the sorting. It be combined with either SORT_BY_INIT_PRIORITY + or SORT_BY_NAME. + * For most ELF based targets, if the --enable-linker-version option is used then the version of the linker will be inserted as a string into the .comment section. diff --git a/ld/ld.h b/ld/ld.h index a0f8a15c7a9..f51add335aa 100644 --- a/ld/ld.h +++ b/ld/ld.h @@ -96,11 +96,14 @@ extern sort_type sort_section; struct wildcard_spec { - const char *name; - struct name_list *exclude_name_list; - struct flag_info *section_flag_list; - size_t namelen, prefixlen, suffixlen; - sort_type sorted; + const char * name; + struct name_list * exclude_name_list; + struct flag_info * section_flag_list; + size_t namelen; + size_t prefixlen; + size_t suffixlen; + sort_type sorted; + bool reversed; }; struct wildcard_list diff --git a/ld/ld.texi b/ld/ld.texi index 1f56ded1041..7ae01b121d7 100644 --- a/ld/ld.texi +++ b/ld/ld.texi @@ -5263,6 +5263,35 @@ the init_priority. In @code{.ctors.NNNNN} and @code{.dtors.NNNNN}, @cindex SORT @code{SORT} is an alias for @code{SORT_BY_NAME}. +@cindex REVERSE +@code{REVERSE} indicates that the sorting should be reversed. If used +on its own then @code{REVERSE} implies @code{SORT_BY_NAME}, otherwise +it reverses the enclosed @code{SORT..} command. Note - reverse +sorting of alignment is not currently supported. + +Note - the sorting commands only accept a single wildcard pattern. So +for example the following will not work: +@smallexample + *(REVERSE(.text* .init*)) +@end smallexample +To resolve this problem list the patterns individually, like this: +@smallexample + *(REVERSE(.text*)) + *(REVERSE(.init*)) +@end smallexample + +Note - you can put the @code{EXCLUDE_FILE} command inside a sorting +command, but not the other way around. So for example: +@smallexample + *(SORT_BY_NAME(EXCLUDE_FILE(foo) .text*)) +@end smallexample +will work, but: +@smallexample + *(EXCLUDE_FILE(foo) SORT_BY_NAME(.text*)) +@end smallexample +will not. + + When there are nested section sorting commands in linker script, there can be at most 1 level of nesting for section sorting commands. @@ -5282,6 +5311,15 @@ treated the same as @code{SORT_BY_NAME} (wildcard section pattern). @code{SORT_BY_ALIGNMENT} (@code{SORT_BY_ALIGNMENT} (wildcard section pattern)) is treated the same as @code{SORT_BY_ALIGNMENT} (wildcard section pattern). @item +@code{SORT_BY_NAME} (@code{REVERSE} (wildcard section pattern)) +reverse sorts by name. +@item +@code{REVERSE} (@code{SORT_BY_NAME} (wildcard section pattern)) +reverse sorts by name. +@item +@code{SORT_BY_INIT_PRIORITY} (@code{REVERSE} (wildcard section pattern)) +reverse sorts by init priority. +@item All other nested section sorting commands are invalid. @end enumerate diff --git a/ld/ldgram.y b/ld/ldgram.y index 2b4b5070982..7b7ae8a0796 100644 --- a/ld/ldgram.y +++ b/ld/ldgram.y @@ -102,7 +102,7 @@ static void yyerror (const char *); %type sect_flags %type memspec_opt memspec_at_opt paren_script_name casesymlist %type wildcard_name -%type section_name_spec filename_spec wildcard_maybe_exclude +%type section_name_spec filename_spec wildcard_maybe_exclude wildcard_maybe_reverse %token INT %token NAME LNAME %type length @@ -132,7 +132,7 @@ static void yyerror (const char *); %token SECTIONS PHDRS INSERT_K AFTER BEFORE LINKER_VERSION %token DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END DATA_SEGMENT_END %token SORT_BY_NAME SORT_BY_ALIGNMENT SORT_NONE -%token SORT_BY_INIT_PRIORITY +%token SORT_BY_INIT_PRIORITY REVERSE %token '{' '}' %token SIZEOF_HEADERS OUTPUT_FORMAT FORCE_COMMON_ALLOCATION OUTPUT_ARCH %token INHIBIT_COMMON_ALLOCATION FORCE_GROUP_ALLOCATION @@ -440,6 +440,7 @@ wildcard_maybe_exclude: $$.sorted = none; $$.exclude_name_list = NULL; $$.section_flag_list = NULL; + $$.reversed = false; } | EXCLUDE_FILE '(' exclude_name_list ')' wildcard_name { @@ -447,65 +448,95 @@ wildcard_maybe_exclude: $$.sorted = none; $$.exclude_name_list = $3; $$.section_flag_list = NULL; + $$.reversed = false; } ; -filename_spec: +wildcard_maybe_reverse: wildcard_maybe_exclude - | SORT_BY_NAME '(' wildcard_maybe_exclude ')' + | REVERSE '(' wildcard_maybe_exclude ')' { $$ = $3; + $$.reversed = true; $$.sorted = by_name; } - | SORT_NONE '(' wildcard_maybe_exclude ')' + ; + +filename_spec: + wildcard_maybe_reverse + | SORT_BY_NAME '(' wildcard_maybe_reverse ')' + { + $$ = $3; + $$.sorted = by_name; + } + | SORT_NONE '(' wildcard_maybe_reverse ')' { $$ = $3; $$.sorted = by_none; + $$.reversed = false; + } + | REVERSE '(' SORT_BY_NAME '(' wildcard_maybe_exclude ')' ')' + { + $$ = $5; + $$.sorted = by_name; + $$.reversed = true; } ; section_name_spec: - wildcard_maybe_exclude - | SORT_BY_NAME '(' wildcard_maybe_exclude ')' + wildcard_maybe_reverse + | SORT_BY_NAME '(' wildcard_maybe_reverse ')' { $$ = $3; $$.sorted = by_name; } - | SORT_BY_ALIGNMENT '(' wildcard_maybe_exclude ')' + | SORT_BY_ALIGNMENT '(' wildcard_maybe_reverse ')' { $$ = $3; $$.sorted = by_alignment; } - | SORT_NONE '(' wildcard_maybe_exclude ')' + | SORT_NONE '(' wildcard_maybe_reverse ')' { $$ = $3; $$.sorted = by_none; } - | SORT_BY_NAME '(' SORT_BY_ALIGNMENT '(' wildcard_maybe_exclude ')' ')' + | SORT_BY_NAME '(' SORT_BY_ALIGNMENT '(' wildcard_maybe_reverse ')' ')' { $$ = $5; $$.sorted = by_name_alignment; } - | SORT_BY_NAME '(' SORT_BY_NAME '(' wildcard_maybe_exclude ')' ')' + | SORT_BY_NAME '(' SORT_BY_NAME '(' wildcard_maybe_reverse ')' ')' { $$ = $5; $$.sorted = by_name; } - | SORT_BY_ALIGNMENT '(' SORT_BY_NAME '(' wildcard_maybe_exclude ')' ')' + | SORT_BY_ALIGNMENT '(' SORT_BY_NAME '(' wildcard_maybe_reverse ')' ')' { $$ = $5; $$.sorted = by_alignment_name; } - | SORT_BY_ALIGNMENT '(' SORT_BY_ALIGNMENT '(' wildcard_maybe_exclude ')' ')' + | SORT_BY_ALIGNMENT '(' SORT_BY_ALIGNMENT '(' wildcard_maybe_reverse ')' ')' { $$ = $5; $$.sorted = by_alignment; } - | SORT_BY_INIT_PRIORITY '(' wildcard_maybe_exclude ')' + | SORT_BY_INIT_PRIORITY '(' wildcard_maybe_reverse ')' { $$ = $3; $$.sorted = by_init_priority; } + | REVERSE '(' SORT_BY_NAME '(' wildcard_maybe_exclude ')' ')' + { + $$ = $5; + $$.sorted = by_name; + $$.reversed = true; + } + | REVERSE '(' SORT_BY_INIT_PRIORITY '(' wildcard_maybe_exclude ')' ')' + { + $$ = $5; + $$.sorted = by_init_priority; + $$.reversed = true; + } ; sect_flag_list: NAME diff --git a/ld/ldlang.c b/ld/ldlang.c index c20247a27d0..566c2b8326f 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -539,7 +539,7 @@ get_init_priority (const asection *sec) /* Compare sections ASEC and BSEC according to SORT. */ static int -compare_section (sort_type sort, asection *asec, asection *bsec) +compare_section (sort_type sort, asection *asec, asection *bsec, bool reversed) { int ret; int a_priority, b_priority; @@ -554,7 +554,10 @@ compare_section (sort_type sort, asection *asec, asection *bsec) b_priority = get_init_priority (bsec); if (a_priority < 0 || b_priority < 0) goto sort_by_name; - ret = a_priority - b_priority; + if (reversed) + ret = b_priority - a_priority; + else + ret = a_priority - b_priority; if (ret) break; else @@ -568,11 +571,17 @@ compare_section (sort_type sort, asection *asec, asection *bsec) case by_name: sort_by_name: - ret = strcmp (bfd_section_name (asec), bfd_section_name (bsec)); + if (reversed) + ret = strcmp (bfd_section_name (bsec), bfd_section_name (asec)); + else + ret = strcmp (bfd_section_name (asec), bfd_section_name (bsec)); break; case by_name_alignment: - ret = strcmp (bfd_section_name (asec), bfd_section_name (bsec)); + if (reversed) + ret = strcmp (bfd_section_name (bsec), bfd_section_name (asec)); + else + ret = strcmp (bfd_section_name (asec), bfd_section_name (bsec)); if (ret) break; /* Fall through. */ @@ -647,7 +656,11 @@ wild_sort (lang_wild_statement_type *wild, else ln = sort_filename (lsec->owner); - i = filename_cmp (fn, ln); + if (wild->filenames_reversed) + i = filename_cmp (ln, fn); + else + i = filename_cmp (fn, ln); + if (i > 0) { tree = &((*tree)->right); continue; } else if (i < 0) @@ -660,7 +673,11 @@ wild_sort (lang_wild_statement_type *wild, if (la) ln = sort_filename (lsec->owner); - i = filename_cmp (fn, ln); + if (wild->filenames_reversed) + i = filename_cmp (ln, fn); + else + i = filename_cmp (fn, ln); + if (i > 0) { tree = &((*tree)->right); continue; } else if (i < 0) @@ -673,7 +690,7 @@ wild_sort (lang_wild_statement_type *wild, /* Find the correct node to append this section. */ if (sec && sec->spec.sorted != none && sec->spec.sorted != by_none - && compare_section (sec->spec.sorted, section, (*tree)->section) < 0) + && compare_section (sec->spec.sorted, section, (*tree)->section, sec->spec.reversed) < 0) tree = &((*tree)->left); else tree = &((*tree)->right); @@ -5151,10 +5168,14 @@ print_wild_statement (lang_wild_statement_type *w, if (w->filenames_sorted) minfo ("SORT_BY_NAME("); + if (w->filenames_reversed) + minfo ("REVERSE("); if (w->filename != NULL) minfo ("%s", w->filename); else minfo ("*"); + if (w->filenames_reversed) + minfo (")"); if (w->filenames_sorted) minfo (")"); @@ -5199,6 +5220,12 @@ print_wild_statement (lang_wild_statement_type *w, break; } + if (sec->spec.reversed) + { + minfo ("REVERSE("); + closing_paren++; + } + if (sec->spec.exclude_name_list != NULL) { name_list *tmp; @@ -8500,9 +8527,10 @@ lang_add_wild (struct wildcard_spec *filespec, if (filespec != NULL) { new_stmt->filename = filespec->name; - new_stmt->filenames_sorted = filespec->sorted == by_name; + new_stmt->filenames_sorted = (filespec->sorted == by_name || filespec->reversed); new_stmt->section_flag_list = filespec->section_flag_list; new_stmt->exclude_name_list = filespec->exclude_name_list; + new_stmt->filenames_reversed = filespec->reversed; } new_stmt->section_list = section_list; new_stmt->keep_sections = keep_sections; diff --git a/ld/ldlang.h b/ld/ldlang.h index 463cce394e9..63749ea5f8c 100644 --- a/ld/ldlang.h +++ b/ld/ldlang.h @@ -390,18 +390,19 @@ typedef struct lang_section_bst struct lang_wild_statement_struct { - lang_statement_header_type header; - const char *filename; - bool filenames_sorted; - bool any_specs_sorted; - struct wildcard_list *section_list; - bool keep_sections; - lang_statement_list_type children; - struct name_list *exclude_name_list; - lang_statement_list_type matching_sections; - - lang_section_bst_type *tree, **rightmost; - struct flag_info *section_flag_list; + lang_statement_header_type header; + lang_statement_list_type children; + lang_statement_list_type matching_sections; + lang_section_bst_type * tree; + lang_section_bst_type ** rightmost; + struct wildcard_list * section_list; + struct name_list * exclude_name_list; + struct flag_info * section_flag_list; + const char * filename; + bool filenames_sorted; + bool filenames_reversed; + bool any_specs_sorted; + bool keep_sections; }; typedef struct lang_address_statement_struct diff --git a/ld/ldlex.l b/ld/ldlex.l index 94b2ea70acd..101f5271b94 100644 --- a/ld/ldlex.l +++ b/ld/ldlex.l @@ -322,6 +322,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)* "SORT" { RTOKEN(SORT_BY_NAME); } "SORT_BY_INIT_PRIORITY" { RTOKEN(SORT_BY_INIT_PRIORITY); } "SORT_NONE" { RTOKEN(SORT_NONE); } +"REVERSE" { RTOKEN(REVERSE); } "NOLOAD" { RTOKEN(NOLOAD); } "READONLY" { RTOKEN(READONLY); } "DSECT" { RTOKEN(DSECT); } diff --git a/ld/testsuite/ld-scripts/sort-file-reversed-1.d b/ld/testsuite/ld-scripts/sort-file-reversed-1.d new file mode 100644 index 00000000000..d1d56bdb69f --- /dev/null +++ b/ld/testsuite/ld-scripts/sort-file-reversed-1.d @@ -0,0 +1,18 @@ +#source: sort-file1.s +#source: sort-file2.s +#ld: -T sort-file-reversed-1.t --no-warn-rwx-segments +#nm: -n + +# Check that SORT_BY_NAME+REVERSE on filenames works. +# The text sections should come in reversed sorted order, the data +# sections in input order. Note how we specifically pass +# the object filenames in alphabetical order +#... +0[0-9a-f]* t infile2 +#... +0[0-9a-f]* t infile1 +#... +0[0-9a-f]* d data1 +#... +0[0-9a-f]* d data2 +#pass diff --git a/ld/testsuite/ld-scripts/sort-file-reversed-1.t b/ld/testsuite/ld-scripts/sort-file-reversed-1.t new file mode 100644 index 00000000000..dd177d3e7cc --- /dev/null +++ b/ld/testsuite/ld-scripts/sort-file-reversed-1.t @@ -0,0 +1,6 @@ +SECTIONS +{ + .text : { SORT_BY_NAME(REVERSE(*))(.text*) } + .data : { *(.data*) } + /DISCARD/ : { *(.*) } +} diff --git a/ld/testsuite/ld-scripts/sort-file-reversed-2.d b/ld/testsuite/ld-scripts/sort-file-reversed-2.d new file mode 100644 index 00000000000..3e829f2d20d --- /dev/null +++ b/ld/testsuite/ld-scripts/sort-file-reversed-2.d @@ -0,0 +1,19 @@ +#source: sort-file1.s +#source: sort-file2.s +#ld: -T sort-file-reversed-2.t --no-warn-rwx-segments +#nm: -n + +# Check that REVERSE+SORT_BY_NAME on filenames works. +# Also check that REVERSE implies SORT_BY_NAME. +# The text sections should come in reversed sorted order, the data +# sections in reversed order too. Note how we specifically pass +# the object filenames in alphabetical order +#... +0[0-9a-f]* t infile2 +#... +0[0-9a-f]* t infile1 +#... +0[0-9a-f]* d data2 +#... +0[0-9a-f]* d data1 +#pass diff --git a/ld/testsuite/ld-scripts/sort-file-reversed-2.t b/ld/testsuite/ld-scripts/sort-file-reversed-2.t new file mode 100644 index 00000000000..1379852f803 --- /dev/null +++ b/ld/testsuite/ld-scripts/sort-file-reversed-2.t @@ -0,0 +1,6 @@ +SECTIONS +{ + .text : { REVERSE(SORT_BY_NAME(*))(.text*) } + .data : { REVERSE(*)(.data*) } + /DISCARD/ : { *(.*) } +} diff --git a/ld/testsuite/ld-scripts/sort-sections-reversed-1.d b/ld/testsuite/ld-scripts/sort-sections-reversed-1.d new file mode 100644 index 00000000000..57f88e587c7 --- /dev/null +++ b/ld/testsuite/ld-scripts/sort-sections-reversed-1.d @@ -0,0 +1,13 @@ +#source: sort_b_a.s +#ld: -T sort-sections-reversed-1.t --no-warn-rwx-segments +#nm: -n + +#... +0[0-9a-f]* t text3 +#... +0[0-9a-f]* t text2 +#... +0[0-9a-f]* t text1 +#... +0[0-9a-f]* t text +#pass diff --git a/ld/testsuite/ld-scripts/sort-sections-reversed-1.t b/ld/testsuite/ld-scripts/sort-sections-reversed-1.t new file mode 100644 index 00000000000..cc7f85e2b47 --- /dev/null +++ b/ld/testsuite/ld-scripts/sort-sections-reversed-1.t @@ -0,0 +1,5 @@ +SECTIONS +{ + .text : { *(SORT_BY_NAME(REVERSE(.text*))) } + /DISCARD/ : { *(.*) } +} diff --git a/ld/testsuite/ld-scripts/sort-sections-reversed-2.d b/ld/testsuite/ld-scripts/sort-sections-reversed-2.d new file mode 100644 index 00000000000..1eaa4793238 --- /dev/null +++ b/ld/testsuite/ld-scripts/sort-sections-reversed-2.d @@ -0,0 +1,13 @@ +#source: sort_b_a.s +#ld: -T sort-sections-reversed-2.t --no-warn-rwx-segments +#nm: -n + +#... +0[0-9a-f]* t text3 +#... +0[0-9a-f]* t text2 +#... +0[0-9a-f]* t text1 +#... +0[0-9a-f]* t text +#pass diff --git a/ld/testsuite/ld-scripts/sort-sections-reversed-2.t b/ld/testsuite/ld-scripts/sort-sections-reversed-2.t new file mode 100644 index 00000000000..3fa082ee251 --- /dev/null +++ b/ld/testsuite/ld-scripts/sort-sections-reversed-2.t @@ -0,0 +1,5 @@ +SECTIONS +{ + .text : { *(REVERSE(SORT_BY_INIT_PRIORITY(.text*))) } + /DISCARD/ : { *(REVERSE(.*)) } +} diff --git a/ld/testsuite/ld-scripts/sort-sections-reversed-3.d b/ld/testsuite/ld-scripts/sort-sections-reversed-3.d new file mode 100644 index 00000000000..e7f244c2c93 --- /dev/null +++ b/ld/testsuite/ld-scripts/sort-sections-reversed-3.d @@ -0,0 +1,15 @@ +#source: sort_b_a.s +#ld: -T sort-sections-reversed-3.t --no-warn-rwx-segments +#nm: -n + +# Check that REVERSE implies SORT_BY_NAME for sections. +# Also check that EXCLUDE_FILE() is supported inside REVERSE. +#... +0[0-9a-f]* t text3 +#... +0[0-9a-f]* t text2 +#... +0[0-9a-f]* t text1 +#... +0[0-9a-f]* t text +#pass diff --git a/ld/testsuite/ld-scripts/sort-sections-reversed-3.t b/ld/testsuite/ld-scripts/sort-sections-reversed-3.t new file mode 100644 index 00000000000..15414a8a51d --- /dev/null +++ b/ld/testsuite/ld-scripts/sort-sections-reversed-3.t @@ -0,0 +1,5 @@ +SECTIONS +{ + .text : { *(REVERSE(EXCLUDE_FILE(foo) .text*)) } + /DISCARD/ : { *(.*) } +}