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.
This commit is contained in:
Alan Modra 2019-09-25 15:30:53 +09:30
parent 6ba2ed48c8
commit 9a24a2763d
3 changed files with 60 additions and 35 deletions

View File

@ -1,3 +1,13 @@
2019-09-25 Alan Modra <amodra@gmail.com>
* 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 <nickc@redhat.com>
* emultempl/avrelf.em (_before_allocation): Silence build warning

View File

@ -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}.

View File

@ -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