From 9a24a2763daa773328a788988048a7b3f344a548 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 25 Sep 2019 15:30:53 +0930 Subject: [PATCH] SORT_BY_INIT_PRIORITY I was looking at the implementation of this script keyword today and couldn't remember why we do what we do in get_init_priority, because the comments explain how the init_priority is encoded but don't say why it is necessary to extract the priority and sort on that. So after figuring out why (again), I wrote some more comments. Then I simplified get_init_priority a little, adding some sanity checking on the strtoul result. This actually makes get_init_priority support sorting by numerical suffix more generally, but I figure this feature would be better as a new keyword (without the .ctors/.dtors special case), so haven't documented the extension. * ld.texi (SORT_BY_ALIGNMENT): Reword slightly. (SORT_BY_INIT_PRIORITY): Elucidate. * ldlang.c: Include limits.h. (get_init_priority): Comment. Change param to a section, return an int. Sanity check priority digits. Support sorting more sections with trailing digits. Return -1 on error. (compare_section): Adjust. --- ld/ChangeLog | 10 ++++++++ ld/ld.texi | 21 +++++++++-------- ld/ldlang.c | 64 +++++++++++++++++++++++++++++++--------------------- 3 files changed, 60 insertions(+), 35 deletions(-) diff --git a/ld/ChangeLog b/ld/ChangeLog index d38c8614c9b..c90a587b3ad 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,13 @@ +2019-09-25 Alan Modra + + * ld.texi (SORT_BY_ALIGNMENT): Reword slightly. + (SORT_BY_INIT_PRIORITY): Elucidate. + * ldlang.c: Include limits.h. + (get_init_priority): Comment. Change param to a section, + return an int. Sanity check priority digits. Support sorting + more sections with trailing digits. Return -1 on error. + (compare_section): Adjust. + 2019-09-25 Nick Clifton * emultempl/avrelf.em (_before_allocation): Silence build warning diff --git a/ld/ld.texi b/ld/ld.texi index 8d5c7bc140e..95fa6a03485 100644 --- a/ld/ld.texi +++ b/ld/ld.texi @@ -4630,17 +4630,20 @@ pattern in parentheses (e.g., @code{SORT_BY_NAME(.text*)}). When the into ascending order by name before placing them in the output file. @cindex SORT_BY_ALIGNMENT -@code{SORT_BY_ALIGNMENT} is very similar to @code{SORT_BY_NAME}. The -difference is @code{SORT_BY_ALIGNMENT} will sort sections into -descending order by alignment before placing them in the output file. -Larger alignments are placed before smaller alignments in order to -reduce the amount of padding necessary. +@code{SORT_BY_ALIGNMENT} is similar to @code{SORT_BY_NAME}. +@code{SORT_BY_ALIGNMENT} will sort sections into descending order of +alignment before placing them in the output file. Placing larger +alignments before smaller alignments can reduce the amount of padding +needed. @cindex SORT_BY_INIT_PRIORITY -@code{SORT_BY_INIT_PRIORITY} is very similar to @code{SORT_BY_NAME}. The -difference is @code{SORT_BY_INIT_PRIORITY} will sort sections into -ascending order by numerical value of the GCC init_priority attribute -encoded in the section name before placing them in the output file. +@code{SORT_BY_INIT_PRIORITY} is also similar to @code{SORT_BY_NAME}. +@code{SORT_BY_INIT_PRIORITY} will sort sections into ascending +numerical order of the GCC init_priority attribute encoded in the +section name before placing them in the output file. In +@code{.init_array.NNNNN} and @code{.fini_array.NNNNN}, @code{NNNNN} is +the init_priority. In @code{.ctors.NNNNN} and @code{.dtors.NNNNN}, +@code{NNNNN} is 65535 minus the init_priority. @cindex SORT @code{SORT} is an alias for @code{SORT_BY_NAME}. diff --git a/ld/ldlang.c b/ld/ldlang.c index 1a49f69d908..a28e9a04535 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -19,6 +19,7 @@ MA 02110-1301, USA. */ #include "sysdep.h" +#include #include "bfd.h" #include "libiberty.h" #include "filenames.h" @@ -403,39 +404,50 @@ match_simple_wild (const char *pattern, const char *name) /* Return the numerical value of the init_priority attribute from section name NAME. */ -static unsigned long -get_init_priority (const char *name) +static int +get_init_priority (const asection *sec) { - char *end; - unsigned long init_priority; + const char *name = bfd_section_name (sec); + const char *dot; /* GCC uses the following section names for the init_priority - attribute with numerical values 101 and 65535 inclusive. A + attribute with numerical values 101 to 65535 inclusive. A lower value means a higher priority. - 1: .init_array.NNNN/.fini_array.NNNN: Where NNNN is the + 1: .init_array.NNNNN/.fini_array.NNNNN: Where NNNNN is the decimal numerical value of the init_priority attribute. The order of execution in .init_array is forward and .fini_array is backward. - 2: .ctors.NNNN/.dtors.NNNN: Where NNNN is 65535 minus the + 2: .ctors.NNNNN/.dtors.NNNNN: Where NNNNN is 65535 minus the decimal numerical value of the init_priority attribute. The order of execution in .ctors is backward and .dtors is forward. - */ - if (strncmp (name, ".init_array.", 12) == 0 - || strncmp (name, ".fini_array.", 12) == 0) - { - init_priority = strtoul (name + 12, &end, 10); - return *end ? 0 : init_priority; - } - else if (strncmp (name, ".ctors.", 7) == 0 - || strncmp (name, ".dtors.", 7) == 0) - { - init_priority = strtoul (name + 7, &end, 10); - return *end ? 0 : 65535 - init_priority; - } - return 0; + .init_array.NNNNN sections would normally be placed in an output + .init_array section, .fini_array.NNNNN in .fini_array, + .ctors.NNNNN in .ctors, and .dtors.NNNNN in .dtors. This means + we should sort by increasing number (and could just use + SORT_BY_NAME in scripts). However if .ctors.NNNNN sections are + being placed in .init_array (which may also contain + .init_array.NNNNN sections) or .dtors.NNNNN sections are being + placed in .fini_array then we need to extract the init_priority + attribute and sort on that. */ + dot = strrchr (name, '.'); + if (dot != NULL && ISDIGIT (dot[1])) + { + char *end; + unsigned long init_priority = strtoul (dot + 1, &end, 10); + if (*end == 0) + { + if (dot == name + 6 + && (strncmp (name, ".ctors", 6) == 0 + || strncmp (name, ".dtors", 6) == 0)) + init_priority = 65535 - init_priority; + if (init_priority <= INT_MAX) + return init_priority; + } + } + return -1; } /* Compare sections ASEC and BSEC according to SORT. */ @@ -444,7 +456,7 @@ static int compare_section (sort_type sort, asection *asec, asection *bsec) { int ret; - unsigned long ainit_priority, binit_priority; + int a_priority, b_priority; switch (sort) { @@ -452,11 +464,11 @@ compare_section (sort_type sort, asection *asec, asection *bsec) abort (); case by_init_priority: - ainit_priority = get_init_priority (bfd_section_name (asec)); - binit_priority = get_init_priority (bfd_section_name (bsec)); - if (ainit_priority == 0 || binit_priority == 0) + a_priority = get_init_priority (asec); + b_priority = get_init_priority (bsec); + if (a_priority < 0 || b_priority < 0) goto sort_by_name; - ret = ainit_priority - binit_priority; + ret = a_priority - b_priority; if (ret) break; else -- 2.30.2