*** empty log message ***
From-SVN: r529
This commit is contained in:
parent
fd9c4f832d
commit
ed5b946218
612
gcc/collect2.c
612
gcc/collect2.c
@ -29,15 +29,17 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include "gstddef.h"
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#define COLLECT
|
||||
|
||||
#include "config.h"
|
||||
@ -45,15 +47,72 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#ifndef __STDC__
|
||||
#include "gvarargs.h"
|
||||
#define generic char
|
||||
#define PROTO(x) ()
|
||||
#define const
|
||||
|
||||
#else
|
||||
#include "stdarg.h"
|
||||
#include "gstdarg.h"
|
||||
#define generic void
|
||||
#define PROTO(x) x
|
||||
#endif
|
||||
|
||||
#ifdef USG
|
||||
#define vfork fork
|
||||
#endif
|
||||
|
||||
#ifndef R_OK
|
||||
#define R_OK 4
|
||||
#define W_OK 2
|
||||
#define X_OK 1
|
||||
#endif
|
||||
|
||||
/* On MSDOS, write temp files in current dir
|
||||
because there's no place else we can expect to use. */
|
||||
#if __MSDOS__
|
||||
#ifndef P_tmpdir
|
||||
#define P_tmpdir "./"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* On certain systems, we have code that works by scanning the object file
|
||||
directly. But this code uses system-specific header files and library
|
||||
functions, so turn it off in a cross-compiler. */
|
||||
|
||||
#ifdef CROSS_COMPILE
|
||||
#undef OBJECT_FORMAT_COFF
|
||||
#undef OBJECT_FORMAT_ROSE
|
||||
#endif
|
||||
|
||||
/* If we can't use a special method, use the ordinary one:
|
||||
run nm to find what symbols are present.
|
||||
In a cross-compiler, this means you need a cross nm,
|
||||
but that isn't quite as unpleasant as special headers. */
|
||||
|
||||
#if !defined (OBJECT_FORMAT_COFF) && !defined (OBJECT_FORMAT_ROSE)
|
||||
#define OBJECT_FORMAT_NONE
|
||||
#endif
|
||||
|
||||
#ifdef OBJECT_FORMAT_COFF
|
||||
|
||||
#include <a.out.h>
|
||||
#include <ar.h>
|
||||
|
||||
#ifdef UMAX
|
||||
#include <sgs.h>
|
||||
#endif
|
||||
|
||||
#ifdef _AIX
|
||||
#define ISCOFF(magic) \
|
||||
((magic) == U802WRMAGIC || (magic) == U802ROMAGIC || (magic) == U802TOCMAGIC)
|
||||
#endif
|
||||
|
||||
#if defined (_AIX) || defined (USG)
|
||||
#undef FREAD
|
||||
#undef FWRITE
|
||||
#endif
|
||||
|
||||
#include <ldfcn.h>
|
||||
|
||||
#endif /* OBJECT_FORMAT_COFF */
|
||||
|
||||
#ifdef OBJECT_FORMAT_ROSE
|
||||
|
||||
#ifdef _OSF_SOURCE
|
||||
@ -69,25 +128,17 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include <mach_o_header.h>
|
||||
#include <mach_o_vals.h>
|
||||
#include <mach_o_types.h>
|
||||
|
||||
#endif /* OBJECT_FORMAT_ROSE */
|
||||
|
||||
#ifdef OBJECT_FORMAT_NONE
|
||||
|
||||
/* Default flags to pass to nm. */
|
||||
#ifndef NM_FLAGS
|
||||
#define NM_FLAGS "-p"
|
||||
#endif
|
||||
|
||||
#ifdef USG
|
||||
#define vfork fork
|
||||
#endif
|
||||
|
||||
/* On MSDOS, write temp files in current dir
|
||||
because there's no place else we can expect to use. */
|
||||
#if __MSDOS__
|
||||
#ifndef P_tmpdir
|
||||
#define P_tmpdir "./"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* OBJECT_FORMAT_NONE */
|
||||
|
||||
/* Linked lists of constructor and destructor names. */
|
||||
|
||||
@ -112,7 +163,9 @@ enum pass {
|
||||
PASS_SECOND /* with constructors linked in */
|
||||
};
|
||||
|
||||
#ifndef NO_SYS_SIGLIST
|
||||
extern char *sys_siglist[];
|
||||
#endif
|
||||
extern char *version_string;
|
||||
|
||||
static int vflag; /* true if -v */
|
||||
@ -129,27 +182,27 @@ static char *nm_file_name; /* pathname of nm */
|
||||
static struct head constructors; /* list of constructors found */
|
||||
static struct head destructors; /* list of destructors found */
|
||||
|
||||
extern char *getenv PROTO(( const char * ));
|
||||
extern char *mktemp PROTO(( char * ));
|
||||
extern int vfork PROTO(( void ));
|
||||
static void add_to_list PROTO(( struct head *headp, char *name ));
|
||||
static void scan_prog_file PROTO(( char *, enum pass ));
|
||||
static void fork_execute PROTO(( char *, char **argv ));
|
||||
static void do_wait PROTO(( char * ));
|
||||
static void write_c_file PROTO(( FILE *, char * ));
|
||||
static void my_exit PROTO(( int ));
|
||||
static void handler PROTO(( int ));
|
||||
static void maybe_unlink PROTO(( char * ));
|
||||
static void choose_temp_base PROTO(( void ));
|
||||
|
||||
generic *xcalloc PROTO(( size_t, size_t ));
|
||||
generic *xmalloc PROTO(( size_t ));
|
||||
extern char *getenv ();
|
||||
extern char *mktemp ();
|
||||
extern int vfork ();
|
||||
static void add_to_list ();
|
||||
static void scan_prog_file ();
|
||||
static void fork_execute ();
|
||||
static void do_wait ();
|
||||
static void write_c_file ();
|
||||
static void my_exit ();
|
||||
static void handler ();
|
||||
static void maybe_unlink ();
|
||||
static void choose_temp_base ();
|
||||
|
||||
generic *xcalloc ();
|
||||
generic *xmalloc ();
|
||||
|
||||
|
||||
#if !defined(HAVE_STRERROR) && !defined(_OSF_SOURCE)
|
||||
|
||||
char *strerror (e)
|
||||
char *
|
||||
strerror (e)
|
||||
int e;
|
||||
{
|
||||
extern char *sys_errlist[];
|
||||
@ -175,10 +228,10 @@ static void
|
||||
my_exit (status)
|
||||
int status;
|
||||
{
|
||||
if (c_file[0])
|
||||
if (c_file != 0 && c_file[0])
|
||||
maybe_unlink (c_file);
|
||||
|
||||
if (o_file[0])
|
||||
if (o_file != 0 && o_file[0])
|
||||
maybe_unlink (o_file);
|
||||
|
||||
exit (status);
|
||||
@ -309,17 +362,15 @@ handler (signo)
|
||||
maybe_unlink (o_file);
|
||||
|
||||
signal (signo, SIG_DFL);
|
||||
|
||||
fatal ("Caught signal %d [%s]", signo, sys_siglist[signo]);
|
||||
kill (getpid (), signo);
|
||||
}
|
||||
|
||||
|
||||
generic *
|
||||
xcalloc (size1, size2)
|
||||
size_t size1, size2;
|
||||
int size1, size2;
|
||||
{
|
||||
generic *ptr = calloc (size1, size2);
|
||||
generic *ptr = (generic *) calloc (size1, size2);
|
||||
if (ptr)
|
||||
return ptr;
|
||||
|
||||
@ -329,9 +380,9 @@ xcalloc (size1, size2)
|
||||
|
||||
generic *
|
||||
xmalloc (size)
|
||||
size_t size;
|
||||
int size;
|
||||
{
|
||||
generic *ptr = malloc (size);
|
||||
generic *ptr = (generic *) malloc (size);
|
||||
if (ptr)
|
||||
return ptr;
|
||||
|
||||
@ -339,12 +390,68 @@ xmalloc (size)
|
||||
return (generic *)0;
|
||||
}
|
||||
|
||||
/* Make a copy of a string INPUT with size SIZE. */
|
||||
|
||||
char *
|
||||
savestring (input, size)
|
||||
char *input;
|
||||
int size;
|
||||
{
|
||||
char *output = (char *) xmalloc (size + 1);
|
||||
strcpy (output, input);
|
||||
return output;
|
||||
}
|
||||
|
||||
/* Decide whether the given symbol is:
|
||||
a constructor (1), a destructor (2), or neither (0). */
|
||||
|
||||
static int
|
||||
is_ctor_dtor (s)
|
||||
char *s;
|
||||
{
|
||||
struct names { char *name; int len; int ret; int two_underscores; };
|
||||
|
||||
register struct names *p;
|
||||
register int ch;
|
||||
register char *orig_s = s;
|
||||
|
||||
static struct names special[] = {
|
||||
#ifdef NO_DOLLAR_IN_LABEL
|
||||
{ "GLOBAL_.I.", sizeof ("GLOBAL_.I.")-1, 1, 0 },
|
||||
{ "GLOBAL_.D.", sizeof ("GLOBAL_.D.")-1, 2, 0 },
|
||||
#else
|
||||
{ "GLOBAL_$I$", sizeof ("GLOBAL_$I$")-1, 1, 0 },
|
||||
{ "GLOBAL_$D$", sizeof ("GLOBAL_$I$")-1, 2, 0 },
|
||||
#endif
|
||||
{ "sti__", sizeof ("sti__")-1, 1, 1 },
|
||||
{ "std__", sizeof ("std__")-1, 2, 1 },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
while ((ch = *s) == '_')
|
||||
++s;
|
||||
|
||||
if (s == orig_s)
|
||||
return 0;
|
||||
|
||||
for (p = &special[0]; p->len > 0; p++)
|
||||
{
|
||||
if (ch == p->name[0]
|
||||
&& (!p->two_underscores || ((s - orig_s) >= 2))
|
||||
&& strncmp(s, p->name, p->len) == 0)
|
||||
{
|
||||
return p->ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Compute a string to use as the base of all temporary file names.
|
||||
It is substituted for %g. */
|
||||
|
||||
static void
|
||||
choose_temp_base PROTO((void))
|
||||
choose_temp_base ()
|
||||
{
|
||||
char *base = getenv ("TMPDIR");
|
||||
int len;
|
||||
@ -388,16 +495,16 @@ main (argc, argv)
|
||||
FILE *outf;
|
||||
char *ld_file_name;
|
||||
char *c_file_name;
|
||||
char *B_option;
|
||||
char *p;
|
||||
char *prefix;
|
||||
char **c_argv = (char **) xcalloc (sizeof (char *), argc+7);
|
||||
char **c_ptr = c_argv;
|
||||
char **c_argv;
|
||||
char **c_ptr;
|
||||
char **ld1_argv = (char **) xcalloc (sizeof (char *), argc+2);
|
||||
char **ld1 = ld1_argv;
|
||||
char **ld2_argv = (char **) xcalloc (sizeof (char *), argc+5);
|
||||
char **ld2 = ld2_argv;
|
||||
int first_file;
|
||||
int num_c_args = argc+7;
|
||||
int len;
|
||||
int clen;
|
||||
|
||||
@ -406,6 +513,21 @@ main (argc, argv)
|
||||
vflag = 1;
|
||||
#endif
|
||||
|
||||
p = (char *) getenv ("COLLECT_GCC_OPTIONS");
|
||||
if (p)
|
||||
while (*p)
|
||||
{
|
||||
char *q = p;
|
||||
while (*q && *q != ' ') q++;
|
||||
if (*p == '-' && (p[1] == 'm' || p[1] == 'f'))
|
||||
num_c_args++;
|
||||
|
||||
if (*q) q++;
|
||||
p = q;
|
||||
}
|
||||
|
||||
c_ptr = c_argv = (char **) xcalloc (sizeof (char *), num_c_args);
|
||||
|
||||
if (argc < 2)
|
||||
fatal ("no arguments");
|
||||
|
||||
@ -466,9 +588,7 @@ main (argc, argv)
|
||||
#endif
|
||||
|
||||
ld_file_name = xcalloc (len + sizeof ("real-ld"), 1);
|
||||
c_file_name = xcalloc (clen + sizeof ("gcc"), 1);
|
||||
nm_file_name = xcalloc (len + sizeof ("gnm"), 1);
|
||||
B_option = xcalloc (len + sizeof ("-B"), 1);
|
||||
|
||||
memcpy (ld_file_name, prefix, len);
|
||||
strcpy (ld_file_name + len, "real-ld");
|
||||
@ -486,23 +606,28 @@ main (argc, argv)
|
||||
}
|
||||
}
|
||||
|
||||
memcpy (c_file_name, prefix, len);
|
||||
strcpy (c_file_name + len, "gcc");
|
||||
if (access (c_file_name, X_OK) < 0)
|
||||
c_file_name = getenv ("COLLECT_GCC");
|
||||
if (c_file_name == 0 || c_file_name[0] != '/')
|
||||
{
|
||||
#ifdef STANDARD_BIN_PREFIX
|
||||
strcpy (c_file_name, STANDARD_BIN_PREFIX);
|
||||
strcat (c_file_name, "gcc");
|
||||
c_file_name = xcalloc (clen + sizeof ("gcc"), 1);
|
||||
memcpy (c_file_name, prefix, len);
|
||||
strcpy (c_file_name + len, "gcc");
|
||||
if (access (c_file_name, X_OK) < 0)
|
||||
#endif
|
||||
{
|
||||
#ifdef STANDARD_EXEC_PREFIX
|
||||
strcpy (c_file_name, STANDARD_EXEC_PREFIX);
|
||||
#ifdef STANDARD_BIN_PREFIX
|
||||
strcpy (c_file_name, STANDARD_BIN_PREFIX);
|
||||
strcat (c_file_name, "gcc");
|
||||
if (access (c_file_name, X_OK) < 0)
|
||||
#endif
|
||||
{
|
||||
strcpy (c_file_name, "gcc");
|
||||
#ifdef STANDARD_EXEC_PREFIX
|
||||
strcpy (c_file_name, STANDARD_EXEC_PREFIX);
|
||||
strcat (c_file_name, "gcc");
|
||||
if (access (c_file_name, X_OK) < 0)
|
||||
#endif
|
||||
{
|
||||
strcpy (c_file_name, "gcc");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -523,9 +648,6 @@ main (argc, argv)
|
||||
}
|
||||
}
|
||||
|
||||
strcpy (B_option, "-B");
|
||||
strcpy (B_option + sizeof ("-B") - 1, prefix);
|
||||
|
||||
*ld1++ = *ld2++ = "ld";
|
||||
|
||||
/* Make temp file names. */
|
||||
@ -534,13 +656,21 @@ main (argc, argv)
|
||||
o_file = xcalloc (temp_filename_length + sizeof (".o"), 1);
|
||||
sprintf (c_file, "%s.c", temp_filename);
|
||||
sprintf (o_file, "%s.o", temp_filename);
|
||||
*c_ptr++ = "gcc";
|
||||
*c_ptr++ = c_file_name;
|
||||
*c_ptr++ = "-c";
|
||||
*c_ptr++ = "-o";
|
||||
*c_ptr++ = o_file;
|
||||
|
||||
/* !!! When GCC calls collect2,
|
||||
it does not know whether it is calling collect2 or ld.
|
||||
So collect2 cannot meaningfully understand any options
|
||||
except those ld understands.
|
||||
If you propose to make GCC pass some other option,
|
||||
just imagine what will happen if ld is really ld!!! */
|
||||
|
||||
/* Parse arguments. Remember output file spec, pass the rest to ld. */
|
||||
/* After the first file, put in the c++ rt0 */
|
||||
/* After the first file, put in the c++ rt0. */
|
||||
|
||||
first_file = 1;
|
||||
while ((arg = *++argv) != (char *)0)
|
||||
{
|
||||
@ -559,22 +689,6 @@ main (argc, argv)
|
||||
}
|
||||
break;
|
||||
|
||||
/* pass -f<xxx>, -B<xxx>, -b<xxx>, -V<xxx>, and -m<xxx>
|
||||
options to gcc. This allows options to be passed
|
||||
that affect search rules, and the size of pointers. */
|
||||
case 'b':
|
||||
case 'B':
|
||||
case 'f':
|
||||
case 'm':
|
||||
case 'V':
|
||||
if (arg[1] != '\0')
|
||||
{
|
||||
ld1--;
|
||||
ld2--;
|
||||
*c_ptr++ = arg;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
outfile = (arg[2] == '\0') ? argv[1] : &arg[2];
|
||||
break;
|
||||
@ -599,13 +713,26 @@ main (argc, argv)
|
||||
}
|
||||
}
|
||||
|
||||
*c_ptr++ = B_option;
|
||||
/* Get any options that the upper GCC wants to pass to the sub-GCC. */
|
||||
p = (char *) getenv ("COLLECT_GCC_OPTIONS");
|
||||
if (p)
|
||||
while (*p)
|
||||
{
|
||||
char *q = p;
|
||||
while (*q && *q != ' ') q++;
|
||||
if (*p == '-' && (p[1] == 'm' || p[1] == 'f'))
|
||||
*c_ptr++ = savestring (p, q - p);
|
||||
|
||||
if (*q) q++;
|
||||
p = q;
|
||||
}
|
||||
|
||||
*c_ptr++ = c_file;
|
||||
*c_ptr = *ld1 = *ld2 = (char *)0;
|
||||
|
||||
if (vflag)
|
||||
{
|
||||
fprintf (stderr, "GNU COLLECT2 version %s", version_string);
|
||||
fprintf (stderr, "collect2 version %s", version_string);
|
||||
#ifdef TARGET_VERSION
|
||||
TARGET_VERSION;
|
||||
#endif
|
||||
@ -614,13 +741,31 @@ main (argc, argv)
|
||||
|
||||
if (debug)
|
||||
{
|
||||
fprintf (stderr, "prefix = %s\n", prefix);
|
||||
fprintf (stderr, "ld_file_name = %s\n", ld_file_name);
|
||||
fprintf (stderr, "c_file_name = %s\n", c_file_name);
|
||||
fprintf (stderr, "nm_file_name = %s\n", nm_file_name);
|
||||
fprintf (stderr, "B_option = %s\n", B_option);
|
||||
fprintf (stderr, "c_file = %s\n", c_file);
|
||||
fprintf (stderr, "o_file = %s\n", o_file);
|
||||
char *ptr;
|
||||
fprintf (stderr, "prefix = %s\n", prefix);
|
||||
fprintf (stderr, "ld_file_name = %s\n", ld_file_name);
|
||||
fprintf (stderr, "c_file_name = %s\n", c_file_name);
|
||||
fprintf (stderr, "nm_file_name = %s\n", nm_file_name);
|
||||
fprintf (stderr, "c_file = %s\n", c_file);
|
||||
fprintf (stderr, "o_file = %s\n", o_file);
|
||||
|
||||
ptr = getenv ("COLLECT_GCC_OPTIONS");
|
||||
if (ptr)
|
||||
fprintf (stderr, "COLLECT_GCC_OPTIONS = %s\n", ptr);
|
||||
|
||||
ptr = getenv ("COLLECT_GCC");
|
||||
if (ptr)
|
||||
fprintf (stderr, "COLLECT_GCC = %s\n", ptr);
|
||||
|
||||
ptr = getenv ("COMPILER_PATH");
|
||||
if (ptr)
|
||||
fprintf (stderr, "COMPILER_PATH = %s\n", ptr);
|
||||
|
||||
ptr = getenv ("LIBRARY_PATH");
|
||||
if (ptr)
|
||||
fprintf (stderr, "LIBRARY_PATH = %s\n", ptr);
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
/* Load the program, searching all libraries.
|
||||
@ -688,21 +833,28 @@ do_wait (prog)
|
||||
wait (&status);
|
||||
if (status)
|
||||
{
|
||||
int sig = WTERMSIG (status);
|
||||
int sig = status & 0x7F;
|
||||
int ret;
|
||||
|
||||
if (sig != -1 && sig != 0)
|
||||
{
|
||||
#ifdef NO_SYS_SIGLIST
|
||||
error ("%s terminated with signal %d %s",
|
||||
prog,
|
||||
sig,
|
||||
(status & 0200) ? ", core dumped" : "");
|
||||
#else
|
||||
error ("%s terminated with signal %d [%s]%s",
|
||||
prog,
|
||||
sig,
|
||||
sys_siglist[sig],
|
||||
(status & 0200) ? ", core dumped" : "");
|
||||
#endif
|
||||
|
||||
my_exit (127);
|
||||
}
|
||||
|
||||
ret = WEXITSTATUS (status);
|
||||
ret = ((status & 0xFF00) >> 8);
|
||||
if (ret != -1 && ret != 0)
|
||||
{
|
||||
error ("%s returned %d exit status", prog, ret);
|
||||
@ -720,8 +872,8 @@ fork_execute (prog, argv)
|
||||
char **argv;
|
||||
{
|
||||
int pid;
|
||||
void (*int_handler) PROTO((int));
|
||||
void (*quit_handler) PROTO((int));
|
||||
void (*int_handler) ();
|
||||
void (*quit_handler) ();
|
||||
|
||||
if (vflag || debug)
|
||||
{
|
||||
@ -748,8 +900,8 @@ fork_execute (prog, argv)
|
||||
fatal_perror ("Execute %s", prog);
|
||||
}
|
||||
|
||||
int_handler = (void (*)PROTO((int)))signal (SIGINT, SIG_IGN);
|
||||
quit_handler = (void (*)PROTO((int)))signal (SIGQUIT, SIG_IGN);
|
||||
int_handler = (void (*) ())signal (SIGINT, SIG_IGN);
|
||||
quit_handler = (void (*) ())signal (SIGQUIT, SIG_IGN);
|
||||
|
||||
do_wait (prog);
|
||||
|
||||
@ -832,18 +984,18 @@ write_c_file (stream, name)
|
||||
|
||||
fprintf (stream, "typedef void entry_pt();\n\n");
|
||||
|
||||
write_list_with_asm (stream, "entry_pt ", constructors);
|
||||
write_list_with_asm (stream, "entry_pt ", constructors.first);
|
||||
|
||||
fprintf (stream, "\nentry_pt * __CTOR_LIST__[] = {\n");
|
||||
fprintf (stream, "\t(entry_pt *) %d,\n", constructors.number);
|
||||
write_list (stream, "\t", constructors);
|
||||
write_list (stream, "\t", constructors.first);
|
||||
fprintf (stream, "\t0\n};\n\n");
|
||||
|
||||
write_list_with_asm (stream, "entry_pt ", destructors);
|
||||
write_list_with_asm (stream, "entry_pt ", destructors.first);
|
||||
|
||||
fprintf (stream, "\nentry_pt * __DTOR_LIST__[] = {\n");
|
||||
fprintf (stream, "\t(entry_pt *) %d,\n", destructors.number);
|
||||
write_list (stream, "\t", destructors);
|
||||
write_list (stream, "\t", destructors.first);
|
||||
fprintf (stream, "\t0\n};\n\n");
|
||||
|
||||
fprintf (stream, "extern entry_pt __main;\n");
|
||||
@ -851,11 +1003,10 @@ write_c_file (stream, name)
|
||||
}
|
||||
|
||||
|
||||
#ifndef OBJECT_FORMAT_ROSE
|
||||
#ifdef OBJECT_FORMAT_NONE
|
||||
|
||||
/* OSF/rose specific version to scan the name list of the loaded
|
||||
program for the symbols g++ uses for static constructors and
|
||||
destructors.
|
||||
/* Generic version to scan the name list of the loaded program for
|
||||
the symbols g++ uses for static constructors and destructors.
|
||||
|
||||
The constructor table begins at __CTOR_LIST__ and contains a count
|
||||
of the number of pointers (or -1 if the constructors are built in a
|
||||
@ -868,8 +1019,8 @@ scan_prog_file (prog_name, which_pass)
|
||||
char *prog_name;
|
||||
enum pass which_pass;
|
||||
{
|
||||
void (*int_handler) PROTO((int));
|
||||
void (*quit_handler) PROTO((int));
|
||||
void (*int_handler) ();
|
||||
void (*quit_handler) ();
|
||||
char *nm_argv[4];
|
||||
int pid;
|
||||
int argc = 0;
|
||||
@ -880,12 +1031,12 @@ scan_prog_file (prog_name, which_pass)
|
||||
if (which_pass != PASS_FIRST)
|
||||
return;
|
||||
|
||||
nm_argv[ argc++ ] = "nm";
|
||||
nm_argv[argc++] = "nm";
|
||||
if (NM_FLAGS[0] != '\0')
|
||||
nm_argv[ argc++ ] = NM_FLAGS;
|
||||
nm_argv[argc++] = NM_FLAGS;
|
||||
|
||||
nm_argv[ argc++ ] = prog_name;
|
||||
nm_argv[ argc++ ] = (char *)0;
|
||||
nm_argv[argc++] = prog_name;
|
||||
nm_argv[argc++] = (char *)0;
|
||||
|
||||
if (pipe (pipe_fd) < 0)
|
||||
fatal_perror ("pipe");
|
||||
@ -932,8 +1083,8 @@ scan_prog_file (prog_name, which_pass)
|
||||
}
|
||||
|
||||
/* Parent context from here on. */
|
||||
int_handler = (void (*)PROTO((int)))signal (SIGINT, SIG_IGN);
|
||||
quit_handler = (void (*)PROTO((int)))signal (SIGQUIT, SIG_IGN);
|
||||
int_handler = (void (*) ())signal (SIGINT, SIG_IGN);
|
||||
quit_handler = (void (*) ())signal (SIGQUIT, SIG_IGN);
|
||||
|
||||
if (close (pipe_fd[1]) < 0)
|
||||
fatal_perror ("Close (%d)", pipe_fd[1]);
|
||||
@ -945,8 +1096,7 @@ scan_prog_file (prog_name, which_pass)
|
||||
while (fgets (buf, sizeof buf, inf) != (char *)0)
|
||||
{
|
||||
int ch, ch2;
|
||||
char *start;
|
||||
char *end;
|
||||
char *name, *end;
|
||||
|
||||
/* If it contains a constructor or destructor name, add the name
|
||||
to the appropriate list. */
|
||||
@ -956,42 +1106,29 @@ scan_prog_file (prog_name, which_pass)
|
||||
|
||||
if (ch == '\0' || ch == '\n')
|
||||
continue;
|
||||
|
||||
start = p;
|
||||
while ((ch = *p) == '_') /* skip any extra '_' inserted */
|
||||
p++;
|
||||
|
||||
for (end = p; (ch2 = *end) != '\0' && !isspace (ch2); end++)
|
||||
;
|
||||
|
||||
name = p;
|
||||
/* Find the end of the symbol name.
|
||||
Don't include `|', because Encore nm can tack that on the end. */
|
||||
for (end = p; (ch2 = *end) != '\0' && !isspace (ch2) && ch2 != '|';
|
||||
end++)
|
||||
continue;
|
||||
|
||||
*end = '\0';
|
||||
if (ch == 'G')
|
||||
switch (is_ctor_dtor (name))
|
||||
{
|
||||
if (! strncmp (p, "GLOBAL_$I$", 10))
|
||||
add_to_list (&constructors, p-1);
|
||||
case 1:
|
||||
add_to_list (&constructors, name);
|
||||
break;
|
||||
|
||||
else if (! strncmp (p, "GLOBAL_$D$", 10))
|
||||
add_to_list (&destructors, p-1);
|
||||
case 2:
|
||||
add_to_list (&destructors, name);
|
||||
break;
|
||||
|
||||
else /* not a constructor or destructor */
|
||||
continue;
|
||||
default: /* not a constructor or destructor */
|
||||
continue;
|
||||
}
|
||||
|
||||
else if (ch == 's' && (p - start) >= 2)
|
||||
{
|
||||
if (! strncmp (p, "sti__", 5))
|
||||
add_to_list (&constructors, p-2);
|
||||
|
||||
else if (! strncmp (p, "std__", 5))
|
||||
add_to_list (&destructors, p-2);
|
||||
|
||||
else /* not a constructor or destructor */
|
||||
continue;
|
||||
}
|
||||
|
||||
else
|
||||
continue;
|
||||
|
||||
if (debug)
|
||||
fprintf (stderr, "\t%s\n", buf);
|
||||
}
|
||||
@ -1008,7 +1145,115 @@ scan_prog_file (prog_name, which_pass)
|
||||
signal (SIGQUIT, quit_handler);
|
||||
}
|
||||
|
||||
#endif /* !OBJECT_FORMAT_ROSE */
|
||||
#endif /* OBJECT_FORMAT_NONE */
|
||||
|
||||
|
||||
/*
|
||||
* COFF specific stuff.
|
||||
*/
|
||||
|
||||
#ifdef OBJECT_FORMAT_COFF
|
||||
|
||||
#if defined(EXTENDED_COFF)
|
||||
# define GCC_SYMBOLS(X) (SYMHEADER(X).isymMax+SYMHEADER(X).iextMax)
|
||||
# define GCC_SYMENT SYMR
|
||||
# define GCC_OK_SYMBOL(X) ((X).st == stProc && (X).sc == scText)
|
||||
# define GCC_SYMINC(X) (1)
|
||||
# define GCC_SYMZERO(X) (SYMHEADER(X).isymMax)
|
||||
#else
|
||||
# define GCC_SYMBOLS(X) (HEADER(ldptr).f_nsyms)
|
||||
# define GCC_SYMENT SYMENT
|
||||
# define GCC_OK_SYMBOL(X) \
|
||||
(((X).n_sclass == C_EXT) && \
|
||||
(((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) || \
|
||||
((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT)))
|
||||
# define GCC_SYMINC(X) ((X).n_numaux+1)
|
||||
# define GCC_SYMZERO(X) 0
|
||||
#endif
|
||||
|
||||
extern char *ldgetname ();
|
||||
|
||||
/* COFF version to scan the name list of the loaded program for
|
||||
the symbols g++ uses for static constructors and destructors.
|
||||
|
||||
The constructor table begins at __CTOR_LIST__ and contains a count
|
||||
of the number of pointers (or -1 if the constructors are built in a
|
||||
separate section by the linker), followed by the pointers to the
|
||||
constructor functions, terminated with a null pointer. The
|
||||
destructor table has the same format, and begins at __DTOR_LIST__. */
|
||||
|
||||
static void
|
||||
scan_prog_file (prog_name, which_pass)
|
||||
char *prog_name;
|
||||
enum pass which_pass;
|
||||
{
|
||||
LDFILE *ldptr;
|
||||
int sym_index, sym_count;
|
||||
|
||||
if (which_pass != PASS_FIRST)
|
||||
return;
|
||||
|
||||
if ((ldptr = ldopen (prog_name, ldptr)) == NULL)
|
||||
fatal ("%s: can't open as COFF file", prog_name);
|
||||
|
||||
if (!ISCOFF (HEADER(ldptr).f_magic))
|
||||
fatal ("%s: not a COFF file", prog_name);
|
||||
|
||||
sym_count = GCC_SYMBOLS (ldptr);
|
||||
sym_index = GCC_SYMZERO (ldptr);
|
||||
while (sym_index < sym_count)
|
||||
{
|
||||
GCC_SYMENT symbol;
|
||||
|
||||
if (ldtbread (ldptr, sym_index, &symbol) <= 0)
|
||||
break;
|
||||
sym_index += GCC_SYMINC (symbol);
|
||||
|
||||
if (GCC_OK_SYMBOL (symbol))
|
||||
{
|
||||
char *name;
|
||||
|
||||
if ((name = ldgetname (ldptr, &symbol)) == NULL)
|
||||
continue; /* should never happen */
|
||||
|
||||
#ifdef _AIX
|
||||
/* All AIX function names begin with a dot. */
|
||||
if (*name++ != '.')
|
||||
continue;
|
||||
#endif
|
||||
|
||||
switch (is_ctor_dtor (name))
|
||||
{
|
||||
case 1:
|
||||
add_to_list (&constructors, name);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
add_to_list (&destructors, name);
|
||||
break;
|
||||
|
||||
default: /* not a constructor or destructor */
|
||||
continue;
|
||||
}
|
||||
|
||||
#if !defined(EXTENDED_COFF)
|
||||
if (debug)
|
||||
fprintf (stderr, "\tsec=%d class=%d type=%s%o %s\n",
|
||||
symbol.n_scnum, symbol.n_sclass,
|
||||
(symbol.n_type ? "0" : ""), symbol.n_type,
|
||||
name);
|
||||
#else
|
||||
if (debug)
|
||||
fprintf (stderr, "\tiss = %5d, value = %5d, index = %5d, name = %s\n",
|
||||
symbol.iss, symbol.value, symbol.index, name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
(void) ldclose(ldptr);
|
||||
}
|
||||
|
||||
#endif /* OBJECT_FORMAT_COFF */
|
||||
|
||||
|
||||
/*
|
||||
@ -1023,7 +1268,7 @@ typedef union load_union
|
||||
{
|
||||
ldc_header_t hdr; /* common header */
|
||||
load_cmd_map_command_t map; /* map indexing other load cmds */
|
||||
interpreter_command_t iprtr; /* interpereter pathname */
|
||||
interpreter_command_t iprtr; /* interpreter pathname */
|
||||
strings_command_t str; /* load commands strings section */
|
||||
region_command_t region; /* region load command */
|
||||
reloc_command_t reloc; /* relocation section */
|
||||
@ -1055,31 +1300,21 @@ struct file_info
|
||||
int use_mmap; /* != 0 if mmap'ed */
|
||||
};
|
||||
|
||||
extern int decode_mach_o_hdr PROTO(( void *in_bufp,
|
||||
size_t in_bufsize,
|
||||
unsigned long hdr_version,
|
||||
mo_header_t *headerp ));
|
||||
extern int decode_mach_o_hdr ();
|
||||
|
||||
extern int encode_mach_o_hdr PROTO(( mo_header_t *headerp,
|
||||
void *out_bufp,
|
||||
size_t out_bufsize ));
|
||||
extern int encode_mach_o_hdr ();
|
||||
|
||||
static void bad_header PROTO(( int status ));
|
||||
static void bad_header ();
|
||||
|
||||
static void print_header PROTO(( mo_header_t *hdr_ptr ));
|
||||
static void print_header ();
|
||||
|
||||
static void print_load_command PROTO(( load_union_t *load_hdr,
|
||||
size_t offset,
|
||||
int number ));
|
||||
static void print_load_command ();
|
||||
|
||||
static void add_func_table PROTO(( mo_header_t *hdr_p,
|
||||
load_all_t *load_array,
|
||||
symbol_info_t *sym,
|
||||
int type ));
|
||||
static void add_func_table ();
|
||||
|
||||
static struct file_info *read_file PROTO(( char *, int, int ));
|
||||
static struct file_info *read_file ();
|
||||
|
||||
static void end_file PROTO(( struct file_info * ));
|
||||
static void end_file ();
|
||||
|
||||
|
||||
/* OSF/rose specific version to scan the name list of the loaded
|
||||
@ -1203,7 +1438,7 @@ scan_prog_file (prog_name, which_pass)
|
||||
|
||||
if (debug)
|
||||
{
|
||||
char *kind = "uknown";
|
||||
char *kind = "unknown";
|
||||
|
||||
switch (load_hdr->sym.symc_kind)
|
||||
{
|
||||
@ -1219,7 +1454,7 @@ scan_prog_file (prog_name, which_pass)
|
||||
if (load_hdr->sym.symc_kind != SYMC_DEFINED_SYMBOLS)
|
||||
continue;
|
||||
|
||||
str_sect = load_array[ load_hdr->sym.symc_strings_section ].section;
|
||||
str_sect = load_array[load_hdr->sym.symc_strings_section].section;
|
||||
if (str_sect == (char *)0)
|
||||
fatal ("string section missing");
|
||||
|
||||
@ -1231,49 +1466,36 @@ scan_prog_file (prog_name, which_pass)
|
||||
{
|
||||
symbol_info_t *sym = ((symbol_info_t *) load_cmd->section) + i;
|
||||
char *name = sym->si_name.symbol_name + str_sect;
|
||||
char *name_start = name;
|
||||
|
||||
if (name[0] != '_')
|
||||
continue;
|
||||
|
||||
while (*++name == '_') /* skip any extra '_' inserted */
|
||||
;
|
||||
|
||||
if (rw)
|
||||
{
|
||||
if (*name != 'm' || (name - name_start) < 2
|
||||
|| strcmp (name, "main"))
|
||||
char *n = name;
|
||||
while (*n == '_')
|
||||
++n;
|
||||
if (*n != 'm' || (n - name) < 2 || strcmp (n, "main"))
|
||||
continue;
|
||||
|
||||
main_sym = sym;
|
||||
}
|
||||
|
||||
else if (*name == 'G')
|
||||
{
|
||||
if (! strncmp (name, "GLOBAL_$I$", 10))
|
||||
add_to_list (&constructors, name_start);
|
||||
|
||||
else if (! strncmp (name, "GLOBAL_$D$", 10))
|
||||
add_to_list (&destructors, name_start);
|
||||
|
||||
else /* not a constructor or destructor */
|
||||
continue;
|
||||
}
|
||||
|
||||
else if (*name == 's' && (name - name_start) > 2)
|
||||
{
|
||||
if (! strncmp (name, "sti__", 5))
|
||||
add_to_list (&constructors, name_start);
|
||||
|
||||
else if (! strncmp (name, "std__", 5))
|
||||
add_to_list (&destructors, name_start);
|
||||
|
||||
else /* not a constructor or destructor */
|
||||
continue;
|
||||
}
|
||||
|
||||
else
|
||||
continue;
|
||||
{
|
||||
switch (is_ctor_dtor (name))
|
||||
{
|
||||
case 1:
|
||||
add_to_list (&constructors, name);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
add_to_list (&destructors, name);
|
||||
break;
|
||||
|
||||
default: /* not a constructor or destructor */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug)
|
||||
fprintf (stderr, "\ttype = 0x%.4x, sc = 0x%.2x, flags = 0x%.8x, name = %.30s\n",
|
||||
@ -1369,7 +1591,7 @@ scan_prog_file (prog_name, which_pass)
|
||||
|
||||
|
||||
/* Add a function table to the load commands to call a function
|
||||
on initition or termination of the process. */
|
||||
on initiation or termination of the process. */
|
||||
|
||||
static void
|
||||
add_func_table (hdr_p, load_array, sym, type)
|
||||
|
Loading…
Reference in New Issue
Block a user