From afd7a018c9e949ee9f1126ae4517567bd9d2dcb1 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Thu, 14 Oct 2004 12:54:47 +0000 Subject: [PATCH] ld/ PR 63 * ldlang.h (lang_output_section_statement_type): Make "next" a struct lang_output_section_statement_struct *. (struct orphan_save): Move from elf32.em. Add "name" and "flags". (lang_output_section_find_by_flags, lang_insert_orphan): Declare. * ldlang.c (lang_output_section_find_1): Adjust for changed output_section_statement "next". (strip_excluded_output_sections): Likewise. (lang_record_phdrs): Likewise. (lang_output_section_find_by_flags): New function. (output_prev_sec_find): Move from pe.em. Adjust iterator. (lang_insert_orphan): New function. Tail end of elf32.em's place_orphan merged with that from pe.em. Allow bfd_section to be placed first. New heuristic for placing new output section statement in existing script, and accompanying split of __start symbol alignment into a separate assignment to dot. (lang_add_section): Consistently use output->bfd_section rather than an alias, section->output_section. (map_input_to_output_sections): Rename overly long arg. Move initialization of data_statement output section to here.. (lang_check_section_addresses): ..from here. (print_assignment): Correct printing of etree_assert. (print_all_symbols): Don't bomb if userdata is NULL. (IGNORE_SECTION): Rearrange. * emultempl/elf32.em (output_rel_find): Adjust interator. (output_prev_sec_find): Delete. (struct orphan_save): Delete. (gld${EMULATION_NAME}_place_orphan): Cater for zero bfd_section flags without creating a duplicate output section statement. Revise code holding history of various orphan section placements. Allow orphan sections to place before script specified output sections. Call lang_output_section_find_by_flags when placement by name fails. Use lang_insert_orphan. * emultempl/mmo.em (output_prev_sec_find): Delete. (struct orphan_save): Delete. (mmo_place_orphan): Revise code holding history of orphan placement. Allow orphans to place before existing output sections. Use lang_insert_orphan. * emultempl/pe.em (output_prev_sec_find): Delete. (struct orphan_save): Delete. (gld_${EMULATION_NAME}_place_orphan): Revise to suit use of lang_insert_orphan. ld/testsuite/ * ld-scripts/overlay-size.d: Update for changed orphan section placement. * ld-mmix/bpo-18.d: Likewise. --- ld/ChangeLog | 45 ++ ld/emultempl/elf32.em | 391 +++++------------ ld/emultempl/mmo.em | 155 +------ ld/emultempl/pe.em | 341 ++++----------- ld/ldlang.c | 571 +++++++++++++++++++++---- ld/ldlang.h | 19 +- ld/testsuite/ChangeLog | 6 + ld/testsuite/ld-mmix/bpo-18.d | 4 +- ld/testsuite/ld-scripts/overlay-size.d | 22 +- 9 files changed, 779 insertions(+), 775 deletions(-) diff --git a/ld/ChangeLog b/ld/ChangeLog index bc1e142f341..fc61f7f8ede 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,48 @@ +2004-10-14 Alan Modra + + PR 63 + * ldlang.h (lang_output_section_statement_type): Make "next" a + struct lang_output_section_statement_struct *. + (struct orphan_save): Move from elf32.em. Add "name" and "flags". + (lang_output_section_find_by_flags, lang_insert_orphan): Declare. + * ldlang.c (lang_output_section_find_1): Adjust for changed + output_section_statement "next". + (strip_excluded_output_sections): Likewise. + (lang_record_phdrs): Likewise. + (lang_output_section_find_by_flags): New function. + (output_prev_sec_find): Move from pe.em. Adjust iterator. + (lang_insert_orphan): New function. Tail end of elf32.em's + place_orphan merged with that from pe.em. Allow bfd_section to + be placed first. New heuristic for placing new output section + statement in existing script, and accompanying split of __start + symbol alignment into a separate assignment to dot. + (lang_add_section): Consistently use output->bfd_section rather than + an alias, section->output_section. + (map_input_to_output_sections): Rename overly long arg. Move + initialization of data_statement output section to here.. + (lang_check_section_addresses): ..from here. + (print_assignment): Correct printing of etree_assert. + (print_all_symbols): Don't bomb if userdata is NULL. + (IGNORE_SECTION): Rearrange. + * emultempl/elf32.em (output_rel_find): Adjust interator. + (output_prev_sec_find): Delete. + (struct orphan_save): Delete. + (gld${EMULATION_NAME}_place_orphan): Cater for zero bfd_section + flags without creating a duplicate output section statement. + Revise code holding history of various orphan section placements. + Allow orphan sections to place before script specified output + sections. Call lang_output_section_find_by_flags when placement + by name fails. Use lang_insert_orphan. + * emultempl/mmo.em (output_prev_sec_find): Delete. + (struct orphan_save): Delete. + (mmo_place_orphan): Revise code holding history of orphan placement. + Allow orphans to place before existing output sections. Use + lang_insert_orphan. + * emultempl/pe.em (output_prev_sec_find): Delete. + (struct orphan_save): Delete. + (gld_${EMULATION_NAME}_place_orphan): Revise to suit use of + lang_insert_orphan. + 2004-10-13 Mark Mitchell * scripttempl/armbpabi.sc: Do not put .gnu.version.* into a diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em index 6273f0e90c8..f9e2cf96255 100644 --- a/ld/emultempl/elf32.em +++ b/ld/emultempl/elf32.em @@ -1172,12 +1172,11 @@ fi if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then cat >>e${EMULATION_NAME}.c <name[4] == 'a'; - for (u = lang_output_section_statement.head; u; u = lookup->next) + for (lookup = &lang_output_section_statement.head->output_section_statement; + lookup != NULL; + lookup = lookup->next) { - lookup = &u->output_section_statement; if (lookup->constraint != -1 && strncmp (".rel", lookup->name, 4) == 0) { @@ -1229,63 +1229,52 @@ output_rel_find (asection *sec, int isdyn) return last; } -/* Find the last output section before given output statement. - Used by place_orphan. */ - -static asection * -output_prev_sec_find (lang_output_section_statement_type *os) -{ - asection *s = (asection *) NULL; - lang_statement_union_type *u; - lang_output_section_statement_type *lookup; - - for (u = lang_output_section_statement.head; - u != (lang_statement_union_type *) NULL; - u = lookup->next) - { - lookup = &u->output_section_statement; - if (lookup == os) - return s; - - if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL) - s = lookup->bfd_section; - } - - return NULL; -} - /* Place an orphan section. We use this to put random SHF_ALLOC sections in the right segment. */ -struct orphan_save { - lang_output_section_statement_type *os; - asection **section; - lang_statement_union_type **stmt; - lang_statement_union_type **os_tail; -}; - static bfd_boolean gld${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s) { - static struct orphan_save hold_text; - static struct orphan_save hold_rodata; - static struct orphan_save hold_data; - static struct orphan_save hold_bss; - static struct orphan_save hold_rel; - static struct orphan_save hold_interp; - static struct orphan_save hold_sdata; - static int count = 1; + static struct orphan_save hold[] = + { + { ".text", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE, + 0, 0, 0, 0 }, + { ".rodata", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, + 0, 0, 0, 0 }, + { ".data", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA, + 0, 0, 0, 0 }, + { ".bss", + SEC_ALLOC, + 0, 0, 0, 0 }, + { 0, + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, + 0, 0, 0, 0 }, + { ".interp", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, + 0, 0, 0, 0 }, + { ".sdata", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_SMALL_DATA, + 0, 0, 0, 0 } + }; + enum orphan_save_index + { + orphan_text = 0, + orphan_rodata, + orphan_data, + orphan_bss, + orphan_rel, + orphan_interp, + orphan_sdata + }; + static int orphan_init_done = 0; struct orphan_save *place; - lang_statement_list_type *old; - lang_statement_list_type add; - etree_type *address; const char *secname; - const char *ps = NULL; + lang_output_section_statement_type *after; lang_output_section_statement_type *os; - lang_statement_union_type **os_tail; - etree_type *load_base; int isdyn = 0; - asection *sec; secname = bfd_get_section_name (s->owner, s); @@ -1308,27 +1297,42 @@ gld${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s) if (os != NULL && (os->bfd_section == NULL + || os->bfd_section->flags == 0 || ((s->flags ^ os->bfd_section->flags) & (SEC_LOAD | SEC_ALLOC)) == 0)) { /* We already have an output section statement with this - name, and its bfd section, if any, has compatible flags. */ + name, and its bfd section, if any, has compatible flags. + If the section already exists but does not have any flags + set, then it has been created by the linker, probably as a + result of a --section-start command line switch. */ lang_add_section (&os->children, s, os, file); return TRUE; } } - if (hold_text.os == NULL) - hold_text.os = lang_output_section_find (".text"); + if (!orphan_init_done) + { + struct orphan_save *ho; + for (ho = hold; ho < hold + sizeof (hold) / sizeof (hold[0]); ++ho) + if (ho->name != NULL) + { + ho->os = lang_output_section_find (ho->name); + if (ho->os != NULL && ho->os->flags == 0) + ho->os->flags = ho->flags; + } + orphan_init_done = 1; + } /* If this is a final link, then always put .gnu.warning.SYMBOL sections into the .text section to get them out of the way. */ if (link_info.executable && ! link_info.relocatable && strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0 - && hold_text.os != NULL) + && hold[orphan_text].os != NULL) { - lang_add_section (&hold_text.os->children, s, hold_text.os, file); + lang_add_section (&hold[orphan_text].os->children, s, + hold[orphan_text].os, file); return TRUE; } @@ -1337,220 +1341,57 @@ gld${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s) right after the .interp section, so that the PT_NOTE segment is stored right after the program headers where the OS can read it in the first page. */ -#define HAVE_SECTION(hold, name) \ -(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL) place = NULL; if ((s->flags & SEC_ALLOC) == 0) ; else if ((s->flags & SEC_LOAD) != 0 - && strncmp (secname, ".note", 5) == 0 - && HAVE_SECTION (hold_interp, ".interp")) - place = &hold_interp; - else if ((s->flags & SEC_HAS_CONTENTS) == 0 - && HAVE_SECTION (hold_bss, ".bss")) - place = &hold_bss; - else if ((s->flags & SEC_SMALL_DATA) != 0 - && HAVE_SECTION (hold_sdata, ".sdata")) - place = &hold_sdata; - else if ((s->flags & SEC_READONLY) == 0 - && HAVE_SECTION (hold_data, ".data")) - place = &hold_data; + && strncmp (secname, ".note", 5) == 0) + place = &hold[orphan_interp]; + else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) + place = &hold[orphan_bss]; + else if ((s->flags & SEC_SMALL_DATA) != 0) + place = &hold[orphan_sdata]; + else if ((s->flags & SEC_READONLY) == 0) + place = &hold[orphan_data]; else if (strncmp (secname, ".rel", 4) == 0 - && (s->flags & SEC_LOAD) != 0 - && (hold_rel.os != NULL - || (hold_rel.os = output_rel_find (s, isdyn)) != NULL)) - place = &hold_rel; - else if ((s->flags & (SEC_CODE | SEC_READONLY)) == SEC_READONLY - && HAVE_SECTION (hold_rodata, ".rodata")) - place = &hold_rodata; - else if ((s->flags & (SEC_CODE | SEC_READONLY)) == (SEC_CODE | SEC_READONLY) - && hold_text.os != NULL) - place = &hold_text; - -#undef HAVE_SECTION - - /* Choose a unique name for the section. This will be needed if the - same section name appears in the input file with different - loadable or allocatable characteristics. But if the section - already exists but does not have any flags set, then it has been - created by the linker, probably as a result of a --section-start - command line switch. */ - if ((sec = bfd_get_section_by_name (output_bfd, secname)) != NULL - && bfd_get_section_flags (output_bfd, sec) != 0) - { - secname = bfd_get_unique_section_name (output_bfd, secname, &count); - if (secname == NULL) - einfo ("%F%P: place_orphan failed: %E\n"); - } - - /* Start building a list of statements for this section. - First save the current statement pointer. */ - old = stat_ptr; + && (s->flags & SEC_LOAD) != 0) + place = &hold[orphan_rel]; + else if ((s->flags & SEC_CODE) == 0) + place = &hold[orphan_rodata]; + else + place = &hold[orphan_text]; - /* If we have found an appropriate place for the output section - statements for this orphan, add them to our own private list, - inserting them later into the global statement list. */ + after = NULL; if (place != NULL) { - stat_ptr = &add; - lang_list_init (stat_ptr); - } - - if (config.build_constructors) - { - /* If the name of the section is representable in C, then create - symbols to mark the start and the end of the section. */ - for (ps = secname; *ps != '\0'; ps++) - if (! ISALNUM (*ps) && *ps != '_') - break; - if (*ps == '\0') + if (place->os == NULL) { - char *symname; - etree_type *e_align; - - symname = (char *) xmalloc (ps - secname + sizeof "__start_"); - sprintf (symname, "__start_%s", secname); - e_align = exp_unop (ALIGN_K, - exp_intop ((bfd_vma) 1 << s->alignment_power)); - lang_add_assignment (exp_assop ('=', symname, e_align)); + if (place->name != NULL) + place->os = lang_output_section_find (place->name); + else + place->os = output_rel_find (s, isdyn); } + after = place->os; + if (after == NULL) + after = lang_output_section_find_by_flags (s, &place->os); + if (after == NULL) + /* *ABS* is always the first output section statement. */ + after = &lang_output_section_statement.head->output_section_statement; } - address = NULL; - if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0) - address = exp_intop ((bfd_vma) 0); - - load_base = NULL; - if (place != NULL && place->os->load_base != NULL) - { - etree_type *lma_from_vma; - lma_from_vma = exp_binop ('-', place->os->load_base, - exp_nameop (ADDR, place->os->name)); - load_base = exp_binop ('+', lma_from_vma, - exp_nameop (ADDR, secname)); - } - - os_tail = lang_output_section_statement.tail; - os = lang_enter_output_section_statement (secname, address, 0, - (etree_type *) NULL, - (etree_type *) NULL, - load_base, 0); - - lang_add_section (&os->children, s, os, file); - - lang_leave_output_section_statement - ((bfd_vma) 0, "*default*", - (struct lang_output_section_phdr_list *) NULL, NULL); - - if (config.build_constructors && *ps == '\0') + /* Choose a unique name for the section. This will be needed if the + same section name appears in the input file with different + loadable or allocatable characteristics. */ + if (bfd_get_section_by_name (output_bfd, secname) != NULL) { - char *symname; - - /* lang_leave_ouput_section_statement resets stat_ptr. Put - stat_ptr back where we want it. */ - if (place != NULL) - stat_ptr = &add; - - symname = (char *) xmalloc (ps - secname + sizeof "__stop_"); - sprintf (symname, "__stop_%s", secname); - lang_add_assignment (exp_assop ('=', symname, - exp_nameop (NAME, "."))); + static int count = 1; + secname = bfd_get_unique_section_name (output_bfd, secname, &count); + if (secname == NULL) + einfo ("%F%P: place_orphan failed: %E\n"); } - /* Restore the global list pointer. */ - stat_ptr = old; - - if (place != NULL && os->bfd_section != NULL) - { - asection *snew, **pps; - - snew = os->bfd_section; - - /* Shuffle the bfd section list to make the output file look - neater. This is really only cosmetic. */ - if (place->section == NULL) - { - asection *bfd_section = place->os->bfd_section; - - /* If the output statement hasn't been used to place - any input sections (and thus doesn't have an output - bfd_section), look for the closest prior output statement - having an output section. */ - if (bfd_section == NULL) - bfd_section = output_prev_sec_find (place->os); - - if (bfd_section != NULL && bfd_section != snew) - place->section = &bfd_section->next; - } - - if (place->section != NULL) - { - /* Unlink the section. */ - for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next) - ; - bfd_section_list_remove (output_bfd, pps); - - /* Now tack it on to the "place->os" section list. */ - bfd_section_list_insert (output_bfd, place->section, snew); - } - - /* Save the end of this list. Further ophans of this type will - follow the one we've just added. */ - place->section = &snew->next; - - /* The following is non-cosmetic. We try to put the output - statements in some sort of reasonable order here, because - they determine the final load addresses of the orphan - sections. In addition, placing output statements in the - wrong order may require extra segments. For instance, - given a typical situation of all read-only sections placed - in one segment and following that a segment containing all - the read-write sections, we wouldn't want to place an orphan - read/write section before or amongst the read-only ones. */ - if (add.head != NULL) - { - lang_statement_union_type *newly_added_os; - - if (place->stmt == NULL) - { - /* Put the new statement list right at the head. */ - *add.tail = place->os->header.next; - place->os->header.next = add.head; - - place->os_tail = &place->os->next; - } - else - { - /* Put it after the last orphan statement we added. */ - *add.tail = *place->stmt; - *place->stmt = add.head; - } - - /* Fix the global list pointer if we happened to tack our - new list at the tail. */ - if (*old->tail == add.head) - old->tail = add.tail; - - /* Save the end of this list. */ - place->stmt = add.tail; - - /* Do the same for the list of output section statements. */ - newly_added_os = *os_tail; - *os_tail = NULL; - newly_added_os->output_section_statement.next = *place->os_tail; - *place->os_tail = newly_added_os; - place->os_tail = &newly_added_os->output_section_statement.next; - - /* Fixing the global list pointer here is a little different. - We added to the list in lang_enter_output_section_statement, - trimmed off the new output_section_statment above when - assigning *os_tail = NULL, but possibly added it back in - the same place when assigning *place->os_tail. */ - if (*os_tail == NULL) - lang_output_section_statement.tail = os_tail; - } - } + lang_insert_orphan (file, s, secname, after, place, NULL, NULL); return TRUE; } @@ -1603,49 +1444,49 @@ cat >>e${EMULATION_NAME}.c <> e${EMULATION_NAME}.c -echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c -sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c -echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c -sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocatable) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c +echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c if cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then : ; else -echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c -sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c fi if test -n "$GENERATE_PIE_SCRIPT" ; then if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then echo ' ; else if (link_info.pie && link_info.combreloc' >> e${EMULATION_NAME}.c echo ' && link_info.relro' >> e${EMULATION_NAME}.c echo ' && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c -sed $sc ldscripts/${EMULATION_NAME}.xdw >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xdw >> e${EMULATION_NAME}.c echo ' ; else if (link_info.pie && link_info.combreloc) return' >> e${EMULATION_NAME}.c -sed $sc ldscripts/${EMULATION_NAME}.xdc >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xdc >> e${EMULATION_NAME}.c fi -echo ' ; else if (link_info.pie) return' >> e${EMULATION_NAME}.c -sed $sc ldscripts/${EMULATION_NAME}.xd >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.pie) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xd >> e${EMULATION_NAME}.c fi if test -n "$GENERATE_SHLIB_SCRIPT" ; then if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then echo ' ; else if (link_info.shared && link_info.combreloc' >> e${EMULATION_NAME}.c echo ' && link_info.relro' >> e${EMULATION_NAME}.c echo ' && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c -sed $sc ldscripts/${EMULATION_NAME}.xsw >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xsw >> e${EMULATION_NAME}.c echo ' ; else if (link_info.shared && link_info.combreloc) return' >> e${EMULATION_NAME}.c -sed $sc ldscripts/${EMULATION_NAME}.xsc >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xsc >> e${EMULATION_NAME}.c fi -echo ' ; else if (link_info.shared) return' >> e${EMULATION_NAME}.c -sed $sc ldscripts/${EMULATION_NAME}.xs >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.shared) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xs >> e${EMULATION_NAME}.c fi if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then echo ' ; else if (link_info.combreloc && link_info.relro' >> e${EMULATION_NAME}.c echo ' && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c -sed $sc ldscripts/${EMULATION_NAME}.xw >> e${EMULATION_NAME}.c -echo ' ; else if (link_info.combreloc) return' >> e${EMULATION_NAME}.c -sed $sc ldscripts/${EMULATION_NAME}.xc >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xw >> e${EMULATION_NAME}.c +echo ' ; else if (link_info.combreloc) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xc >> e${EMULATION_NAME}.c fi -echo ' ; else return' >> e${EMULATION_NAME}.c -sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c -echo '; }' >> e${EMULATION_NAME}.c +echo ' ; else return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c +echo '; }' >> e${EMULATION_NAME}.c else # Scripts read from the filesystem. diff --git a/ld/emultempl/mmo.em b/ld/emultempl/mmo.em index d6d30e676c0..cbe51082141 100644 --- a/ld/emultempl/mmo.em +++ b/ld/emultempl/mmo.em @@ -32,47 +32,6 @@ EOF cat >>e${EMULATION_NAME}.c <next) - { - lookup = &u->output_section_statement; - if (lookup->constraint == -1) - continue; - if (lookup == os) - break; - if (lookup->bfd_section != NULL - && lookup->bfd_section != bfd_abs_section_ptr - && lookup->bfd_section != bfd_com_section_ptr - && lookup->bfd_section != bfd_und_section_ptr) - s = lookup->bfd_section; - } - - if (u == NULL) - return NULL; - - return s; -} - -struct orphan_save { - lang_output_section_statement_type *os; - asection **section; - lang_statement_union_type **stmt; -}; - -#define HAVE_SECTION(hold, name) \ -(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL) - /* Place an orphan section. We use this to put random SEC_CODE or SEC_READONLY sections right after MMO_TEXT_SECTION_NAME. Much borrowed from elf32.em. */ @@ -80,21 +39,25 @@ struct orphan_save { static bfd_boolean mmo_place_orphan (lang_input_statement_type *file, asection *s) { - static struct orphan_save hold_text; + static struct orphan_save hold_text = + { + MMO_TEXT_SECTION_NAME, + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE, + 0, 0, 0, 0 + }; struct orphan_save *place; + const char *secname; + lang_output_section_statement_type *after; lang_output_section_statement_type *os; - lang_statement_list_type *old; - lang_statement_list_type add; - asection *snew, **pps, *bfd_section; /* We have nothing to say for anything other than a final link. */ if (link_info.relocatable - || (bfd_get_section_flags (s->owner, s) - & (SEC_EXCLUDE | SEC_LOAD)) != SEC_LOAD) + || (s->flags & (SEC_EXCLUDE | SEC_LOAD)) != SEC_LOAD) return FALSE; /* Only care for sections we're going to load. */ - os = lang_output_section_find (bfd_get_section_name (s->owner, s)); + secname = s->name; + os = lang_output_section_find (secname); /* We have an output section by this name. Place the section inside it (regardless of whether the linker script lists it as input). */ @@ -106,108 +69,28 @@ mmo_place_orphan (lang_input_statement_type *file, asection *s) /* If this section does not have .text-type section flags or there's no MMO_TEXT_SECTION_NAME, we don't have anything to say. */ - if ((bfd_get_section_flags (s->owner, s) & (SEC_CODE | SEC_READONLY)) == 0) + if ((s->flags & (SEC_CODE | SEC_READONLY)) == 0) return FALSE; if (hold_text.os == NULL) - hold_text.os = lang_output_section_find (MMO_TEXT_SECTION_NAME); + hold_text.os = lang_output_section_find (hold_text.name); place = &hold_text; + if (hold_text.os != NULL) + after = hold_text.os; + else + after = &lang_output_section_statement.head->output_section_statement; /* If there's an output section by this name, we'll use it, regardless of section flags, in contrast to what's done in elf32.em. */ - - /* Start building a list of statements for this section. - First save the current statement pointer. */ - old = stat_ptr; - - /* Add the output section statements for this orphan to our own private - list, inserting them later into the global statement list. */ - stat_ptr = &add; - lang_list_init (stat_ptr); - - os = lang_enter_output_section_statement (bfd_get_section_name (s->owner, - s), - NULL, 0, - (etree_type *) NULL, - (etree_type *) NULL, - (etree_type *) NULL, 0); - - lang_add_section (&os->children, s, os, file); - - lang_leave_output_section_statement - ((bfd_vma) 0, "*default*", - (struct lang_output_section_phdr_list *) NULL, NULL); - - /* Restore the global list pointer. */ - stat_ptr = old; - - snew = os->bfd_section; - if (snew == NULL) - /* /DISCARD/ section. */ - return TRUE; + os = lang_insert_orphan (file, s, secname, after, place, NULL, NULL); /* We need an output section for .text as a root, so if there was none (might happen with a peculiar linker script such as in "map addresses", map-address.exp), we grab the output section created above. */ if (hold_text.os == NULL) - { - if (os == NULL) - return FALSE; - hold_text.os = os; - } - - bfd_section = place->os->bfd_section; - if (place->section == NULL && bfd_section == NULL) - bfd_section = output_prev_sec_find (place->os); - - if (place->section != NULL - || (bfd_section != NULL - && bfd_section != snew)) - { - /* Shuffle the section to make the output file look neater. This is - really only cosmetic. */ - if (place->section == NULL) - /* Put orphans after the first section on the list. */ - place->section = &bfd_section->next; - - /* Unlink the section. */ - for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next) - ; - bfd_section_list_remove (output_bfd, pps); - - /* Now tack it on to the "place->os" section list. */ - bfd_section_list_insert (output_bfd, place->section, snew); - } - place->section = &snew->next; /* Save the end of this list. */ - - if (add.head != NULL) - { - /* We try to put the output statements in some sort of reasonable - order here, because they determine the final load addresses of - the orphan sections. */ - if (place->stmt == NULL) - { - /* Put the new statement list right at the head. */ - *add.tail = place->os->header.next; - place->os->header.next = add.head; - } - else - { - /* Put it after the last orphan statement we added. */ - *add.tail = *place->stmt; - *place->stmt = add.head; - } - - /* Fix the global list pointer if we happened to tack our new list - at the tail. */ - if (*old->tail == add.head) - old->tail = add.tail; - - /* Save the end of this list. */ - place->stmt = add.tail; - } + hold_text.os = os; return TRUE; } diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em index 7f674502c7f..8e52b7bc8a0 100644 --- a/ld/emultempl/pe.em +++ b/ld/emultempl/pe.em @@ -1485,33 +1485,6 @@ gld_${EMULATION_NAME}_finish (void) } -/* Find the last output section before given output statement. - Used by place_orphan. */ - -static asection * -output_prev_sec_find (lang_output_section_statement_type *os) -{ - asection *s = (asection *) NULL; - lang_statement_union_type *u; - lang_output_section_statement_type *lookup; - - for (u = lang_output_section_statement.head; - u != (lang_statement_union_type *) NULL; - u = lookup->next) - { - lookup = &u->output_section_statement; - if (lookup->constraint == -1) - continue; - if (lookup == os) - return s; - - if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL) - s = lookup->bfd_section; - } - - return NULL; -} - /* Place an orphan section. We use this to put sections in a reasonable place in the file, and @@ -1525,280 +1498,132 @@ output_prev_sec_find (lang_output_section_statement_type *os) default linker script using wildcards, and are sorted by sort_sections. */ -struct orphan_save -{ - lang_output_section_statement_type *os; - asection **section; - lang_statement_union_type **stmt; - lang_statement_union_type **os_tail; -}; - static bfd_boolean gld_${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s) { const char *secname; - char *hold_section_name; + const char *orig_secname; char *dollar = NULL; - const char *ps = NULL; lang_output_section_statement_type *os; lang_statement_list_type add_child; secname = bfd_get_section_name (s->owner, s); /* Look through the script to see where to place this section. */ - hold_section_name = xstrdup (secname); - if (!link_info.relocatable) + orig_secname = secname; + if (!link_info.relocatable + && (dollar = strchr (secname, '$')) != NULL) { - dollar = strchr (hold_section_name, '$'); - if (dollar != NULL) - *dollar = '\0'; + size_t len = dollar - orig_secname; + char *newname = xmalloc (len + 1); + memcpy (newname, orig_secname, len); + newname[len] = '\0'; + secname = newname; } - os = lang_output_section_find (hold_section_name); + os = lang_output_section_find (secname); lang_list_init (&add_child); if (os != NULL && (os->bfd_section == NULL + || os->bfd_section->flags == 0 || ((s->flags ^ os->bfd_section->flags) & (SEC_LOAD | SEC_ALLOC)) == 0)) { /* We already have an output section statement with this - name, and its bfd section, if any, has compatible flags. */ + name, and its bfd section, if any, has compatible flags. + If the section already exists but does not have any flags set, + then it has been created by the linker, probably as a result of + a --section-start command line switch. */ lang_add_section (&add_child, s, os, file); } else { + static struct orphan_save hold[] = + { + { ".text", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE, + 0, 0, 0, 0 }, + { ".rdata", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, + 0, 0, 0, 0 }, + { ".data", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA, + 0, 0, 0, 0 }, + { ".bss", + SEC_ALLOC, + 0, 0, 0, 0 } + }; + enum orphan_save_index + { + orphan_text = 0, + orphan_rodata, + orphan_data, + orphan_bss + }; + static int orphan_init_done = 0; struct orphan_save *place; - static struct orphan_save hold_text; - static struct orphan_save hold_rdata; - static struct orphan_save hold_data; - static struct orphan_save hold_bss; - static int count = 1; - char *outsecname; - lang_statement_list_type *old; - lang_statement_list_type add; - lang_statement_union_type **os_tail; + lang_output_section_statement_type *after; etree_type *address; - etree_type *load_base; - asection *sec; + + if (!orphan_init_done) + { + struct orphan_save *ho; + for (ho = hold; ho < hold + sizeof (hold) / sizeof (hold[0]); ++ho) + if (ho->name != NULL) + { + ho->os = lang_output_section_find (ho->name); + if (ho->os != NULL && ho->os->flags == 0) + ho->os->flags = ho->flags; + } + orphan_init_done = 1; + } /* Try to put the new output section in a reasonable place based on the section name and section flags. */ -#define HAVE_SECTION(hold, name) \ -(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL) place = NULL; if ((s->flags & SEC_ALLOC) == 0) ; - else if ((s->flags & SEC_HAS_CONTENTS) == 0 - && HAVE_SECTION (hold_bss, ".bss")) - place = &hold_bss; - else if ((s->flags & SEC_READONLY) == 0 - && HAVE_SECTION (hold_data, ".data")) - place = &hold_data; - else if ((s->flags & SEC_CODE) == 0 - && (s->flags & SEC_READONLY) != 0 - && HAVE_SECTION (hold_rdata, ".rdata")) - place = &hold_rdata; - else if ((s->flags & SEC_CODE) != 0 - && (s->flags & SEC_READONLY) != 0 - && HAVE_SECTION (hold_text, ".text")) - place = &hold_text; - -#undef HAVE_SECTION - - /* Choose a unique name for the section. This will be needed if the - same section name appears in the input file with different - loadable or allocatable characteristics. But if the section - already exists but does not have any flags set, then it has been - created by the linker, probably as a result of a --section-start - command line switch. */ - sec = bfd_get_section_by_name (output_bfd, hold_section_name); - if (sec != NULL - && bfd_get_section_flags (output_bfd, sec) != 0) - { - outsecname = bfd_get_unique_section_name (output_bfd, - hold_section_name, &count); - if (outsecname == NULL) - einfo ("%F%P: place_orphan failed: %E\n"); - } + else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) + place = &hold[orphan_bss]; + else if ((s->flags & SEC_READONLY) == 0) + place = &hold[orphan_data]; + else if ((s->flags & SEC_CODE) == 0) + place = &hold[orphan_rodata]; else - outsecname = xstrdup (hold_section_name); - - /* Start building a list of statements for this section. */ - old = stat_ptr; + place = &hold[orphan_text]; - /* If we have found an appropriate place for the output section - statements for this orphan, add them to our own private list, - inserting them later into the global statement list. */ + after = NULL; if (place != NULL) { - stat_ptr = &add; - lang_list_init (stat_ptr); - } - - if (config.build_constructors) - { - /* If the name of the section is representable in C, then create - symbols to mark the start and the end of the section. */ - for (ps = outsecname; *ps != '\0'; ps++) - if (! ISALNUM ((unsigned char) *ps) && *ps != '_') - break; - if (*ps == '\0') - { - char *symname; - etree_type *e_align; - - symname = (char *) xmalloc (ps - outsecname + sizeof "___start_"); - sprintf (symname, "___start_%s", outsecname); - e_align = exp_unop (ALIGN_K, - exp_intop ((bfd_vma) 1 << s->alignment_power)); - lang_add_assignment (exp_assop ('=', symname, e_align)); - } - } - - if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0) - address = exp_intop ((bfd_vma) 0); - else - { - /* All sections in an executable must be aligned to a page - boundary. */ - address = exp_unop (ALIGN_K, - exp_nameop (NAME, "__section_alignment__")); + if (place->os == NULL) + place->os = lang_output_section_find (place->name); + after = place->os; + if (after == NULL) + after = lang_output_section_find_by_flags (s, &place->os); + if (after == NULL) + /* *ABS* is always the first output section statement. */ + after = (&lang_output_section_statement.head + ->output_section_statement); } - load_base = NULL; - if (place != NULL && place->os->load_base != NULL) - { - etree_type *lma_from_vma; - lma_from_vma = exp_binop ('-', place->os->load_base, - exp_nameop (ADDR, place->os->name)); - load_base = exp_binop ('+', lma_from_vma, - exp_nameop (ADDR, secname)); - } - - os_tail = lang_output_section_statement.tail; - os = lang_enter_output_section_statement (outsecname, address, 0, - (etree_type *) NULL, - (etree_type *) NULL, - load_base, 0); - - lang_add_section (&add_child, s, os, file); - - lang_leave_output_section_statement - ((bfd_vma) 0, "*default*", - (struct lang_output_section_phdr_list *) NULL, NULL); - - if (config.build_constructors && *ps == '\0') + /* Choose a unique name for the section. This will be needed if the + same section name appears in the input file with different + loadable or allocatable characteristics. */ + if (bfd_get_section_by_name (output_bfd, secname) != NULL) { - char *symname; - - /* lang_leave_ouput_section_statement resets stat_ptr. - Put stat_ptr back where we want it. */ - if (place != NULL) - stat_ptr = &add; - - symname = (char *) xmalloc (ps - outsecname + sizeof "___stop_"); - sprintf (symname, "___stop_%s", outsecname); - lang_add_assignment (exp_assop ('=', symname, - exp_nameop (NAME, "."))); + static int count = 1; + secname = bfd_get_unique_section_name (output_bfd, secname, &count); + if (secname == NULL) + einfo ("%F%P: place_orphan failed: %E\n"); } - stat_ptr = old; - - if (place != NULL && os->bfd_section != NULL) - { - asection *snew, **pps; - - snew = os->bfd_section; - - /* Shuffle the bfd section list to make the output file look - neater. This is really only cosmetic. */ - if (place->section == NULL) - { - asection *bfd_section = place->os->bfd_section; - - /* If the output statement hasn't been used to place - any input sections (and thus doesn't have an output - bfd_section), look for the closest prior output statement - having an output section. */ - if (bfd_section == NULL) - bfd_section = output_prev_sec_find (place->os); - - if (bfd_section != NULL && bfd_section != snew) - place->section = &bfd_section->next; - } - - if (place->section != NULL) - { - /* Unlink the section. */ - for (pps = &output_bfd->sections; - *pps != snew; - pps = &(*pps)->next) - ; - bfd_section_list_remove (output_bfd, pps); - - /* Now tack it on to the "place->os" section list. */ - bfd_section_list_insert (output_bfd, place->section, snew); - } - - /* Save the end of this list. Further ophans of this type will - follow the one we've just added. */ - place->section = &snew->next; - - /* The following is non-cosmetic. We try to put the output - statements in some sort of reasonable order here, because - they determine the final load addresses of the orphan - sections. In addition, placing output statements in the - wrong order may require extra segments. For instance, - given a typical situation of all read-only sections placed - in one segment and following that a segment containing all - the read-write sections, we wouldn't want to place an orphan - read/write section before or amongst the read-only ones. */ - if (add.head != NULL) - { - lang_statement_union_type *newly_added_os; - - if (place->stmt == NULL) - { - /* Put the new statement list right at the head. */ - *add.tail = place->os->header.next; - place->os->header.next = add.head; - - place->os_tail = &place->os->next; - } - else - { - /* Put it after the last orphan statement we added. */ - *add.tail = *place->stmt; - *place->stmt = add.head; - } - - /* Fix the global list pointer if we happened to tack our - new list at the tail. */ - if (*old->tail == add.head) - old->tail = add.tail; - - /* Save the end of this list. */ - place->stmt = add.tail; - - /* Do the same for the list of output section statements. */ - newly_added_os = *os_tail; - *os_tail = NULL; - newly_added_os->output_section_statement.next = *place->os_tail; - *place->os_tail = newly_added_os; - place->os_tail = &newly_added_os->output_section_statement.next; - - /* Fixing the global list pointer here is a little different. - We added to the list in lang_enter_output_section_statement, - trimmed off the new output_section_statment above when - assigning *os_tail = NULL, but possibly added it back in - the same place when assigning *place->os_tail. */ - if (*os_tail == NULL) - lang_output_section_statement.tail = os_tail; - } - } + /* All sections in an executable must be aligned to a page boundary. */ + address = exp_unop (ALIGN_K, exp_nameop (NAME, "__section_alignment__")); + os = lang_insert_orphan (file, s, secname, after, place, address, + &add_child); } { @@ -1830,7 +1655,7 @@ gld_${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s else { found_dollar = TRUE; - if (strcmp (secname, lname) < 0) + if (strcmp (orig_secname, lname) < 0) break; } } @@ -1843,8 +1668,6 @@ gld_${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s } } - free (hold_section_name); - return TRUE; } diff --git a/ld/ldlang.c b/ld/ldlang.c index e520625e94e..fee5950b6f1 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -612,13 +612,12 @@ lang_memory_default (asection *section) static lang_output_section_statement_type * lang_output_section_find_1 (const char *const name, int constraint) { - lang_statement_union_type *u; lang_output_section_statement_type *lookup; - for (u = lang_output_section_statement.head; u != NULL; u = lookup->next) + for (lookup = &lang_output_section_statement.head->output_section_statement; + lookup != NULL; + lookup = lookup->next) { - lookup = &u->output_section_statement; - if (strcmp (name, lookup->name) == 0 && lookup->constraint != -1 && (constraint == 0 || constraint == lookup->constraint)) @@ -666,7 +665,7 @@ lang_output_section_statement_lookup_1 (const char *const name, int constraint) lang_statement_append (&lang_output_section_statement, (lang_statement_union_type *) lookup, - &lookup->next); + (lang_statement_union_type **) &lookup->next); } return lookup; } @@ -677,6 +676,389 @@ lang_output_section_statement_lookup (const char *const name) return lang_output_section_statement_lookup_1 (name, 0); } +/* A variant of lang_output_section_find used by place_orphan. + Returns the output statement that should precede a new output + statement for SEC. If an exact match is found on certain flags, + sets *EXACT too. */ + +lang_output_section_statement_type * +lang_output_section_find_by_flags (const asection *sec, + lang_output_section_statement_type **exact) +{ + lang_output_section_statement_type *first, *look, *found; + flagword flags; + + /* We know the first statement on this list is *ABS*. May as well + skip it. */ + first = &lang_output_section_statement.head->output_section_statement; + first = first->next; + + /* First try for an exact match. */ + found = NULL; + for (look = first; look; look = look->next) + { + flags = look->flags; + if (look->bfd_section != NULL) + flags = look->bfd_section->flags; + flags ^= sec->flags; + if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY + | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL))) + found = look; + } + if (found != NULL) + { + *exact = found; + return found; + } + + if (sec->flags & SEC_CODE) + { + /* Try for a rw code section. */ + for (look = first; look; look = look->next) + { + flags = look->flags; + if (look->bfd_section != NULL) + flags = look->bfd_section->flags; + flags ^= sec->flags; + if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD + | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL))) + found = look; + } + return found; + } + + if (sec->flags & (SEC_READONLY | SEC_THREAD_LOCAL)) + { + /* .rodata can go after .text, .sdata2 after .rodata. */ + for (look = first; look; look = look->next) + { + flags = look->flags; + if (look->bfd_section != NULL) + flags = look->bfd_section->flags; + flags ^= sec->flags; + if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD + | SEC_READONLY)) + && !(look->flags & (SEC_SMALL_DATA | SEC_THREAD_LOCAL))) + found = look; + } + return found; + } + + if (sec->flags & SEC_SMALL_DATA) + { + /* .sdata goes after .data, .sbss after .sdata. */ + for (look = first; look; look = look->next) + { + flags = look->flags; + if (look->bfd_section != NULL) + flags = look->bfd_section->flags; + flags ^= sec->flags; + if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD + | SEC_THREAD_LOCAL)) + || ((look->flags & SEC_SMALL_DATA) + && !(sec->flags & SEC_HAS_CONTENTS))) + found = look; + } + return found; + } + + if (sec->flags & SEC_HAS_CONTENTS) + { + /* .data goes after .rodata. */ + for (look = first; look; look = look->next) + { + flags = look->flags; + if (look->bfd_section != NULL) + flags = look->bfd_section->flags; + flags ^= sec->flags; + if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD + | SEC_SMALL_DATA | SEC_THREAD_LOCAL))) + found = look; + } + return found; + } + + /* .bss goes last. */ + for (look = first; look; look = look->next) + { + flags = look->flags; + if (look->bfd_section != NULL) + flags = look->bfd_section->flags; + flags ^= sec->flags; + if (!(flags & SEC_ALLOC)) + found = look; + } + + return found; +} + +/* Find the last output section before given output statement. + Used by place_orphan. */ + +static asection * +output_prev_sec_find (lang_output_section_statement_type *os) +{ + asection *s = (asection *) NULL; + lang_output_section_statement_type *lookup; + + for (lookup = &lang_output_section_statement.head->output_section_statement; + lookup != NULL; + lookup = lookup->next) + { + if (lookup->constraint == -1) + continue; + if (lookup == os) + return s; + + if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL) + s = lookup->bfd_section; + } + + return NULL; +} + +lang_output_section_statement_type * +lang_insert_orphan (lang_input_statement_type *file, + asection *s, + const char *secname, + lang_output_section_statement_type *after, + struct orphan_save *place, + etree_type *address, + lang_statement_list_type *add_child) +{ + lang_statement_list_type *old; + lang_statement_list_type add; + const char *ps; + etree_type *load_base; + lang_output_section_statement_type *os; + lang_output_section_statement_type **os_tail; + + /* Start building a list of statements for this section. + First save the current statement pointer. */ + old = stat_ptr; + + /* If we have found an appropriate place for the output section + statements for this orphan, add them to our own private list, + inserting them later into the global statement list. */ + if (after != NULL) + { + stat_ptr = &add; + lang_list_init (stat_ptr); + } + + ps = NULL; + if (config.build_constructors) + { + /* If the name of the section is representable in C, then create + symbols to mark the start and the end of the section. */ + for (ps = secname; *ps != '\0'; ps++) + if (! ISALNUM ((unsigned char) *ps) && *ps != '_') + break; + if (*ps == '\0') + { + char *symname; + etree_type *e_align; + + symname = (char *) xmalloc (ps - secname + sizeof "__start_" + 1); + symname[0] = bfd_get_symbol_leading_char (output_bfd); + sprintf (symname + (symname[0] != 0), "__start_%s", secname); + e_align = exp_unop (ALIGN_K, + exp_intop ((bfd_vma) 1 << s->alignment_power)); + lang_add_assignment (exp_assop ('=', ".", e_align)); + lang_add_assignment (exp_assop ('=', symname, + exp_nameop (NAME, "."))); + } + } + + if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0) + address = exp_intop (0); + + load_base = NULL; + if (after != NULL && after->load_base != NULL) + { + etree_type *lma_from_vma; + lma_from_vma = exp_binop ('-', after->load_base, + exp_nameop (ADDR, after->name)); + load_base = exp_binop ('+', lma_from_vma, + exp_nameop (ADDR, secname)); + } + + os_tail = ((lang_output_section_statement_type **) + lang_output_section_statement.tail); + os = lang_enter_output_section_statement (secname, address, 0, NULL, NULL, + load_base, 0); + + if (add_child == NULL) + add_child = &os->children; + lang_add_section (add_child, s, os, file); + + lang_leave_output_section_statement (0, "*default*", NULL, NULL); + + if (config.build_constructors && *ps == '\0') + { + char *symname; + + /* lang_leave_ouput_section_statement resets stat_ptr. + Put stat_ptr back where we want it. */ + if (after != NULL) + stat_ptr = &add; + + symname = (char *) xmalloc (ps - secname + sizeof "__stop_" + 1); + symname[0] = bfd_get_symbol_leading_char (output_bfd); + sprintf (symname + (symname[0] != 0), "__stop_%s", secname); + lang_add_assignment (exp_assop ('=', symname, + exp_nameop (NAME, "."))); + } + + /* Restore the global list pointer. */ + if (after != NULL) + stat_ptr = old; + + if (after != NULL && os->bfd_section != NULL) + { + asection *snew, **pps; + + snew = os->bfd_section; + + /* Shuffle the bfd section list to make the output file look + neater. This is really only cosmetic. */ + if (place->section == NULL + && after != (&lang_output_section_statement.head + ->output_section_statement)) + { + asection *bfd_section = after->bfd_section; + + /* If the output statement hasn't been used to place any input + sections (and thus doesn't have an output bfd_section), + look for the closest prior output statement having an + output section. */ + if (bfd_section == NULL) + bfd_section = output_prev_sec_find (after); + + if (bfd_section != NULL && bfd_section != snew) + place->section = &bfd_section->next; + } + + if (place->section == NULL) + place->section = &output_bfd->sections; + + /* Unlink the section. */ + for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next) + continue; + bfd_section_list_remove (output_bfd, pps); + + /* Now tack it back on in the right place. */ + bfd_section_list_insert (output_bfd, place->section, snew); + + /* Save the end of this list. Further ophans of this type will + follow the one we've just added. */ + place->section = &snew->next; + + /* The following is non-cosmetic. We try to put the output + statements in some sort of reasonable order here, because they + determine the final load addresses of the orphan sections. + In addition, placing output statements in the wrong order may + require extra segments. For instance, given a typical + situation of all read-only sections placed in one segment and + following that a segment containing all the read-write + sections, we wouldn't want to place an orphan read/write + section before or amongst the read-only ones. */ + if (add.head != NULL) + { + lang_output_section_statement_type *newly_added_os; + + if (place->stmt == NULL) + { + lang_statement_union_type **where; + lang_statement_union_type **assign = NULL; + + /* 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. */ + 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) + assign = where; + } + 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; + 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_afile_asection_pair_statement_enum: + break; + } + break; + } + + *add.tail = *where; + *where = add.head; + + place->os_tail = &after->next; + } + else + { + /* Put it after the last orphan statement we added. */ + *add.tail = *place->stmt; + *place->stmt = add.head; + } + + /* Fix the global list pointer if we happened to tack our + new list at the tail. */ + if (*old->tail == add.head) + old->tail = add.tail; + + /* Save the end of this list. */ + place->stmt = add.tail; + + /* Do the same for the list of output section statements. */ + newly_added_os = *os_tail; + *os_tail = NULL; + newly_added_os->next = *place->os_tail; + *place->os_tail = newly_added_os; + place->os_tail = &newly_added_os->next; + + /* Fixing the global list pointer here is a little different. + We added to the list in lang_enter_output_section_statement, + trimmed off the new output_section_statment above when + assigning *os_tail = NULL, but possibly added it back in + the same place when assigning *place->os_tail. */ + if (*os_tail == NULL) + lang_output_section_statement.tail + = (lang_statement_union_type **) os_tail; + } + } + return os; +} + static void lang_map_flags (flagword flag) { @@ -792,7 +1174,7 @@ sort_def_symbol (hash_entry, info) } else if (!ud->map_symbol_def_tail) ud->map_symbol_def_tail = &ud->map_symbol_def_head; - + def = obstack_alloc (&map_obstack, sizeof *def); def->entry = hash_entry; *(ud->map_symbol_def_tail) = def; @@ -867,7 +1249,7 @@ exp_init_os (etree_type *exp) case etree_assert: exp_init_os (exp->assert_s.child); break; - + case etree_unary: exp_init_os (exp->unary.child); break; @@ -991,32 +1373,32 @@ lang_add_section (lang_statement_list_type *ptr, flags &= ~ (SEC_LINK_ONCE | SEC_LINK_DUPLICATES); /* If this is not the first input section, and the SEC_READONLY - flag is not currently set, then don't set it just because the - input section has it set. */ + flag is not currently set, then don't set it just because the + input section has it set. */ - if (! first && (section->output_section->flags & SEC_READONLY) == 0) + if (! first && (output->bfd_section->flags & SEC_READONLY) == 0) flags &= ~ SEC_READONLY; /* Keep SEC_MERGE and SEC_STRINGS only if they are the same. */ if (! first - && ((section->output_section->flags & (SEC_MERGE | SEC_STRINGS)) + && ((output->bfd_section->flags & (SEC_MERGE | SEC_STRINGS)) != (flags & (SEC_MERGE | SEC_STRINGS)) || ((flags & SEC_MERGE) - && section->output_section->entsize != section->entsize))) + && output->bfd_section->entsize != section->entsize))) { - section->output_section->flags &= ~ (SEC_MERGE | SEC_STRINGS); + output->bfd_section->flags &= ~ (SEC_MERGE | SEC_STRINGS); flags &= ~ (SEC_MERGE | SEC_STRINGS); } - section->output_section->flags |= flags; + output->bfd_section->flags |= flags; if (flags & SEC_MERGE) - section->output_section->entsize = section->entsize; + output->bfd_section->entsize = section->entsize; /* If SEC_READONLY is not set in the input section, then clear - it from the output section. */ + it from the output section. */ if ((section->flags & SEC_READONLY) == 0) - section->output_section->flags &= ~SEC_READONLY; + output->bfd_section->flags &= ~SEC_READONLY; switch (output->sectype) { @@ -1036,7 +1418,7 @@ lang_add_section (lang_statement_list_type *ptr, /* Copy over SEC_SMALL_DATA. */ if (section->flags & SEC_SMALL_DATA) - section->output_section->flags |= SEC_SMALL_DATA; + output->bfd_section->flags |= SEC_SMALL_DATA; if (section->alignment_power > output->bfd_section->alignment_power) output->bfd_section->alignment_power = section->alignment_power; @@ -1047,7 +1429,7 @@ lang_add_section (lang_statement_list_type *ptr, if (section->flags & SEC_BLOCK) { - section->output_section->flags |= SEC_BLOCK; + output->bfd_section->flags |= SEC_BLOCK; /* FIXME: This value should really be obtained from the bfd... */ output->block_value = 128; } @@ -1122,7 +1504,7 @@ wild_sort (lang_wild_statement_type *wild, ls = &l->input_section; /* Sorting by filename takes precedence over sorting by section - name. */ + name. */ if (wild->filenames_sorted) { @@ -1131,9 +1513,9 @@ wild_sort (lang_wild_statement_type *wild, int i; /* The PE support for the .idata section as generated by - dlltool assumes that files will be sorted by the name of - the archive and then the name of the file within the - archive. */ + dlltool assumes that files will be sorted by the name of + the archive and then the name of the file within the + archive. */ if (file->the_bfd != NULL && bfd_my_archive (file->the_bfd) != NULL) @@ -1181,7 +1563,7 @@ wild_sort (lang_wild_statement_type *wild, } /* Here either the files are not sorted by name, or we are - looking at the sections for this file. */ + looking at the sections for this file. */ if (sec != NULL && sec->spec.sorted != none) { @@ -1832,8 +2214,8 @@ open_input_bfds (lang_statement_union_type *s, bfd_boolean force) s->input_statement.target = current_target; /* If we are being called from within a group, and this - is an archive which has already been searched, then - force it to be researched unless the whole archive + is an archive which has already been searched, then + force it to be researched unless the whole archive has been loaded already. */ if (force && !s->input_statement.whole_archive @@ -2125,19 +2507,19 @@ update_wild_statements (lang_statement_union_type *s) static void map_input_to_output_sections (lang_statement_union_type *s, const char *target, - lang_output_section_statement_type *output_section_statement) + lang_output_section_statement_type *os) { for (; s != NULL; s = s->header.next) { switch (s->header.type) { case lang_wild_statement_enum: - wild (&s->wild_statement, target, output_section_statement); + wild (&s->wild_statement, target, os); break; case lang_constructors_statement_enum: map_input_to_output_sections (constructor_list.head, target, - output_section_statement); + os); break; case lang_output_section_statement_enum: if (s->output_section_statement.constraint) @@ -2169,27 +2551,32 @@ map_input_to_output_sections case lang_group_statement_enum: map_input_to_output_sections (s->group_statement.children.head, target, - output_section_statement); + os); break; case lang_data_statement_enum: /* Make sure that any sections mentioned in the expression are initialized. */ exp_init_os (s->data_statement.exp); - /* FALLTHROUGH */ + if (os != NULL && os->bfd_section == NULL) + init_os (os); + /* The output section gets contents, and then we inspect for + any flags set in the input script which override any ALLOC. */ + os->bfd_section->flags |= SEC_HAS_CONTENTS; + if (!(os->flags & SEC_NEVER_LOAD)) + os->bfd_section->flags |= SEC_ALLOC | SEC_LOAD; + break; case lang_fill_statement_enum: case lang_input_section_enum: case lang_object_symbols_statement_enum: case lang_reloc_statement_enum: case lang_padding_statement_enum: case lang_input_statement_enum: - if (output_section_statement != NULL - && output_section_statement->bfd_section == NULL) - init_os (output_section_statement); + if (os != NULL && os->bfd_section == NULL) + init_os (os); break; case lang_assignment_statement_enum: - if (output_section_statement != NULL - && output_section_statement->bfd_section == NULL) - init_os (output_section_statement); + if (os != NULL && os->bfd_section == NULL) + init_os (os); /* Make sure that any sections mentioned in the assignment are initialized. */ @@ -2201,13 +2588,13 @@ map_input_to_output_sections case lang_address_statement_enum: /* Mark the specified section with the supplied address. */ { - lang_output_section_statement_type *os = - lang_output_section_statement_lookup - (s->address_statement.section_name); + lang_output_section_statement_type *aos + = (lang_output_section_statement_lookup + (s->address_statement.section_name)); - if (os->bfd_section == NULL) - init_os (os); - os->addr_tree = s->address_statement.address; + if (aos->bfd_section == NULL) + init_os (aos); + aos->addr_tree = s->address_statement.address; } break; } @@ -2221,16 +2608,14 @@ map_input_to_output_sections static void strip_excluded_output_sections (void) { - lang_statement_union_type *u; + lang_output_section_statement_type *os; - for (u = lang_output_section_statement.head; - u != NULL; - u = u->output_section_statement.next) + for (os = &lang_output_section_statement.head->output_section_statement; + os != NULL; + os = os->next) { - lang_output_section_statement_type *os; asection *s; - os = &u->output_section_statement; if (os->constraint == -1) continue; s = os->bfd_section; @@ -2302,23 +2687,35 @@ print_assignment (lang_assignment_statement_type *assignment, lang_output_section_statement_type *output_section) { int i; + int is_dot; + etree_type *tree; etree_value_type result; for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++) print_space (); - result = exp_fold_tree (assignment->exp->assign.src, output_section, - lang_final_phase_enum, print_dot, &print_dot); + if (assignment->exp->type.node_class == etree_assert) + { + is_dot = 0; + tree = assignment->exp->assert_s.child; + } + else + { + const char *dst = assignment->exp->assign.dst; + is_dot = dst[0] == '.' && dst[1] == 0; + tree = assignment->exp->assign.src; + } + + result = exp_fold_tree (tree, output_section, lang_final_phase_enum, + print_dot, &print_dot); if (result.valid_p) { - const char *dst; bfd_vma value; value = result.value + result.section->bfd_section->vma; - dst = assignment->exp->assign.dst; minfo ("0x%V", value); - if (dst[0] == '.' && dst[1] == 0) + if (is_dot) print_dot = value; } else @@ -2330,9 +2727,7 @@ print_assignment (lang_assignment_statement_type *assignment, } minfo (" "); - exp_print_tree (assignment->exp); - print_nl (); } @@ -2379,6 +2774,9 @@ print_all_symbols (sec) struct fat_user_section_struct *ud = get_userdata (sec); struct map_symbol_def *def; + if (!ud) + return; + *ud->map_symbol_def_tail = 0; for (def = ud->map_symbol_def_head; def; def = def->next) print_one_symbol (def->entry, sec); @@ -2863,14 +3261,15 @@ size_input_section } #define IGNORE_SECTION(s) \ - (((s->flags & SEC_THREAD_LOCAL) != 0 \ - ? (s->flags & (SEC_LOAD | SEC_NEVER_LOAD)) != SEC_LOAD \ - : (s->flags & (SEC_ALLOC | SEC_NEVER_LOAD)) != SEC_ALLOC) \ + ((s->flags & SEC_NEVER_LOAD) != 0 \ + || (s->flags & SEC_ALLOC) == 0 \ + || ((s->flags & SEC_THREAD_LOCAL) != 0 \ + && (s->flags & SEC_LOAD) == 0) \ || s->size == 0) /* Check to see if any allocated sections overlap with other allocated - sections. This can happen when the linker script specifically specifies - the output section addresses of the two sections. */ + sections. This can happen if a linker script specifies the output + section addresses of the two sections. */ static void lang_check_section_addresses (void) @@ -3090,7 +3489,7 @@ lang_size_sections_1 lang_allocating_phase_enum, dot, &dot); os->processed = 0; - + if (!r.valid_p) einfo (_("%F%S: non constant or forward reference" " address expression for section %s\n"), @@ -3220,14 +3619,6 @@ lang_size_sections_1 size = TO_SIZE ((unsigned) 1); dot += TO_ADDR (size); output_section_statement->bfd_section->size += size; - /* The output section gets contents, and then we inspect for - any flags set in the input script which override any ALLOC. */ - output_section_statement->bfd_section->flags |= SEC_HAS_CONTENTS; - if (!(output_section_statement->flags & SEC_NEVER_LOAD)) - { - output_section_statement->bfd_section->flags |= - SEC_ALLOC | SEC_LOAD; - } } break; @@ -3714,7 +4105,7 @@ lang_finish (void) const char *send; /* We couldn't find the entry symbol. Try parsing it as a - number. */ + number. */ val = bfd_scan_vma (entry_symbol.name, &send, 0); if (*send == '\0') { @@ -3815,10 +4206,10 @@ lang_check (void) bfd_error_handler_type pfn = NULL; /* If we aren't supposed to warn about mismatched input - files, temporarily set the BFD error handler to a - function which will do nothing. We still want to call - bfd_merge_private_bfd_data, since it may set up - information which is needed in the output file. */ + files, temporarily set the BFD error handler to a + function which will do nothing. We still want to call + bfd_merge_private_bfd_data, since it may set up + information which is needed in the output file. */ if (! command_line.warn_mismatch) pfn = bfd_set_error_handler (ignore_bfd_errors); if (! bfd_merge_private_bfd_data (input_bfd, output_bfd)) @@ -3965,7 +4356,7 @@ lang_place_orphans (void) if (s->output_section == NULL) { /* This section of the file is not attached, root - around for a sensible place for it to go. */ + around for a sensible place for it to go. */ if (file->just_syms_flag) abort (); @@ -3984,8 +4375,8 @@ lang_place_orphans (void) { #if 0 /* This message happens when using the - svr3.ifile linker script, so I have - disabled it. */ + svr3.ifile linker script, so I have + disabled it. */ info_msg (_("%P: no [COMMON] command," " defaulting to .bss\n")); #endif @@ -4855,7 +5246,7 @@ lang_record_phdrs (void) asection **secs; lang_output_section_phdr_list *last; struct lang_phdr *l; - lang_statement_union_type *u; + lang_output_section_statement_type *os; alc = 10; secs = xmalloc (alc * sizeof (asection *)); @@ -4867,14 +5258,12 @@ lang_record_phdrs (void) bfd_vma at; c = 0; - for (u = lang_output_section_statement.head; - u != NULL; - u = u->output_section_statement.next) + for (os = &lang_output_section_statement.head->output_section_statement; + os != NULL; + os = os->next) { - lang_output_section_statement_type *os; lang_output_section_phdr_list *pl; - os = &u->output_section_statement; if (os->constraint == -1) continue; @@ -4930,22 +5319,22 @@ lang_record_phdrs (void) free (secs); /* Make sure all the phdr assignments succeeded. */ - for (u = lang_output_section_statement.head; - u != NULL; - u = u->output_section_statement.next) + for (os = &lang_output_section_statement.head->output_section_statement; + os != NULL; + os = os->next) { lang_output_section_phdr_list *pl; - if (u->output_section_statement.constraint == -1 - || u->output_section_statement.bfd_section == NULL) + if (os->constraint == -1 + || os->bfd_section == NULL) continue; - for (pl = u->output_section_statement.phdrs; + for (pl = os->phdrs; pl != NULL; pl = pl->next) if (! pl->used && strcmp (pl->name, "NONE") != 0) einfo (_("%X%P: section `%s' assigned to non-existent phdr `%s'\n"), - u->output_section_statement.name, pl->name); + os->name, pl->name); } } diff --git a/ld/ldlang.h b/ld/ldlang.h index f7e2fa619e7..9b0f9eff181 100644 --- a/ld/ldlang.h +++ b/ld/ldlang.h @@ -131,7 +131,7 @@ typedef struct lang_output_section_statement_struct union etree_union *addr_tree; lang_statement_list_type children; const char *memspec; - union lang_statement_union *next; + struct lang_output_section_statement_struct *next; const char *name; int processed; @@ -410,6 +410,17 @@ struct lang_definedness_hash_entry int iteration; }; +/* Used by place_orphan to keep track of orphan sections and statements. */ + +struct orphan_save { + const char *name; + flagword flags; + lang_output_section_statement_type *os; + asection **section; + lang_statement_union_type **stmt; + lang_output_section_statement_type **os_tail; +}; + extern struct unique_sections *unique_section_list; extern lang_output_section_statement_type *abs_output_section; @@ -501,6 +512,12 @@ extern void ldlang_add_file (lang_input_statement_type *); extern lang_output_section_statement_type *lang_output_section_find (const char * const); +extern lang_output_section_statement_type *lang_output_section_find_by_flags + (const asection *, lang_output_section_statement_type **exact); +extern lang_output_section_statement_type *lang_insert_orphan + (lang_input_statement_type *, asection *, const char *, + lang_output_section_statement_type *, struct orphan_save *, + etree_type *, lang_statement_list_type *); extern lang_input_statement_type *lang_add_input_file (const char *, lang_input_file_enum_type, const char *); extern void lang_add_keepsyms_file diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index da6dc8aac92..f9a8bd54f16 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2004-10-14 Alan Modra + + * ld-scripts/overlay-size.d: Update for changed orphan section + placement. + * ld-mmix/bpo-18.d: Likewise. + 2004-10-07 Bob Wilson * ld-xtensa/lcall1.s: Use .literal directive. diff --git a/ld/testsuite/ld-mmix/bpo-18.d b/ld/testsuite/ld-mmix/bpo-18.d index 39c9282c45d..9a88569026f 100644 --- a/ld/testsuite/ld-mmix/bpo-18.d +++ b/ld/testsuite/ld-mmix/bpo-18.d @@ -12,9 +12,9 @@ SYMBOL TABLE: 0+100 l d \.text 0+ 4000000000001060 l d \.text\.away 0+ +400000000000106c l d \.data 0+ +400000000000106c l d \.bss 0+ 0+7e0 l d \.MMIX\.reg_contents 0+ -4000000000001088 l d \.data 0+ -4000000000001088 l d \.bss 0+ 0+ l d \*ABS\* 0+ 0+ l d \*ABS\* 0+ 0+ l d \*ABS\* 0+ diff --git a/ld/testsuite/ld-scripts/overlay-size.d b/ld/testsuite/ld-scripts/overlay-size.d index f54f56dfe71..9021aa43827 100644 --- a/ld/testsuite/ld-scripts/overlay-size.d +++ b/ld/testsuite/ld-scripts/overlay-size.d @@ -5,25 +5,25 @@ # The .bss[123] LMAs are deliberately blanked out. We can't # reliably map overlaid sections to segments. #... - 0 \.bss1 +0+010 +0+20000 .* + .. \.bss1 +0+010 +0+20000 .* #... - 1 \.bss2 +0+030 +0+20000 .* + .. \.bss2 +0+030 +0+20000 .* #... - 2 \.bss3 +0+020 +0+20000 .* + .. \.bss3 +0+020 +0+20000 .* #... - 3 \.mtext +0+020 +0+10000 +0+30000 .* + .. \.mtext +0+020 +0+10000 +0+30000 .* #... - 4 \.mbss +0+230 +0+20030 .* + .. \.mbss +0+230 +0+20030 .* #... - 5 \.text1 +0+080 +0+10020 +0+30020 .* + .. \.text1 +0+080 +0+10020 +0+30020 .* #... - 6 \.text2 +0+040 +0+10020 +0+300a0 .* + .. \.text2 +0+040 +0+10020 +0+300a0 .* #... - 7 \.text3 +0+020 +0+10020 +0+300e0 .* + .. \.text3 +0+020 +0+10020 +0+300e0 .* #... - 8 \.data1 +0+030 +0+20260 +0+30100 .* + .. \.data1 +0+030 +0+20260 +0+30100 .* #... - 9 \.data2 +0+040 +0+20260 +0+30130 .* + .. \.data2 +0+040 +0+20260 +0+30130 .* #... - 10 \.data3 +0+050 +0+20260 +0+30170 .* + .. \.data3 +0+050 +0+20260 +0+30170 .* #pass -- 2.30.2