diff options
author | David Edelsohn <dje@gcc.gnu.org> | 1998-02-19 14:41:03 -0500 |
---|---|---|
committer | David Edelsohn <dje@gcc.gnu.org> | 1998-02-19 14:41:03 -0500 |
commit | db126753a6da192ce01557e62ed56263477d8c8c (patch) | |
tree | 215eb66ba09531a3d7393cd3b08b2b62b190b590 | |
parent | e642002f8629578ceea4977d14ffb2d183d5276a (diff) | |
download | gcc-db126753a6da192ce01557e62ed56263477d8c8c.zip gcc-db126753a6da192ce01557e62ed56263477d8c8c.tar.gz gcc-db126753a6da192ce01557e62ed56263477d8c8c.tar.bz2 |
[multiple changes]
Thu Feb 19 22:36:53 1998 Andrey Slepuhin <pooh@msu.net>
David Edelsohn <edelsohn@mhpcc.edu>
* collect2.c (XCOFF_SCAN_LIBS): Remove.
(export_flag): New variable.
(export_file): #ifdef COLLECT_EXPORT_LIST.
(import_file, exports, imports, undefined): New variables.
(libs, cmdline_lib_dirs, libpath_lib_dirs, libpath, libexts): Same.
(dump_list, dump_prefix_list, is_in_list): New functions.
(write_export_file): $ifdef COLLECT_EXPORT_LIST.
(write_import_file, resolve_lib_name): New functions.
(use_import_list, ignore_library): Same.
(collect_exit): maybe_unlink import_file and #ifdef.
(handler): Same.
(main): New variable importf, #ifdef exportf. Move parsing of
-shared before general argument parsing. Resolve AIX library
paths and import libgcc.a symbols. Treat .so shared libraries the
same as objects and .a libraries. Create alias for object_lst and
increment it instead of original pointer. Scan AIX libraries as
objects earlier instead of using scan_libraries. Perform AIX
tlink later to resolve templates instead of forking ld.
(GCC_OK_SYMBOL): Ensure symbol not in undef section.
(GCC_UNDEF_SYMBOL): New macro.
(scan_prog_file): Loop for members of AIX libraries. Handle
export/import of ctors/dtors.
(aix_std_libs): New variable.
(scan_libraries, XCOFF): Delete.
Fri Feb 19 22:36:52 1998 Robert Lipe <robertl@dgii.com>
* collect2.c (full_real_ld_suffix): #ifdef CROSS_COMPILE.
From-SVN: r18128
-rw-r--r-- | gcc/ChangeLog | 32 | ||||
-rw-r--r-- | gcc/collect2.c | 725 |
2 files changed, 511 insertions, 246 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1e42f3d..8c3f426 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,35 @@ +Thu Feb 19 22:36:53 1998 Andrey Slepuhin <pooh@msu.net> + David Edelsohn <edelsohn@mhpcc.edu> + + * collect2.c (XCOFF_SCAN_LIBS): Remove. + (export_flag): New variable. + (export_file): #ifdef COLLECT_EXPORT_LIST. + (import_file, exports, imports, undefined): New variables. + (libs, cmdline_lib_dirs, libpath_lib_dirs, libpath, libexts): Same. + (dump_list, dump_prefix_list, is_in_list): New functions. + (write_export_file): $ifdef COLLECT_EXPORT_LIST. + (write_import_file, resolve_lib_name): New functions. + (use_import_list, ignore_library): Same. + (collect_exit): maybe_unlink import_file and #ifdef. + (handler): Same. + (main): New variable importf, #ifdef exportf. Move parsing of + -shared before general argument parsing. Resolve AIX library + paths and import libgcc.a symbols. Treat .so shared libraries the + same as objects and .a libraries. Create alias for object_lst and + increment it instead of original pointer. Scan AIX libraries as + objects earlier instead of using scan_libraries. Perform AIX + tlink later to resolve templates instead of forking ld. + (GCC_OK_SYMBOL): Ensure symbol not in undef section. + (GCC_UNDEF_SYMBOL): New macro. + (scan_prog_file): Loop for members of AIX libraries. Handle + export/import of ctors/dtors. + (aix_std_libs): New variable. + (scan_libraries, XCOFF): Delete. + +Thu Feb 19 22:36:52 1998 Robert Lipe <robertl@dgii.com> + + * collect2.c (full_real_ld_suffix): #ifdef CROSS_COMPILE. + 1998-02-19 Mike Stump <mrs@wrs.com> * Makefile.in: Use $tooldir for sys-include to match toplevel diff --git a/gcc/collect2.c b/gcc/collect2.c index 3c21e9c..456716c 100644 --- a/gcc/collect2.c +++ b/gcc/collect2.c @@ -99,7 +99,7 @@ extern char *choose_temp_base (); /* On certain systems, we have code that works by scanning the object file directly. But this code uses system-specific header files and library functions, so turn it off in a cross-compiler. Likewise, the names of - the utilities aren't correct for a cross-compiler; we have to hope that + the utilities are not correct for a cross-compiler; we have to hope that cross-versions are in the proper directories. */ #ifdef CROSS_COMPILE @@ -112,10 +112,10 @@ extern char *choose_temp_base (); #undef REAL_STRIP_FILE_NAME #endif -/* If we can't use a special method, use the ordinary one: +/* If we cannot use a special method, use the ordinary one: run nm to find what symbols are present. In a cross-compiler, this means you need a cross nm, - but that isn't quite as unpleasant as special headers. */ + but that is not quite as unpleasant as special headers. */ #if !defined (OBJECT_FORMAT_COFF) && !defined (OBJECT_FORMAT_ROSE) #define OBJECT_FORMAT_NONE @@ -147,10 +147,6 @@ extern char *choose_temp_base (); #define MY_ISCOFF(X) ISCOFF (X) #endif -#ifdef XCOFF_DEBUGGING_INFO -#define XCOFF_SCAN_LIBS -#endif - #endif /* OBJECT_FORMAT_COFF */ #ifdef OBJECT_FORMAT_ROSE @@ -189,7 +185,7 @@ extern char *choose_temp_base (); #define SYMBOL__MAIN __main #endif -#if defined (LDD_SUFFIX) || SUNOS4_SHARED_LIBRARIES || defined(XCOFF_SCAN_LIBS) +#if defined (LDD_SUFFIX) || SUNOS4_SHARED_LIBRARIES #define SCAN_LIBRARIES #endif @@ -234,6 +230,9 @@ extern char *version_string; int vflag; /* true if -v */ static int rflag; /* true if -r */ static int strip_flag; /* true if -s */ +#ifdef COLLECT_EXPORT_LIST +static int export_flag; /* true if -bE */ +#endif int debug; /* true if -debug */ @@ -243,7 +242,10 @@ static int temp_filename_length; /* Length of temp_filename */ static char *temp_filename; /* Base of temp filenames */ static char *c_file; /* <xxx>.c for constructor/destructor list. */ static char *o_file; /* <xxx>.o for constructor/destructor list. */ +#ifdef COLLECT_EXPORT_LIST static char *export_file; /* <xxx>.x for AIX export list. */ +static char *import_file; /* <xxx>.p for AIX import list. */ +#endif char *ldout; /* File for ld errors. */ static char *output_file; /* Output file for ld. */ static char *nm_file_name; /* pathname of nm */ @@ -254,7 +256,11 @@ static char *initname, *fininame; /* names of init and fini funcs */ static struct head constructors; /* list of constructors found */ static struct head destructors; /* list of destructors found */ +#ifdef COLLECT_EXPORT_LIST static struct head exports; /* list of exported symbols */ +static struct head imports; /* list of imported symbols */ +static struct head undefined; /* list of undefined symbols */ +#endif static struct head frame_tables; /* list of frame unwind info tables */ struct obstack temporary_obstack; @@ -284,6 +290,16 @@ struct path_prefix char *name; /* Name of this list (used in config stuff) */ }; +#ifdef COLLECT_EXPORT_LIST +/* Lists to keep libraries to be scanned for global constructors/destructors. */ +static struct head libs; /* list of libraries */ +static struct path_prefix cmdline_lib_dirs; /* directories specified with -L */ +static struct path_prefix libpath_lib_dirs; /* directories in LIBPATH */ +static struct path_prefix *libpaths[3] = {&cmdline_lib_dirs, + &libpath_lib_dirs, NULL}; +static char *libexts[3] = {"a", "so", NULL}; /* possible library extentions */ +#endif + void collect_exit PROTO((int)); void collect_execute PROTO((char *, char **, char *)); void dump_file PROTO((char *)); @@ -299,13 +315,22 @@ static void fork_execute PROTO((char *, char **)); static void maybe_unlink PROTO((char *)); static void add_to_list PROTO((struct head *, char *)); static void write_list PROTO((FILE *, char *, struct id *)); +static void dump_list PROTO((FILE *, char *, struct id *)); +static void dump_prefix_list PROTO((FILE *, char *, struct prefix_list *)); +static int is_in_list PROTO((char *, struct id *)); static void write_list_with_asm PROTO((FILE *, char *, struct id *)); static void write_c_file PROTO((FILE *, char *)); -static void write_export_file PROTO((FILE *)); static void scan_prog_file PROTO((char *, enum pass)); #ifdef SCAN_LIBRARIES static void scan_libraries PROTO((char *)); #endif +#ifdef COLLECT_EXPORT_LIST +static void write_export_file PROTO((FILE *)); +static void write_import_file PROTO((FILE *)); +static char *resolve_lib_name PROTO((char *)); +static int use_import_list PROTO((char *)); +static int ignore_library PROTO((char *)); +#endif char *xcalloc (); char *xmalloc (); @@ -378,9 +403,14 @@ collect_exit (status) if (o_file != 0 && o_file[0]) maybe_unlink (o_file); +#ifdef COLLECT_EXPORT_LIST if (export_file != 0 && export_file[0]) maybe_unlink (export_file); + if (import_file != 0 && import_file[0]) + maybe_unlink (import_file); +#endif + if (ldout != 0 && ldout[0]) { dump_file (ldout); @@ -454,9 +484,14 @@ handler (signo) if (ldout != 0 && ldout[0]) maybe_unlink (ldout); +#ifdef COLLECT_EXPORT_LIST if (export_file != 0 && export_file[0]) maybe_unlink (export_file); + if (import_file != 0 && import_file[0]) + maybe_unlink (import_file); +#endif + signal (signo, SIG_DFL); kill (getpid (), signo); } @@ -639,7 +674,7 @@ is_ctor_dtor (s) #endif { "GLOBAL__FI_", sizeof ("GLOBAL__FI_")-1, 3, 0 }, { "GLOBAL__FD_", sizeof ("GLOBAL__FD_")-1, 4, 0 }, -#ifdef CFRONT_LOSSAGE /* Don't collect cfront initialization functions. +#ifdef CFRONT_LOSSAGE /* Do not collect cfront initialization functions. cfront has its own linker procedure to collect them; if collect2 gets them too, they get collected twice when the cfront procedure is run and the compiler used @@ -925,7 +960,9 @@ main (argc, argv) char *ld_suffix = "ld"; char *full_ld_suffix = ld_suffix; char *real_ld_suffix = "real-ld"; +#ifdef CROSS_COMPILE char *full_real_ld_suffix = real_ld_suffix; +#endif char *collect_ld_suffix = "collect-ld"; char *nm_suffix = "nm"; char *full_nm_suffix = nm_suffix; @@ -940,7 +977,11 @@ main (argc, argv) char *gstrip_suffix = "gstrip"; char *full_gstrip_suffix = gstrip_suffix; char *arg; - FILE *outf, *exportf; + FILE *outf; +#ifdef COLLECT_EXPORT_LIST + FILE *exportf; + FILE *importf; +#endif char *ld_file_name; char *collect_name; char *collect_names; @@ -978,12 +1019,12 @@ main (argc, argv) In practice, collect will rarely invoke itself. This can happen now that we are no longer called gld. A perfect example is when running - gcc in a build directory that has been installed. When looking for - ld's, we'll find our installed version and believe that's the real ld. */ + gcc in a build directory that has been installed. When looking for + ld, we will find our installed version and believe that's the real ld. */ /* We must also append COLLECT_NAME to COLLECT_NAMES to watch for the previous version of collect (the one that used COLLECT_NAME and only - handled two levels of recursion). If we don't we may mutually recurse + handled two levels of recursion). If we do not we may mutually recurse forever. This can happen (I think) when bootstrapping the old version and a new one is installed (rare, but we should handle it). ??? Hopefully references to COLLECT_NAME can be removed at some point. */ @@ -1006,7 +1047,7 @@ main (argc, argv) prefix_from_env ("COLLECT_NAMES", &our_file_names); /* Set environment variable COLLECT_NAME to our name so the previous version - of collect won't find us. If it does we'll mutually recurse forever. + of collect will not find us. If it does we will mutually recurse forever. This can happen when bootstrapping the new version and an old version is installed. ??? Hopefully this bit of code can be removed at some point. */ @@ -1207,17 +1248,49 @@ main (argc, argv) temp_filename_length = strlen (temp_filename); c_file = xcalloc (temp_filename_length + sizeof (".c"), 1); o_file = xcalloc (temp_filename_length + sizeof (".o"), 1); +#ifdef COLLECT_EXPORT_LIST export_file = xmalloc (temp_filename_length + sizeof (".x")); + import_file = xmalloc (temp_filename_length + sizeof (".p")); +#endif ldout = xmalloc (temp_filename_length + sizeof (".ld")); sprintf (ldout, "%s.ld", temp_filename); sprintf (c_file, "%s.c", temp_filename); sprintf (o_file, "%s.o", temp_filename); +#ifdef COLLECT_EXPORT_LIST sprintf (export_file, "%s.x", temp_filename); + sprintf (import_file, "%s.p", temp_filename); +#endif *c_ptr++ = c_file_name; *c_ptr++ = "-c"; *c_ptr++ = "-o"; *c_ptr++ = o_file; +#ifdef COLLECT_EXPORT_LIST + /* Generate a list of directories from LIBPATH. */ + prefix_from_env ("LIBPATH", &libpath_lib_dirs); + /* Add to this list also two standard directories where + AIX loader always searches for libraries. */ + add_prefix (&libpath_lib_dirs, "/lib"); + add_prefix (&libpath_lib_dirs, "/usr/lib"); +#endif + + /* Get any options that the upper GCC wants to pass to the sub-GCC. + + AIX support needs to know if -shared has been specified before + parsing commandline arguments. */ + + p = (char *) getenv ("COLLECT_GCC_OPTIONS"); + while (p && *p) + { + char *q = extract_string (&p); + if (*q == '-' && (q[1] == 'm' || q[1] == 'f')) + *c_ptr++ = obstack_copy0 (&permanent_obstack, q, strlen (q)); + if (strncmp (q, "-shared", sizeof ("-shared") - 1) == 0) + shared_obj = 1; + } + obstack_free (&temporary_obstack, temporary_firstobj); + *c_ptr++ = "-fno-exceptions"; + /* !!! When GCC calls collect2, it does not know whether it is calling collect2 or ld. So collect2 cannot meaningfully understand any options @@ -1237,6 +1310,15 @@ main (argc, argv) { switch (arg[1]) { +#ifdef COLLECT_EXPORT_LIST + /* We want to disable automatic exports on AIX when user + explicitly puts an export list in command line */ + case 'b': + if (arg[2] == 'E' || strncmp (&arg[2], "export", 6) == 0) + export_flag = 1; + break; +#endif + case 'd': if (!strcmp (arg, "-debug")) { @@ -1256,7 +1338,31 @@ main (argc, argv) *ld2++ = o_file; *ld2++ = arg; } +#ifdef COLLECT_EXPORT_LIST + { + /* Resolving full library name. */ + char *s = resolve_lib_name (arg+2); + + /* If we will use an import list for this library, + we should exclude it from ld args. */ + if (use_import_list (s)) + { + ld1--; + ld2--; + } + + /* Saving a full library name. */ + add_to_list (&libs, s); + } +#endif + break; + +#ifdef COLLECT_EXPORT_LIST + /* Saving directories where to search for libraries. */ + case 'L': + add_prefix (&cmdline_lib_dirs, arg+2); break; +#endif case 'o': if (arg[2] == '\0') @@ -1274,7 +1380,7 @@ main (argc, argv) if (arg[2] == '\0' && do_collecting) { /* We must strip after the nm run, otherwise C++ linking - won't work. Thus we strip in the second ld run, or + will not work. Thus we strip in the second ld run, or else with strip if there is no second ld run. */ strip_flag = 1; ld1--; @@ -1288,7 +1394,8 @@ main (argc, argv) } } else if ((p = rindex (arg, '.')) != (char *) 0 - && (strcmp (p, ".o") == 0 || strcmp (p, ".a") == 0)) + && (strcmp (p, ".o") == 0 || strcmp (p, ".a") == 0 + || strcmp (p, ".so") == 0)) { if (first_file) { @@ -1305,39 +1412,66 @@ main (argc, argv) } if (p[1] == 'o') *object++ = arg; +#ifdef COLLECT_EXPORT_LIST + /* libraries can be specified directly, i.e. without -l flag. */ + else + { + /* If we will use an import list for this library, + we should exclude it from ld args. */ + if (use_import_list (arg)) + { + ld1--; + ld2--; + } + + /* Saving a full library name. */ + add_to_list (&libs, arg); + } +#endif } } - /* Get any options that the upper GCC wants to pass to the sub-GCC. */ - p = (char *) getenv ("COLLECT_GCC_OPTIONS"); - while (p && *p) +#ifdef COLLECT_EXPORT_LIST + /* This is added only for debugging purposes. */ + if (debug) { - char *q = extract_string (&p); - if (*q == '-' && (q[1] == 'm' || q[1] == 'f')) - *c_ptr++ = obstack_copy0 (&permanent_obstack, q, strlen (q)); - if (strncmp (q, "-shared", sizeof ("shared") - 1) == 0) - shared_obj = 1; + fprintf (stderr, "List of libraries:\n"); + dump_list (stderr, "\t", libs.first); } - obstack_free (&temporary_obstack, temporary_firstobj); - *c_ptr++ = "-fno-exceptions"; -#ifdef COLLECT_EXPORT_LIST /* The AIX linker will discard static constructors in object files if nothing else in the file is referenced, so look at them first. */ - while (object_lst < object) - scan_prog_file (*object_lst++, PASS_OBJ); - { - char *buf = alloca (strlen (export_file) + 5); - sprintf (buf, "-bE:%s", export_file); - *ld1++ = buf; - *ld2++ = buf; + char **export_object_lst = object_lst; + while (export_object_lst < object) + scan_prog_file (*export_object_lst++, PASS_OBJ); + } + { + struct id *list = libs.first; + for (; list; list = list->next) + scan_prog_file (list->name, PASS_FIRST); + } + { + char *buf1 = alloca (strlen (export_file) + 5); + char *buf2 = alloca (strlen (import_file) + 5); + sprintf (buf1, "-bE:%s", export_file); + sprintf (buf2, "-bI:%s", import_file); + *ld1++ = buf1; + *ld2++ = buf1; + *ld1++ = buf2; + *ld2++ = buf2; exportf = fopen (export_file, "w"); if (exportf == (FILE *) 0) fatal_perror ("%s", export_file); write_export_file (exportf); if (fclose (exportf)) fatal_perror ("closing %s", export_file); + importf = fopen (import_file, "w"); + if (importf == (FILE *) 0) + fatal_perror ("%s", import_file); + write_import_file (importf); + if (fclose (importf)) + fatal_perror ("closing %s", import_file); } #endif @@ -1399,23 +1533,32 @@ main (argc, argv) /* Load the program, searching all libraries and attempting to provide undefined symbols from repository information. */ - do_tlink (ld1_argv, object_lst); + /* On AIX we do this later. */ +#ifndef COLLECT_EXPORT_LIST + do_tlink (ld1_argv, object_lst); +#else - /* If -r or they'll be run via some other method, don't build the + /* If -r or they will be run via some other method, do not build the constructor or destructor list, just return now. */ if (rflag || ! do_collecting) { /* But make sure we delete the export file we may have created. */ if (export_file != 0 && export_file[0]) maybe_unlink (export_file); + if (import_file != 0 && import_file[0]) + maybe_unlink (import_file); return 0; } +#endif /* Examine the namelist with nm and search it for static constructors and destructors to call. Write the constructor and destructor tables to a .s file and reload. */ + /* On AIX we already done scanning for global constructors/destructors. */ +#ifndef COLLECT_EXPORT_LIST scan_prog_file (output_file, PASS_FIRST); +#endif #ifdef SCAN_LIBRARIES scan_libraries (output_file); @@ -1429,14 +1572,18 @@ main (argc, argv) if (constructors.number == 0 && destructors.number == 0 && frame_tables.number == 0 -#ifdef SCAN_LIBRARIES +#if defined (SCAN_LIBRARIES) || defined (COLLECT_EXPORT_LIST) /* If we will be running these functions ourselves, we want to emit - stubs into the shared library so that we don't have to relink + stubs into the shared library so that we do not have to relink dependent programs when we add static objects. */ && ! shared_obj #endif ) { +#ifdef COLLECT_EXPORT_LIST + /* Doing tlink without additional code generation */ + do_tlink (ld1_argv, object_lst); +#endif /* Strip now if it was requested on the command line. */ if (strip_flag) { @@ -1449,6 +1596,7 @@ main (argc, argv) #ifdef COLLECT_EXPORT_LIST maybe_unlink (export_file); + maybe_unlink (import_file); #endif return 0; } @@ -1505,15 +1653,26 @@ main (argc, argv) Link the tables in with the rest of the program. */ fork_execute ("gcc", c_argv); +#ifdef COLLECT_EXPORT_LIST + /* On AIX we must call tlink because of possible templates resolution */ + do_tlink (ld2_argv, object_lst); +#else + /* Otherwise, simply call ld because tlink is already done */ fork_execute ("ld", ld2_argv); /* Let scan_prog_file do any final mods (OSF/rose needs this for constructors/destructors in shared libraries. */ scan_prog_file (output_file, PASS_SECOND); +#endif maybe_unlink (c_file); maybe_unlink (o_file); + +#ifdef COLLECT_EXPORT_LIST maybe_unlink (export_file); + maybe_unlink (import_file); +#endif + return 0; } @@ -1596,8 +1755,8 @@ collect_execute (prog, argv, redir) fflush (stdout); fflush (stderr); - /* If we can't find a program we need, complain error. Do this here - since we might not end up needing something that we couldn't find. */ + /* If we cannot find a program we need, complain error. Do this here + since we might not end up needing something that we could not find. */ if (argv[0] == 0) fatal ("cannot find `%s'", prog); @@ -1700,6 +1859,47 @@ write_list (stream, prefix, list) } } +/* This function is really used only on AIX, but may be useful. */ +static int +is_in_list (prefix, list) + char *prefix; + struct id *list; +{ + while (list) + { + if (!strcmp (prefix, list->name)) return 1; + list = list->next; + } + return 0; +} + +/* Added for debugging purpose. */ +static void +dump_list (stream, prefix, list) + FILE *stream; + char *prefix; + struct id *list; +{ + while (list) + { + fprintf (stream, "%s%s,\n", prefix, list->name); + list = list->next; + } +} + +static void +dump_prefix_list (stream, prefix, list) + FILE *stream; + char *prefix; + struct prefix_list *list; +{ + while (list) + { + fprintf (stream, "%s%s,\n", prefix, list->prefix); + list = list->next; + } +} + static void write_list_with_asm (stream, prefix, list) FILE *stream; @@ -1930,6 +2130,7 @@ write_c_file (stream, name) fprintf (stream, "#ifdef __cplusplus\n}\n#endif\n"); } +#ifdef COLLECT_EXPORT_LIST static void write_export_file (stream) FILE *stream; @@ -1938,6 +2139,17 @@ write_export_file (stream) for (; list; list = list->next) fprintf (stream, "%s\n", list->name); } + +static void +write_import_file (stream) + FILE *stream; +{ + struct id *list = imports.first; + fprintf (stream, "%s\n", "#! ."); + for (; list; list = list->next) + fprintf (stream, "%s\n", list->name); +} +#endif #ifdef OBJECT_FORMAT_NONE @@ -1967,7 +2179,7 @@ scan_prog_file (prog_name, which_pass) if (which_pass == PASS_SECOND) return; - /* If we don't have an `nm', complain. */ + /* If we do not have an `nm', complain. */ if (nm_file_name == 0) fatal ("cannot find `nm'"); @@ -2057,7 +2269,7 @@ scan_prog_file (prog_name, which_pass) name = p; /* Find the end of the symbol name. - Don't include `|', because Encore nm can tack that on the end. */ + Do not include `|', because Encore nm can tack that on the end. */ for (end = p; (ch2 = *end) != '\0' && !isspace (ch2) && ch2 != '|'; end++) continue; @@ -2181,7 +2393,7 @@ libselect (d) We must verify that the extension is numeric, because Sun saves the original versions of patched libraries with a .FCS extension. Files with - invalid extensions must go last in the sort, so that they won't be used. */ + invalid extensions must go last in the sort, so that they will not be used. */ static int libcompare (d1, d2) @@ -2409,7 +2621,7 @@ scan_libraries (prog_name) char buf[1024]; FILE *inf; - /* If we don't have an `ldd', complain. */ + /* If we do not have an `ldd', complain. */ if (ldd_file_name == 0) { error ("cannot find `ldd'"); @@ -2554,8 +2766,11 @@ scan_libraries (prog_name) # define GCC_SYMENT SYMENT # define GCC_OK_SYMBOL(X) \ (((X).n_sclass == C_EXT) && \ - (((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) || \ - ((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT))) + ((X).n_scnum > N_UNDEF) && \ + (((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) || \ + ((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT))) +# define GCC_UNDEF_SYMBOL(X) \ + (((X).n_sclass == C_EXT) && ((X).n_scnum == N_UNDEF)) # define GCC_SYMINC(X) ((X).n_numaux+1) # define GCC_SYMZERO(X) 0 # define GCC_CHECK_HDR(X) (1) @@ -2579,246 +2794,264 @@ scan_prog_file (prog_name, which_pass) { LDFILE *ldptr = NULL; int sym_index, sym_count; + int is_shared = 0; +#ifdef COLLECT_EXPORT_LIST + /* Should we generate an import list for given prog_name? */ + int import_flag = (which_pass == PASS_OBJ ? 0 : use_import_list (prog_name)); +#endif if (which_pass != PASS_FIRST && which_pass != PASS_OBJ) return; - if ((ldptr = ldopen (prog_name, ldptr)) == NULL) - fatal ("%s: can't open as COFF file", prog_name); - - if (!MY_ISCOFF (HEADER (ldptr).f_magic)) - fatal ("%s: not a COFF file", prog_name); +#ifdef COLLECT_EXPORT_LIST + /* We do not need scanning for some standard C libraries. */ + if (which_pass == PASS_FIRST && ignore_library (prog_name)) + return; - if (GCC_CHECK_HDR (ldptr)) + /* On AIX we have a loop, because there is not much difference + between an object and an archive. This trick allows us to + eliminate scan_libraries() function. */ + do { - sym_count = GCC_SYMBOLS (ldptr); - sym_index = GCC_SYMZERO (ldptr); - while (sym_index < sym_count) +#endif + if ((ldptr = ldopen (prog_name, ldptr)) != NULL) { - GCC_SYMENT symbol; - if (ldtbread (ldptr, sym_index, &symbol) <= 0) - break; - sym_index += GCC_SYMINC (symbol); + if (!MY_ISCOFF (HEADER (ldptr).f_magic)) + fatal ("%s: not a COFF file", prog_name); - if (GCC_OK_SYMBOL (symbol)) +#ifdef COLLECT_EXPORT_LIST + /* Is current archive member a shared object? */ + is_shared = HEADER (ldptr).f_flags & F_SHROBJ; +#endif + if (GCC_CHECK_HDR (ldptr)) { - char *name; + sym_count = GCC_SYMBOLS (ldptr); + sym_index = GCC_SYMZERO (ldptr); + while (sym_index < sym_count) + { + GCC_SYMENT symbol; + + if (ldtbread (ldptr, sym_index, &symbol) <= 0) + break; + sym_index += GCC_SYMINC (symbol); + + if (GCC_OK_SYMBOL (symbol)) + { + char *name; - if ((name = ldgetname (ldptr, &symbol)) == NULL) - continue; /* should never happen */ + if ((name = ldgetname (ldptr, &symbol)) == NULL) + continue; /* should never happen */ #ifdef XCOFF_DEBUGGING_INFO - /* All AIX function names have a duplicate entry beginning - with a dot. */ - if (*name == '.') - ++name; + /* All AIX function names have a duplicate entry + beginning with a dot. */ + if (*name == '.') + ++name; #endif - switch (is_ctor_dtor (name)) - { - case 1: - add_to_list (&constructors, name); - if (which_pass == PASS_OBJ) - add_to_list (&exports, name); - break; + switch (is_ctor_dtor (name)) + { + case 1: + if (! is_shared) add_to_list (&constructors, name); + if (which_pass == PASS_OBJ) + add_to_list (&exports, name); +#ifdef COLLECT_EXPORT_LIST + /* If this symbol was undefined and we are building + an import list, we should add a symbol to this + list. */ + else + if (import_flag + && is_in_list (name, undefined.first)) + add_to_list (&imports, name); +#endif + break; + + case 2: + if (! is_shared) add_to_list (&destructors, name); + if (which_pass == PASS_OBJ) + add_to_list (&exports, name); +#ifdef COLLECT_EXPORT_LIST + /* If this symbol was undefined and we are building + an import list, we should add a symbol to this + list. */ + else + if (import_flag + && is_in_list (name, undefined.first)) + add_to_list (&imports, name); +#endif + break; - case 2: - add_to_list (&destructors, name); - if (which_pass == PASS_OBJ) - add_to_list (&exports, name); - break; +#ifdef COLLECT_EXPORT_LIST + case 3: + if (is_shared) + add_to_list (&constructors, name); + break; - default: /* not a constructor or destructor */ - continue; - } + case 4: + if (is_shared) + add_to_list (&destructors, name); + break; +#endif + + default: /* not a constructor or destructor */ +#ifdef COLLECT_EXPORT_LIST + /* If we are building a shared object on AIX we need + to explicitly export all global symbols or add + them to import list. */ + if (shared_obj) + if (which_pass == PASS_OBJ && (! export_flag)) + add_to_list (&exports, name); + else if (! is_shared && which_pass == PASS_FIRST + && import_flag + && is_in_list(name, undefined.first)) + add_to_list (&imports, name); +#endif + continue; + } #if !defined(EXTENDED_COFF) - if (debug) - fprintf (stderr, "\tsec=%d class=%d type=%s%o %s\n", - symbol.n_scnum, symbol.n_sclass, - (symbol.n_type ? "0" : ""), symbol.n_type, - name); + if (debug) + fprintf (stderr, "\tsec=%d class=%d type=%s%o %s\n", + symbol.n_scnum, symbol.n_sclass, + (symbol.n_type ? "0" : ""), symbol.n_type, + name); #else - if (debug) - fprintf (stderr, "\tiss = %5d, value = %5d, index = %5d, name = %s\n", - symbol.iss, symbol.value, symbol.index, name); + if (debug) + fprintf (stderr, + "\tiss = %5d, value = %5d, index = %5d, name = %s\n", + symbol.iss, symbol.value, symbol.index, name); +#endif + } +#ifdef COLLECT_EXPORT_LIST + /* If we are building a shared object we should collect + information about undefined symbols for later + import list generation. */ + else if (shared_obj && GCC_UNDEF_SYMBOL (symbol)) + { + char *name; + + if ((name = ldgetname (ldptr, &symbol)) == NULL) + continue; /* should never happen */ + + /* All AIX function names have a duplicate entry + beginning with a dot. */ + if (*name == '.') + ++name; + add_to_list (&undefined, name); + } #endif + } } } + else + { + fatal ("%s: cannot open as COFF file", prog_name); + } +#ifdef COLLECT_EXPORT_LIST + /* On AIX loop continues while there are more members in archive. */ } - + while (ldclose (ldptr) == FAILURE); +#else + /* Otherwise we simply close ldptr. */ (void) ldclose(ldptr); +#endif } -#ifdef XCOFF_SCAN_LIBS -/* Scan imported AIX libraries for GCC static ctors and dtors. - FIXME: it is possible to link an executable without the actual import - library by using an "import file" - a text file listing symbols - exported by a library. To support this, we would have to scan - import files as well as actual shared binaries to find GCC ctors. - TODO: use memory mapping instead of 'ld' routines, files are already - memory mapped, but we could eliminate the extra in-memory copies. - Is it worth the effort? */ -static void -scan_libraries (prog_name) +#ifdef COLLECT_EXPORT_LIST + +/* This new function is used to decide whether we should + generate import list for an object or to use it directly. */ +static int +use_import_list (prog_name) char *prog_name; { - LDFILE *ldptr; - SCNHDR ldsh; - static struct path_prefix libpath; /* we should only do this once */ + char *p; - if ((ldptr = ldopen (prog_name, ldptr)) == NULL) - fatal ("%s: can't open as COFF file", prog_name); - - if (!MY_ISCOFF (HEADER (ldptr).f_magic)) - fatal ("%s: not a COFF file", prog_name); + /* If we do not build a shared object then import list should not be used. */ + if (! shared_obj) return 0; - /* find and read loader section */ - if (ldnshread (ldptr, _LOADER, &ldsh)) - { - LDHDR ldh; - char *impbuf; - int entry; + /* Currently we check only for libgcc, but this can be changed in future. */ + p = strstr (prog_name, "libgcc.a"); + if (p != 0 && (strlen (p) == sizeof ("libgcc.a") - 1)) + return 1; + return 0; +} - FSEEK (ldptr, ldsh.s_scnptr, BEGINNING); - FREAD (&ldh, sizeof (ldh), 1, ldptr); - /* read import library list */ - impbuf = alloca (ldh.l_istlen); - FSEEK (ldptr, ldh.l_impoff + ldsh.s_scnptr, BEGINNING); - FREAD (impbuf, ldh.l_istlen, 1, ldptr); +/* Given a library name without "lib" prefix, this function + returns a full library name including a path. */ +static char * +resolve_lib_name (name) + char *name; +{ + char *lib_buf; + int i, j, l = 0; - if (debug) - fprintf (stderr, "LIBPATH=%s\n", impbuf); - prefix_from_string (impbuf, &libpath); + for (i = 0; libpaths[i]; i++) + if (libpaths[i]->max_len > l) + l = libpaths[i]->max_len; - /* skip LIBPATH and empty base and member fields */ - impbuf += strlen (impbuf) + 3; - for (entry = 1; entry < ldh.l_nimpid; ++entry) - { - char *impath = impbuf; - char *implib = impath + strlen (impath) + 1; - char *impmem = implib + strlen (implib) + 1; - char *soname = NULL; - char *trial; - int pathlen; - LDFILE *libptr = NULL; - struct prefix_list *pl; - ARCHDR ah; - - impbuf = impmem + strlen (impmem) + 1; - if (debug) - fprintf (stderr, "PATH+BASE=%s%s\n", impath, implib); - /* Skip AIX kernel exports */ - if (*impath == '/' && *(impath+1) == '\0' - && strcmp (implib, "unix") == 0) - continue; - pathlen = strlen (impath); - trial = alloca (MAX (pathlen + 1, libpath.max_len) - + strlen (implib) + 1); - if (*impath) - { - strcpy (trial, impath); - if (impath[pathlen - 1] != '/') - trial[pathlen++] = '/'; - strcpy (trial + pathlen, implib); - if (access (trial, R_OK) == 0) - soname = trial; - } - else - for (pl = libpath.plist; pl; pl = pl->next) - { - strcpy (trial, pl->prefix); - strcat (trial, implib); - if (access (trial, R_OK) == 0) - { - soname = trial; - break; - } - } + lib_buf = xmalloc (l + strlen(name) + 10); - if (! soname) - fatal ("%s: library not found", implib); - if (debug) - if (*impmem) - fprintf (stderr, "%s (%s)\n", soname, impmem); - else - fprintf (stderr, "%s\n", soname); - - do + for (i = 0; libpaths[i]; i++) + { + struct prefix_list *list = libpaths[i]->plist; + for (; list; list = list->next) + { + for (j = 0; libexts[j]; j++) { - /* scan imported shared objects for GCC GLOBAL ctors */ - short type; - if ((libptr = ldopen (soname, libptr)) == NULL) - fatal ("%s: can't open import library", soname); - if (TYPE (libptr) == ARTYPE) - { - LDFILE *memptr; - if (! *impmem) - fatal ("%s: no archive member specified", soname); - ldahread (libptr, &ah); - if (strcmp (ah.ar_name, impmem)) - continue; - } - type = HEADER (libptr).f_magic; - if (HEADER (libptr).f_flags & F_SHROBJ) + /* The following lines are needed because path_prefix list + may contain directories both with trailing '/' and + without it. */ + char *p = ""; + if (list->prefix[strlen(list->prefix)-1] != '/') + p = "/"; + sprintf (lib_buf, "%s%slib%s.%s", + list->prefix, p, name, libexts[j]); +if (debug) fprintf (stderr, "searching for: %s\n", lib_buf); + if (file_exists (lib_buf)) { - SCNHDR soldsh; - LDHDR soldh; - long symcnt, i; - char *ldstrings; - LDSYM *lsyms; - if (!ldnshread (libptr, _LOADER, &soldsh)) - fatal ("%s: not an import library", soname); - FSEEK (libptr, soldsh.s_scnptr, BEGINNING); - if (FREAD (&soldh, sizeof (soldh), 1, libptr) != 1) - fatal ("%s: can't read loader section", soname); - /*fprintf (stderr, "\tscanning %s\n", soname);*/ - symcnt = soldh.l_nsyms; - lsyms = (LDSYM *) alloca (symcnt * sizeof (*lsyms)); - symcnt = FREAD (lsyms, sizeof (*lsyms), symcnt, libptr); - ldstrings = alloca (soldh.l_stlen); - FSEEK (libptr, soldsh.s_scnptr+soldh.l_stoff, BEGINNING); - FREAD (ldstrings, soldh.l_stlen, 1, libptr); - for (i = 0; i < symcnt; ++i) - { - LDSYM *l = lsyms + i; - if (LDR_EXPORT (*l)) - { - char *expname = 0; - if (l->l_zeroes) - expname = l->l_name; - else if (l->l_offset < soldh.l_stlen) - expname = ldstrings + l->l_offset; - switch (is_ctor_dtor (expname)) - { - case 3: - if (debug) - fprintf (stderr, "\t%s\n", expname); - add_to_list (&constructors, expname); - break; - - case 4: - add_to_list (&destructors, expname); - break; - - default: /* not a constructor or destructor */ - continue; - } - } - } +if (debug) fprintf (stderr, "found: %s\n", lib_buf); + return (lib_buf); } - else - fprintf (stderr, "%s: type = %04X flags = %04X\n", - ah.ar_name, type, HEADER (libptr).f_flags); } - while (ldclose (libptr) == FAILURE); - /* printf (stderr, "closed %s\n", soname); */ } } + if (debug) + fprintf (stderr, "not found\n"); + else + fatal ("Library lib%s not found", name); + return (NULL); +} + +/* Array of standard AIX libraries which should not + be scanned for ctors/dtors. */ +static char* aix_std_libs[] = { + "/unix", + "/lib/libc.a", + "/lib/libc_r.a", + "/usr/lib/libc.a", + "/usr/lib/libc_r.a", + "/usr/lib/threads/libc.a", + "/usr/ccs/lib/libc.a", + "/usr/ccs/lib/libc_r.a", + NULL +}; + +/* This function checks the filename and returns 1 + if this name matches the location of a standard AIX library. */ +static int +ignore_library (name) + char *name; +{ + char **p = &aix_std_libs[0]; + while (*p++ != NULL) + if (! strcmp (name, *p)) return 1; + return 0; } -#endif /* XCOFF_SCAN_LIBS */ + +#endif #endif /* OBJECT_FORMAT_COFF */ @@ -2912,7 +3145,7 @@ scan_prog_file (prog_name, which_pass) prog_fd = open (prog_name, (rw) ? O_RDWR : O_RDONLY); if (prog_fd < 0) - fatal_perror ("can't read %s", prog_name); + fatal_perror ("cannot read %s", prog_name); obj_file = read_file (prog_name, prog_fd, rw); obj = obj_file->start; @@ -3084,7 +3317,7 @@ scan_prog_file (prog_name, which_pass) fatal ("no cmd_strings found"); /* Add __main to initializer list. - If we are building a program instead of a shared library, don't + If we are building a program instead of a shared library, do not do anything, since in the current version, you cannot do mallocs and such in the constructors. */ |