diff options
author | Alan Modra <amodra@gmail.com> | 2008-01-25 12:03:37 +0000 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2008-01-25 12:03:37 +0000 |
commit | 53d25da64b00c1cf7f10d04785d66fa003f8bfc9 (patch) | |
tree | b1bad03e3da788202674fed0b1233f865cbad54d /ld/ldlang.c | |
parent | 5ca3b13d654923e893cb2661700bc06e7af32a49 (diff) | |
download | gdb-53d25da64b00c1cf7f10d04785d66fa003f8bfc9.zip gdb-53d25da64b00c1cf7f10d04785d66fa003f8bfc9.tar.gz gdb-53d25da64b00c1cf7f10d04785d66fa003f8bfc9.tar.bz2 |
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.
Diffstat (limited to 'ld/ldlang.c')
-rw-r--r-- | ld/ldlang.c | 307 |
1 files changed, 245 insertions, 62 deletions
diff --git a/ld/ldlang.c b/ld/ldlang.c index c5ad76d..de3f64b7 100644 --- a/ld/ldlang.c +++ b/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. */ |