ld/
* ld.texinfo (INSERT): Describe. * ldgram.y (ldgram_in_script, ldgram_had_equals): Delete. (INSERT_K, AFTER, BEFORE): Add as tokens. (ifile_p1): Handle INSERT statements. (saved_script_handle, force_make_executable): Move to.. * ldmain.c: ..here. (previous_script_handle): New global var. * ldmain.h (saved_script_handle, force_make_executable): Declare. (previous_script_handle): Likewise. * ldlex.l (INSERT_K, AFTER, BEFORE): Add tokens. * lexsup.c (parge_args <-T>): Set previous_script_handle. * ldlang.c (lang_for_each_statement_worker): Handle insert statement. (map_input_to_output_sections, print_statement): Likewise. (lang_size_sections_1, lang_do_assignments_1): Likewise. (insert_os_after): New function, extracted from.. (lang_insert_orphan): ..here. (process_insert_statements): New function. (lang_process): Call it. (lang_add_insert): New function. * ldlang.h (lang_insert_statement_enum): New. (lang_insert_statement_type): New. (lang_statement_union_type): Add insert_statement. (lang_add_insert): Declare. ld/testsuite/ * ld-spu/ovl.lnk: Delete overlay. * ld-spu/ovl1.lnk: New file. * ld-spu/ovl2.lnk: New file. * ld-spu/ovl.d: Update. * ld-spu/ovl2.d: Update.
This commit is contained in:
parent
5ca3b13d65
commit
53d25da64b
15 changed files with 363 additions and 81 deletions
307
ld/ldlang.c
307
ld/ldlang.c
|
@ -845,6 +845,7 @@ lang_for_each_statement_worker (void (*func) (lang_statement_union_type *),
|
|||
case lang_padding_statement_enum:
|
||||
case lang_address_statement_enum:
|
||||
case lang_fill_statement_enum:
|
||||
case lang_insert_statement_enum:
|
||||
break;
|
||||
default:
|
||||
FAIL ();
|
||||
|
@ -1451,6 +1452,73 @@ output_prev_sec_find (lang_output_section_statement_type *os)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Look for a suitable place for a new output section statement. The
|
||||
idea is to skip over anything that might be inside a SECTIONS {}
|
||||
statement in a script, before we find another output section
|
||||
statement. Assignments to "dot" before an output section statement
|
||||
are assumed to belong to it. An exception to this rule is made for
|
||||
the first assignment to dot, otherwise we might put an orphan
|
||||
before . = . + SIZEOF_HEADERS or similar assignments that set the
|
||||
initial address. */
|
||||
|
||||
static lang_statement_union_type **
|
||||
insert_os_after (lang_output_section_statement_type *after)
|
||||
{
|
||||
lang_statement_union_type **where;
|
||||
lang_statement_union_type **assign = NULL;
|
||||
bfd_boolean ignore_first;
|
||||
|
||||
ignore_first
|
||||
= after == &lang_output_section_statement.head->output_section_statement;
|
||||
|
||||
for (where = &after->header.next;
|
||||
*where != NULL;
|
||||
where = &(*where)->header.next)
|
||||
{
|
||||
switch ((*where)->header.type)
|
||||
{
|
||||
case lang_assignment_statement_enum:
|
||||
if (assign == NULL)
|
||||
{
|
||||
lang_assignment_statement_type *ass;
|
||||
|
||||
ass = &(*where)->assignment_statement;
|
||||
if (ass->exp->type.node_class != etree_assert
|
||||
&& ass->exp->assign.dst[0] == '.'
|
||||
&& ass->exp->assign.dst[1] == 0
|
||||
&& !ignore_first)
|
||||
assign = where;
|
||||
}
|
||||
ignore_first = FALSE;
|
||||
continue;
|
||||
case lang_wild_statement_enum:
|
||||
case lang_input_section_enum:
|
||||
case lang_object_symbols_statement_enum:
|
||||
case lang_fill_statement_enum:
|
||||
case lang_data_statement_enum:
|
||||
case lang_reloc_statement_enum:
|
||||
case lang_padding_statement_enum:
|
||||
case lang_constructors_statement_enum:
|
||||
assign = NULL;
|
||||
continue;
|
||||
case lang_output_section_statement_enum:
|
||||
if (assign != NULL)
|
||||
where = assign;
|
||||
break;
|
||||
case lang_input_statement_enum:
|
||||
case lang_address_statement_enum:
|
||||
case lang_target_statement_enum:
|
||||
case lang_output_statement_enum:
|
||||
case lang_group_statement_enum:
|
||||
case lang_insert_statement_enum:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return where;
|
||||
}
|
||||
|
||||
lang_output_section_statement_type *
|
||||
lang_insert_orphan (asection *s,
|
||||
const char *secname,
|
||||
|
@ -1606,64 +1674,7 @@ lang_insert_orphan (asection *s,
|
|||
|
||||
if (place->stmt == NULL)
|
||||
{
|
||||
lang_statement_union_type **where;
|
||||
lang_statement_union_type **assign = NULL;
|
||||
bfd_boolean ignore_first;
|
||||
|
||||
/* Look for a suitable place for the new statement list.
|
||||
The idea is to skip over anything that might be inside
|
||||
a SECTIONS {} statement in a script, before we find
|
||||
another output_section_statement. Assignments to "dot"
|
||||
before an output section statement are assumed to
|
||||
belong to it. An exception to this rule is made for
|
||||
the first assignment to dot, otherwise we might put an
|
||||
orphan before . = . + SIZEOF_HEADERS or similar
|
||||
assignments that set the initial address. */
|
||||
|
||||
ignore_first = after == (&lang_output_section_statement.head
|
||||
->output_section_statement);
|
||||
for (where = &after->header.next;
|
||||
*where != NULL;
|
||||
where = &(*where)->header.next)
|
||||
{
|
||||
switch ((*where)->header.type)
|
||||
{
|
||||
case lang_assignment_statement_enum:
|
||||
if (assign == NULL)
|
||||
{
|
||||
lang_assignment_statement_type *ass;
|
||||
ass = &(*where)->assignment_statement;
|
||||
if (ass->exp->type.node_class != etree_assert
|
||||
&& ass->exp->assign.dst[0] == '.'
|
||||
&& ass->exp->assign.dst[1] == 0
|
||||
&& !ignore_first)
|
||||
assign = where;
|
||||
}
|
||||
ignore_first = FALSE;
|
||||
continue;
|
||||
case lang_wild_statement_enum:
|
||||
case lang_input_section_enum:
|
||||
case lang_object_symbols_statement_enum:
|
||||
case lang_fill_statement_enum:
|
||||
case lang_data_statement_enum:
|
||||
case lang_reloc_statement_enum:
|
||||
case lang_padding_statement_enum:
|
||||
case lang_constructors_statement_enum:
|
||||
assign = NULL;
|
||||
continue;
|
||||
case lang_output_section_statement_enum:
|
||||
if (assign != NULL)
|
||||
where = assign;
|
||||
break;
|
||||
case lang_input_statement_enum:
|
||||
case lang_address_statement_enum:
|
||||
case lang_target_statement_enum:
|
||||
case lang_output_statement_enum:
|
||||
case lang_group_statement_enum:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
lang_statement_union_type **where = insert_os_after (after);
|
||||
|
||||
*add.tail = *where;
|
||||
*where = add.head;
|
||||
|
@ -3312,6 +3323,154 @@ map_input_to_output_sections
|
|||
aos->addr_tree = s->address_statement.address;
|
||||
}
|
||||
break;
|
||||
case lang_insert_statement_enum:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* An insert statement snips out all the linker statements from the
|
||||
start of the list and places them after the output section
|
||||
statement specified by the insert. This operation is complicated
|
||||
by the fact that we keep a doubly linked list of output section
|
||||
statements as well as the singly linked list of all statements. */
|
||||
|
||||
static void
|
||||
process_insert_statements (void)
|
||||
{
|
||||
lang_statement_union_type **s;
|
||||
lang_output_section_statement_type *first_os = NULL;
|
||||
lang_output_section_statement_type *last_os = NULL;
|
||||
|
||||
/* "start of list" is actually the statement immediately after
|
||||
the special abs_section output statement, so that it isn't
|
||||
reordered. */
|
||||
s = &lang_output_section_statement.head;
|
||||
while (*(s = &(*s)->header.next) != NULL)
|
||||
{
|
||||
if ((*s)->header.type == lang_output_section_statement_enum)
|
||||
{
|
||||
/* Keep pointers to the first and last output section
|
||||
statement in the sequence we may be about to move. */
|
||||
last_os = &(*s)->output_section_statement;
|
||||
if (first_os == NULL)
|
||||
first_os = last_os;
|
||||
}
|
||||
else if ((*s)->header.type == lang_insert_statement_enum)
|
||||
{
|
||||
lang_insert_statement_type *i = &(*s)->insert_statement;
|
||||
lang_output_section_statement_type *where;
|
||||
lang_output_section_statement_type *os;
|
||||
lang_statement_union_type **ptr;
|
||||
lang_statement_union_type *first;
|
||||
|
||||
where = lang_output_section_find (i->where);
|
||||
if (where != NULL && i->is_before)
|
||||
{
|
||||
do
|
||||
where = where->prev;
|
||||
while (where != NULL && where->constraint == -1);
|
||||
}
|
||||
if (where == NULL)
|
||||
{
|
||||
einfo (_("%X%P: %s not found for insert\n"), i->where);
|
||||
continue;
|
||||
}
|
||||
/* You can't insert into the list you are moving. */
|
||||
for (os = first_os; os != NULL; os = os->next)
|
||||
if (os == where || os == last_os)
|
||||
break;
|
||||
if (os == where)
|
||||
{
|
||||
einfo (_("%X%P: %s not found for insert\n"), i->where);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Deal with reordering the output section statement list. */
|
||||
if (last_os != NULL)
|
||||
{
|
||||
asection *first_sec, *last_sec;
|
||||
|
||||
/* Snip out the output sections we are moving. */
|
||||
first_os->prev->next = last_os->next;
|
||||
if (last_os->next == NULL)
|
||||
lang_output_section_statement.tail
|
||||
= (union lang_statement_union **) &first_os->prev->next;
|
||||
else
|
||||
last_os->next->prev = first_os->prev;
|
||||
/* Add them in at the new position. */
|
||||
last_os->next = where->next;
|
||||
if (where->next == NULL)
|
||||
lang_output_section_statement.tail
|
||||
= (union lang_statement_union **) &last_os->next;
|
||||
else
|
||||
where->next->prev = last_os;
|
||||
first_os->prev = where;
|
||||
where->next = first_os;
|
||||
|
||||
/* Move the bfd sections in the same way. */
|
||||
first_sec = NULL;
|
||||
last_sec = NULL;
|
||||
for (os = first_os; os != NULL; os = os->next)
|
||||
{
|
||||
if (os->bfd_section != NULL
|
||||
&& os->bfd_section->owner != NULL)
|
||||
{
|
||||
last_sec = os->bfd_section;
|
||||
if (first_sec == NULL)
|
||||
first_sec = last_sec;
|
||||
}
|
||||
if (os == last_os)
|
||||
break;
|
||||
}
|
||||
if (last_sec != NULL)
|
||||
{
|
||||
asection *sec = where->bfd_section;
|
||||
if (sec == NULL)
|
||||
sec = output_prev_sec_find (where);
|
||||
|
||||
/* The place we want to insert must come after the
|
||||
sections we are moving. So if we find no
|
||||
section or if the section is the same as our
|
||||
last section, then no move is needed. */
|
||||
if (sec != NULL && sec != last_sec)
|
||||
{
|
||||
/* Trim them off. */
|
||||
if (first_sec->prev != NULL)
|
||||
first_sec->prev->next = last_sec->next;
|
||||
else
|
||||
output_bfd->sections = last_sec->next;
|
||||
if (last_sec->next != NULL)
|
||||
last_sec->next->prev = first_sec->prev;
|
||||
else
|
||||
output_bfd->section_last = first_sec->prev;
|
||||
/* Add back. */
|
||||
last_sec->next = sec->next;
|
||||
if (sec->next != NULL)
|
||||
sec->next->prev = last_sec;
|
||||
else
|
||||
output_bfd->section_last = last_sec;
|
||||
first_sec->prev = sec;
|
||||
sec->next = first_sec;
|
||||
}
|
||||
}
|
||||
|
||||
first_os = NULL;
|
||||
last_os = NULL;
|
||||
}
|
||||
|
||||
ptr = insert_os_after (where);
|
||||
/* Snip everything after the abs_section output statement we
|
||||
know is at the start of the list, up to and including
|
||||
the insert statement we are currently processing. */
|
||||
first = lang_output_section_statement.head->header.next;
|
||||
lang_output_section_statement.head->header.next = (*s)->header.next;
|
||||
/* Add them back where they belong. */
|
||||
*s = *ptr;
|
||||
if (*s == NULL)
|
||||
statement_list.tail = s;
|
||||
*ptr = first;
|
||||
s = &lang_output_section_statement.head;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3954,6 +4113,11 @@ print_statement (lang_statement_union_type *s,
|
|||
case lang_group_statement_enum:
|
||||
print_group (&s->group_statement, os);
|
||||
break;
|
||||
case lang_insert_statement_enum:
|
||||
minfo ("INSERT %s %s\n",
|
||||
s->insert_statement.is_before ? "BEFORE" : "AFTER",
|
||||
s->insert_statement.where);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4734,13 +4898,16 @@ lang_size_sections_1
|
|||
fill, dot, relax, check_regions);
|
||||
break;
|
||||
|
||||
default:
|
||||
FAIL ();
|
||||
case lang_insert_statement_enum:
|
||||
break;
|
||||
|
||||
/* We can only get here when relaxing is turned on. */
|
||||
case lang_address_statement_enum:
|
||||
break;
|
||||
|
||||
default:
|
||||
FAIL ();
|
||||
break;
|
||||
}
|
||||
prev = &s->header.next;
|
||||
}
|
||||
|
@ -4999,12 +5166,15 @@ lang_do_assignments_1 (lang_statement_union_type *s,
|
|||
current_os, fill, dot);
|
||||
break;
|
||||
|
||||
default:
|
||||
FAIL ();
|
||||
case lang_insert_statement_enum:
|
||||
break;
|
||||
|
||||
case lang_address_statement_enum:
|
||||
break;
|
||||
|
||||
default:
|
||||
FAIL ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return dot;
|
||||
|
@ -5853,6 +6023,8 @@ lang_process (void)
|
|||
to the correct output sections. */
|
||||
map_input_to_output_sections (statement_list.head, NULL, NULL);
|
||||
|
||||
process_insert_statements ();
|
||||
|
||||
/* Find any sections not attached explicitly and handle them. */
|
||||
lang_place_orphans ();
|
||||
|
||||
|
@ -6269,6 +6441,17 @@ lang_add_output_format (const char *format,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
lang_add_insert (const char *where, int is_before)
|
||||
{
|
||||
lang_insert_statement_type *new;
|
||||
|
||||
new = new_stat (lang_insert_statement, stat_ptr);
|
||||
new->where = where;
|
||||
new->is_before = is_before;
|
||||
saved_script_handle = previous_script_handle;
|
||||
}
|
||||
|
||||
/* Enter a group. This creates a new lang_group_statement, and sets
|
||||
stat_ptr to build new statements within the group. */
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue