diff options
author | Alan Modra <amodra@gmail.com> | 2004-10-14 12:54:47 +0000 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2004-10-14 12:54:47 +0000 |
commit | afd7a018c9e949ee9f1126ae4517567bd9d2dcb1 (patch) | |
tree | 5d15c82c78d6d590e11d9b519e7ac7c8a8bd127f /ld/emultempl | |
parent | ad4c72d28343c31f9d4036beb90d18e2efa390ea (diff) | |
download | gdb-afd7a018c9e949ee9f1126ae4517567bd9d2dcb1.zip gdb-afd7a018c9e949ee9f1126ae4517567bd9d2dcb1.tar.gz gdb-afd7a018c9e949ee9f1126ae4517567bd9d2dcb1.tar.bz2 |
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.
Diffstat (limited to 'ld/emultempl')
-rw-r--r-- | ld/emultempl/elf32.em | 391 | ||||
-rw-r--r-- | ld/emultempl/mmo.em | 155 | ||||
-rw-r--r-- | ld/emultempl/pe.em | 341 |
3 files changed, 217 insertions, 670 deletions
diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em index 6273f0e..f9e2cf9 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 <<EOF -/* A variant of lang_output_section_find. Used by place_orphan. */ +/* A variant of lang_output_section_find used by place_orphan. */ static lang_output_section_statement_type * output_rel_find (asection *sec, int isdyn) { - lang_statement_union_type *u; lang_output_section_statement_type *lookup; lang_output_section_statement_type *last = NULL; lang_output_section_statement_type *last_alloc = NULL; @@ -1185,9 +1184,10 @@ output_rel_find (asection *sec, int isdyn) lang_output_section_statement_type *last_rel_alloc = NULL; int rela = sec->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 <<EOF if (link_info.relocatable && config.build_constructors) return EOF -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 +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 d6d30e6..cbe5108 100644 --- a/ld/emultempl/mmo.em +++ b/ld/emultempl/mmo.em @@ -32,47 +32,6 @@ EOF cat >>e${EMULATION_NAME}.c <<EOF -/* 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 = 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) - 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 7f67450..8e52b7b 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; } |