From fe6e29571a4ee4824ed7c243af5014281e13c91c Mon Sep 17 00:00:00 2001 From: David Edelsohn Date: Wed, 22 May 1996 19:09:32 +0000 Subject: [PATCH] * ldlang.c (wild_doit): Don't copy over SEC_LINK_{ONCE,DUPLICATES} if final link. * emultempl/pe.em (sfunc): Renamed to sort_by_file_name. (sort_by_section_name, sort_sections_1): New functions. (sort_sections): Only sort by file name sections in .idata. Add "Grouped Sections" support. (gld${EMULATION_NAME}_place_orphan): Rewrite to support Grouped Sections. (gld${EMULATION_NAME}_place_section): Delete. * scripttempl/pe.sc (.text,.data,.rdata): Add *(.foo\$). (.CRT,.rsrc): Rewrite to use Grouped Section support. --- ld/ChangeLog | 18 +++ ld/emultempl/pe.em | 381 +++++++++++++++++++++++---------------------- 2 files changed, 210 insertions(+), 189 deletions(-) diff --git a/ld/ChangeLog b/ld/ChangeLog index a11a852b17..790dd6fa8c 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,21 @@ +Wed May 22 11:31:30 1996 Doug Evans + + * ldlang.c (wild_doit): Don't copy over SEC_LINK_{ONCE,DUPLICATES} + if final link. + * emultempl/pe.em (sfunc): Renamed to sort_by_file_name. + (sort_by_section_name, sort_sections_1): New functions. + (sort_sections): Only sort by file name sections in .idata. + Add "Grouped Sections" support. + (gld${EMULATION_NAME}_place_orphan): Rewrite to support Grouped + Sections. + (gld${EMULATION_NAME}_place_section): Delete. + * scripttempl/pe.sc (.text,.data,.rdata): Add *(.foo\$). + (.CRT,.rsrc): Rewrite to use Grouped Section support. + +Tue May 21 14:31:48 1996 Stan Shebs + + * mpw-eppcmac.c: Update to reflect changes to aix.em. + Sun May 19 16:59:44 1996 Doug Evans * ldlang.c (dprint_statement): Stop printing at end of list. diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em index 02dbd4401a..e4696fa223 100644 --- a/ld/emultempl/pe.em +++ b/ld/emultempl/pe.em @@ -25,7 +25,6 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - #include "bfd.h" #include "sysdep.h" #include "bfdlink.h" @@ -46,12 +45,23 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define TARGET_IS_${EMULATION_NAME} +static void gld_${EMULATION_NAME}_set_symbols PARAMS ((void)); +static void gld_${EMULATION_NAME}_after_open PARAMS ((void)); static void gld_${EMULATION_NAME}_before_parse PARAMS ((void)); -static char *gld_${EMULATION_NAME}_get_script PARAMS ((int *isfile)); +static void gld_${EMULATION_NAME}_before_allocation PARAMS ((void)); static boolean gld${EMULATION_NAME}_place_orphan PARAMS ((lang_input_statement_type *, asection *)); -static void gld${EMULATION_NAME}_place_section - PARAMS ((lang_statement_union_type *)); +static char *gld_${EMULATION_NAME}_get_script PARAMS ((int *)); +static int gld_${EMULATION_NAME}_parse_args PARAMS ((int, char **)); + +#if 0 /* argument to qsort so don't prototype */ +static int sort_by_file_name PARAMS ((void *, void *)); +static int sort_by_section_name PARAMS ((void *, void *)); +#endif +static lang_statement_union_type **sort_sections_1 + PARAMS ((lang_statement_union_type **, lang_statement_union_type *, int, + int (*)())); +static void sort_sections PARAMS ((lang_statement_union_type *)); static struct internal_extra_pe_aouthdr pe; static int dll; @@ -61,7 +71,8 @@ gld_${EMULATION_NAME}_before_parse() { ldfile_output_architecture = bfd_arch_${ARCH}; } - + +/* PE format extra command line options. */ /* Used for setting flags in the PE header. */ #define OPTION_BASE_FILE (300 + 1) @@ -195,7 +206,7 @@ set_pe_value (name) { char *end; - set_pe_name (name, strtoul (optarg, &end, 16)); + set_pe_name (name, strtoul (optarg, &end, 0)); if (end == optarg) { einfo ("%P%F: invalid hex number for PE parameter '%s'\n", optarg); @@ -308,9 +319,9 @@ gld_${EMULATION_NAME}_parse_args(argc, argv) } return 1; } - + static void -gld_${EMULATION_NAME}_set_symbols() +gld_${EMULATION_NAME}_set_symbols() { /* Run through and invent symbols for all the names and insert the defaults. */ @@ -363,11 +374,12 @@ gld_${EMULATION_NAME}_after_open() } -/* Callback function for qsort in sort_sections. */ +/* Callback functions for qsort in sort_sections. */ -static int sfunc (a, b) -void *a; -void *b; +static int +sort_by_file_name (a, b) + void *a; + void *b; { lang_statement_union_type **ra = a; lang_statement_union_type **rb = b; @@ -375,7 +387,63 @@ void *b; (*rb)->input_section.ifile->filename); } -/* Sort the input sections of archives into filename order. */ +static int +sort_by_section_name (a, b) + void *a; + void *b; +{ + lang_statement_union_type **ra = a; + lang_statement_union_type **rb = b; + return strcmp ((*ra)->input_section.section->name, + (*rb)->input_section.section->name); +} + +/* Subroutine of sort_sections to a contiguous subset of a list of sections. + NEXT_AFTER is the element after the last one to sort. + The result is a pointer to the last element's "next" pointer. */ + +static lang_statement_union_type ** +sort_sections_1 (startptr, next_after, count, sort_func) + lang_statement_union_type **startptr,*next_after; + int count; + int (*sort_func) (); +{ + lang_statement_union_type **vec; + lang_statement_union_type *p; + int i; + + if (count == 0) + return startptr; + + vec = (lang_statement_union_type **) + alloca (count * sizeof (lang_statement_union_type *)); + + for (p = *startptr, i = 0; i < count; i++, p = p->next) + vec[i] = p; + + qsort (vec, count, sizeof (vec[0]), sort_func); + + /* Fill in the next pointers again. */ + *startptr = vec[0]; + for (i = 0; i < count - 1; i++) + vec[i]->header.next = vec[i + 1]; + vec[i]->header.next = next_after; + return &(vec[i]->header.next); +} + +/* Sort the .idata\$foo input sections of archives into filename order. + The reason is so dlltool can arrange to have the pe dll import information + generated correctly - the head of the list goes into dh.o, the tail into + dt.o, and the guts into ds[nnnn].o. Note that this is only needed for the + .idata section. + FIXME: This may no longer be necessary with grouped sections. Instead of + sorting on dh.o, ds[nnnn].o, dt.o, one could, for example, have dh.o use + .idata\$4h, have ds[nnnn].o use .idata\$4s[nnnn], and have dt.o use .idata\$4t. + This would have to be elaborated upon to handle multiple dll's + [assuming such an eloboration is possible of course]. + + We also sort sections in '\$' wild statements. These are created by the + place_orphans routine to implement grouped sections. */ static void sort_sections (s) @@ -391,52 +459,63 @@ sort_sections (s) { lang_statement_union_type **p = &s->wild_statement.children.head; - /* Sort any children in the same archive. Run through all - the children of this wild statement, when an - input_section in an archive is found, scan forward to - find all input_sections which are in the same archive. - Sort them by their filename and then re-thread the - pointer chain. */ - - while (*p) + /* Is this the .idata section? */ + if (strncmp (s->wild_statement.section_name, ".idata", 6) == 0) { - lang_statement_union_type *start = *p; - if (start->header.type != lang_input_section_enum - || !start->input_section.ifile->the_bfd->my_archive) - p = &(start->header.next); - else + /* Sort any children in the same archive. Run through all + the children of this wild statement, when an + input_section in an archive is found, scan forward to + find all input_sections which are in the same archive. + Sort them by their filename and then re-thread the + pointer chain. */ + + while (*p) { - lang_statement_union_type **vec; - lang_statement_union_type *end; - lang_statement_union_type *np; - int count; - int i; + lang_statement_union_type *start = *p; + if (start->header.type != lang_input_section_enum + || !start->input_section.ifile->the_bfd->my_archive) + p = &(start->header.next); + else + { + lang_statement_union_type *end; + int count; - for (end = start, count = 0; - end && end->header.type == lang_input_section_enum - && (end->input_section.ifile->the_bfd->my_archive - == start->input_section.ifile->the_bfd->my_archive); - end = end->next) - count++; + for (end = start, count = 0; + end && end->header.type == lang_input_section_enum + && (end->input_section.ifile->the_bfd->my_archive + == start->input_section.ifile->the_bfd->my_archive); + end = end->next) + count++; - np = end; - - vec = (lang_statement_union_type **) - alloca (count * sizeof (lang_statement_union_type *)); - - for (end = start, i = 0; i < count; i++, end = end->next) - vec[i] = end; - - qsort (vec, count, sizeof (vec[0]), sfunc); - - /* Fill in the next pointers again. */ - *p = vec[0]; - for (i = 0; i < count - 1; i++) - vec[i]->header.next = vec[i + 1]; - vec[i]->header.next = np; - p = &(vec[i]->header.next); + p = sort_sections_1 (p, end, count, sort_by_file_name); + } } + break; } + + /* If this is a collection of grouped sections, sort them. + The linker script must explicitly mention "*(.foo\$)". + Don't sort them if \$ is not the last character (not sure if + this is really useful, but it allows explicitly mentioning + some \$ sections and letting the linker handle the rest). */ + { + char *q = strchr (s->wild_statement.section_name, '\$'); + + if (q && q[1] == 0) + { + lang_statement_union_type *end; + int count; + + for (end = *p, count = 0; end; end = end->next) + { + if (end->header.type != lang_input_section_enum) + abort (); + count++; + } + (void) sort_sections_1 (p, end, count, sort_by_section_name); + } + break; + } } break; default: @@ -462,19 +541,15 @@ gld_${EMULATION_NAME}_before_allocation() ppc_allocate_toc_section (&link_info); #endif - sort_sections (*stat_ptr); + sort_sections (stat_ptr->head); } -/* Place an orphan section. We use this to put random sections - (e.g. those used to implement linkonce support) into the right place. */ - -/* These are used to communicate information from - gld${EMULATION_NAME}_place_section to gld${EMULATION_NAME}_place_orphan. */ -static asection *hold_section; -static lang_output_section_statement_type *hold_use; -static lang_output_section_statement_type *hold_text; -static lang_output_section_statement_type *hold_rdata; -static lang_output_section_statement_type *hold_data; +/* Place an orphan section. We use this to put sections with a '\$' in them + into the right place. Any section with a '\$' in them (e.g. .text\$foo) + gets mapped to the output section with everything from the '\$' on stripped + (e.g. .text). + See the Microsoft Portable Executable and Common Object File Format + Specification 4.1, section 4.2, Grouped Sections. */ /*ARGSUSED*/ static boolean @@ -482,149 +557,78 @@ gld${EMULATION_NAME}_place_orphan (file, s) lang_input_statement_type *file; asection *s; { - lang_output_section_statement_type *place; - asection *snew, **pps; - lang_statement_list_type *old; - lang_statement_list_type add; - etree_type *address; - const char *secname, *ps; + const char *secname; + char *output_secname, *ps; lang_output_section_statement_type *os; + lang_statement_list_type *ptr; + lang_statement_union_type *l; if ((s->flags & SEC_ALLOC) == 0) return false; - /* Look through the script to see where to place this section. */ - hold_section = s; - hold_use = NULL; - lang_for_each_statement (gld${EMULATION_NAME}_place_section); - - if (hold_use != NULL) - { - /* We have already placed a section with this name. */ - wild_doit (&hold_use->children, s, hold_use, file); - return true; - } + /* Don't process grouped sections unless doing a final link. + If they're marked as COMDAT sections, we don't want .text\$foo to + end up in .text and then have .text disappear because it's marked + link-once-discard. */ + if (link_info.relocateable) + return false; secname = bfd_get_section_name (s->owner, s); - /* Decide which output section the section should go in. - This is here to help implement "one-only" support. Such functions and - variables are prefixed with .text., .rdata., or .data. We must keep all - all functions together but the linker doesn't support wildcard section - names. */ - place = NULL; - if (strncmp (secname, ".text.", 6) == 0 - && hold_text != NULL) - place = hold_text; - else if (strncmp (secname, ".rdata.", 7) == 0 - && hold_rdata != NULL) - place = hold_rdata; - else if (strncmp (secname, ".data.", 6) == 0 - && hold_data != NULL) - place = hold_data; - if (place == NULL) + /* Everything from the '\$' on gets deleted so don't allow '\$' as the + first character. */ + if (*secname == '\$') + einfo ("%P%F: section %s has '\$' as first character\n", secname); + if (strchr (secname + 1, '\$') == NULL) return false; - /* Create the section in the output file, and put it in the right - place. This shuffling is to make the output file look neater. */ - snew = bfd_make_section (output_bfd, secname); - if (snew == NULL) - einfo ("%P%F: output format %s cannot represent section called %s\n", - output_bfd->xvec->name, secname); - if (place->bfd_section != NULL) + /* Look up the output section. The Microsoft specs say sections names in + image files never contain a '\$'. Fortunately, lang_..._lookup creates + the section if it doesn't exist. */ + output_secname = buystring (secname); + ps = strchr (output_secname + 1, '\$'); + *ps = 0; + os = lang_output_section_statement_lookup (output_secname); + + /* Find the '\$' wild statement for this section. We currently require the + linker script to explicitly mention "*(.foo\$)". + FIXME: ppcpe.sc has .CRT\$foo in the .rdata section. According to the + Microsoft docs this isn't correct so it's not (currently) handled. */ + + ps[0] = '\$'; + ps[1] = 0; + for (l = os->children.head; l; l = l->next) { - for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next) - ; - *pps = snew->next; - snew->next = place->bfd_section->next; - place->bfd_section->next = snew; + if (l->header.type == lang_wild_statement_enum + && strcmp (l->wild_statement.section_name, output_secname) == 0) + break; } - - /* Start building a list of statements for this section. */ - old = stat_ptr; - stat_ptr = &add; - lang_list_init (stat_ptr); - -#if 0 /* ??? elf32.em does this, do we need to? */ - /* 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' && config.build_constructors) + ps[0] = 0; + if (l == NULL) +#if 1 + einfo ("%P%F: *(%s\$) missing from linker script\n", output_secname); +#else /* FIXME: This block is untried. It exists to convey the intent, + should one decide to not require *(.foo\$) to appear in the linker + script. */ { - char *symname; - - symname = (char *) xmalloc (ps - secname + sizeof "__start_"); - sprintf (symname, "__start_%s", secname); - lang_add_assignment (exp_assop ('=', symname, - exp_nameop (NAME, "."))); + lang_wild_statement_type *new = new_stat (lang_wild_statement, + &os->children); + new->section_name = xmalloc (strlen (output_secname) + 2); + sprintf (new->section_name, "%s\$", output_secname); + new->filename = NULL; + lang_list_init (&new->children); + l = new; } #endif - if (! link_info.relocateable) - address = NULL; - else - address = exp_intop ((bfd_vma) 0); - - lang_enter_output_section_statement (secname, address, 0, - (bfd_vma) 0, - (etree_type *) NULL, - (etree_type *) NULL, - (etree_type *) NULL); - - os = lang_output_section_statement_lookup (secname); - wild_doit (&os->children, s, os, file); - - lang_leave_output_section_statement ((bfd_vma) 0, "*default*"); - stat_ptr = &add; - -#if 0 /* ??? elf32.em does this, do we need to? */ - if (*ps == '\0' && config.build_constructors) - { - char *symname; - - symname = (char *) xmalloc (ps - secname + sizeof "__stop_"); - sprintf (symname, "__stop_%s", secname); - lang_add_assignment (exp_assop ('=', symname, - exp_nameop (NAME, "."))); - } -#endif - - /* Now stick the new statement list right after PLACE. */ - *add.tail = place->header.next; - place->header.next = add.head; - - stat_ptr = old; + /* Link the input section in and we're done for now. + The sections still have to be sorted, but that has to wait until + all such sections have been processed by us. The sorting is done by + sort_sections. */ + wild_doit (&l->wild_statement.children, s, os, file); return true; } - -/* Subroutine of gld${EMULATION_NAME}_place_orphan, passed as argument to - lang_for_each_statement to see if S has already been output, and to scan - for .text,.rdata,.data. */ - -static void -gld${EMULATION_NAME}_place_section (s) - lang_statement_union_type *s; -{ - lang_output_section_statement_type *os; - - if (s->header.type != lang_output_section_statement_enum) - return; - - os = &s->output_section_statement; - - if (strcmp (os->name, hold_section->name) == 0) - hold_use = os; - - if (strcmp (os->name, ".text") == 0) - hold_text = os; - else if (strcmp (os->name, ".rdata") == 0) - hold_rdata = os; - else if (strcmp (os->name, ".data") == 0) - hold_data = os; -} static char * gld_${EMULATION_NAME}_get_script(isfile) @@ -677,4 +681,3 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = gld_${EMULATION_NAME}_parse_args }; EOF -