diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1996-06-10 10:55:58 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1996-06-10 10:55:58 +0000 |
commit | a7e831079363e3bb45f3172f6e59ba48e335682b (patch) | |
tree | ee4324eac9a9d66f189fab60498ec42b8226b7fc /gnu/usr.bin/binutils/ld/emultempl | |
parent | 467cb0a471d13c5186a6ee166e60b47c30da64e9 (diff) |
Bring Cygnus versions into the trunk, keeping our local patches
Diffstat (limited to 'gnu/usr.bin/binutils/ld/emultempl')
-rw-r--r-- | gnu/usr.bin/binutils/ld/emultempl/aix.em | 67 | ||||
-rw-r--r-- | gnu/usr.bin/binutils/ld/emultempl/elf32.em | 199 | ||||
-rw-r--r-- | gnu/usr.bin/binutils/ld/emultempl/generic.em | 2 | ||||
-rw-r--r-- | gnu/usr.bin/binutils/ld/emultempl/linux.em | 4 | ||||
-rw-r--r-- | gnu/usr.bin/binutils/ld/emultempl/lnk960.em | 4 | ||||
-rw-r--r-- | gnu/usr.bin/binutils/ld/emultempl/pe.em | 291 | ||||
-rw-r--r-- | gnu/usr.bin/binutils/ld/emultempl/sunos.em | 53 |
7 files changed, 526 insertions, 94 deletions
diff --git a/gnu/usr.bin/binutils/ld/emultempl/aix.em b/gnu/usr.bin/binutils/ld/emultempl/aix.em index c40b86c2953..42aa1e162e0 100644 --- a/gnu/usr.bin/binutils/ld/emultempl/aix.em +++ b/gnu/usr.bin/binutils/ld/emultempl/aix.em @@ -75,6 +75,9 @@ static unsigned short modtype = ('1' << 8) | 'L'; permitted). */ static int textro; +/* Whether to implement Unix like linker semantics. */ +static int unix_ld; + /* Structure used to hold import file list. */ struct filelist @@ -137,6 +140,7 @@ gld${EMULATION_NAME}_parse_args (argc, argv) #define OPTION_PD (OPTION_NOSTRCMPCT + 1) #define OPTION_PT (OPTION_PD + 1) #define OPTION_STRCMPCT (OPTION_PT + 1) +#define OPTION_UNIX (OPTION_STRCMPCT + 1) static struct option longopts[] = { {"basis", no_argument, NULL, OPTION_IGNORE}, @@ -164,6 +168,7 @@ gld${EMULATION_NAME}_parse_args (argc, argv) {"bmodtype", required_argument, NULL, OPTION_MODTYPE}, {"bnoautoimp", no_argument, NULL, OPTION_NOAUTOIMP}, {"bnodelcsect", no_argument, NULL, OPTION_IGNORE}, + {"bnoentry", no_argument, NULL, OPTION_IGNORE}, {"bnogc", no_argument, &gc, 0}, {"bnso", no_argument, NULL, OPTION_NOAUTOIMP}, {"bnostrcmpct", no_argument, NULL, OPTION_NOSTRCMPCT}, @@ -177,6 +182,7 @@ gld${EMULATION_NAME}_parse_args (argc, argv) {"bstrcmpct", no_argument, NULL, OPTION_STRCMPCT}, {"btextro", no_argument, &textro, 1}, {"static", no_argument, NULL, OPTION_NOAUTOIMP}, + {"unix", no_argument, NULL, OPTION_UNIX}, {NULL, no_argument, NULL, 0} }; @@ -333,7 +339,7 @@ gld${EMULATION_NAME}_parse_args (argc, argv) break; case OPTION_NOSTRCMPCT: - config.traditional_format = true; + link_info.traditional_format = true; break; case OPTION_PD: @@ -382,13 +388,56 @@ gld${EMULATION_NAME}_parse_args (argc, argv) break; case OPTION_STRCMPCT: - config.traditional_format = false; + link_info.traditional_format = false; + break; + + case OPTION_UNIX: + unix_ld = true; break; } return 1; } +/* This is called when an input file can not be recognized as a BFD + object or an archive. If the file starts with #!, we must treat it + as an import file. This is for AIX compatibility. */ + +static boolean +gld${EMULATION_NAME}_unrecognized_file (entry) + lang_input_statement_type *entry; +{ + FILE *e; + boolean ret; + + e = fopen (entry->filename, FOPEN_RT); + if (e == NULL) + return false; + + ret = false; + + if (getc (e) == '#' && getc (e) == '!') + { + struct filelist *n; + struct filelist **flpp; + + n = (struct filelist *) xmalloc (sizeof (struct filelist)); + n->next = NULL; + n->name = entry->filename; + flpp = &import_files; + while (*flpp != NULL) + flpp = &(*flpp)->next; + *flpp = n; + + ret = true; + entry->loaded = true; + } + + fclose (e); + + return ret; +} + /* This is called after the input files have been opened. */ static void @@ -400,9 +449,11 @@ gld${EMULATION_NAME}_after_open () /* Call ldctor_build_sets, after pretending that this is a relocateable link. We do this because AIX requires relocation entries for all references to symbols, even in a final - executable. */ + executable. Of course, we only want to do this if we are + producing an XCOFF output file. */ r = link_info.relocateable; - link_info.relocateable = true; + if (strstr (bfd_get_target (output_bfd), "xcoff") != NULL) + link_info.relocateable = true; ldctor_build_sets (); link_info.relocateable = r; @@ -494,9 +545,10 @@ gld${EMULATION_NAME}_before_allocation () if (! bfd_xcoff_size_dynamic_sections (output_bfd, &link_info, libpath, entry_symbol, file_align, maxstack, maxdata, - gc ? true : false, + gc && ! unix_ld ? true : false, modtype, textro ? true : false, + unix_ld, special_sections)) einfo ("%P%F: failed to set dynamic section sizes: %E\n"); @@ -626,7 +678,7 @@ gld${EMULATION_NAME}_read_file (filename, import) o = (struct obstack *) xmalloc (sizeof (struct obstack)); obstack_specify_allocation (o, 0, 0, xmalloc, gld${EMULATION_NAME}_free); - f = fopen (filename, "r"); + f = fopen (filename, FOPEN_RT); if (f == NULL) { bfd_set_error (bfd_error_system_call); @@ -692,7 +744,7 @@ gld${EMULATION_NAME}_read_file (filename, import) (void) obstack_finish (o); keep = true; imppath = s; - impfile = NULL; + file = NULL; while (! isspace ((unsigned char) *s) && *s != '(' && *s != '\0') { if (*s == '/') @@ -986,5 +1038,6 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = 0, /* place_orphan */ 0, /* set_symbols */ gld${EMULATION_NAME}_parse_args, + gld${EMULATION_NAME}_unrecognized_file }; EOF diff --git a/gnu/usr.bin/binutils/ld/emultempl/elf32.em b/gnu/usr.bin/binutils/ld/emultempl/elf32.em index 8b2f6259748..45cab9ffb99 100644 --- a/gnu/usr.bin/binutils/ld/emultempl/elf32.em +++ b/gnu/usr.bin/binutils/ld/emultempl/elf32.em @@ -4,7 +4,7 @@ cat >e${EMULATION_NAME}.c <<EOF /* This file is is generated by a shell script. DO NOT EDIT! */ /* 32 bit ELF emulation code for ${EMULATION_NAME} - Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc. + Copyright (C) 1991, 93, 94, 95, 1996 Free Software Foundation, Inc. Written by Steve Chamberlain <sac@cygnus.com> ELF support by Ian Lance Taylor <ian@cygnus.com> @@ -66,7 +66,7 @@ static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile)); static void gld${EMULATION_NAME}_before_parse() { - ldfile_output_architecture = bfd_arch_${ARCH}; + ldfile_output_architecture = bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`; config.dynamic_link = ${DYNAMIC_LINK-true}; } @@ -131,6 +131,95 @@ gld${EMULATION_NAME}_open_dynamic_archive (arch, search, entry) return true; } +EOF +if [ "x${host}" = "x${target}" ] ; then + if [ "x${DEFAULT_EMULATION}" = "x${EMULATION_NAME}" ] ; then +cat >>e${EMULATION_NAME}.c <<EOF + +/* For a native linker, check the file /etc/ld.so.conf for directories + in which we may find shared libraries. /etc/ld.so.conf is really + only meaningful on Linux, but we check it on other systems anyhow. */ + +static boolean gld${EMULATION_NAME}_check_ld_so_conf PARAMS ((const char *)); + +static boolean +gld${EMULATION_NAME}_check_ld_so_conf (name) + const char *name; +{ + static boolean initialized; + static char *ld_so_conf; + + if (! initialized) + { + FILE *f; + + f = fopen ("/etc/ld.so.conf", FOPEN_RT); + if (f != NULL) + { + char *b; + size_t len, alloc; + int c; + + len = 0; + alloc = 100; + b = (char *) xmalloc (alloc); + + while ((c = getc (f)) != EOF) + { + if (len + 1 >= alloc) + { + alloc *= 2; + b = (char *) xrealloc (b, alloc); + } + if (c != ':' + && c != ' ' + && c != '\t' + && c != '\n' + && c != ',') + { + b[len] = c; + ++len; + } + else + { + if (len > 0 && b[len - 1] != ':') + { + b[len] = ':'; + ++len; + } + } + } + + if (len > 0 && b[len - 1] == ':') + --len; + + if (len > 0) + b[len] = '\0'; + else + { + free (b); + b = NULL; + } + + fclose (f); + + ld_so_conf = b; + } + + initialized = true; + } + + if (ld_so_conf == NULL) + return false; + + return gld${EMULATION_NAME}_search_needed (ld_so_conf, name); +} + +EOF + fi +fi +cat >>e${EMULATION_NAME}.c <<EOF + /* These variables are required to pass information back and forth between after_open and check_needed and stat_needed. */ @@ -199,12 +288,14 @@ gld${EMULATION_NAME}_after_open () continue; } EOF -if [ "x${host_alias}" = "x${target_alias}" ] ; then +if [ "x${host}" = "x${target}" ] ; then + if [ "x${DEFAULT_EMULATION}" = "x${EMULATION_NAME}" ] ; then cat >>e${EMULATION_NAME}.c <<EOF lib_path = (const char *) getenv ("LD_LIBRARY_PATH"); if (gld${EMULATION_NAME}_search_needed (lib_path, l->name)) continue; EOF + fi fi cat >>e${EMULATION_NAME}.c <<EOF len = strlen (l->name); @@ -222,6 +313,16 @@ cat >>e${EMULATION_NAME}.c <<EOF } if (search != NULL) continue; +EOF +if [ "x${host}" = "x${target}" ] ; then + if [ "x${DEFAULT_EMULATION}" = "x${EMULATION_NAME}" ] ; then +cat >>e${EMULATION_NAME}.c <<EOF + if (gld${EMULATION_NAME}_check_ld_so_conf (l->name)) + continue; +EOF + fi +fi +cat >>e${EMULATION_NAME}.c <<EOF einfo ("%P: warning: %s, needed by %B, not found\n", l->name, l->by); @@ -334,19 +435,42 @@ static void gld${EMULATION_NAME}_check_needed (s) lang_input_statement_type *s; { + if (global_found) + return; + if (s->filename != NULL && strcmp (s->filename, global_needed->name) == 0) - global_found = true; - else if (s->search_dirs_flag - && s->filename != NULL - && strchr (global_needed->name, '/') == NULL) + { + global_found = true; + return; + } + + if (s->the_bfd != NULL) + { + const char *soname; + + soname = bfd_elf_get_dt_soname (s->the_bfd); + if (soname != NULL + && strcmp (soname, global_needed->name) == 0) + { + global_found = true; + return; + } + } + + if (s->search_dirs_flag + && s->filename != NULL + && strchr (global_needed->name, '/') == NULL) { const char *f; f = strrchr (s->filename, '/'); if (f != NULL && strcmp (f + 1, global_needed->name) == 0) - global_found = true; + { + global_found = true; + return; + } } } @@ -357,21 +481,58 @@ static void gld${EMULATION_NAME}_stat_needed (s) lang_input_statement_type *s; { + struct stat st; + const char *suffix; + const char *soname; + const char *f; + if (global_found) return; - if (s->the_bfd != NULL) + if (s->the_bfd == NULL) + return; + + if (bfd_stat (s->the_bfd, &st) != 0) { - struct stat st; + einfo ("%P:%B: bfd_stat failed: %E\n", s->the_bfd); + return; + } - if (bfd_stat (s->the_bfd, &st) != 0) - einfo ("%P:%B: bfd_stat failed: %E\n", s->the_bfd); - else - { - if (st.st_dev == global_stat.st_dev - && st.st_ino == global_stat.st_ino) - global_found = true; - } + if (st.st_dev == global_stat.st_dev + && st.st_ino == global_stat.st_ino) + { + global_found = true; + return; } + + /* We issue a warning if it looks like we are including two + different versions of the same shared library. For example, + there may be a problem if -lc picks up libc.so.6 but some other + shared library has a DT_NEEDED entry of libc.so.5. This is a + hueristic test, and it will only work if the name looks like + NAME.so.VERSION. FIXME: Depending on file names is error-prone. + If we really want to issue warnings about mixing version numbers + of shared libraries, we need to find a better way. */ + + if (strchr (global_needed->name, '/') != NULL) + return; + suffix = strstr (global_needed->name, ".so."); + if (suffix == NULL) + return; + suffix += sizeof ".so." - 1; + + soname = bfd_elf_get_dt_soname (s->the_bfd); + if (soname == NULL) + soname = s->filename; + + f = strrchr (soname, '/'); + if (f != NULL) + ++f; + else + f = soname; + + if (strncmp (f, global_needed->name, suffix - global_needed->name) == 0) + einfo ("%P: warning: %s, needed by %B, may conflict with %s\n", + global_needed->name, global_needed->by, f); } /* This is called after the sections have been attached to output @@ -536,7 +697,7 @@ gld${EMULATION_NAME}_find_exp_assignment (exp) break; case etree_trinary: - gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs); + gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.cond); gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs); gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.rhs); break; diff --git a/gnu/usr.bin/binutils/ld/emultempl/generic.em b/gnu/usr.bin/binutils/ld/emultempl/generic.em index 6b8e6758e31..1c0c8eb214d 100644 --- a/gnu/usr.bin/binutils/ld/emultempl/generic.em +++ b/gnu/usr.bin/binutils/ld/emultempl/generic.em @@ -42,7 +42,7 @@ static void gld${EMULATION_NAME}_before_parse() { #ifndef TARGET_ /* I.e., if not generic. */ - ldfile_output_architecture = bfd_arch_${ARCH}; + ldfile_set_output_arch ("`echo ${ARCH}`"); #endif /* not TARGET_ */ } diff --git a/gnu/usr.bin/binutils/ld/emultempl/linux.em b/gnu/usr.bin/binutils/ld/emultempl/linux.em index 1f9d37eec2b..6860c3ffaf2 100644 --- a/gnu/usr.bin/binutils/ld/emultempl/linux.em +++ b/gnu/usr.bin/binutils/ld/emultempl/linux.em @@ -4,7 +4,7 @@ cat >e${EMULATION_NAME}.c <<EOF /* This file is is generated by a shell script. DO NOT EDIT! */ /* Linux a.out emulation code for ${EMULATION_NAME} - Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc. + Copyright (C) 1991, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. Written by Steve Chamberlain <sac@cygnus.com> Linux support by Eric Youngdale <ericy@cais.cais.com> @@ -125,7 +125,7 @@ gld${EMULATION_NAME}_before_allocation () /* Let the backend work out the sizes of any sections required by dynamic linking. */ - if (! bfd_linux_size_dynamic_sections (output_bfd, &link_info)) + if (! bfd_${EMULATION_NAME}_size_dynamic_sections (output_bfd, &link_info)) einfo ("%P%F: failed to set dynamic section sizes: %E\n"); } diff --git a/gnu/usr.bin/binutils/ld/emultempl/lnk960.em b/gnu/usr.bin/binutils/ld/emultempl/lnk960.em index 8f6ad40c6c9..066d46bb328 100644 --- a/gnu/usr.bin/binutils/ld/emultempl/lnk960.em +++ b/gnu/usr.bin/binutils/ld/emultempl/lnk960.em @@ -200,6 +200,8 @@ machine_table[] = { bfd_mach_i960_ca ,"CA" }, { bfd_mach_i960_ka_sa ,"KA" }, { bfd_mach_i960_ka_sa ,"SA" }, + { bfd_mach_i960_jx ,"JX" }, + { bfd_mach_i960_hx ,"HX" }, { bfd_mach_i960_core ,"core" }, { bfd_mach_i960_kb_sb ,"kb" }, @@ -209,6 +211,8 @@ machine_table[] = { bfd_mach_i960_ca ,"ca" }, { bfd_mach_i960_ka_sa ,"ka" }, { bfd_mach_i960_ka_sa ,"sa" }, + { bfd_mach_i960_jx ,"jx" }, + { bfd_mach_i960_hx ,"hx" }, { 0, (char *) NULL } }; diff --git a/gnu/usr.bin/binutils/ld/emultempl/pe.em b/gnu/usr.bin/binutils/ld/emultempl/pe.em index 3e40d78ddb0..55257390890 100644 --- a/gnu/usr.bin/binutils/ld/emultempl/pe.em +++ b/gnu/usr.bin/binutils/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,9 +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 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; @@ -58,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) @@ -76,7 +90,7 @@ gld_${EMULATION_NAME}_before_parse() #define OPTION_SUBSYSTEM (OPTION_STACK + 1) #define OPTION_HEAP (OPTION_SUBSYSTEM + 1) - static struct option longopts[] = { +static struct option longopts[] = { /* PE options */ {"base-file", required_argument, NULL, OPTION_BASE_FILE}, {"dll", no_argument, NULL, OPTION_DLL}, @@ -99,8 +113,6 @@ gld_${EMULATION_NAME}_before_parse() /* PE/WIN32; added routines to get the subsystem type, heap and/or stack parameters which may be input from the command line */ - - typedef struct { void *ptr; int size; @@ -194,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); @@ -266,10 +278,10 @@ gld_${EMULATION_NAME}_parse_args(argc, argv) /* PE options */ case OPTION_HEAP: - set_pe_stack_heap ("__heap_reserve__", "__heap_commit__"); + set_pe_stack_heap ("__size_of_heap_reserve__", "__size_of_heap_commit__"); break; case OPTION_STACK: - set_pe_stack_heap ("__stack_reserve__", "__stack_commit__"); + set_pe_stack_heap ("__size_of_stack_reserve__", "__size_of_stack_commit__"); break; case OPTION_SUBSYSTEM: set_pe_subsystem (); @@ -307,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. */ @@ -321,9 +333,10 @@ gld_${EMULATION_NAME}_set_symbols() ? NT_DLL_IMAGE_BASE : NT_EXE_IMAGE_BASE; /* Glue the assignments into the abs section */ - save=stat_ptr; + save = stat_ptr; stat_ptr = &(abs_output_section->children); + for (j = 0; init[j].ptr; j++) { long val = init[j].value; @@ -360,12 +373,13 @@ gld_${EMULATION_NAME}_after_open() pe_data(output_bfd)->dll = init[DLLOFF].value; } + +/* Callback functions for qsort in sort_sections. */ -/* Callback function 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; @@ -373,8 +387,64 @@ 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) lang_statement_union_type *s; @@ -389,51 +459,64 @@ 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. */ + /* Is this the .idata section? */ + if (s->wild_statement.section_name != NULL + && strncmp (s->wild_statement.section_name, ".idata", 6) == 0) + { + /* 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 *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++; + + p = sort_sections_1 (p, end, count, sort_by_file_name); + } + } + break; + } - while (*p) + /* 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). */ + if (s->wild_statement.section_name != NULL) { - 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 + char *q = strchr (s->wild_statement.section_name, '\$'); + + if (q && q[1] == 0) { - lang_statement_union_type **vec; lang_statement_union_type *end; - lang_statement_union_type *np; int count; - int i; - - 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); + 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; @@ -460,9 +543,95 @@ 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 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 +gld${EMULATION_NAME}_place_orphan (file, s) + lang_input_statement_type *file; + asection *s; +{ + 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; + + /* 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); + + /* 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; + + /* 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) + { + if (l->header.type == lang_wild_statement_enum + && strcmp (l->wild_statement.section_name, output_secname) == 0) + break; + } + 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. */ + { + 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 + + /* 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; +} + static char * gld_${EMULATION_NAME}_get_script(isfile) int *isfile; @@ -492,7 +661,6 @@ echo '; }' >> e${EMULATION_NAME} cat >>e${EMULATION_NAME}.c <<EOF - struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = { gld_${EMULATION_NAME}_before_parse, @@ -510,9 +678,8 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = NULL, /* finish */ NULL, /* create output section statements */ NULL, /* open dynamic archive */ - NULL, /* place orphan */ + gld${EMULATION_NAME}_place_orphan, gld_${EMULATION_NAME}_set_symbols, gld_${EMULATION_NAME}_parse_args }; EOF - diff --git a/gnu/usr.bin/binutils/ld/emultempl/sunos.em b/gnu/usr.bin/binutils/ld/emultempl/sunos.em index abcc9739279..5f36bd1ae37 100644 --- a/gnu/usr.bin/binutils/ld/emultempl/sunos.em +++ b/gnu/usr.bin/binutils/ld/emultempl/sunos.em @@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "bfd.h" #include "sysdep.h" #include "bfdlink.h" +#include "libiberty.h" #include "ld.h" #include "ldmain.h" @@ -57,6 +58,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #endif static void gld${EMULATION_NAME}_before_parse PARAMS ((void)); +static void gld${EMULATION_NAME}_set_symbols PARAMS ((void)); static void gld${EMULATION_NAME}_create_output_section_statements PARAMS ((void)); static void gld${EMULATION_NAME}_find_so @@ -87,6 +89,46 @@ gld${EMULATION_NAME}_before_parse() config.dynamic_link = true; } +/* This is called after the command line arguments have been parsed, + but before the linker script has been read. If this is a native + linker, we add the directories in LD_LIBRARY_PATH to the search + list. */ + +static void +gld${EMULATION_NAME}_set_symbols () +{ +EOF +if [ "x${host}" = "x${target}" ] ; then + if [ "x${DEFAULT_EMULATION}" = "x${EMULATION_NAME}" ] ; then +cat >>e${EMULATION_NAME}.c <<EOF + const char *env; + + env = (const char *) getenv ("LD_LIBRARY_PATH"); + if (env != NULL) + { + char *l; + + l = xstrdup (env); + while (1) + { + char *c; + + c = strchr (l, ':'); + if (c != NULL) + *c++ = '\0'; + if (*l != '\0') + ldfile_add_library_path (l, false); + if (c == NULL) + break; + l = c; + } + } +EOF + fi +fi +cat >>e${EMULATION_NAME}.c <<EOF +} + /* Despite the name, we use this routine to search for dynamic libraries. On SunOS this requires a directory search. We need to find the .so file with the highest version number. The user may @@ -404,12 +446,14 @@ gld${EMULATION_NAME}_after_open () continue; } EOF -if [ "x${host_alias}" = "x${target_alias}" ] ; then +if [ "x${host}" = "x${target}" ] ; then + if [ "x${DEFAULT_EMULATION}" = "x${EMULATION_NAME}" ] ; then cat >>e${EMULATION_NAME}.c <<EOF lib_path = (const char *) getenv ("LD_LIBRARY_PATH"); if (gld${EMULATION_NAME}_search_needed (lib_path, lname)) continue; EOF + fi fi cat >>e${EMULATION_NAME}.c <<EOF if (command_line.rpath != NULL) @@ -617,7 +661,8 @@ gld${EMULATION_NAME}_before_allocation () if (h->type == bfd_link_hash_undefined && h->u.undef.abfd != NULL && (h->u.undef.abfd->flags & DYNAMIC) == 0 - && strcmp (h->root.string, "__DYNAMIC") != 0) + && strcmp (h->root.string, "__DYNAMIC") != 0 + && strcmp (h->root.string, "__GLOBAL_OFFSET_TABLE_") != 0) { find_assign = h->root.string; found_assign = false; @@ -964,6 +1009,8 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = "${OUTPUT_FORMAT}", NULL, /* finish */ gld${EMULATION_NAME}_create_output_section_statements, - NULL /* open_dynamic_library */ + NULL, /* open_dynamic_library */ + NULL, /* place_orphan */ + gld${EMULATION_NAME}_set_symbols }; EOF |