150397Sobrien/* Collect static initialization info into data structures that can be
250397Sobrien   traversed by C++ initialization and finalization routines.
390075Sobrien   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
4169689Skan   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
518334Speter   Contributed by Chris Smith (csmith@convex.com).
618334Speter   Heavily modified by Michael Meissner (meissner@cygnus.com),
718334Speter   Per Bothner (bothner@cygnus.com), and John Gilmore (gnu@cygnus.com).
818334Speter
990075SobrienThis file is part of GCC.
1018334Speter
1190075SobrienGCC is free software; you can redistribute it and/or modify it under
1290075Sobrienthe terms of the GNU General Public License as published by the Free
1390075SobrienSoftware Foundation; either version 2, or (at your option) any later
1490075Sobrienversion.
1518334Speter
1690075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1790075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1890075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1990075Sobrienfor more details.
2018334Speter
2118334SpeterYou should have received a copy of the GNU General Public License
2290075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
23169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
24169689Skan02110-1301, USA.  */
2518334Speter
2618334Speter
2750397Sobrien/* Build tables of static constructors and destructors and run ld.  */
2818334Speter
2918334Speter#include "config.h"
3050397Sobrien#include "system.h"
31132718Skan#include "coretypes.h"
32132718Skan#include "tm.h"
3318334Speter#include <signal.h>
3490075Sobrien#if ! defined( SIGCHLD ) && defined( SIGCLD )
3590075Sobrien#  define SIGCHLD SIGCLD
3690075Sobrien#endif
3718334Speter
3890075Sobrien#ifndef LIBRARY_PATH_ENV
3990075Sobrien#define LIBRARY_PATH_ENV "LIBRARY_PATH"
4090075Sobrien#endif
4190075Sobrien
4218334Speter#define COLLECT
4318334Speter
4452284Sobrien#include "collect2.h"
4518334Speter#include "demangle.h"
4618334Speter#include "obstack.h"
4752284Sobrien#include "intl.h"
4890075Sobrien#include "version.h"
4918334Speter
5018334Speter/* On certain systems, we have code that works by scanning the object file
5118334Speter   directly.  But this code uses system-specific header files and library
5218334Speter   functions, so turn it off in a cross-compiler.  Likewise, the names of
5350397Sobrien   the utilities are not correct for a cross-compiler; we have to hope that
5418334Speter   cross-versions are in the proper directories.  */
5518334Speter
56259563Spfg#ifdef CROSS_DIRECTORY_STRUCTURE
5718334Speter#undef OBJECT_FORMAT_COFF
5818334Speter#undef MD_EXEC_PREFIX
5918334Speter#undef REAL_LD_FILE_NAME
6018334Speter#undef REAL_NM_FILE_NAME
6118334Speter#undef REAL_STRIP_FILE_NAME
6218334Speter#endif
6318334Speter
6450397Sobrien/* If we cannot use a special method, use the ordinary one:
6518334Speter   run nm to find what symbols are present.
6618334Speter   In a cross-compiler, this means you need a cross nm,
6750397Sobrien   but that is not quite as unpleasant as special headers.  */
6818334Speter
69132718Skan#if !defined (OBJECT_FORMAT_COFF)
7018334Speter#define OBJECT_FORMAT_NONE
7118334Speter#endif
7218334Speter
7318334Speter#ifdef OBJECT_FORMAT_COFF
7418334Speter
7518334Speter#include <a.out.h>
7618334Speter#include <ar.h>
7718334Speter
7818334Speter#ifdef UMAX
7918334Speter#include <sgs.h>
8018334Speter#endif
8118334Speter
8218334Speter/* Many versions of ldfcn.h define these.  */
8318334Speter#ifdef FREAD
8418334Speter#undef FREAD
8518334Speter#undef FWRITE
8618334Speter#endif
8718334Speter
8818334Speter#include <ldfcn.h>
8918334Speter
9018334Speter/* Some systems have an ISCOFF macro, but others do not.  In some cases
9118334Speter   the macro may be wrong.  MY_ISCOFF is defined in tm.h files for machines
92132718Skan   that either do not have an ISCOFF macro in /usr/include or for those
9318334Speter   where it is wrong.  */
9418334Speter
9518334Speter#ifndef MY_ISCOFF
9618334Speter#define MY_ISCOFF(X) ISCOFF (X)
9718334Speter#endif
9818334Speter
9918334Speter#endif /* OBJECT_FORMAT_COFF */
10018334Speter
10118334Speter#ifdef OBJECT_FORMAT_NONE
10218334Speter
10318334Speter/* Default flags to pass to nm.  */
10418334Speter#ifndef NM_FLAGS
10552284Sobrien#define NM_FLAGS "-n"
10618334Speter#endif
10718334Speter
10818334Speter#endif /* OBJECT_FORMAT_NONE */
10918334Speter
11018334Speter/* Some systems use __main in a way incompatible with its use in gcc, in these
11118334Speter   cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
112117395Skan   give the same symbol without quotes for an alternative entry point.  */
11318334Speter#ifndef NAME__MAIN
11418334Speter#define NAME__MAIN "__main"
11518334Speter#endif
11618334Speter
11752284Sobrien/* This must match tree.h.  */
11852284Sobrien#define DEFAULT_INIT_PRIORITY 65535
11952284Sobrien
12090075Sobrien#ifndef COLLECT_SHARED_INIT_FUNC
12190075Sobrien#define COLLECT_SHARED_INIT_FUNC(STREAM, FUNC) \
12290075Sobrien  fprintf ((STREAM), "void _GLOBAL__DI() {\n\t%s();\n}\n", (FUNC))
12390075Sobrien#endif
12490075Sobrien#ifndef COLLECT_SHARED_FINI_FUNC
12590075Sobrien#define COLLECT_SHARED_FINI_FUNC(STREAM, FUNC) \
12690075Sobrien  fprintf ((STREAM), "void _GLOBAL__DD() {\n\t%s();\n}\n", (FUNC))
12790075Sobrien#endif
12890075Sobrien
129169689Skan#ifdef LDD_SUFFIX
13018334Speter#define SCAN_LIBRARIES
13118334Speter#endif
13218334Speter
13318334Speter#ifdef USE_COLLECT2
13418334Speterint do_collecting = 1;
13518334Speter#else
13618334Speterint do_collecting = 0;
13718334Speter#endif
13890075Sobrien
13990075Sobrien/* Nonzero if we should suppress the automatic demangling of identifiers
14090075Sobrien   in linker error messages.  Set from COLLECT_NO_DEMANGLE.  */
14190075Sobrienint no_demangle;
14218334Speter
14350397Sobrien/* Linked lists of constructor and destructor names.  */
14418334Speter
145132718Skanstruct id
14618334Speter{
14718334Speter  struct id *next;
14818334Speter  int sequence;
14918334Speter  char name[1];
15018334Speter};
15118334Speter
15218334Speterstruct head
15318334Speter{
15418334Speter  struct id *first;
15518334Speter  struct id *last;
15618334Speter  int number;
15718334Speter};
15818334Speter
15918334Speter/* Enumeration giving which pass this is for scanning the program file.  */
16018334Speter
16118334Speterenum pass {
16218334Speter  PASS_FIRST,				/* without constructors */
16318334Speter  PASS_OBJ,				/* individual objects */
164169689Skan  PASS_LIB,				/* looking for shared libraries */
16518334Speter  PASS_SECOND				/* with constructors linked in */
16618334Speter};
16718334Speter
16818334Speterint vflag;				/* true if -v */
16918334Speterstatic int rflag;			/* true if -r */
17018334Speterstatic int strip_flag;			/* true if -s */
171169689Skanstatic const char *demangle_flag;
17250397Sobrien#ifdef COLLECT_EXPORT_LIST
17350397Sobrienstatic int export_flag;                 /* true if -bE */
17450397Sobrienstatic int aix64_flag;			/* true if -b64 */
175146895Skanstatic int aixrtl_flag;			/* true if -brtl */
17650397Sobrien#endif
17718334Speter
17818334Speterint debug;				/* true if -debug */
17918334Speter
180169689Skanstatic int shared_obj;			/* true if -shared */
18118334Speter
18290075Sobrienstatic const char *c_file;		/* <xxx>.c for constructor/destructor list.  */
18390075Sobrienstatic const char *o_file;		/* <xxx>.o for constructor/destructor list.  */
18450397Sobrien#ifdef COLLECT_EXPORT_LIST
185169689Skanstatic const char *export_file;		/* <xxx>.x for AIX export list.  */
18650397Sobrien#endif
187169689Skanconst char *ldout;			/* File for ld stdout.  */
188169689Skanconst char *lderrout;			/* File for ld stderr.  */
18990075Sobrienstatic const char *output_file;		/* Output file for ld.  */
19090075Sobrienstatic const char *nm_file_name;	/* pathname of nm */
19150397Sobrien#ifdef LDD_SUFFIX
19290075Sobrienstatic const char *ldd_file_name;	/* pathname of ldd (or equivalent) */
19350397Sobrien#endif
19490075Sobrienstatic const char *strip_file_name;		/* pathname of strip */
195169689Skanconst char *c_file_name;		/* pathname of gcc */
19618334Speterstatic char *initname, *fininame;	/* names of init and fini funcs */
19718334Speter
19818334Speterstatic struct head constructors;	/* list of constructors found */
19918334Speterstatic struct head destructors;		/* list of destructors found */
20050397Sobrien#ifdef COLLECT_EXPORT_LIST
20118334Speterstatic struct head exports;		/* list of exported symbols */
20250397Sobrien#endif
20350397Sobrienstatic struct head frame_tables;	/* list of frame unwind info tables */
20418334Speter
20518334Speterstruct obstack temporary_obstack;
20618334Speterchar * temporary_firstobj;
20718334Speter
20818334Speter/* Structure to hold all the directories in which to search for files to
20918334Speter   execute.  */
21018334Speter
21118334Speterstruct prefix_list
21218334Speter{
21390075Sobrien  const char *prefix;         /* String to prepend to the path.  */
21450397Sobrien  struct prefix_list *next;   /* Next in linked list.  */
21518334Speter};
21618334Speter
21718334Speterstruct path_prefix
21818334Speter{
21918334Speter  struct prefix_list *plist;  /* List of prefixes to try */
22018334Speter  int max_len;                /* Max length of a prefix in PLIST */
22190075Sobrien  const char *name;           /* Name of this list (used in config stuff) */
22218334Speter};
22318334Speter
22450397Sobrien#ifdef COLLECT_EXPORT_LIST
22590075Sobrien/* Lists to keep libraries to be scanned for global constructors/destructors.  */
22650397Sobrienstatic struct head libs;                    /* list of libraries */
22750397Sobrienstatic struct path_prefix cmdline_lib_dirs; /* directories specified with -L */
22850397Sobrienstatic struct path_prefix libpath_lib_dirs; /* directories in LIBPATH */
22950397Sobrienstatic struct path_prefix *libpaths[3] = {&cmdline_lib_dirs,
23050397Sobrien					  &libpath_lib_dirs, NULL};
23150397Sobrien#endif
23250397Sobrien
233132718Skanstatic void handler (int);
234132718Skanstatic int is_ctor_dtor (const char *);
235132718Skanstatic char *find_a_file (struct path_prefix *, const char *);
236132718Skanstatic void add_prefix (struct path_prefix *, const char *);
237132718Skanstatic void prefix_from_env (const char *, struct path_prefix *);
238132718Skanstatic void prefix_from_string (const char *, struct path_prefix *);
239169689Skanstatic void do_wait (const char *, struct pex_obj *);
240132718Skanstatic void fork_execute (const char *, char **);
241132718Skanstatic void maybe_unlink (const char *);
242132718Skanstatic void add_to_list (struct head *, const char *);
243132718Skanstatic int extract_init_priority (const char *);
244132718Skanstatic void sort_ids (struct head *);
245132718Skanstatic void write_list (FILE *, const char *, struct id *);
24650397Sobrien#ifdef COLLECT_EXPORT_LIST
247132718Skanstatic void dump_list (FILE *, const char *, struct id *);
24850397Sobrien#endif
24950397Sobrien#if 0
250132718Skanstatic void dump_prefix_list (FILE *, const char *, struct prefix_list *);
25150397Sobrien#endif
252132718Skanstatic void write_list_with_asm (FILE *, const char *, struct id *);
253132718Skanstatic void write_c_file (FILE *, const char *);
254132718Skanstatic void write_c_file_stat (FILE *, const char *);
25590075Sobrien#ifndef LD_INIT_SWITCH
256132718Skanstatic void write_c_file_glob (FILE *, const char *);
25790075Sobrien#endif
258132718Skanstatic void scan_prog_file (const char *, enum pass);
25950397Sobrien#ifdef SCAN_LIBRARIES
260132718Skanstatic void scan_libraries (const char *);
26150397Sobrien#endif
26290075Sobrien#if LINK_ELIMINATE_DUPLICATE_LDIRECTORIES
263132718Skanstatic int is_in_args (const char *, const char **, const char **);
26490075Sobrien#endif
26550397Sobrien#ifdef COLLECT_EXPORT_LIST
26690075Sobrien#if 0
267132718Skanstatic int is_in_list (const char *, struct id *);
26850397Sobrien#endif
269132718Skanstatic void write_aix_file (FILE *, struct id *);
270132718Skanstatic char *resolve_lib_name (const char *);
27190075Sobrien#endif
272132718Skanstatic char *extract_string (const char **);
27318334Speter
27418334Speter/* Delete tempfiles and exit function.  */
27518334Speter
27618334Spetervoid
277132718Skancollect_exit (int status)
27818334Speter{
27918334Speter  if (c_file != 0 && c_file[0])
28018334Speter    maybe_unlink (c_file);
28118334Speter
28218334Speter  if (o_file != 0 && o_file[0])
28318334Speter    maybe_unlink (o_file);
28418334Speter
28550397Sobrien#ifdef COLLECT_EXPORT_LIST
28618334Speter  if (export_file != 0 && export_file[0])
28718334Speter    maybe_unlink (export_file);
28850397Sobrien#endif
28950397Sobrien
29018334Speter  if (ldout != 0 && ldout[0])
29118334Speter    {
292169689Skan      dump_file (ldout, stdout);
29318334Speter      maybe_unlink (ldout);
29418334Speter    }
29518334Speter
296169689Skan  if (lderrout != 0 && lderrout[0])
297169689Skan    {
298169689Skan      dump_file (lderrout, stderr);
299169689Skan      maybe_unlink (lderrout);
300169689Skan    }
301169689Skan
30218334Speter  if (status != 0 && output_file != 0 && output_file[0])
30318334Speter    maybe_unlink (output_file);
30418334Speter
30518334Speter  exit (status);
30618334Speter}
30718334Speter
30818334Speter
30952284Sobrien/* Notify user of a non-error.  */
31052284Sobrienvoid
311169689Skannotice (const char *cmsgid, ...)
31252284Sobrien{
313132718Skan  va_list ap;
31452284Sobrien
315169689Skan  va_start (ap, cmsgid);
316169689Skan  vfprintf (stderr, _(cmsgid), ap);
317132718Skan  va_end (ap);
31852284Sobrien}
31952284Sobrien
32050397Sobrien/* Die when sys call fails.  */
32118334Speter
32218334Spetervoid
323169689Skanfatal_perror (const char * cmsgid, ...)
32418334Speter{
32518334Speter  int e = errno;
326132718Skan  va_list ap;
32718334Speter
328169689Skan  va_start (ap, cmsgid);
32918334Speter  fprintf (stderr, "collect2: ");
330169689Skan  vfprintf (stderr, _(cmsgid), ap);
33190075Sobrien  fprintf (stderr, ": %s\n", xstrerror (e));
332132718Skan  va_end (ap);
33352284Sobrien
33450397Sobrien  collect_exit (FATAL_EXIT_CODE);
33518334Speter}
33618334Speter
33750397Sobrien/* Just die.  */
33818334Speter
33918334Spetervoid
340169689Skanfatal (const char * cmsgid, ...)
34118334Speter{
342132718Skan  va_list ap;
343132718Skan
344169689Skan  va_start (ap, cmsgid);
34518334Speter  fprintf (stderr, "collect2: ");
346169689Skan  vfprintf (stderr, _(cmsgid), ap);
34718334Speter  fprintf (stderr, "\n");
348132718Skan  va_end (ap);
34952284Sobrien
35050397Sobrien  collect_exit (FATAL_EXIT_CODE);
35118334Speter}
35218334Speter
35318334Speter/* Write error message.  */
35418334Speter
35518334Spetervoid
356169689Skanerror (const char * gmsgid, ...)
35718334Speter{
358132718Skan  va_list ap;
35952284Sobrien
360169689Skan  va_start (ap, gmsgid);
36118334Speter  fprintf (stderr, "collect2: ");
362169689Skan  vfprintf (stderr, _(gmsgid), ap);
36318334Speter  fprintf (stderr, "\n");
364132718Skan  va_end(ap);
36518334Speter}
36618334Speter
36718334Speter/* In case obstack is linked in, and abort is defined to fancy_abort,
36818334Speter   provide a default entry.  */
36918334Speter
37018334Spetervoid
371169689Skanfancy_abort (const char *file, int line, const char *func)
37218334Speter{
373169689Skan  fatal ("internal gcc abort in %s, at %s:%d", func, file, line);
37418334Speter}
37518334Speter
37618334Speterstatic void
377132718Skanhandler (int signo)
37818334Speter{
37918334Speter  if (c_file != 0 && c_file[0])
38018334Speter    maybe_unlink (c_file);
38118334Speter
38218334Speter  if (o_file != 0 && o_file[0])
38318334Speter    maybe_unlink (o_file);
38418334Speter
38518334Speter  if (ldout != 0 && ldout[0])
38618334Speter    maybe_unlink (ldout);
38718334Speter
388169689Skan  if (lderrout != 0 && lderrout[0])
389169689Skan    maybe_unlink (lderrout);
390169689Skan
39150397Sobrien#ifdef COLLECT_EXPORT_LIST
39250397Sobrien  if (export_file != 0 && export_file[0])
39350397Sobrien    maybe_unlink (export_file);
39450397Sobrien#endif
39550397Sobrien
39618334Speter  signal (signo, SIG_DFL);
397169689Skan  raise (signo);
39818334Speter}
39918334Speter
40018334Speter
40118334Speterint
402132718Skanfile_exists (const char *name)
40318334Speter{
40418334Speter  return access (name, R_OK) == 0;
40518334Speter}
40618334Speter
40750397Sobrien/* Parse a reasonable subset of shell quoting syntax.  */
40850397Sobrien
40950397Sobrienstatic char *
410132718Skanextract_string (const char **pp)
41150397Sobrien{
41290075Sobrien  const char *p = *pp;
41350397Sobrien  int backquote = 0;
41450397Sobrien  int inside = 0;
41550397Sobrien
41650397Sobrien  for (;;)
41750397Sobrien    {
41850397Sobrien      char c = *p;
41950397Sobrien      if (c == '\0')
42050397Sobrien	break;
42150397Sobrien      ++p;
42250397Sobrien      if (backquote)
42350397Sobrien	obstack_1grow (&temporary_obstack, c);
42450397Sobrien      else if (! inside && c == ' ')
42550397Sobrien	break;
42650397Sobrien      else if (! inside && c == '\\')
42750397Sobrien	backquote = 1;
42850397Sobrien      else if (c == '\'')
42950397Sobrien	inside = !inside;
43050397Sobrien      else
43150397Sobrien	obstack_1grow (&temporary_obstack, c);
43250397Sobrien    }
43350397Sobrien
43450397Sobrien  obstack_1grow (&temporary_obstack, '\0');
43550397Sobrien  *pp = p;
436169689Skan  return XOBFINISH (&temporary_obstack, char *);
43750397Sobrien}
43818334Speter
43918334Spetervoid
440169689Skandump_file (const char *name, FILE *to)
44118334Speter{
44218334Speter  FILE *stream = fopen (name, "r");
44318334Speter
44418334Speter  if (stream == 0)
44518334Speter    return;
44618334Speter  while (1)
44718334Speter    {
44818334Speter      int c;
44918334Speter      while (c = getc (stream),
45090075Sobrien	     c != EOF && (ISIDNUM (c) || c == '$' || c == '.'))
45118334Speter	obstack_1grow (&temporary_obstack, c);
45218334Speter      if (obstack_object_size (&temporary_obstack) > 0)
45318334Speter	{
45490075Sobrien	  const char *word, *p;
45590075Sobrien	  char *result;
45618334Speter	  obstack_1grow (&temporary_obstack, '\0');
457169689Skan	  word = XOBFINISH (&temporary_obstack, const char *);
45818334Speter
45918334Speter	  if (*word == '.')
460169689Skan	    ++word, putc ('.', to);
46118334Speter	  p = word;
462117395Skan	  if (!strncmp (p, USER_LABEL_PREFIX, strlen (USER_LABEL_PREFIX)))
463117395Skan	    p += strlen (USER_LABEL_PREFIX);
46418334Speter
465169689Skan#ifdef HAVE_LD_DEMANGLE
466169689Skan	  result = 0;
467169689Skan#else
46818334Speter	  if (no_demangle)
46918334Speter	    result = 0;
47018334Speter	  else
47196263Sobrien	    result = cplus_demangle (p, DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE);
472169689Skan#endif
47318334Speter
47418334Speter	  if (result)
47518334Speter	    {
47618334Speter	      int diff;
477169689Skan	      fputs (result, to);
47818334Speter
47918334Speter	      diff = strlen (word) - strlen (result);
48090075Sobrien	      while (diff > 0 && c == ' ')
481169689Skan		--diff, putc (' ', to);
48218334Speter	      while (diff < 0 && c == ' ')
48318334Speter		++diff, c = getc (stream);
48418334Speter
48518334Speter	      free (result);
48618334Speter	    }
48718334Speter	  else
488169689Skan	    fputs (word, to);
48918334Speter
490169689Skan	  fflush (to);
49118334Speter	  obstack_free (&temporary_obstack, temporary_firstobj);
49218334Speter	}
49318334Speter      if (c == EOF)
49418334Speter	break;
495169689Skan      putc (c, to);
49618334Speter    }
49750397Sobrien  fclose (stream);
49818334Speter}
49918334Speter
50090075Sobrien/* Decide whether the given symbol is: a constructor (1), a destructor
50190075Sobrien   (2), a routine in a shared object that calls all the constructors
50290075Sobrien   (3) or destructors (4), a DWARF exception-handling table (5), or
50390075Sobrien   nothing special (0).  */
50418334Speter
50518334Speterstatic int
506132718Skanis_ctor_dtor (const char *s)
50718334Speter{
50890075Sobrien  struct names { const char *const name; const int len; const int ret;
50990075Sobrien    const int two_underscores; };
51018334Speter
51190075Sobrien  const struct names *p;
51290075Sobrien  int ch;
51390075Sobrien  const char *orig_s = s;
51418334Speter
51590075Sobrien  static const struct names special[] = {
516102780Skan#ifndef NO_DOLLAR_IN_LABEL
517102780Skan    { "GLOBAL__I$", sizeof ("GLOBAL__I$")-1, 1, 0 },
518102780Skan    { "GLOBAL__D$", sizeof ("GLOBAL__D$")-1, 2, 0 },
519102780Skan#else
520102780Skan#ifndef NO_DOT_IN_LABEL
521102780Skan    { "GLOBAL__I.", sizeof ("GLOBAL__I.")-1, 1, 0 },
522102780Skan    { "GLOBAL__D.", sizeof ("GLOBAL__D.")-1, 2, 0 },
523102780Skan#endif /* NO_DOT_IN_LABEL */
524102780Skan#endif /* NO_DOLLAR_IN_LABEL */
52518334Speter    { "GLOBAL__I_", sizeof ("GLOBAL__I_")-1, 1, 0 },
52618334Speter    { "GLOBAL__D_", sizeof ("GLOBAL__D_")-1, 2, 0 },
52750397Sobrien    { "GLOBAL__F_", sizeof ("GLOBAL__F_")-1, 5, 0 },
52818334Speter    { "GLOBAL__FI_", sizeof ("GLOBAL__FI_")-1, 3, 0 },
52918334Speter    { "GLOBAL__FD_", sizeof ("GLOBAL__FD_")-1, 4, 0 },
53018334Speter    { NULL, 0, 0, 0 }
53118334Speter  };
53218334Speter
53318334Speter  while ((ch = *s) == '_')
53418334Speter    ++s;
53518334Speter
53618334Speter  if (s == orig_s)
53718334Speter    return 0;
53818334Speter
53918334Speter  for (p = &special[0]; p->len > 0; p++)
54018334Speter    {
54118334Speter      if (ch == p->name[0]
54218334Speter	  && (!p->two_underscores || ((s - orig_s) >= 2))
54318334Speter	  && strncmp(s, p->name, p->len) == 0)
54418334Speter	{
54518334Speter	  return p->ret;
54618334Speter	}
54718334Speter    }
54818334Speter  return 0;
54918334Speter}
55018334Speter
55118334Speter/* We maintain two prefix lists: one from COMPILER_PATH environment variable
55218334Speter   and one from the PATH variable.  */
55318334Speter
55418334Speterstatic struct path_prefix cpath, path;
55518334Speter
556259563Spfg#ifdef CROSS_DIRECTORY_STRUCTURE
55718334Speter/* This is the name of the target machine.  We use it to form the name
55818334Speter   of the files to execute.  */
55918334Speter
56090075Sobrienstatic const char *const target_machine = TARGET_MACHINE;
56118334Speter#endif
56218334Speter
56318334Speter/* Search for NAME using prefix list PPREFIX.  We only look for executable
564132718Skan   files.
56518334Speter
56650397Sobrien   Return 0 if not found, otherwise return its name, allocated with malloc.  */
56718334Speter
56818334Speterstatic char *
569132718Skanfind_a_file (struct path_prefix *pprefix, const char *name)
57018334Speter{
57118334Speter  char *temp;
57218334Speter  struct prefix_list *pl;
57318334Speter  int len = pprefix->max_len + strlen (name) + 1;
57418334Speter
57550397Sobrien  if (debug)
57650397Sobrien    fprintf (stderr, "Looking for '%s'\n", name);
577132718Skan
57890075Sobrien#ifdef HOST_EXECUTABLE_SUFFIX
57990075Sobrien  len += strlen (HOST_EXECUTABLE_SUFFIX);
58018334Speter#endif
58118334Speter
582169689Skan  temp = XNEWVEC (char, len);
58318334Speter
58418334Speter  /* Determine the filename to execute (special case for absolute paths).  */
58518334Speter
58650397Sobrien  if (*name == '/'
58752284Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
58852284Sobrien      || (*name && name[1] == ':')
58950397Sobrien#endif
59050397Sobrien      )
59118334Speter    {
59218334Speter      if (access (name, X_OK) == 0)
59318334Speter	{
59418334Speter	  strcpy (temp, name);
59550397Sobrien
59650397Sobrien	  if (debug)
59750397Sobrien	    fprintf (stderr, "  - found: absolute path\n");
598132718Skan
59918334Speter	  return temp;
60018334Speter	}
60150397Sobrien
60290075Sobrien#ifdef HOST_EXECUTABLE_SUFFIX
60352284Sobrien	/* Some systems have a suffix for executable files.
60452284Sobrien	   So try appending that.  */
60552284Sobrien      strcpy (temp, name);
60690075Sobrien	strcat (temp, HOST_EXECUTABLE_SUFFIX);
607132718Skan
60852284Sobrien	if (access (temp, X_OK) == 0)
60952284Sobrien	  return temp;
61052284Sobrien#endif
61152284Sobrien
61250397Sobrien      if (debug)
61350397Sobrien	fprintf (stderr, "  - failed to locate using absolute path\n");
61418334Speter    }
61518334Speter  else
61618334Speter    for (pl = pprefix->plist; pl; pl = pl->next)
61718334Speter      {
61890075Sobrien	struct stat st;
61990075Sobrien
62018334Speter	strcpy (temp, pl->prefix);
62118334Speter	strcat (temp, name);
622132718Skan
62390075Sobrien	if (stat (temp, &st) >= 0
62490075Sobrien	    && ! S_ISDIR (st.st_mode)
62590075Sobrien	    && access (temp, X_OK) == 0)
62618334Speter	  return temp;
62718334Speter
62890075Sobrien#ifdef HOST_EXECUTABLE_SUFFIX
62918334Speter	/* Some systems have a suffix for executable files.
63018334Speter	   So try appending that.  */
63190075Sobrien	strcat (temp, HOST_EXECUTABLE_SUFFIX);
632132718Skan
63390075Sobrien	if (stat (temp, &st) >= 0
63490075Sobrien	    && ! S_ISDIR (st.st_mode)
63590075Sobrien	    && access (temp, X_OK) == 0)
63618334Speter	  return temp;
63718334Speter#endif
63818334Speter      }
63918334Speter
64050397Sobrien  if (debug && pprefix->plist == NULL)
64150397Sobrien    fprintf (stderr, "  - failed: no entries in prefix list\n");
64250397Sobrien
64318334Speter  free (temp);
64418334Speter  return 0;
64518334Speter}
64618334Speter
64718334Speter/* Add an entry for PREFIX to prefix list PPREFIX.  */
64818334Speter
64918334Speterstatic void
650132718Skanadd_prefix (struct path_prefix *pprefix, const char *prefix)
65118334Speter{
65218334Speter  struct prefix_list *pl, **prev;
65318334Speter  int len;
65418334Speter
65518334Speter  if (pprefix->plist)
65618334Speter    {
65718334Speter      for (pl = pprefix->plist; pl->next; pl = pl->next)
65818334Speter	;
65918334Speter      prev = &pl->next;
66018334Speter    }
66118334Speter  else
66218334Speter    prev = &pprefix->plist;
66318334Speter
664132718Skan  /* Keep track of the longest prefix.  */
66518334Speter
66618334Speter  len = strlen (prefix);
66718334Speter  if (len > pprefix->max_len)
66818334Speter    pprefix->max_len = len;
66918334Speter
670169689Skan  pl = XNEW (struct prefix_list);
67152284Sobrien  pl->prefix = xstrdup (prefix);
67218334Speter
67318334Speter  if (*prev)
67418334Speter    pl->next = *prev;
67518334Speter  else
67618334Speter    pl->next = (struct prefix_list *) 0;
67718334Speter  *prev = pl;
67818334Speter}
67918334Speter
68018334Speter/* Take the value of the environment variable ENV, break it into a path, and
68118334Speter   add of the entries to PPREFIX.  */
68218334Speter
68318334Speterstatic void
684132718Skanprefix_from_env (const char *env, struct path_prefix *pprefix)
68518334Speter{
68690075Sobrien  const char *p;
687117395Skan  GET_ENVIRONMENT (p, env);
68818334Speter
68918334Speter  if (p)
69018334Speter    prefix_from_string (p, pprefix);
69118334Speter}
69218334Speter
69318334Speterstatic void
694132718Skanprefix_from_string (const char *p, struct path_prefix *pprefix)
69518334Speter{
69690075Sobrien  const char *startp, *endp;
697169689Skan  char *nstore = XNEWVEC (char, strlen (p) + 3);
69818334Speter
69950397Sobrien  if (debug)
70050397Sobrien    fprintf (stderr, "Convert string '%s' into prefixes, separator = '%c'\n", p, PATH_SEPARATOR);
701132718Skan
70218334Speter  startp = endp = p;
70318334Speter  while (1)
70418334Speter    {
70518334Speter      if (*endp == PATH_SEPARATOR || *endp == 0)
70618334Speter	{
70718334Speter	  strncpy (nstore, startp, endp-startp);
70818334Speter	  if (endp == startp)
70918334Speter	    {
71018334Speter	      strcpy (nstore, "./");
71118334Speter	    }
71290075Sobrien	  else if (! IS_DIR_SEPARATOR (endp[-1]))
71318334Speter	    {
71490075Sobrien	      nstore[endp-startp] = DIR_SEPARATOR;
71518334Speter	      nstore[endp-startp+1] = 0;
71618334Speter	    }
71718334Speter	  else
71818334Speter	    nstore[endp-startp] = 0;
71918334Speter
72050397Sobrien	  if (debug)
72150397Sobrien	    fprintf (stderr, "  - add prefix: %s\n", nstore);
722132718Skan
72318334Speter	  add_prefix (pprefix, nstore);
72418334Speter	  if (*endp == 0)
72518334Speter	    break;
72618334Speter	  endp = startp = endp + 1;
72718334Speter	}
72818334Speter      else
72918334Speter	endp++;
73018334Speter    }
73118334Speter}
73218334Speter
73350397Sobrien/* Main program.  */
73418334Speter
73518334Speterint
736132718Skanmain (int argc, char **argv)
73718334Speter{
73890075Sobrien  static const char *const ld_suffix	= "ld";
73990075Sobrien  static const char *const real_ld_suffix = "real-ld";
74090075Sobrien  static const char *const collect_ld_suffix = "collect-ld";
74190075Sobrien  static const char *const nm_suffix	= "nm";
74290075Sobrien  static const char *const gnm_suffix	= "gnm";
74318334Speter#ifdef LDD_SUFFIX
74490075Sobrien  static const char *const ldd_suffix	= LDD_SUFFIX;
74518334Speter#endif
74690075Sobrien  static const char *const strip_suffix = "strip";
74790075Sobrien  static const char *const gstrip_suffix = "gstrip";
74890075Sobrien
749259563Spfg#ifdef CROSS_DIRECTORY_STRUCTURE
75090075Sobrien  /* If we look for a program in the compiler directories, we just use
75190075Sobrien     the short name, since these directories are already system-specific.
75290075Sobrien     But it we look for a program in the system directories, we need to
75390075Sobrien     qualify the program name with the target machine.  */
75490075Sobrien
75590075Sobrien  const char *const full_ld_suffix =
75690075Sobrien    concat(target_machine, "-", ld_suffix, NULL);
75790075Sobrien  const char *const full_nm_suffix =
75890075Sobrien    concat (target_machine, "-", nm_suffix, NULL);
75990075Sobrien  const char *const full_gnm_suffix =
76090075Sobrien    concat (target_machine, "-", gnm_suffix, NULL);
76190075Sobrien#ifdef LDD_SUFFIX
76290075Sobrien  const char *const full_ldd_suffix =
76390075Sobrien    concat (target_machine, "-", ldd_suffix, NULL);
76490075Sobrien#endif
76590075Sobrien  const char *const full_strip_suffix =
76690075Sobrien    concat (target_machine, "-", strip_suffix, NULL);
76790075Sobrien  const char *const full_gstrip_suffix =
76890075Sobrien    concat (target_machine, "-", gstrip_suffix, NULL);
76990075Sobrien#else
77090075Sobrien  const char *const full_ld_suffix	= ld_suffix;
77190075Sobrien  const char *const full_nm_suffix	= nm_suffix;
77290075Sobrien  const char *const full_gnm_suffix	= gnm_suffix;
77390075Sobrien#ifdef LDD_SUFFIX
77490075Sobrien  const char *const full_ldd_suffix	= ldd_suffix;
77590075Sobrien#endif
77690075Sobrien  const char *const full_strip_suffix	= strip_suffix;
77790075Sobrien  const char *const full_gstrip_suffix	= gstrip_suffix;
778259563Spfg#endif /* CROSS_DIRECTORY_STRUCTURE */
77990075Sobrien
78090075Sobrien  const char *arg;
78150397Sobrien  FILE *outf;
78250397Sobrien#ifdef COLLECT_EXPORT_LIST
78350397Sobrien  FILE *exportf;
78450397Sobrien#endif
78590075Sobrien  const char *ld_file_name;
78690075Sobrien  const char *p;
78718334Speter  char **c_argv;
78890075Sobrien  const char **c_ptr;
78952284Sobrien  char **ld1_argv;
79090075Sobrien  const char **ld1;
79152284Sobrien  char **ld2_argv;
79290075Sobrien  const char **ld2;
79352284Sobrien  char **object_lst;
79490075Sobrien  const char **object;
79518334Speter  int first_file;
79650397Sobrien  int num_c_args	= argc+9;
79718334Speter
79890075Sobrien  no_demangle = !! getenv ("COLLECT_NO_DEMANGLE");
79990075Sobrien
80090075Sobrien  /* Suppress demangling by the real linker, which may be broken.  */
80190075Sobrien  putenv (xstrdup ("COLLECT_NO_DEMANGLE="));
80290075Sobrien
80352284Sobrien#if defined (COLLECT2_HOST_INITIALIZATION)
80490075Sobrien  /* Perform system dependent initialization, if necessary.  */
80552284Sobrien  COLLECT2_HOST_INITIALIZATION;
80652284Sobrien#endif
80752284Sobrien
80890075Sobrien#ifdef SIGCHLD
80990075Sobrien  /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
81090075Sobrien     receive the signal.  A different setting is inheritable */
81190075Sobrien  signal (SIGCHLD, SIG_DFL);
81252284Sobrien#endif
81352284Sobrien
814169689Skan  /* Unlock the stdio streams.  */
815169689Skan  unlock_std_streams ();
816169689Skan
81790075Sobrien  gcc_init_libintl ();
81890075Sobrien
81952284Sobrien  /* Do not invoke xcalloc before this point, since locale needs to be
82052284Sobrien     set first, in case a diagnostic is issued.  */
82152284Sobrien
822169689Skan  ld1 = (const char **)(ld1_argv = xcalloc(sizeof (char *), argc+4));
823169689Skan  ld2 = (const char **)(ld2_argv = xcalloc(sizeof (char *), argc+11));
824132718Skan  object = (const char **)(object_lst = xcalloc(sizeof (char *), argc));
82552284Sobrien
82618334Speter#ifdef DEBUG
82718334Speter  debug = 1;
82818334Speter#endif
82918334Speter
83050397Sobrien  /* Parse command line early for instances of -debug.  This allows
83150397Sobrien     the debug flag to be set before functions like find_a_file()
83250397Sobrien     are called.  */
83350397Sobrien  {
83450397Sobrien    int i;
835132718Skan
83650397Sobrien    for (i = 1; argv[i] != NULL; i ++)
837132718Skan      {
838132718Skan	if (! strcmp (argv[i], "-debug"))
839132718Skan	  debug = 1;
840132718Skan      }
84150397Sobrien    vflag = debug;
84250397Sobrien  }
84350397Sobrien
84450397Sobrien#ifndef DEFAULT_A_OUT_NAME
84518334Speter  output_file = "a.out";
84650397Sobrien#else
84750397Sobrien  output_file = DEFAULT_A_OUT_NAME;
84850397Sobrien#endif
84918334Speter
85018334Speter  obstack_begin (&temporary_obstack, 0);
851132718Skan  temporary_firstobj = obstack_alloc (&temporary_obstack, 0);
85250397Sobrien
853169689Skan#ifndef HAVE_LD_DEMANGLE
85490075Sobrien  current_demangling_style = auto_demangling;
855169689Skan#endif
85650397Sobrien  p = getenv ("COLLECT_GCC_OPTIONS");
85750397Sobrien  while (p && *p)
85850397Sobrien    {
85990075Sobrien      const char *q = extract_string (&p);
86050397Sobrien      if (*q == '-' && (q[1] == 'm' || q[1] == 'f'))
86150397Sobrien	num_c_args++;
86250397Sobrien    }
86350397Sobrien  obstack_free (&temporary_obstack, temporary_firstobj);
86418334Speter
865132718Skan  /* -fno-profile-arcs -fno-test-coverage -fno-branch-probabilities
866132718Skan     -fno-exceptions -w */
867132718Skan  num_c_args += 5;
86818334Speter
869132718Skan  c_ptr = (const char **) (c_argv = xcalloc (sizeof (char *), num_c_args));
87090075Sobrien
87118334Speter  if (argc < 2)
87218334Speter    fatal ("no arguments");
87318334Speter
87418334Speter#ifdef SIGQUIT
87518334Speter  if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
87618334Speter    signal (SIGQUIT, handler);
87718334Speter#endif
87818334Speter  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
87918334Speter    signal (SIGINT, handler);
88018334Speter#ifdef SIGALRM
88118334Speter  if (signal (SIGALRM, SIG_IGN) != SIG_IGN)
88218334Speter    signal (SIGALRM, handler);
88318334Speter#endif
88418334Speter#ifdef SIGHUP
88518334Speter  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
88618334Speter    signal (SIGHUP, handler);
88718334Speter#endif
88818334Speter  if (signal (SIGSEGV, SIG_IGN) != SIG_IGN)
88918334Speter    signal (SIGSEGV, handler);
89018334Speter#ifdef SIGBUS
89118334Speter  if (signal (SIGBUS, SIG_IGN) != SIG_IGN)
89218334Speter    signal (SIGBUS, handler);
89318334Speter#endif
89418334Speter
89518334Speter  /* Extract COMPILER_PATH and PATH into our prefix list.  */
89618334Speter  prefix_from_env ("COMPILER_PATH", &cpath);
89718334Speter  prefix_from_env ("PATH", &path);
89818334Speter
89918334Speter  /* Try to discover a valid linker/nm/strip to use.  */
90018334Speter
90118334Speter  /* Maybe we know the right file to use (if not cross).  */
90252284Sobrien  ld_file_name = 0;
90352284Sobrien#ifdef DEFAULT_LINKER
90452284Sobrien  if (access (DEFAULT_LINKER, X_OK) == 0)
90552284Sobrien    ld_file_name = DEFAULT_LINKER;
90652284Sobrien  if (ld_file_name == 0)
90752284Sobrien#endif
90818334Speter#ifdef REAL_LD_FILE_NAME
90918334Speter  ld_file_name = find_a_file (&path, REAL_LD_FILE_NAME);
91018334Speter  if (ld_file_name == 0)
91118334Speter#endif
91218334Speter  /* Search the (target-specific) compiler dirs for ld'.  */
91318334Speter  ld_file_name = find_a_file (&cpath, real_ld_suffix);
91418334Speter  /* Likewise for `collect-ld'.  */
91518334Speter  if (ld_file_name == 0)
91618334Speter    ld_file_name = find_a_file (&cpath, collect_ld_suffix);
91718334Speter  /* Search the compiler directories for `ld'.  We have protection against
91818334Speter     recursive calls in find_a_file.  */
91918334Speter  if (ld_file_name == 0)
92018334Speter    ld_file_name = find_a_file (&cpath, ld_suffix);
92118334Speter  /* Search the ordinary system bin directories
92218334Speter     for `ld' (if native linking) or `TARGET-ld' (if cross).  */
92318334Speter  if (ld_file_name == 0)
92418334Speter    ld_file_name = find_a_file (&path, full_ld_suffix);
92518334Speter
92618334Speter#ifdef REAL_NM_FILE_NAME
92718334Speter  nm_file_name = find_a_file (&path, REAL_NM_FILE_NAME);
92818334Speter  if (nm_file_name == 0)
92918334Speter#endif
93018334Speter  nm_file_name = find_a_file (&cpath, gnm_suffix);
93118334Speter  if (nm_file_name == 0)
93218334Speter    nm_file_name = find_a_file (&path, full_gnm_suffix);
93318334Speter  if (nm_file_name == 0)
93418334Speter    nm_file_name = find_a_file (&cpath, nm_suffix);
93518334Speter  if (nm_file_name == 0)
93618334Speter    nm_file_name = find_a_file (&path, full_nm_suffix);
93718334Speter
93818334Speter#ifdef LDD_SUFFIX
93918334Speter  ldd_file_name = find_a_file (&cpath, ldd_suffix);
94018334Speter  if (ldd_file_name == 0)
94118334Speter    ldd_file_name = find_a_file (&path, full_ldd_suffix);
94218334Speter#endif
94318334Speter
94418334Speter#ifdef REAL_STRIP_FILE_NAME
94518334Speter  strip_file_name = find_a_file (&path, REAL_STRIP_FILE_NAME);
94618334Speter  if (strip_file_name == 0)
94718334Speter#endif
94818334Speter  strip_file_name = find_a_file (&cpath, gstrip_suffix);
94918334Speter  if (strip_file_name == 0)
95018334Speter    strip_file_name = find_a_file (&path, full_gstrip_suffix);
95118334Speter  if (strip_file_name == 0)
95218334Speter    strip_file_name = find_a_file (&cpath, strip_suffix);
95318334Speter  if (strip_file_name == 0)
95418334Speter    strip_file_name = find_a_file (&path, full_strip_suffix);
95518334Speter
95618334Speter  /* Determine the full path name of the C compiler to use.  */
95718334Speter  c_file_name = getenv ("COLLECT_GCC");
95818334Speter  if (c_file_name == 0)
95918334Speter    {
960259563Spfg#ifdef CROSS_DIRECTORY_STRUCTURE
96190075Sobrien      c_file_name = concat (target_machine, "-gcc", NULL);
96218334Speter#else
96318334Speter      c_file_name = "gcc";
96418334Speter#endif
96518334Speter    }
96618334Speter
96718334Speter  p = find_a_file (&cpath, c_file_name);
96818334Speter
96918334Speter  /* Here it should be safe to use the system search path since we should have
97018334Speter     already qualified the name of the compiler when it is needed.  */
97118334Speter  if (p == 0)
97218334Speter    p = find_a_file (&path, c_file_name);
97318334Speter
97418334Speter  if (p)
97518334Speter    c_file_name = p;
97618334Speter
97718334Speter  *ld1++ = *ld2++ = ld_file_name;
97818334Speter
97950397Sobrien  /* Make temp file names.  */
98050397Sobrien  c_file = make_temp_file (".c");
98150397Sobrien  o_file = make_temp_file (".o");
98250397Sobrien#ifdef COLLECT_EXPORT_LIST
98350397Sobrien  export_file = make_temp_file (".x");
98450397Sobrien#endif
98550397Sobrien  ldout = make_temp_file (".ld");
986169689Skan  lderrout = make_temp_file (".le");
98718334Speter  *c_ptr++ = c_file_name;
98850397Sobrien  *c_ptr++ = "-x";
98950397Sobrien  *c_ptr++ = "c";
99018334Speter  *c_ptr++ = "-c";
99118334Speter  *c_ptr++ = "-o";
99218334Speter  *c_ptr++ = o_file;
99318334Speter
99450397Sobrien#ifdef COLLECT_EXPORT_LIST
99550397Sobrien  /* Generate a list of directories from LIBPATH.  */
99650397Sobrien  prefix_from_env ("LIBPATH", &libpath_lib_dirs);
99750397Sobrien  /* Add to this list also two standard directories where
99850397Sobrien     AIX loader always searches for libraries.  */
99950397Sobrien  add_prefix (&libpath_lib_dirs, "/lib");
100050397Sobrien  add_prefix (&libpath_lib_dirs, "/usr/lib");
100150397Sobrien#endif
100250397Sobrien
1003132718Skan  /* Get any options that the upper GCC wants to pass to the sub-GCC.
100450397Sobrien
100550397Sobrien     AIX support needs to know if -shared has been specified before
100650397Sobrien     parsing commandline arguments.  */
100750397Sobrien
100850397Sobrien  p = getenv ("COLLECT_GCC_OPTIONS");
100950397Sobrien  while (p && *p)
101050397Sobrien    {
101190075Sobrien      const char *q = extract_string (&p);
101250397Sobrien      if (*q == '-' && (q[1] == 'm' || q[1] == 'f'))
1013117395Skan	*c_ptr++ = xstrdup (q);
101452284Sobrien      if (strcmp (q, "-EL") == 0 || strcmp (q, "-EB") == 0)
1015117395Skan	*c_ptr++ = xstrdup (q);
101690075Sobrien      if (strcmp (q, "-shared") == 0)
101750397Sobrien	shared_obj = 1;
101890075Sobrien      if (*q == '-' && q[1] == 'B')
101990075Sobrien	{
1020117395Skan	  *c_ptr++ = xstrdup (q);
102190075Sobrien	  if (q[2] == 0)
102290075Sobrien	    {
102390075Sobrien	      q = extract_string (&p);
1024117395Skan	      *c_ptr++ = xstrdup (q);
102590075Sobrien	    }
102690075Sobrien	}
102750397Sobrien    }
102850397Sobrien  obstack_free (&temporary_obstack, temporary_firstobj);
1029132718Skan  *c_ptr++ = "-fno-profile-arcs";
1030132718Skan  *c_ptr++ = "-fno-test-coverage";
1031132718Skan  *c_ptr++ = "-fno-branch-probabilities";
103250397Sobrien  *c_ptr++ = "-fno-exceptions";
103390075Sobrien  *c_ptr++ = "-w";
103450397Sobrien
103518334Speter  /* !!! When GCC calls collect2,
103618334Speter     it does not know whether it is calling collect2 or ld.
103718334Speter     So collect2 cannot meaningfully understand any options
103818334Speter     except those ld understands.
103918334Speter     If you propose to make GCC pass some other option,
104018334Speter     just imagine what will happen if ld is really ld!!!  */
104118334Speter
104250397Sobrien  /* Parse arguments.  Remember output file spec, pass the rest to ld.  */
104318334Speter  /* After the first file, put in the c++ rt0.  */
104418334Speter
104518334Speter  first_file = 1;
1046169689Skan#ifdef HAVE_LD_DEMANGLE
1047169689Skan  if (!demangle_flag && !no_demangle)
1048169689Skan    demangle_flag = "--demangle";
1049169689Skan  if (demangle_flag)
1050169689Skan    *ld1++ = *ld2++ = demangle_flag;
1051169689Skan#endif
105250397Sobrien  while ((arg = *++argv) != (char *) 0)
105318334Speter    {
105418334Speter      *ld1++ = *ld2++ = arg;
105518334Speter
105618334Speter      if (arg[0] == '-')
105718334Speter	{
105818334Speter	  switch (arg[1])
105918334Speter	    {
106050397Sobrien#ifdef COLLECT_EXPORT_LIST
106150397Sobrien	    /* We want to disable automatic exports on AIX when user
106250397Sobrien	       explicitly puts an export list in command line */
106350397Sobrien	    case 'b':
106450397Sobrien	      if (arg[2] == 'E' || strncmp (&arg[2], "export", 6) == 0)
1065169689Skan		export_flag = 1;
106652284Sobrien	      else if (arg[2] == '6' && arg[3] == '4')
106750397Sobrien		aix64_flag = 1;
1068146895Skan	      else if (arg[2] == 'r' && arg[3] == 't' && arg[4] == 'l')
1069146895Skan		aixrtl_flag = 1;
107050397Sobrien	      break;
107150397Sobrien#endif
107250397Sobrien
107318334Speter	    case 'd':
107418334Speter	      if (!strcmp (arg, "-debug"))
107518334Speter		{
107650397Sobrien		  /* Already parsed.  */
107718334Speter		  ld1--;
107818334Speter		  ld2--;
107918334Speter		}
1080169689Skan	      if (!strcmp (arg, "-dynamic-linker") && argv[1])
1081169689Skan		{
1082169689Skan		  ++argv;
1083169689Skan		  *ld1++ = *ld2++ = *argv;
1084169689Skan		}
108518334Speter	      break;
108618334Speter
108718334Speter	    case 'l':
108818334Speter	      if (first_file)
108918334Speter		{
109018334Speter		  /* place o_file BEFORE this argument! */
109118334Speter		  first_file = 0;
109218334Speter		  ld2--;
109318334Speter		  *ld2++ = o_file;
109418334Speter		  *ld2++ = arg;
109518334Speter		}
109650397Sobrien#ifdef COLLECT_EXPORT_LIST
109750397Sobrien	      {
1098169689Skan		/* Resolving full library name.  */
109990075Sobrien		const char *s = resolve_lib_name (arg+2);
110050397Sobrien
110150397Sobrien		/* Saving a full library name.  */
110250397Sobrien		add_to_list (&libs, s);
110350397Sobrien	      }
110450397Sobrien#endif
110518334Speter	      break;
110618334Speter
110750397Sobrien#ifdef COLLECT_EXPORT_LIST
110850397Sobrien	    /* Saving directories where to search for libraries.  */
1109132718Skan	    case 'L':
111050397Sobrien	      add_prefix (&cmdline_lib_dirs, arg+2);
111150397Sobrien	      break;
1112132718Skan#else
111390075Sobrien#if LINK_ELIMINATE_DUPLICATE_LDIRECTORIES
111490075Sobrien	    case 'L':
111590075Sobrien	      if (is_in_args (arg, (const char **) ld1_argv, ld1-1))
111690075Sobrien		--ld1;
111790075Sobrien	      break;
111890075Sobrien#endif /* LINK_ELIMINATE_DUPLICATE_LDIRECTORIES */
111950397Sobrien#endif
112050397Sobrien
112118334Speter	    case 'o':
112218334Speter	      if (arg[2] == '\0')
112318334Speter		output_file = *ld1++ = *ld2++ = *++argv;
112490075Sobrien	      else if (1
112590075Sobrien#ifdef SWITCHES_NEED_SPACES
112690075Sobrien		       && ! strchr (SWITCHES_NEED_SPACES, arg[1])
112790075Sobrien#endif
112890075Sobrien		       )
112990075Sobrien
113018334Speter		output_file = &arg[2];
113118334Speter	      break;
113218334Speter
113318334Speter	    case 'r':
113418334Speter	      if (arg[2] == '\0')
113518334Speter		rflag = 1;
113618334Speter	      break;
113718334Speter
113818334Speter	    case 's':
113918334Speter	      if (arg[2] == '\0' && do_collecting)
114018334Speter		{
114118334Speter		  /* We must strip after the nm run, otherwise C++ linking
114250397Sobrien		     will not work.  Thus we strip in the second ld run, or
114318334Speter		     else with strip if there is no second ld run.  */
114418334Speter		  strip_flag = 1;
114518334Speter		  ld1--;
114618334Speter		}
114718334Speter	      break;
114818334Speter
114918334Speter	    case 'v':
115018334Speter	      if (arg[2] == '\0')
115118334Speter		vflag = 1;
115218334Speter	      break;
1153169689Skan
1154169689Skan	    case '-':
1155169689Skan	      if (strcmp (arg, "--no-demangle") == 0)
1156169689Skan		{
1157169689Skan		  demangle_flag = arg;
1158169689Skan		  no_demangle = 1;
1159169689Skan		  ld1--;
1160169689Skan		  ld2--;
1161169689Skan		}
1162169689Skan	      else if (strncmp (arg, "--demangle", 10) == 0)
1163169689Skan		{
1164169689Skan		  demangle_flag = arg;
1165169689Skan		  no_demangle = 0;
1166169689Skan#ifndef HAVE_LD_DEMANGLE
1167169689Skan		  if (arg[10] == '=')
1168169689Skan		    {
1169169689Skan		      enum demangling_styles style
1170169689Skan			= cplus_demangle_name_to_style (arg+11);
1171169689Skan		      if (style == unknown_demangling)
1172169689Skan			error ("unknown demangling style '%s'", arg+11);
1173169689Skan		      else
1174169689Skan			current_demangling_style = style;
1175169689Skan		    }
1176169689Skan#endif
1177169689Skan		  ld1--;
1178169689Skan		  ld2--;
1179169689Skan		}
1180169689Skan	      break;
118118334Speter	    }
118218334Speter	}
118390075Sobrien      else if ((p = strrchr (arg, '.')) != (char *) 0
118450397Sobrien	       && (strcmp (p, ".o") == 0 || strcmp (p, ".a") == 0
118590075Sobrien		   || strcmp (p, ".so") == 0 || strcmp (p, ".lo") == 0
118690075Sobrien		   || strcmp (p, ".obj") == 0))
118718334Speter	{
118818334Speter	  if (first_file)
118918334Speter	    {
119018334Speter	      first_file = 0;
119118334Speter	      if (p[1] == 'o')
119218334Speter		*ld2++ = o_file;
119318334Speter	      else
119418334Speter		{
119518334Speter		  /* place o_file BEFORE this argument! */
119618334Speter		  ld2--;
119718334Speter		  *ld2++ = o_file;
119818334Speter		  *ld2++ = arg;
119918334Speter		}
120018334Speter	    }
120190075Sobrien	  if (p[1] == 'o' || p[1] == 'l')
120218334Speter	    *object++ = arg;
120350397Sobrien#ifdef COLLECT_EXPORT_LIST
120450397Sobrien	  /* libraries can be specified directly, i.e. without -l flag.  */
1205132718Skan	  else
1206132718Skan	    {
120750397Sobrien	      /* Saving a full library name.  */
1208169689Skan	      add_to_list (&libs, arg);
1209169689Skan	    }
121050397Sobrien#endif
121118334Speter	}
121218334Speter    }
121318334Speter
121450397Sobrien#ifdef COLLECT_EXPORT_LIST
121550397Sobrien  /* This is added only for debugging purposes.  */
121650397Sobrien  if (debug)
121750397Sobrien    {
121850397Sobrien      fprintf (stderr, "List of libraries:\n");
121950397Sobrien      dump_list (stderr, "\t", libs.first);
122050397Sobrien    }
122118334Speter
122218334Speter  /* The AIX linker will discard static constructors in object files if
122318334Speter     nothing else in the file is referenced, so look at them first.  */
122418334Speter  {
122590075Sobrien      const char **export_object_lst = (const char **)object_lst;
122690075Sobrien
122750397Sobrien      while (export_object_lst < object)
122850397Sobrien	scan_prog_file (*export_object_lst++, PASS_OBJ);
122950397Sobrien  }
123050397Sobrien  {
123150397Sobrien    struct id *list = libs.first;
123290075Sobrien
123350397Sobrien    for (; list; list = list->next)
123450397Sobrien      scan_prog_file (list->name, PASS_FIRST);
123550397Sobrien  }
123690075Sobrien
123790075Sobrien  if (exports.first)
123890075Sobrien    {
123990075Sobrien      char *buf = concat ("-bE:", export_file, NULL);
1240132718Skan
124190075Sobrien      *ld1++ = buf;
124290075Sobrien      *ld2++ = buf;
124390075Sobrien
124490075Sobrien      exportf = fopen (export_file, "w");
124590075Sobrien      if (exportf == (FILE *) 0)
124690075Sobrien	fatal_perror ("fopen %s", export_file);
124790075Sobrien      write_aix_file (exportf, exports.first);
124890075Sobrien      if (fclose (exportf))
124990075Sobrien	fatal_perror ("fclose %s", export_file);
125090075Sobrien    }
125118334Speter#endif
125218334Speter
125318334Speter  *c_ptr++ = c_file;
125490075Sobrien  *c_ptr = *ld1 = *object = (char *) 0;
125518334Speter
125618334Speter  if (vflag)
125718334Speter    {
125852284Sobrien      notice ("collect2 version %s", version_string);
125918334Speter#ifdef TARGET_VERSION
126018334Speter      TARGET_VERSION;
126118334Speter#endif
126218334Speter      fprintf (stderr, "\n");
126318334Speter    }
126418334Speter
126518334Speter  if (debug)
126618334Speter    {
126790075Sobrien      const char *ptr;
126818334Speter      fprintf (stderr, "ld_file_name        = %s\n",
126918334Speter	       (ld_file_name ? ld_file_name : "not found"));
127018334Speter      fprintf (stderr, "c_file_name         = %s\n",
127118334Speter	       (c_file_name ? c_file_name : "not found"));
127218334Speter      fprintf (stderr, "nm_file_name        = %s\n",
127318334Speter	       (nm_file_name ? nm_file_name : "not found"));
127418334Speter#ifdef LDD_SUFFIX
127518334Speter      fprintf (stderr, "ldd_file_name       = %s\n",
127618334Speter	       (ldd_file_name ? ldd_file_name : "not found"));
127718334Speter#endif
127818334Speter      fprintf (stderr, "strip_file_name     = %s\n",
127918334Speter	       (strip_file_name ? strip_file_name : "not found"));
128018334Speter      fprintf (stderr, "c_file              = %s\n",
128118334Speter	       (c_file ? c_file : "not found"));
128218334Speter      fprintf (stderr, "o_file              = %s\n",
128318334Speter	       (o_file ? o_file : "not found"));
128418334Speter
128518334Speter      ptr = getenv ("COLLECT_GCC_OPTIONS");
128618334Speter      if (ptr)
128718334Speter	fprintf (stderr, "COLLECT_GCC_OPTIONS = %s\n", ptr);
128818334Speter
128918334Speter      ptr = getenv ("COLLECT_GCC");
129018334Speter      if (ptr)
129118334Speter	fprintf (stderr, "COLLECT_GCC         = %s\n", ptr);
129218334Speter
129318334Speter      ptr = getenv ("COMPILER_PATH");
129418334Speter      if (ptr)
129518334Speter	fprintf (stderr, "COMPILER_PATH       = %s\n", ptr);
129618334Speter
129790075Sobrien      ptr = getenv (LIBRARY_PATH_ENV);
129818334Speter      if (ptr)
129990075Sobrien	fprintf (stderr, "%-20s= %s\n", LIBRARY_PATH_ENV, ptr);
130018334Speter
130118334Speter      fprintf (stderr, "\n");
130218334Speter    }
130318334Speter
130450397Sobrien  /* Load the program, searching all libraries and attempting to provide
130550397Sobrien     undefined symbols from repository information.  */
130618334Speter
130750397Sobrien  /* On AIX we do this later.  */
130850397Sobrien#ifndef COLLECT_EXPORT_LIST
130952750Sobrien  do_tlink (ld1_argv, object_lst);
131050397Sobrien#endif
131118334Speter
131250397Sobrien  /* If -r or they will be run via some other method, do not build the
131350397Sobrien     constructor or destructor list, just return now.  */
131450397Sobrien  if (rflag
131550397Sobrien#ifndef COLLECT_EXPORT_LIST
131650397Sobrien      || ! do_collecting
131750397Sobrien#endif
131850397Sobrien      )
131950397Sobrien    {
132050397Sobrien#ifdef COLLECT_EXPORT_LIST
132152750Sobrien      /* Do the link we avoided above if we are exiting.  */
132252750Sobrien      do_tlink (ld1_argv, object_lst);
132352750Sobrien
132450397Sobrien      /* But make sure we delete the export file we may have created.  */
132550397Sobrien      if (export_file != 0 && export_file[0])
132650397Sobrien	maybe_unlink (export_file);
132750397Sobrien#endif
132850397Sobrien      maybe_unlink (c_file);
132950397Sobrien      maybe_unlink (o_file);
133050397Sobrien      return 0;
133150397Sobrien    }
133218334Speter
133318334Speter  /* Examine the namelist with nm and search it for static constructors
133418334Speter     and destructors to call.
133550397Sobrien     Write the constructor and destructor tables to a .s file and reload.  */
133618334Speter
133790075Sobrien  /* On AIX we already scanned for global constructors/destructors.  */
133850397Sobrien#ifndef COLLECT_EXPORT_LIST
133918334Speter  scan_prog_file (output_file, PASS_FIRST);
134050397Sobrien#endif
134118334Speter
134218334Speter#ifdef SCAN_LIBRARIES
134318334Speter  scan_libraries (output_file);
134418334Speter#endif
134518334Speter
134618334Speter  if (debug)
134718334Speter    {
134852284Sobrien      notice ("%d constructor(s) found\n", constructors.number);
134952284Sobrien      notice ("%d destructor(s)  found\n", destructors.number);
135052284Sobrien      notice ("%d frame table(s) found\n", frame_tables.number);
135118334Speter    }
135218334Speter
135318334Speter  if (constructors.number == 0 && destructors.number == 0
135450397Sobrien      && frame_tables.number == 0
135550397Sobrien#if defined (SCAN_LIBRARIES) || defined (COLLECT_EXPORT_LIST)
135618334Speter      /* If we will be running these functions ourselves, we want to emit
135750397Sobrien	 stubs into the shared library so that we do not have to relink
135818334Speter	 dependent programs when we add static objects.  */
135918334Speter      && ! shared_obj
136018334Speter#endif
136118334Speter      )
136218334Speter    {
136350397Sobrien#ifdef COLLECT_EXPORT_LIST
1364132718Skan      /* Do tlink without additional code generation.  */
136550397Sobrien      do_tlink (ld1_argv, object_lst);
136650397Sobrien#endif
136718334Speter      /* Strip now if it was requested on the command line.  */
136818334Speter      if (strip_flag)
136918334Speter	{
1370169689Skan	  char **real_strip_argv = XCNEWVEC (char *, 3);
137190075Sobrien	  const char ** strip_argv = (const char **) real_strip_argv;
1372132718Skan
137318334Speter	  strip_argv[0] = strip_file_name;
137418334Speter	  strip_argv[1] = output_file;
137518334Speter	  strip_argv[2] = (char *) 0;
137690075Sobrien	  fork_execute ("strip", real_strip_argv);
137718334Speter	}
137818334Speter
137918334Speter#ifdef COLLECT_EXPORT_LIST
138018334Speter      maybe_unlink (export_file);
138118334Speter#endif
138250397Sobrien      maybe_unlink (c_file);
138350397Sobrien      maybe_unlink (o_file);
138418334Speter      return 0;
138518334Speter    }
138618334Speter
138790075Sobrien  /* Sort ctor and dtor lists by priority.  */
138852284Sobrien  sort_ids (&constructors);
138952284Sobrien  sort_ids (&destructors);
139052284Sobrien
139118334Speter  maybe_unlink(output_file);
139218334Speter  outf = fopen (c_file, "w");
139350397Sobrien  if (outf == (FILE *) 0)
139452284Sobrien    fatal_perror ("fopen %s", c_file);
139518334Speter
139618334Speter  write_c_file (outf, c_file);
139718334Speter
139818334Speter  if (fclose (outf))
139952284Sobrien    fatal_perror ("fclose %s", c_file);
140018334Speter
140118334Speter  /* Tell the linker that we have initializer and finalizer functions.  */
140218334Speter#ifdef LD_INIT_SWITCH
140390075Sobrien#ifdef COLLECT_EXPORT_LIST
140490075Sobrien  *ld2++ = concat (LD_INIT_SWITCH, ":", initname, ":", fininame, NULL);
140590075Sobrien#else
140618334Speter  *ld2++ = LD_INIT_SWITCH;
140718334Speter  *ld2++ = initname;
140818334Speter  *ld2++ = LD_FINI_SWITCH;
140918334Speter  *ld2++ = fininame;
141018334Speter#endif
141190075Sobrien#endif
141218334Speter
141318334Speter#ifdef COLLECT_EXPORT_LIST
141418334Speter  if (shared_obj)
141518334Speter    {
141690075Sobrien      /* If we did not add export flag to link arguments before, add it to
141790075Sobrien	 second link phase now.  No new exports should have been added.  */
141890075Sobrien      if (! exports.first)
141990075Sobrien	*ld2++ = concat ("-bE:", export_file, NULL);
142090075Sobrien
1421132718Skan#ifndef LD_INIT_SWITCH
142218334Speter      add_to_list (&exports, initname);
142318334Speter      add_to_list (&exports, fininame);
142418334Speter      add_to_list (&exports, "_GLOBAL__DI");
142518334Speter      add_to_list (&exports, "_GLOBAL__DD");
1426132718Skan#endif
142718334Speter      exportf = fopen (export_file, "w");
142850397Sobrien      if (exportf == (FILE *) 0)
142952284Sobrien	fatal_perror ("fopen %s", export_file);
143090075Sobrien      write_aix_file (exportf, exports.first);
143118334Speter      if (fclose (exportf))
143252284Sobrien	fatal_perror ("fclose %s", export_file);
143318334Speter    }
143418334Speter#endif
143518334Speter
143690075Sobrien  /* End of arguments to second link phase.  */
143790075Sobrien  *ld2 = (char*) 0;
143890075Sobrien
143918334Speter  if (debug)
144018334Speter    {
144118334Speter      fprintf (stderr, "\n========== output_file = %s, c_file = %s\n",
144218334Speter	       output_file, c_file);
144318334Speter      write_c_file (stderr, "stderr");
144418334Speter      fprintf (stderr, "========== end of c_file\n\n");
144518334Speter#ifdef COLLECT_EXPORT_LIST
144618334Speter      fprintf (stderr, "\n========== export_file = %s\n", export_file);
144790075Sobrien      write_aix_file (stderr, exports.first);
144818334Speter      fprintf (stderr, "========== end of export_file\n\n");
144918334Speter#endif
145018334Speter    }
145118334Speter
145218334Speter  /* Assemble the constructor and destructor tables.
145350397Sobrien     Link the tables in with the rest of the program.  */
145418334Speter
145518334Speter  fork_execute ("gcc",  c_argv);
145650397Sobrien#ifdef COLLECT_EXPORT_LIST
1457132718Skan  /* On AIX we must call tlink because of possible templates resolution.  */
145850397Sobrien  do_tlink (ld2_argv, object_lst);
145950397Sobrien#else
1460132718Skan  /* Otherwise, simply call ld because tlink is already done.  */
146118334Speter  fork_execute ("ld", ld2_argv);
146218334Speter
146318334Speter  /* Let scan_prog_file do any final mods (OSF/rose needs this for
146418334Speter     constructors/destructors in shared libraries.  */
146518334Speter  scan_prog_file (output_file, PASS_SECOND);
1466132718Skan#endif
146718334Speter
146818334Speter  maybe_unlink (c_file);
146918334Speter  maybe_unlink (o_file);
147050397Sobrien
147150397Sobrien#ifdef COLLECT_EXPORT_LIST
147218334Speter  maybe_unlink (export_file);
147350397Sobrien#endif
147450397Sobrien
147518334Speter  return 0;
147618334Speter}
147718334Speter
147818334Speter
1479117395Skan/* Wait for a process to finish, and exit if a nonzero status is found.  */
148018334Speter
148118334Speterint
1482169689Skancollect_wait (const char *prog, struct pex_obj *pex)
148318334Speter{
148418334Speter  int status;
148518334Speter
1486169689Skan  if (!pex_get_status (pex, 1, &status))
1487169689Skan    fatal_perror ("can't get program status");
1488169689Skan  pex_free (pex);
1489169689Skan
149018334Speter  if (status)
149118334Speter    {
149218334Speter      if (WIFSIGNALED (status))
149318334Speter	{
149418334Speter	  int sig = WTERMSIG (status);
149590075Sobrien	  error ("%s terminated with signal %d [%s]%s",
149690075Sobrien		 prog, sig, strsignal(sig),
1497117395Skan		 WCOREDUMP(status) ? ", core dumped" : "");
149850397Sobrien	  collect_exit (FATAL_EXIT_CODE);
149918334Speter	}
150018334Speter
150118334Speter      if (WIFEXITED (status))
150218334Speter	return WEXITSTATUS (status);
150318334Speter    }
150418334Speter  return 0;
150518334Speter}
150618334Speter
150718334Speterstatic void
1508169689Skando_wait (const char *prog, struct pex_obj *pex)
150918334Speter{
1510169689Skan  int ret = collect_wait (prog, pex);
151118334Speter  if (ret != 0)
151218334Speter    {
151318334Speter      error ("%s returned %d exit status", prog, ret);
151418334Speter      collect_exit (ret);
151518334Speter    }
151618334Speter}
151718334Speter
151818334Speter
151952284Sobrien/* Execute a program, and wait for the reply.  */
152018334Speter
1521169689Skanstruct pex_obj *
1522169689Skancollect_execute (const char *prog, char **argv, const char *outname,
1523169689Skan		 const char *errname)
152418334Speter{
1525169689Skan  struct pex_obj *pex;
1526169689Skan  const char *errmsg;
1527169689Skan  int err;
152818334Speter
152918334Speter  if (vflag || debug)
153018334Speter    {
153118334Speter      char **p_argv;
153290075Sobrien      const char *str;
153318334Speter
153418334Speter      if (argv[0])
153518334Speter	fprintf (stderr, "%s", argv[0]);
153618334Speter      else
153752284Sobrien	notice ("[cannot find %s]", prog);
153818334Speter
153950397Sobrien      for (p_argv = &argv[1]; (str = *p_argv) != (char *) 0; p_argv++)
154018334Speter	fprintf (stderr, " %s", str);
154118334Speter
154218334Speter      fprintf (stderr, "\n");
154318334Speter    }
154418334Speter
154518334Speter  fflush (stdout);
154618334Speter  fflush (stderr);
154718334Speter
154850397Sobrien  /* If we cannot find a program we need, complain error.  Do this here
154950397Sobrien     since we might not end up needing something that we could not find.  */
155018334Speter
155118334Speter  if (argv[0] == 0)
1552169689Skan    fatal ("cannot find '%s'", prog);
155318334Speter
1554169689Skan  pex = pex_init (0, "collect2", NULL);
1555169689Skan  if (pex == NULL)
1556169689Skan    fatal_perror ("pex_init failed");
155752284Sobrien
1558169689Skan  errmsg = pex_run (pex, PEX_LAST | PEX_SEARCH, argv[0], argv, outname,
1559169689Skan		    errname, &err);
1560169689Skan  if (errmsg != NULL)
156118334Speter    {
1562169689Skan      if (err != 0)
1563169689Skan	{
1564169689Skan	  errno = err;
1565260011Spfg	  fatal_perror ("%s", errmsg);
1566169689Skan	}
1567169689Skan      else
1568260011Spfg	fatal ("%s", errmsg);
156918334Speter    }
157052284Sobrien
1571169689Skan  return pex;
157218334Speter}
157318334Speter
157418334Speterstatic void
1575132718Skanfork_execute (const char *prog, char **argv)
157618334Speter{
1577169689Skan  struct pex_obj *pex;
1578169689Skan
1579169689Skan  pex = collect_execute (prog, argv, NULL, NULL);
1580169689Skan  do_wait (prog, pex);
158118334Speter}
158218334Speter
158318334Speter/* Unlink a file unless we are debugging.  */
158418334Speter
158518334Speterstatic void
1586132718Skanmaybe_unlink (const char *file)
158718334Speter{
158818334Speter  if (!debug)
1589169689Skan    unlink_if_ordinary (file);
159018334Speter  else
159152284Sobrien    notice ("[Leaving %s]\n", file);
159218334Speter}
159318334Speter
159418334Speter
159552284Sobrienstatic long sequence_number = 0;
159652284Sobrien
159718334Speter/* Add a name to a linked list.  */
159818334Speter
159918334Speterstatic void
1600132718Skanadd_to_list (struct head *head_ptr, const char *name)
160118334Speter{
1602132718Skan  struct id *newid = xcalloc (sizeof (struct id) + strlen (name), 1);
160318334Speter  struct id *p;
160418334Speter  strcpy (newid->name, name);
160518334Speter
160618334Speter  if (head_ptr->first)
160718334Speter    head_ptr->last->next = newid;
160818334Speter  else
160918334Speter    head_ptr->first = newid;
161018334Speter
161118334Speter  /* Check for duplicate symbols.  */
161218334Speter  for (p = head_ptr->first;
161318334Speter       strcmp (name, p->name) != 0;
161418334Speter       p = p->next)
161518334Speter    ;
161618334Speter  if (p != newid)
161718334Speter    {
161818334Speter      head_ptr->last->next = 0;
161918334Speter      free (newid);
162018334Speter      return;
162118334Speter    }
162218334Speter
162318334Speter  newid->sequence = ++sequence_number;
162418334Speter  head_ptr->last = newid;
162518334Speter  head_ptr->number++;
162618334Speter}
162718334Speter
162852284Sobrien/* Grab the init priority number from an init function name that
162952284Sobrien   looks like "_GLOBAL_.I.12345.foo".  */
163052284Sobrien
163152284Sobrienstatic int
1632132718Skanextract_init_priority (const char *name)
163352284Sobrien{
163452284Sobrien  int pos = 0, pri;
163552284Sobrien
163652284Sobrien  while (name[pos] == '_')
163752284Sobrien    ++pos;
163852284Sobrien  pos += 10; /* strlen ("GLOBAL__X_") */
163952284Sobrien
164090075Sobrien  /* Extract init_p number from ctor/dtor name.  */
164152284Sobrien  pri = atoi (name + pos);
164252284Sobrien  return pri ? pri : DEFAULT_INIT_PRIORITY;
164352284Sobrien}
164452284Sobrien
164552284Sobrien/* Insertion sort the ids from ctor/dtor list HEAD_PTR in descending order.
164652284Sobrien   ctors will be run from right to left, dtors from left to right.  */
164752284Sobrien
164852284Sobrienstatic void
1649132718Skansort_ids (struct head *head_ptr)
165052284Sobrien{
165152284Sobrien  /* id holds the current element to insert.  id_next holds the next
165252284Sobrien     element to insert.  id_ptr iterates through the already sorted elements
165352284Sobrien     looking for the place to insert id.  */
165452284Sobrien  struct id *id, *id_next, **id_ptr;
165552284Sobrien
165652284Sobrien  id = head_ptr->first;
165752284Sobrien
165852284Sobrien  /* We don't have any sorted elements yet.  */
165952284Sobrien  head_ptr->first = NULL;
166052284Sobrien
166152284Sobrien  for (; id; id = id_next)
166252284Sobrien    {
166352284Sobrien      id_next = id->next;
166452284Sobrien      id->sequence = extract_init_priority (id->name);
166552284Sobrien
166652284Sobrien      for (id_ptr = &(head_ptr->first); ; id_ptr = &((*id_ptr)->next))
166752284Sobrien	if (*id_ptr == NULL
166852284Sobrien	    /* If the sequence numbers are the same, we put the id from the
166952284Sobrien	       file later on the command line later in the list.  */
167052284Sobrien	    || id->sequence > (*id_ptr)->sequence
167152284Sobrien	    /* Hack: do lexical compare, too.
167252284Sobrien	    || (id->sequence == (*id_ptr)->sequence
1673169689Skan		&& strcmp (id->name, (*id_ptr)->name) > 0) */
167452284Sobrien	    )
167552284Sobrien	  {
167652284Sobrien	    id->next = *id_ptr;
167752284Sobrien	    *id_ptr = id;
167852284Sobrien	    break;
167952284Sobrien	  }
168052284Sobrien    }
168152284Sobrien
168252284Sobrien  /* Now set the sequence numbers properly so write_c_file works.  */
168352284Sobrien  for (id = head_ptr->first; id; id = id->next)
168452284Sobrien    id->sequence = ++sequence_number;
168552284Sobrien}
168652284Sobrien
168718334Speter/* Write: `prefix', the names on list LIST, `suffix'.  */
168818334Speter
168918334Speterstatic void
1690132718Skanwrite_list (FILE *stream, const char *prefix, struct id *list)
169118334Speter{
169218334Speter  while (list)
169318334Speter    {
169418334Speter      fprintf (stream, "%sx%d,\n", prefix, list->sequence);
169518334Speter      list = list->next;
169618334Speter    }
169718334Speter}
169818334Speter
169990075Sobrien#if LINK_ELIMINATE_DUPLICATE_LDIRECTORIES
170090075Sobrien/* Given a STRING, return nonzero if it occurs in the list in range
170190075Sobrien   [ARGS_BEGIN,ARGS_END).  */
170290075Sobrien
170390075Sobrienstatic int
1704132718Skanis_in_args (const char *string, const char **args_begin,
1705132718Skan	    const char **args_end)
170690075Sobrien{
170790075Sobrien  const char **args_pointer;
170890075Sobrien  for (args_pointer = args_begin; args_pointer != args_end; ++args_pointer)
170990075Sobrien    if (strcmp (string, *args_pointer) == 0)
171090075Sobrien      return 1;
171190075Sobrien  return 0;
171290075Sobrien}
171390075Sobrien#endif /* LINK_ELIMINATE_DUPLICATE_LDIRECTORIES */
171490075Sobrien
171550397Sobrien#ifdef COLLECT_EXPORT_LIST
171650397Sobrien/* This function is really used only on AIX, but may be useful.  */
171790075Sobrien#if 0
171850397Sobrienstatic int
1719132718Skanis_in_list (const char *prefix, struct id *list)
172050397Sobrien{
172150397Sobrien  while (list)
172250397Sobrien    {
172350397Sobrien      if (!strcmp (prefix, list->name)) return 1;
172450397Sobrien      list = list->next;
172550397Sobrien    }
172650397Sobrien    return 0;
172750397Sobrien}
172850397Sobrien#endif
172990075Sobrien#endif /* COLLECT_EXPORT_LIST */
173050397Sobrien
173150397Sobrien/* Added for debugging purpose.  */
173250397Sobrien#ifdef COLLECT_EXPORT_LIST
173318334Speterstatic void
1734132718Skandump_list (FILE *stream, const char *prefix, struct id *list)
173550397Sobrien{
173650397Sobrien  while (list)
173750397Sobrien    {
173850397Sobrien      fprintf (stream, "%s%s,\n", prefix, list->name);
173950397Sobrien      list = list->next;
174050397Sobrien    }
174150397Sobrien}
174250397Sobrien#endif
174350397Sobrien
174450397Sobrien#if 0
174550397Sobrienstatic void
1746132718Skandump_prefix_list (FILE *stream, const char *prefix, struct prefix_list *list)
174750397Sobrien{
174850397Sobrien  while (list)
174950397Sobrien    {
175050397Sobrien      fprintf (stream, "%s%s,\n", prefix, list->prefix);
175150397Sobrien      list = list->next;
175250397Sobrien    }
175350397Sobrien}
175450397Sobrien#endif
175550397Sobrien
175650397Sobrienstatic void
1757132718Skanwrite_list_with_asm (FILE *stream, const char *prefix, struct id *list)
175818334Speter{
175918334Speter  while (list)
176018334Speter    {
176118334Speter      fprintf (stream, "%sx%d __asm__ (\"%s\");\n",
176218334Speter	       prefix, list->sequence, list->name);
176318334Speter      list = list->next;
176418334Speter    }
176518334Speter}
176618334Speter
176718334Speter/* Write out the constructor and destructor tables statically (for a shared
176818334Speter   object), along with the functions to execute them.  */
176918334Speter
177018334Speterstatic void
1771132718Skanwrite_c_file_stat (FILE *stream, const char *name ATTRIBUTE_UNUSED)
177218334Speter{
177390075Sobrien  const char *p, *q;
177490075Sobrien  char *prefix, *r;
177550397Sobrien  int frames = (frame_tables.number > 0);
177618334Speter
177718334Speter  /* Figure out name of output_file, stripping off .so version.  */
177890075Sobrien  p = strrchr (output_file, '/');
177918334Speter  if (p == 0)
178090075Sobrien    p = output_file;
178118334Speter  else
178218334Speter    p++;
178318334Speter  q = p;
178418334Speter  while (q)
178518334Speter    {
178690075Sobrien      q = strchr (q,'.');
178718334Speter      if (q == 0)
178818334Speter	{
178918334Speter	  q = p + strlen (p);
179018334Speter	  break;
179118334Speter	}
179218334Speter      else
179318334Speter	{
179418334Speter	  if (strncmp (q, ".so", 3) == 0)
179518334Speter	    {
179618334Speter	      q += 3;
179718334Speter	      break;
179818334Speter	    }
179918334Speter	  else
180018334Speter	    q++;
180118334Speter	}
180218334Speter    }
180318334Speter  /* q points to null at end of the string (or . of the .so version) */
1804169689Skan  prefix = XNEWVEC (char, q - p + 1);
180518334Speter  strncpy (prefix, p, q - p);
180618334Speter  prefix[q - p] = 0;
180790075Sobrien  for (r = prefix; *r; r++)
180890075Sobrien    if (!ISALNUM ((unsigned char)*r))
180990075Sobrien      *r = '_';
181018334Speter  if (debug)
181152284Sobrien    notice ("\nwrite_c_file - output name is %s, prefix is %s\n",
181252284Sobrien	    output_file, prefix);
181318334Speter
181490075Sobrien  initname = concat ("_GLOBAL__FI_", prefix, NULL);
181590075Sobrien  fininame = concat ("_GLOBAL__FD_", prefix, NULL);
181618334Speter
181718334Speter  free (prefix);
181818334Speter
1819132718Skan  /* Write the tables as C code.  */
182018334Speter
182118334Speter  fprintf (stream, "static int count;\n");
182218334Speter  fprintf (stream, "typedef void entry_pt();\n");
182318334Speter  write_list_with_asm (stream, "extern entry_pt ", constructors.first);
182450397Sobrien
182550397Sobrien  if (frames)
182650397Sobrien    {
182750397Sobrien      write_list_with_asm (stream, "extern void *", frame_tables.first);
182850397Sobrien
182950397Sobrien      fprintf (stream, "\tstatic void *frame_table[] = {\n");
183050397Sobrien      write_list (stream, "\t\t&", frame_tables.first);
183150397Sobrien      fprintf (stream, "\t0\n};\n");
183250397Sobrien
183350397Sobrien      /* This must match what's in frame.h.  */
183450397Sobrien      fprintf (stream, "struct object {\n");
183550397Sobrien      fprintf (stream, "  void *pc_begin;\n");
183650397Sobrien      fprintf (stream, "  void *pc_end;\n");
183750397Sobrien      fprintf (stream, "  void *fde_begin;\n");
183850397Sobrien      fprintf (stream, "  void *fde_array;\n");
183950397Sobrien      fprintf (stream, "  __SIZE_TYPE__ count;\n");
184050397Sobrien      fprintf (stream, "  struct object *next;\n");
184150397Sobrien      fprintf (stream, "};\n");
184250397Sobrien
184350397Sobrien      fprintf (stream, "extern void __register_frame_info_table (void *, struct object *);\n");
184450397Sobrien      fprintf (stream, "extern void *__deregister_frame_info (void *);\n");
184550397Sobrien
184650397Sobrien      fprintf (stream, "static void reg_frame () {\n");
184750397Sobrien      fprintf (stream, "\tstatic struct object ob;\n");
184850397Sobrien      fprintf (stream, "\t__register_frame_info_table (frame_table, &ob);\n");
184950397Sobrien      fprintf (stream, "\t}\n");
185050397Sobrien
185150397Sobrien      fprintf (stream, "static void dereg_frame () {\n");
185250397Sobrien      fprintf (stream, "\t__deregister_frame_info (frame_table);\n");
185350397Sobrien      fprintf (stream, "\t}\n");
185450397Sobrien    }
185550397Sobrien
185618334Speter  fprintf (stream, "void %s() {\n", initname);
185750397Sobrien  if (constructors.number > 0 || frames)
185818334Speter    {
185918334Speter      fprintf (stream, "\tstatic entry_pt *ctors[] = {\n");
186018334Speter      write_list (stream, "\t\t", constructors.first);
186150397Sobrien      if (frames)
186250397Sobrien	fprintf (stream, "\treg_frame,\n");
186318334Speter      fprintf (stream, "\t};\n");
186418334Speter      fprintf (stream, "\tentry_pt **p;\n");
186518334Speter      fprintf (stream, "\tif (count++ != 0) return;\n");
186650397Sobrien      fprintf (stream, "\tp = ctors + %d;\n", constructors.number + frames);
186718334Speter      fprintf (stream, "\twhile (p > ctors) (*--p)();\n");
186818334Speter    }
186918334Speter  else
187018334Speter    fprintf (stream, "\t++count;\n");
187118334Speter  fprintf (stream, "}\n");
187218334Speter  write_list_with_asm (stream, "extern entry_pt ", destructors.first);
187318334Speter  fprintf (stream, "void %s() {\n", fininame);
187450397Sobrien  if (destructors.number > 0 || frames)
187518334Speter    {
187618334Speter      fprintf (stream, "\tstatic entry_pt *dtors[] = {\n");
187718334Speter      write_list (stream, "\t\t", destructors.first);
187850397Sobrien      if (frames)
187950397Sobrien	fprintf (stream, "\tdereg_frame,\n");
188018334Speter      fprintf (stream, "\t};\n");
188118334Speter      fprintf (stream, "\tentry_pt **p;\n");
188218334Speter      fprintf (stream, "\tif (--count != 0) return;\n");
188318334Speter      fprintf (stream, "\tp = dtors;\n");
188418334Speter      fprintf (stream, "\twhile (p < dtors + %d) (*p++)();\n",
188550397Sobrien	       destructors.number + frames);
188618334Speter    }
188718334Speter  fprintf (stream, "}\n");
188818334Speter
188918334Speter  if (shared_obj)
189018334Speter    {
189190075Sobrien      COLLECT_SHARED_INIT_FUNC(stream, initname);
189290075Sobrien      COLLECT_SHARED_FINI_FUNC(stream, fininame);
189318334Speter    }
189418334Speter}
189518334Speter
189650397Sobrien/* Write the constructor/destructor tables.  */
189718334Speter
189850397Sobrien#ifndef LD_INIT_SWITCH
189918334Speterstatic void
1900132718Skanwrite_c_file_glob (FILE *stream, const char *name ATTRIBUTE_UNUSED)
190118334Speter{
1902132718Skan  /* Write the tables as C code.  */
190318334Speter
190450397Sobrien  int frames = (frame_tables.number > 0);
190550397Sobrien
190618334Speter  fprintf (stream, "typedef void entry_pt();\n\n");
1907132718Skan
190818334Speter  write_list_with_asm (stream, "extern entry_pt ", constructors.first);
190950397Sobrien
191050397Sobrien  if (frames)
191150397Sobrien    {
191250397Sobrien      write_list_with_asm (stream, "extern void *", frame_tables.first);
191350397Sobrien
191450397Sobrien      fprintf (stream, "\tstatic void *frame_table[] = {\n");
191550397Sobrien      write_list (stream, "\t\t&", frame_tables.first);
191650397Sobrien      fprintf (stream, "\t0\n};\n");
191750397Sobrien
191850397Sobrien      /* This must match what's in frame.h.  */
191950397Sobrien      fprintf (stream, "struct object {\n");
192050397Sobrien      fprintf (stream, "  void *pc_begin;\n");
192150397Sobrien      fprintf (stream, "  void *pc_end;\n");
192250397Sobrien      fprintf (stream, "  void *fde_begin;\n");
192350397Sobrien      fprintf (stream, "  void *fde_array;\n");
192450397Sobrien      fprintf (stream, "  __SIZE_TYPE__ count;\n");
192550397Sobrien      fprintf (stream, "  struct object *next;\n");
192650397Sobrien      fprintf (stream, "};\n");
192750397Sobrien
192850397Sobrien      fprintf (stream, "extern void __register_frame_info_table (void *, struct object *);\n");
192950397Sobrien      fprintf (stream, "extern void *__deregister_frame_info (void *);\n");
193050397Sobrien
193150397Sobrien      fprintf (stream, "static void reg_frame () {\n");
193250397Sobrien      fprintf (stream, "\tstatic struct object ob;\n");
193350397Sobrien      fprintf (stream, "\t__register_frame_info_table (frame_table, &ob);\n");
193450397Sobrien      fprintf (stream, "\t}\n");
193550397Sobrien
193650397Sobrien      fprintf (stream, "static void dereg_frame () {\n");
193750397Sobrien      fprintf (stream, "\t__deregister_frame_info (frame_table);\n");
193850397Sobrien      fprintf (stream, "\t}\n");
193950397Sobrien    }
194050397Sobrien
194118334Speter  fprintf (stream, "\nentry_pt * __CTOR_LIST__[] = {\n");
194250397Sobrien  fprintf (stream, "\t(entry_pt *) %d,\n", constructors.number + frames);
194318334Speter  write_list (stream, "\t", constructors.first);
194450397Sobrien  if (frames)
194550397Sobrien    fprintf (stream, "\treg_frame,\n");
194618334Speter  fprintf (stream, "\t0\n};\n\n");
194718334Speter
194818334Speter  write_list_with_asm (stream, "extern entry_pt ", destructors.first);
194918334Speter
195018334Speter  fprintf (stream, "\nentry_pt * __DTOR_LIST__[] = {\n");
195150397Sobrien  fprintf (stream, "\t(entry_pt *) %d,\n", destructors.number + frames);
195218334Speter  write_list (stream, "\t", destructors.first);
195350397Sobrien  if (frames)
195450397Sobrien    fprintf (stream, "\tdereg_frame,\n");
195518334Speter  fprintf (stream, "\t0\n};\n\n");
195618334Speter
195718334Speter  fprintf (stream, "extern entry_pt %s;\n", NAME__MAIN);
195818334Speter  fprintf (stream, "entry_pt *__main_reference = %s;\n\n", NAME__MAIN);
195918334Speter}
196050397Sobrien#endif /* ! LD_INIT_SWITCH */
196118334Speter
196218334Speterstatic void
1963132718Skanwrite_c_file (FILE *stream, const char *name)
196418334Speter{
196550397Sobrien  fprintf (stream, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
196618334Speter#ifndef LD_INIT_SWITCH
196718334Speter  if (! shared_obj)
196818334Speter    write_c_file_glob (stream, name);
196918334Speter  else
197018334Speter#endif
197118334Speter    write_c_file_stat (stream, name);
197250397Sobrien  fprintf (stream, "#ifdef __cplusplus\n}\n#endif\n");
197318334Speter}
197418334Speter
197550397Sobrien#ifdef COLLECT_EXPORT_LIST
197618334Speterstatic void
1977132718Skanwrite_aix_file (FILE *stream, struct id *list)
197818334Speter{
197918334Speter  for (; list; list = list->next)
198090075Sobrien    {
198190075Sobrien      fputs (list->name, stream);
198290075Sobrien      putc ('\n', stream);
198390075Sobrien    }
198418334Speter}
198550397Sobrien#endif
198618334Speter
198718334Speter#ifdef OBJECT_FORMAT_NONE
198818334Speter
198918334Speter/* Generic version to scan the name list of the loaded program for
199018334Speter   the symbols g++ uses for static constructors and destructors.
199118334Speter
199218334Speter   The constructor table begins at __CTOR_LIST__ and contains a count
199318334Speter   of the number of pointers (or -1 if the constructors are built in a
199418334Speter   separate section by the linker), followed by the pointers to the
199518334Speter   constructor functions, terminated with a null pointer.  The
199618334Speter   destructor table has the same format, and begins at __DTOR_LIST__.  */
199718334Speter
199818334Speterstatic void
1999132718Skanscan_prog_file (const char *prog_name, enum pass which_pass)
200018334Speter{
2001132718Skan  void (*int_handler) (int);
2002169689Skan#ifdef SIGQUIT
2003132718Skan  void (*quit_handler) (int);
2004169689Skan#endif
200590075Sobrien  char *real_nm_argv[4];
200690075Sobrien  const char **nm_argv = (const char **) real_nm_argv;
200718334Speter  int argc = 0;
2008169689Skan  struct pex_obj *pex;
2009169689Skan  const char *errmsg;
2010169689Skan  int err;
201118334Speter  char *p, buf[1024];
201218334Speter  FILE *inf;
201318334Speter
201418334Speter  if (which_pass == PASS_SECOND)
201518334Speter    return;
201618334Speter
201750397Sobrien  /* If we do not have an `nm', complain.  */
201818334Speter  if (nm_file_name == 0)
2019169689Skan    fatal ("cannot find 'nm'");
202018334Speter
202118334Speter  nm_argv[argc++] = nm_file_name;
202218334Speter  if (NM_FLAGS[0] != '\0')
202318334Speter    nm_argv[argc++] = NM_FLAGS;
202418334Speter
202518334Speter  nm_argv[argc++] = prog_name;
202650397Sobrien  nm_argv[argc++] = (char *) 0;
202718334Speter
202818334Speter  /* Trace if needed.  */
202918334Speter  if (vflag)
203018334Speter    {
203190075Sobrien      const char **p_argv;
203290075Sobrien      const char *str;
203318334Speter
203450397Sobrien      for (p_argv = &nm_argv[0]; (str = *p_argv) != (char *) 0; p_argv++)
203518334Speter	fprintf (stderr, " %s", str);
203618334Speter
203718334Speter      fprintf (stderr, "\n");
203818334Speter    }
203918334Speter
204018334Speter  fflush (stdout);
204118334Speter  fflush (stderr);
204218334Speter
2043169689Skan  pex = pex_init (PEX_USE_PIPES, "collect2", NULL);
2044169689Skan  if (pex == NULL)
2045169689Skan    fatal_perror ("pex_init failed");
204618334Speter
2047169689Skan  errmsg = pex_run (pex, 0, nm_file_name, real_nm_argv, NULL, NULL, &err);
2048169689Skan  if (errmsg != NULL)
204918334Speter    {
2050169689Skan      if (err != 0)
2051169689Skan	{
2052169689Skan	  errno = err;
2053260011Spfg	  fatal_perror ("%s", errmsg);
2054169689Skan	}
2055169689Skan      else
2056260011Spfg	fatal ("%s", errmsg);
205718334Speter    }
205818334Speter
2059132718Skan  int_handler  = (void (*) (int)) signal (SIGINT,  SIG_IGN);
206018334Speter#ifdef SIGQUIT
2061132718Skan  quit_handler = (void (*) (int)) signal (SIGQUIT, SIG_IGN);
206218334Speter#endif
206318334Speter
2064169689Skan  inf = pex_read_output (pex, 0);
2065169689Skan  if (inf == NULL)
2066169689Skan    fatal_perror ("can't open nm output");
206718334Speter
206818334Speter  if (debug)
206918334Speter    fprintf (stderr, "\nnm output with constructors/destructors.\n");
207018334Speter
207118334Speter  /* Read each line of nm output.  */
207250397Sobrien  while (fgets (buf, sizeof buf, inf) != (char *) 0)
207318334Speter    {
207418334Speter      int ch, ch2;
207518334Speter      char *name, *end;
207618334Speter
207718334Speter      /* If it contains a constructor or destructor name, add the name
207850397Sobrien	 to the appropriate list.  */
207918334Speter
208018334Speter      for (p = buf; (ch = *p) != '\0' && ch != '\n' && ch != '_'; p++)
208118334Speter	if (ch == ' ' && p[1] == 'U' && p[2] == ' ')
208218334Speter	  break;
208318334Speter
208418334Speter      if (ch != '_')
208518334Speter	continue;
2086132718Skan
208718334Speter      name = p;
208818334Speter      /* Find the end of the symbol name.
208950397Sobrien	 Do not include `|', because Encore nm can tack that on the end.  */
209050397Sobrien      for (end = p; (ch2 = *end) != '\0' && !ISSPACE (ch2) && ch2 != '|';
209118334Speter	   end++)
209218334Speter	continue;
209318334Speter
209418334Speter
209518334Speter      *end = '\0';
209618334Speter      switch (is_ctor_dtor (name))
209718334Speter	{
209818334Speter	case 1:
209918334Speter	  if (which_pass != PASS_LIB)
210018334Speter	    add_to_list (&constructors, name);
210118334Speter	  break;
210218334Speter
210318334Speter	case 2:
210418334Speter	  if (which_pass != PASS_LIB)
210518334Speter	    add_to_list (&destructors, name);
210618334Speter	  break;
210718334Speter
210818334Speter	case 3:
210918334Speter	  if (which_pass != PASS_LIB)
211018334Speter	    fatal ("init function found in object %s", prog_name);
211118334Speter#ifndef LD_INIT_SWITCH
211218334Speter	  add_to_list (&constructors, name);
211318334Speter#endif
211418334Speter	  break;
211518334Speter
211618334Speter	case 4:
211718334Speter	  if (which_pass != PASS_LIB)
211818334Speter	    fatal ("fini function found in object %s", prog_name);
211918334Speter#ifndef LD_FINI_SWITCH
212018334Speter	  add_to_list (&destructors, name);
212118334Speter#endif
212218334Speter	  break;
212318334Speter
212450397Sobrien	case 5:
212550397Sobrien	  if (which_pass != PASS_LIB)
212650397Sobrien	    add_to_list (&frame_tables, name);
212752284Sobrien	  break;
212850397Sobrien
212918334Speter	default:		/* not a constructor or destructor */
213018334Speter	  continue;
213118334Speter	}
213218334Speter
213318334Speter      if (debug)
213418334Speter	fprintf (stderr, "\t%s\n", buf);
213518334Speter    }
213618334Speter
213718334Speter  if (debug)
213818334Speter    fprintf (stderr, "\n");
213918334Speter
2140169689Skan  do_wait (nm_file_name, pex);
214118334Speter
214218334Speter  signal (SIGINT,  int_handler);
214318334Speter#ifdef SIGQUIT
214418334Speter  signal (SIGQUIT, quit_handler);
214518334Speter#endif
214618334Speter}
214718334Speter
214818334Speter#ifdef LDD_SUFFIX
214918334Speter
215018334Speter/* Use the List Dynamic Dependencies program to find shared libraries that
215118334Speter   the output file depends upon and their initialization/finalization
215218334Speter   routines, if any.  */
215318334Speter
2154132718Skanstatic void
2155132718Skanscan_libraries (const char *prog_name)
215618334Speter{
215718334Speter  static struct head libraries;		/* list of shared libraries found */
215818334Speter  struct id *list;
2159132718Skan  void (*int_handler) (int);
2160169689Skan#ifdef SIGQUIT
2161132718Skan  void (*quit_handler) (int);
2162169689Skan#endif
216390075Sobrien  char *real_ldd_argv[4];
216490075Sobrien  const char **ldd_argv = (const char **) real_ldd_argv;
216518334Speter  int argc = 0;
2166169689Skan  struct pex_obj *pex;
2167169689Skan  const char *errmsg;
2168169689Skan  int err;
216918334Speter  char buf[1024];
217018334Speter  FILE *inf;
217118334Speter
217250397Sobrien  /* If we do not have an `ldd', complain.  */
217318334Speter  if (ldd_file_name == 0)
217418334Speter    {
2175169689Skan      error ("cannot find 'ldd'");
217618334Speter      return;
217718334Speter    }
217818334Speter
217918334Speter  ldd_argv[argc++] = ldd_file_name;
218018334Speter  ldd_argv[argc++] = prog_name;
218118334Speter  ldd_argv[argc++] = (char *) 0;
218218334Speter
218318334Speter  /* Trace if needed.  */
218418334Speter  if (vflag)
218518334Speter    {
218690075Sobrien      const char **p_argv;
218790075Sobrien      const char *str;
218818334Speter
218918334Speter      for (p_argv = &ldd_argv[0]; (str = *p_argv) != (char *) 0; p_argv++)
219018334Speter	fprintf (stderr, " %s", str);
219118334Speter
219218334Speter      fprintf (stderr, "\n");
219318334Speter    }
219418334Speter
219518334Speter  fflush (stdout);
219618334Speter  fflush (stderr);
219718334Speter
2198169689Skan  pex = pex_init (PEX_USE_PIPES, "collect2", NULL);
2199169689Skan  if (pex == NULL)
2200169689Skan    fatal_perror ("pex_init failed");
220118334Speter
2202169689Skan  errmsg = pex_run (pex, 0, ldd_file_name, real_ldd_argv, NULL, NULL, &err);
2203169689Skan  if (errmsg != NULL)
220418334Speter    {
2205169689Skan      if (err != 0)
2206169689Skan	{
2207169689Skan	  errno = err;
2208169689Skan	  fatal_perror (errmsg);
2209169689Skan	}
2210169689Skan      else
2211169689Skan	fatal (errmsg);
221218334Speter    }
221318334Speter
2214132718Skan  int_handler  = (void (*) (int)) signal (SIGINT,  SIG_IGN);
221518334Speter#ifdef SIGQUIT
2216132718Skan  quit_handler = (void (*) (int)) signal (SIGQUIT, SIG_IGN);
221718334Speter#endif
221818334Speter
2219169689Skan  inf = pex_read_output (pex, 0);
2220169689Skan  if (inf == NULL)
2221169689Skan    fatal_perror ("can't open ldd output");
222218334Speter
222318334Speter  if (debug)
222452284Sobrien    notice ("\nldd output with constructors/destructors.\n");
222518334Speter
222618334Speter  /* Read each line of ldd output.  */
222718334Speter  while (fgets (buf, sizeof buf, inf) != (char *) 0)
222818334Speter    {
222990075Sobrien      int ch2;
223018334Speter      char *name, *end, *p = buf;
223118334Speter
223250397Sobrien      /* Extract names of libraries and add to list.  */
223318334Speter      PARSE_LDD_OUTPUT (p);
223418334Speter      if (p == 0)
223518334Speter	continue;
223618334Speter
223718334Speter      name = p;
223818334Speter      if (strncmp (name, "not found", sizeof ("not found") - 1) == 0)
223918334Speter	fatal ("dynamic dependency %s not found", buf);
224018334Speter
224150397Sobrien      /* Find the end of the symbol name.  */
2242132718Skan      for (end = p;
224350397Sobrien	   (ch2 = *end) != '\0' && ch2 != '\n' && !ISSPACE (ch2) && ch2 != '|';
224418334Speter	   end++)
224518334Speter	continue;
224618334Speter      *end = '\0';
224718334Speter
224818334Speter      if (access (name, R_OK) == 0)
2249169689Skan	add_to_list (&libraries, name);
225018334Speter      else
225118334Speter	fatal ("unable to open dynamic dependency '%s'", buf);
225218334Speter
225318334Speter      if (debug)
225418334Speter	fprintf (stderr, "\t%s\n", buf);
225518334Speter    }
225618334Speter  if (debug)
225718334Speter    fprintf (stderr, "\n");
225818334Speter
2259169689Skan  do_wait (ldd_file_name, pex);
226018334Speter
226118334Speter  signal (SIGINT,  int_handler);
226218334Speter#ifdef SIGQUIT
226318334Speter  signal (SIGQUIT, quit_handler);
226418334Speter#endif
226518334Speter
2266132718Skan  /* Now iterate through the library list adding their symbols to
226718334Speter     the list.  */
226818334Speter  for (list = libraries.first; list; list = list->next)
226918334Speter    scan_prog_file (list->name, PASS_LIB);
227018334Speter}
227118334Speter
227218334Speter#endif /* LDD_SUFFIX */
227318334Speter
227418334Speter#endif /* OBJECT_FORMAT_NONE */
227518334Speter
227618334Speter
227718334Speter/*
227818334Speter * COFF specific stuff.
227918334Speter */
228018334Speter
228118334Speter#ifdef OBJECT_FORMAT_COFF
228218334Speter
2283132718Skan#if defined (EXTENDED_COFF)
228490075Sobrien
228518334Speter#   define GCC_SYMBOLS(X)	(SYMHEADER(X).isymMax + SYMHEADER(X).iextMax)
228618334Speter#   define GCC_SYMENT		SYMR
228752284Sobrien#   define GCC_OK_SYMBOL(X)	((X).st == stProc || (X).st == stGlobal)
228818334Speter#   define GCC_SYMINC(X)	(1)
228918334Speter#   define GCC_SYMZERO(X)	(SYMHEADER(X).isymMax)
229018334Speter#   define GCC_CHECK_HDR(X)	(PSYMTAB(X) != 0)
229190075Sobrien
229218334Speter#else
229390075Sobrien
229418334Speter#   define GCC_SYMBOLS(X)	(HEADER(ldptr).f_nsyms)
229518334Speter#   define GCC_SYMENT		SYMENT
2296132718Skan#   if defined (C_WEAKEXT)
2297132718Skan#     define GCC_OK_SYMBOL(X) \
2298132718Skan       (((X).n_sclass == C_EXT || (X).n_sclass == C_WEAKEXT) && \
2299169689Skan	((X).n_scnum > N_UNDEF) && \
2300169689Skan	(aix64_flag \
2301169689Skan	 || (((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) \
2302169689Skan	     || ((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT))))
2303132718Skan#     define GCC_UNDEF_SYMBOL(X) \
2304132718Skan       (((X).n_sclass == C_EXT || (X).n_sclass == C_WEAKEXT) && \
2305169689Skan	((X).n_scnum == N_UNDEF))
2306132718Skan#   else
2307132718Skan#     define GCC_OK_SYMBOL(X) \
2308132718Skan       (((X).n_sclass == C_EXT) && \
2309169689Skan	((X).n_scnum > N_UNDEF) && \
2310169689Skan	(aix64_flag \
2311169689Skan	 || (((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) \
2312169689Skan	     || ((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT))))
2313132718Skan#     define GCC_UNDEF_SYMBOL(X) \
2314132718Skan       (((X).n_sclass == C_EXT) && ((X).n_scnum == N_UNDEF))
2315132718Skan#   endif
231618334Speter#   define GCC_SYMINC(X)	((X).n_numaux+1)
231718334Speter#   define GCC_SYMZERO(X)	0
231890075Sobrien
231990075Sobrien/* 0757 = U803XTOCMAGIC (AIX 4.3) and 0767 = U64_TOCMAGIC (AIX V5) */
232090075Sobrien#ifdef _AIX51
232150397Sobrien#   define GCC_CHECK_HDR(X) \
232250397Sobrien     ((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \
232390075Sobrien      || (HEADER (X).f_magic == 0767 && aix64_flag))
232490075Sobrien#else
232590075Sobrien#   define GCC_CHECK_HDR(X) \
232690075Sobrien     ((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \
232750397Sobrien      || (HEADER (X).f_magic == 0757 && aix64_flag))
232818334Speter#endif
232918334Speter
233090075Sobrien#endif
233190075Sobrien
2332132718Skan#ifdef COLLECT_EXPORT_LIST
2333132718Skan/* Array of standard AIX libraries which should not
2334132718Skan   be scanned for ctors/dtors.  */
2335132718Skanstatic const char *const aix_std_libs[] = {
2336132718Skan  "/unix",
2337132718Skan  "/lib/libc.a",
2338132718Skan  "/lib/libm.a",
2339132718Skan  "/lib/libc_r.a",
2340132718Skan  "/lib/libm_r.a",
2341132718Skan  "/usr/lib/libc.a",
2342132718Skan  "/usr/lib/libm.a",
2343132718Skan  "/usr/lib/libc_r.a",
2344132718Skan  "/usr/lib/libm_r.a",
2345132718Skan  "/usr/lib/threads/libc.a",
2346132718Skan  "/usr/ccs/lib/libc.a",
2347132718Skan  "/usr/ccs/lib/libm.a",
2348132718Skan  "/usr/ccs/lib/libc_r.a",
2349132718Skan  "/usr/ccs/lib/libm_r.a",
2350132718Skan  NULL
2351132718Skan};
235218334Speter
2353132718Skan/* This function checks the filename and returns 1
2354132718Skan   if this name matches the location of a standard AIX library.  */
2355132718Skanstatic int ignore_library (const char *);
2356132718Skanstatic int
2357132718Skanignore_library (const char *name)
2358132718Skan{
2359132718Skan  const char *const *p = &aix_std_libs[0];
2360132718Skan  while (*p++ != NULL)
2361132718Skan    if (! strcmp (name, *p)) return 1;
2362132718Skan  return 0;
2363132718Skan}
2364132718Skan#endif /* COLLECT_EXPORT_LIST */
2365132718Skan
2366132718Skan#if defined (HAVE_DECL_LDGETNAME) && !HAVE_DECL_LDGETNAME
2367132718Skanextern char *ldgetname (LDFILE *, GCC_SYMENT *);
2368132718Skan#endif
2369132718Skan
237018334Speter/* COFF version to scan the name list of the loaded program for
237118334Speter   the symbols g++ uses for static constructors and destructors.
237218334Speter
237318334Speter   The constructor table begins at __CTOR_LIST__ and contains a count
237418334Speter   of the number of pointers (or -1 if the constructors are built in a
237518334Speter   separate section by the linker), followed by the pointers to the
237618334Speter   constructor functions, terminated with a null pointer.  The
237718334Speter   destructor table has the same format, and begins at __DTOR_LIST__.  */
237818334Speter
237918334Speterstatic void
2380132718Skanscan_prog_file (const char *prog_name, enum pass which_pass)
238118334Speter{
238218334Speter  LDFILE *ldptr = NULL;
238318334Speter  int sym_index, sym_count;
238450397Sobrien  int is_shared = 0;
238518334Speter
238618334Speter  if (which_pass != PASS_FIRST && which_pass != PASS_OBJ)
238718334Speter    return;
238818334Speter
238950397Sobrien#ifdef COLLECT_EXPORT_LIST
239050397Sobrien  /* We do not need scanning for some standard C libraries.  */
239150397Sobrien  if (which_pass == PASS_FIRST && ignore_library (prog_name))
239250397Sobrien    return;
239318334Speter
239450397Sobrien  /* On AIX we have a loop, because there is not much difference
239550397Sobrien     between an object and an archive. This trick allows us to
239650397Sobrien     eliminate scan_libraries() function.  */
239750397Sobrien  do
239818334Speter    {
239950397Sobrien#endif
240090075Sobrien      /* Some platforms (e.g. OSF4) declare ldopen as taking a
2401169689Skan	 non-const char * filename parameter, even though it will not
2402169689Skan	 modify that string.  So we must cast away const-ness here,
2403169689Skan	 which will cause -Wcast-qual to burp.  */
240490075Sobrien      if ((ldptr = ldopen ((char *)prog_name, ldptr)) != NULL)
240518334Speter	{
240650397Sobrien	  if (! MY_ISCOFF (HEADER (ldptr).f_magic))
240750397Sobrien	    fatal ("%s: not a COFF file", prog_name);
240818334Speter
240950397Sobrien	  if (GCC_CHECK_HDR (ldptr))
241018334Speter	    {
241150397Sobrien	      sym_count = GCC_SYMBOLS (ldptr);
241250397Sobrien	      sym_index = GCC_SYMZERO (ldptr);
241318334Speter
241450397Sobrien#ifdef COLLECT_EXPORT_LIST
241550397Sobrien	      /* Is current archive member a shared object?  */
241650397Sobrien	      is_shared = HEADER (ldptr).f_flags & F_SHROBJ;
241750397Sobrien#endif
241818334Speter
241950397Sobrien	      while (sym_index < sym_count)
242050397Sobrien		{
242150397Sobrien		  GCC_SYMENT symbol;
242250397Sobrien
242350397Sobrien		  if (ldtbread (ldptr, sym_index, &symbol) <= 0)
242450397Sobrien		    break;
242550397Sobrien		  sym_index += GCC_SYMINC (symbol);
242650397Sobrien
242750397Sobrien		  if (GCC_OK_SYMBOL (symbol))
242850397Sobrien		    {
242950397Sobrien		      char *name;
243050397Sobrien
243150397Sobrien		      if ((name = ldgetname (ldptr, &symbol)) == NULL)
2432132718Skan			continue;		/* Should never happen.  */
243350397Sobrien
243418334Speter#ifdef XCOFF_DEBUGGING_INFO
243550397Sobrien		      /* All AIX function names have a duplicate entry
243650397Sobrien			 beginning with a dot.  */
243750397Sobrien		      if (*name == '.')
243850397Sobrien			++name;
243918334Speter#endif
244018334Speter
244150397Sobrien		      switch (is_ctor_dtor (name))
244250397Sobrien			{
244350397Sobrien			case 1:
244490075Sobrien			  if (! is_shared)
244590075Sobrien			    add_to_list (&constructors, name);
2446132718Skan#if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
244750397Sobrien			  if (which_pass == PASS_OBJ)
244850397Sobrien			    add_to_list (&exports, name);
244950397Sobrien#endif
245050397Sobrien			  break;
245118334Speter
245250397Sobrien			case 2:
245390075Sobrien			  if (! is_shared)
245490075Sobrien			    add_to_list (&destructors, name);
2455132718Skan#if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
245650397Sobrien			  if (which_pass == PASS_OBJ)
245750397Sobrien			    add_to_list (&exports, name);
245850397Sobrien#endif
245950397Sobrien			  break;
246018334Speter
246150397Sobrien#ifdef COLLECT_EXPORT_LIST
246250397Sobrien			case 3:
246390075Sobrien#ifndef LD_INIT_SWITCH
246450397Sobrien			  if (is_shared)
246550397Sobrien			    add_to_list (&constructors, name);
246690075Sobrien#endif
246750397Sobrien			  break;
246818334Speter
246950397Sobrien			case 4:
247090075Sobrien#ifndef LD_INIT_SWITCH
247150397Sobrien			  if (is_shared)
247250397Sobrien			    add_to_list (&destructors, name);
247390075Sobrien#endif
247450397Sobrien			  break;
247550397Sobrien#endif
247650397Sobrien
247752284Sobrien			case 5:
247852284Sobrien			  if (! is_shared)
247952284Sobrien			    add_to_list (&frame_tables, name);
2480132718Skan#if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
248190075Sobrien			  if (which_pass == PASS_OBJ)
248290075Sobrien			    add_to_list (&exports, name);
248390075Sobrien#endif
248452284Sobrien			  break;
248552284Sobrien
248650397Sobrien			default:	/* not a constructor or destructor */
248750397Sobrien#ifdef COLLECT_EXPORT_LIST
2488132718Skan			  /* Explicitly export all global symbols when
2489132718Skan			     building a shared object on AIX, but do not
2490132718Skan			     re-export symbols from another shared object
2491132718Skan			     and do not export symbols if the user
2492132718Skan			     provides an explicit export list.  */
2493132718Skan			  if (shared_obj && !is_shared
2494132718Skan			      && which_pass == PASS_OBJ && !export_flag)
2495132718Skan			    add_to_list (&exports, name);
249650397Sobrien#endif
249750397Sobrien			  continue;
249850397Sobrien			}
249950397Sobrien
250090075Sobrien		      if (debug)
250118334Speter#if !defined(EXTENDED_COFF)
250250397Sobrien			fprintf (stderr, "\tsec=%d class=%d type=%s%o %s\n",
250350397Sobrien				 symbol.n_scnum, symbol.n_sclass,
250450397Sobrien				 (symbol.n_type ? "0" : ""), symbol.n_type,
250550397Sobrien				 name);
250618334Speter#else
250750397Sobrien			fprintf (stderr,
250850397Sobrien				 "\tiss = %5d, value = %5ld, index = %5d, name = %s\n",
250950397Sobrien				 symbol.iss, (long) symbol.value, symbol.index, name);
251050397Sobrien#endif
251150397Sobrien		    }
251250397Sobrien		}
251350397Sobrien	    }
251450397Sobrien#ifdef COLLECT_EXPORT_LIST
251550397Sobrien	  else
251650397Sobrien	    {
251750397Sobrien	      /* If archive contains both 32-bit and 64-bit objects,
251850397Sobrien		 we want to skip objects in other mode so mismatch normal.  */
251918334Speter	      if (debug)
252050397Sobrien		fprintf (stderr, "%s : magic=%o aix64=%d mismatch\n",
252150397Sobrien			 prog_name, HEADER (ldptr).f_magic, aix64_flag);
252250397Sobrien	    }
252318334Speter#endif
252418334Speter	}
252550397Sobrien      else
252650397Sobrien	{
252750397Sobrien	  fatal ("%s: cannot open as COFF file", prog_name);
252850397Sobrien	}
252950397Sobrien#ifdef COLLECT_EXPORT_LIST
253050397Sobrien      /* On AIX loop continues while there are more members in archive.  */
253118334Speter    }
253250397Sobrien  while (ldclose (ldptr) == FAILURE);
253350397Sobrien#else
253450397Sobrien  /* Otherwise we simply close ldptr.  */
253518334Speter  (void) ldclose(ldptr);
253650397Sobrien#endif
253718334Speter}
2538117395Skan#endif /* OBJECT_FORMAT_COFF */
253918334Speter
254050397Sobrien#ifdef COLLECT_EXPORT_LIST
254150397Sobrien/* Given a library name without "lib" prefix, this function
254250397Sobrien   returns a full library name including a path.  */
254350397Sobrienstatic char *
2544132718Skanresolve_lib_name (const char *name)
254550397Sobrien{
254650397Sobrien  char *lib_buf;
254750397Sobrien  int i, j, l = 0;
2548146895Skan  /* Library extensions for AIX dynamic linking.  */
2549146895Skan  const char * const libexts[2] = {"a", "so"};
255018336Speter
255150397Sobrien  for (i = 0; libpaths[i]; i++)
255250397Sobrien    if (libpaths[i]->max_len > l)
255350397Sobrien      l = libpaths[i]->max_len;
255418336Speter
255550397Sobrien  lib_buf = xmalloc (l + strlen(name) + 10);
255650397Sobrien
255750397Sobrien  for (i = 0; libpaths[i]; i++)
255850397Sobrien    {
255950397Sobrien      struct prefix_list *list = libpaths[i]->plist;
256050397Sobrien      for (; list; list = list->next)
256118334Speter	{
256290075Sobrien	  /* The following lines are needed because path_prefix list
256390075Sobrien	     may contain directories both with trailing '/' and
256490075Sobrien	     without it.  */
256590075Sobrien	  const char *p = "";
256690075Sobrien	  if (list->prefix[strlen(list->prefix)-1] != '/')
256790075Sobrien	    p = "/";
2568146895Skan	  for (j = 0; j < 2; j++)
256918334Speter	    {
2570132718Skan	      sprintf (lib_buf, "%s%slib%s.%s",
2571146895Skan		       list->prefix, p, name,
2572146895Skan		       libexts[(j + aixrtl_flag) % 2]);
2573146895Skan	      if (debug) fprintf (stderr, "searching for: %s\n", lib_buf);
257450397Sobrien	      if (file_exists (lib_buf))
257518334Speter		{
2576146895Skan		  if (debug) fprintf (stderr, "found: %s\n", lib_buf);
257750397Sobrien		  return (lib_buf);
257818334Speter		}
257918334Speter	    }
258018334Speter	}
258118334Speter    }
258250397Sobrien  if (debug)
258350397Sobrien    fprintf (stderr, "not found\n");
258450397Sobrien  else
258590075Sobrien    fatal ("library lib%s not found", name);
258650397Sobrien  return (NULL);
258718334Speter}
2588117395Skan#endif /* COLLECT_EXPORT_LIST */
2589