This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
SORT_BY_INIT_PRIORITY
- From: Alan Modra <amodra at gmail dot com>
- To: binutils at sourceware dot org
- Date: Thu, 26 Sep 2019 00:14:03 +0930
- Subject: 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.
diff --git a/ld/ld.texi b/ld/ld.texi
index 8d5c7bc140..95fa6a0348 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 1a49f69d90..a28e9a0453 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -19,6 +19,7 @@
MA 02110-1301, USA. */
#include "sysdep.h"
+#include <limits.h>
#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
--
Alan Modra
Australia Development Lab, IBM