* emultempl/ppc64elf.em (move_input_section, sort_toc_sections): New.

(ppc_before_allocation): Call sort_toc_sections.
	(no_toc_sort, OPTION_NO_TOC_SORT): New.
	(PARSE_AND_LIST_PROLOGUE, PARSE_AND_LIST_LONGOPTS,
	 PARSE_AND_LIST_OPTIONS): Handle --no-toc-sort.
This commit is contained in:
Alan Modra 2010-03-15 02:03:00 +00:00
parent 1bbe090216
commit d43d0b53f6
2 changed files with 156 additions and 1 deletions

View File

@ -1,3 +1,11 @@
2010-03-15 Alan Modra <amodra@gmail.com>
* emultempl/ppc64elf.em (move_input_section, sort_toc_sections): New.
(ppc_before_allocation): Call sort_toc_sections.
(no_toc_sort, OPTION_NO_TOC_SORT): New.
(PARSE_AND_LIST_PROLOGUE, PARSE_AND_LIST_LONGOPTS,
PARSE_AND_LIST_OPTIONS): Handle --no-toc-sort.
2010-03-14 Alan Modra <amodra@gmail.com>
PR ld/11378

View File

@ -58,6 +58,9 @@ static int no_toc_opt = 0;
/* Whether to allow multiple toc sections. */
static int no_multi_toc = 0;
/* Whether to sort input toc and got sections. */
static int no_toc_sort = 0;
/* Whether to emit symbols for stubs. */
static int emit_stub_syms = -1;
@ -97,6 +100,132 @@ ppc_create_output_section_statements (void)
ppc64_elf_init_stub_bfd (stub_file->the_bfd, &link_info);
}
/* Move the input section statement at *U which happens to be on LIST
to be just before *TO. */
static void
move_input_section (lang_statement_list_type *list,
lang_statement_union_type **u,
lang_statement_union_type **to)
{
lang_statement_union_type *s = *u;
asection *i = s->input_section.section;
asection *p, *n;
/* Snip the input section from the statement list. If it was the
last statement, fix the list tail pointer. */
*u = s->header.next;
if (*u == NULL)
list->tail = u;
/* Add it back in the new position. */
s->header.next = *to;
*to = s;
if (list->tail == to)
list->tail = &s->header.next;
/* Trim I off the bfd map_head/map_tail doubly linked lists. */
n = i->map_head.s;
p = i->map_tail.s;
(p != NULL ? p : i->output_section)->map_head.s = n;
(n != NULL ? n : i->output_section)->map_tail.s = p;
/* Add I back on in its new position. */
if (s->header.next->header.type == lang_input_section_enum)
{
n = s->header.next->input_section.section;
p = n->map_tail.s;
}
else
{
/* If the next statement is not an input section statement then
TO must point at the previous input section statement
header.next field. */
lang_input_section_type *prev = (lang_input_section_type *)
((char *) to - offsetof (lang_statement_union_type, header.next));
ASSERT (prev->header.type == lang_input_section_enum);
p = prev->section;
n = p->map_head.s;
}
i->map_head.s = n;
i->map_tail.s = p;
(p != NULL ? p : i->output_section)->map_head.s = i;
(n != NULL ? n : i->output_section)->map_tail.s = i;
}
/* Sort input section statements in the linker script tree rooted at
LIST so that those whose owning bfd happens to have a section
called .init or .fini are placed first. Place any TOC sections
referenced by small TOC relocs next, with TOC sections referenced
only by bigtoc relocs last. */
static void
sort_toc_sections (lang_statement_list_type *list,
lang_statement_union_type **ini,
lang_statement_union_type **small)
{
lang_statement_union_type *s, **u;
asection *i;
u = &list->head;
while ((s = *u) != NULL)
{
switch (s->header.type)
{
case lang_wild_statement_enum:
sort_toc_sections (&s->wild_statement.children, ini, small);
break;
case lang_group_statement_enum:
sort_toc_sections (&s->group_statement.children, ini, small);
break;
case lang_input_section_enum:
i = s->input_section.section;
/* Leave the stub_file .got where it is. We put the .got
header there. */
if (i->owner == stub_file->the_bfd)
break;
if (bfd_get_section_by_name (i->owner, ".init") != NULL
|| bfd_get_section_by_name (i->owner, ".fini") != NULL)
{
if (ini != NULL && *ini != s)
{
move_input_section (list, u, ini);
if (small == ini)
small = &s->header.next;
ini = &s->header.next;
continue;
}
if (small == ini)
small = &s->header.next;
ini = &s->header.next;
break;
}
else if (ini == NULL)
ini = u;
if (ppc64_elf_has_small_toc_reloc (i))
{
if (small != NULL && *small != s)
{
move_input_section (list, u, small);
small = &s->header.next;
continue;
}
small = &s->header.next;
}
else if (small == NULL)
small = u;
break;
default:
break;
}
u = &s->header.next;
}
}
static void
ppc_before_allocation (void)
{
@ -126,6 +255,15 @@ ppc_before_allocation (void)
&& !link_info.relocatable
&& !ppc64_elf_edit_toc (&link_info))
einfo ("%X%P: can not edit %s %E\n", "toc");
if (!no_toc_sort)
{
lang_output_section_statement_type *toc_os;
toc_os = lang_output_section_find (".got");
if (toc_os != NULL)
sort_toc_sections (&toc_os->children, NULL, NULL);
}
}
gld${EMULATION_NAME}_before_allocation ();
@ -507,7 +645,8 @@ PARSE_AND_LIST_PROLOGUE='
#define OPTION_NO_OPD_OPT (OPTION_NO_TLS_GET_ADDR_OPT + 1)
#define OPTION_NO_TOC_OPT (OPTION_NO_OPD_OPT + 1)
#define OPTION_NO_MULTI_TOC (OPTION_NO_TOC_OPT + 1)
#define OPTION_NON_OVERLAPPING_OPD (OPTION_NO_MULTI_TOC + 1)
#define OPTION_NO_TOC_SORT (OPTION_NO_MULTI_TOC + 1)
#define OPTION_NON_OVERLAPPING_OPD (OPTION_NO_TOC_SORT + 1)
'
PARSE_AND_LIST_LONGOPTS='
@ -521,6 +660,7 @@ PARSE_AND_LIST_LONGOPTS='
{ "no-opd-optimize", no_argument, NULL, OPTION_NO_OPD_OPT },
{ "no-toc-optimize", no_argument, NULL, OPTION_NO_TOC_OPT },
{ "no-multi-toc", no_argument, NULL, OPTION_NO_MULTI_TOC },
{ "no-toc-sort", no_argument, NULL, OPTION_NO_TOC_SORT },
{ "non-overlapping-opd", no_argument, NULL, OPTION_NON_OVERLAPPING_OPD },
'
@ -566,6 +706,9 @@ PARSE_AND_LIST_OPTIONS='
--no-multi-toc Disallow automatic multiple toc sections.\n"
));
fprintf (file, _("\
--no-toc-sort Don'\''t sort TOC and GOT sections.\n"
));
fprintf (file, _("\
--non-overlapping-opd Canonicalize .opd, so that there are no\n\
overlapping .opd entries.\n"
));
@ -617,6 +760,10 @@ PARSE_AND_LIST_ARGS_CASES='
no_multi_toc = 1;
break;
case OPTION_NO_TOC_SORT:
no_toc_sort = 1;
break;
case OPTION_NON_OVERLAPPING_OPD:
non_overlapping_opd = 1;
break;