diff options
Diffstat (limited to 'ld')
-rw-r--r-- | ld/ChangeLog | 24 | ||||
-rw-r--r-- | ld/NEWS | 4 | ||||
-rw-r--r-- | ld/ld.h | 13 | ||||
-rw-r--r-- | ld/ld.texi | 38 | ||||
-rw-r--r-- | ld/ldgram.y | 59 | ||||
-rw-r--r-- | ld/ldlang.c | 44 | ||||
-rw-r--r-- | ld/ldlang.h | 25 | ||||
-rw-r--r-- | ld/ldlex.l | 1 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/sort-file-reversed-1.d | 18 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/sort-file-reversed-1.t | 6 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/sort-file-reversed-2.d | 19 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/sort-file-reversed-2.t | 6 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/sort-sections-reversed-1.d | 13 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/sort-sections-reversed-1.t | 5 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/sort-sections-reversed-2.d | 13 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/sort-sections-reversed-2.t | 5 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/sort-sections-reversed-3.d | 15 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/sort-sections-reversed-3.t | 5 |
18 files changed, 274 insertions, 39 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog index 49c73eb..95f4712 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,27 @@ +2023-11-01 Nick Clifton <nickc@redhat.com> + + 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 <nickc@redhat.com> * po/ka.po: New Georgian translation. @@ -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. @@ -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 @@ -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 2b4b507..7b7ae8a 100644 --- a/ld/ldgram.y +++ b/ld/ldgram.y @@ -102,7 +102,7 @@ static void yyerror (const char *); %type <flag_info> sect_flags %type <name> memspec_opt memspec_at_opt paren_script_name casesymlist %type <cname> wildcard_name -%type <wildcard> section_name_spec filename_spec wildcard_maybe_exclude +%type <wildcard> section_name_spec filename_spec wildcard_maybe_exclude wildcard_maybe_reverse %token <bigint> INT %token <name> NAME LNAME %type <integer> 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 c20247a..566c2b8 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 463cce3..63749ea 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 @@ -322,6 +322,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)* <WILD>"SORT" { RTOKEN(SORT_BY_NAME); } <WILD>"SORT_BY_INIT_PRIORITY" { RTOKEN(SORT_BY_INIT_PRIORITY); } <WILD>"SORT_NONE" { RTOKEN(SORT_NONE); } +<WILD>"REVERSE" { RTOKEN(REVERSE); } <EXPRESSION>"NOLOAD" { RTOKEN(NOLOAD); } <EXPRESSION>"READONLY" { RTOKEN(READONLY); } <EXPRESSION>"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 0000000..d1d56bd --- /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 0000000..dd177d3 --- /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 0000000..3e829f2 --- /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 0000000..1379852 --- /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 0000000..57f88e5 --- /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 0000000..cc7f85e --- /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 0000000..1eaa479 --- /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 0000000..3fa082e --- /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 0000000..e7f244c --- /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 0000000..15414a8 --- /dev/null +++ b/ld/testsuite/ld-scripts/sort-sections-reversed-3.t @@ -0,0 +1,5 @@ +SECTIONS +{ + .text : { *(REVERSE(EXCLUDE_FILE(foo) .text*)) } + /DISCARD/ : { *(.*) } +} |