diff options
author | obrien <obrien@FreeBSD.org> | 2000-11-15 21:26:21 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2000-11-15 21:26:21 +0000 |
commit | c35474ed1e39105c9c740b60fd5c803f1c65c0a7 (patch) | |
tree | f3b50ba60e37e126a0150a13191d6e933ae872f1 /contrib/binutils | |
parent | 088732419025219c7f20b1f049d6fcbeb9feda85 (diff) | |
download | FreeBSD-src-c35474ed1e39105c9c740b60fd5c803f1c65c0a7.zip FreeBSD-src-c35474ed1e39105c9c740b60fd5c803f1c65c0a7.tar.gz |
Merge rev 1.2 into Binutils 2.10.1.
Teach `ld' about FreeBSD (ie, fix the All the World's Linux) and how to
access our ld ELF hints.
Diffstat (limited to 'contrib/binutils')
-rw-r--r-- | contrib/binutils/ld/emultempl/elf32.em | 309 |
1 files changed, 184 insertions, 125 deletions
diff --git a/contrib/binutils/ld/emultempl/elf32.em b/contrib/binutils/ld/emultempl/elf32.em index a53f3d7..7554447 100644 --- a/contrib/binutils/ld/emultempl/elf32.em +++ b/contrib/binutils/ld/emultempl/elf32.em @@ -8,7 +8,7 @@ cat >e${EMULATION_NAME}.c <<EOF /* This file is is generated by a shell script. DO NOT EDIT! */ /* ${ELFSIZE} bit ELF emulation code for ${EMULATION_NAME} - Copyright (C) 1991, 93, 94, 95, 96, 97, 98, 1999 + Copyright (C) 1991, 93, 94, 95, 96, 97, 98, 99, 2000 Free Software Foundation, Inc. Written by Steve Chamberlain <sac@cygnus.com> ELF support by Ian Lance Taylor <ian@cygnus.com> @@ -64,10 +64,9 @@ static void gld${EMULATION_NAME}_before_allocation PARAMS ((void)); static void gld${EMULATION_NAME}_find_statement_assignment PARAMS ((lang_statement_union_type *)); static void gld${EMULATION_NAME}_find_exp_assignment PARAMS ((etree_type *)); +static lang_output_section_statement_type *output_rel_find 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 *isfile)); static void @@ -451,7 +450,7 @@ cat >>e${EMULATION_NAME}.c <<EOF if (force < 2) continue; - einfo ("%P: warning: %s, needed by %B, not found (try using --rpath)\n", + einfo ("%P: warning: %s, needed by %B, not found (try using -rpath or -rpath-link)\n", l->name, l->by); } } @@ -937,58 +936,83 @@ gld${EMULATION_NAME}_find_exp_assignment (exp) } } +/* A variant of lang_output_section_find. Used by place_orphan. */ + +static lang_output_section_statement_type * +output_rel_find () +{ + 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 (strncmp (".rel", lookup->name, 4) == 0 + && lookup->bfd_section != NULL + && (lookup->bfd_section->flags & SEC_ALLOC) != 0) + { + return lookup; + } + } + return (lang_output_section_statement_type *) NULL; +} + /* Place an orphan section. We use this to put random SHF_ALLOC sections in the right segment. */ -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_rodata; -static lang_output_section_statement_type *hold_data; -static lang_output_section_statement_type *hold_bss; -static lang_output_section_statement_type *hold_rel; -static lang_output_section_statement_type *hold_interp; +struct orphan_save { + lang_output_section_statement_type *os; + asection **section; + lang_statement_union_type **stmt; +}; -/*ARGSUSED*/ static boolean gld${EMULATION_NAME}_place_orphan (file, s) lang_input_statement_type *file; asection *s; { - lang_output_section_statement_type *place; - asection *snew, **pps; + 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; + struct orphan_save *place; lang_statement_list_type *old; lang_statement_list_type add; etree_type *address; - const char *secname, *ps; + const char *secname; const char *outsecname; + const char *ps = NULL; lang_output_section_statement_type *os; - if ((s->flags & SEC_ALLOC) == 0) - return false; + secname = bfd_get_section_name (s->owner, s); - /* 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); + /* Look through the script to see where to place this section. */ + os = lang_output_section_find (secname); - if (hold_use != NULL) + if (os != NULL + && os->bfd_section != NULL + && ((s->flags ^ os->bfd_section->flags) & (SEC_LOAD | SEC_ALLOC)) == 0) { /* We have already placed a section with this name. */ - wild_doit (&hold_use->children, s, hold_use, file); + wild_doit (&os->children, s, os, file); return true; } - secname = bfd_get_section_name (s->owner, s); + if (hold_text.os == NULL) + hold_text.os = lang_output_section_find (".text"); /* 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.shared && ! link_info.relocateable && strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0 - && hold_text != NULL) + && hold_text.os != NULL) { - wild_doit (&hold_text->children, s, hold_text, file); + wild_doit (&hold_text.os->children, s, hold_text.os, file); return true; } @@ -997,31 +1021,37 @@ gld${EMULATION_NAME}_place_orphan (file, 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. */ - place = NULL; +#define HAVE_SECTION(hold, name) \ +(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL) + if (s->flags & SEC_EXCLUDE) return false; + + place = NULL; + if ((s->flags & SEC_ALLOC) == 0) + ; else if ((s->flags & SEC_LOAD) != 0 - && strncmp (secname, ".note", 4) == 0 - && hold_interp != NULL) - place = hold_interp; + && strncmp (secname, ".note", 4) == 0 + && HAVE_SECTION (hold_interp, ".interp")) + place = &hold_interp; else if ((s->flags & SEC_HAS_CONTENTS) == 0 - && hold_bss != NULL) - place = hold_bss; + && HAVE_SECTION (hold_bss, ".bss")) + place = &hold_bss; else if ((s->flags & SEC_READONLY) == 0 - && hold_data != NULL) - place = hold_data; + && HAVE_SECTION (hold_data, ".data")) + place = &hold_data; else if (strncmp (secname, ".rel", 4) == 0 - && hold_rel != NULL) - place = hold_rel; - else if ((s->flags & SEC_CODE) == 0 - && (s->flags & SEC_READONLY) != 0 - && hold_rodata != NULL) - place = hold_rodata; - else if ((s->flags & SEC_READONLY) != 0 - && hold_text != NULL) - place = hold_text; - if (place == NULL) - return false; + && (hold_rel.os != NULL + || (hold_rel.os = output_rel_find ()) != 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 @@ -1047,113 +1077,142 @@ gld${EMULATION_NAME}_place_orphan (file, s) outsecname = newname; } - /* 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, outsecname); - if (snew == NULL) - einfo ("%P%F: output format %s cannot represent section called %s\n", - output_bfd->xvec->name, outsecname); - if (place->bfd_section != NULL) - { - for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next) - ; - *pps = snew->next; - snew->next = place->bfd_section->next; - place->bfd_section->next = snew; - } - - /* Start building a list of statements for this section. */ + /* Start building a list of statements for this section. + First save the current statement pointer. */ old = stat_ptr; - stat_ptr = &add; - lang_list_init (stat_ptr); - /* 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' && config.build_constructors) + /* 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 (place != NULL) { - char *symname; + stat_ptr = &add; + lang_list_init (stat_ptr); + } - symname = (char *) xmalloc (ps - outsecname + sizeof "__start_"); - sprintf (symname, "__start_%s", outsecname); - lang_add_assignment (exp_assop ('=', symname, - exp_unop (ALIGN_K, - exp_intop ((bfd_vma) 1 - << s->alignment_power)))); + 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.relocateable) - address = NULL; - else + if (link_info.relocateable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0) address = exp_intop ((bfd_vma) 0); + else + address = NULL; - lang_enter_output_section_statement (outsecname, address, 0, - (bfd_vma) 0, - (etree_type *) NULL, - (etree_type *) NULL, - (etree_type *) NULL); + os = lang_enter_output_section_statement (outsecname, address, 0, + (bfd_vma) 0, + (etree_type *) NULL, + (etree_type *) NULL, + (etree_type *) NULL); - os = lang_output_section_statement_lookup (outsecname); wild_doit (&os->children, s, os, file); lang_leave_output_section_statement - ((bfd_vma) 0, "*default*", (struct lang_output_section_phdr_list *) NULL, - "*default*"); - stat_ptr = &add; + ((bfd_vma) 0, "*default*", + (struct lang_output_section_phdr_list *) NULL, "*default*"); - if (*ps == '\0' && config.build_constructors) + 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 (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, "."))); } - /* Now stick the new statement list right after PLACE. */ - *add.tail = place->header.next; - place->header.next = add.head; - + /* Restore the global list pointer. */ stat_ptr = old; - return true; -} + if (place != NULL) + { + asection *snew, **pps; -static void -gld${EMULATION_NAME}_place_section (s) - lang_statement_union_type *s; -{ - lang_output_section_statement_type *os; + snew = os->bfd_section; + if (place->section != NULL + || (place->os->bfd_section != NULL + && place->os->bfd_section != snew)) + { + /* Shuffle the section to make the output file look neater. + This is really only cosmetic. */ + if (place->section == NULL) + { +#if 0 + /* Finding the end of the list is a little tricky. We + make a wild stab at it by comparing section flags. */ + flagword first_flags = place->os->bfd_section->flags; + for (pps = &place->os->bfd_section->next; + *pps != NULL && (*pps)->flags == first_flags; + pps = &(*pps)->next) + ; + place->section = pps; +#else + /* Put orphans after the first section on the list. */ + place->section = &place->os->bfd_section->next; +#endif + } - if (s->header.type != lang_output_section_statement_enum) - return; + /* Unlink the section. */ + for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next) + ; + *pps = snew->next; - os = &s->output_section_statement; + /* Now tack it on to the "place->os" section list. */ + snew->next = *place->section; + *place->section = snew; + } + place->section = &snew->next; /* Save the end of this list. */ - if (strcmp (os->name, hold_section->name) == 0 - && os->bfd_section != NULL - && ((hold_section->flags & (SEC_LOAD | SEC_ALLOC)) - == (os->bfd_section->flags & (SEC_LOAD | SEC_ALLOC)))) - hold_use = os; - - if (strcmp (os->name, ".text") == 0) - hold_text = os; - else if (strcmp (os->name, ".rodata") == 0) - hold_rodata = os; - else if (strcmp (os->name, ".data") == 0) - hold_data = os; - else if (strcmp (os->name, ".bss") == 0) - hold_bss = os; - else if (hold_rel == NULL - && os->bfd_section != NULL - && (os->bfd_section->flags & SEC_ALLOC) != 0 - && strncmp (os->name, ".rel", 4) == 0) - hold_rel = os; - else if (strcmp (os->name, ".interp") == 0) - hold_interp = os; + 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; + } + } + + return true; } static char * |